mirror of
https://github.com/oxalica/nil.git
synced 2024-11-23 03:57:06 +03:00
Track Attr source info in Ty
This commit is contained in:
parent
dfffc45c35
commit
3fa46cc956
@ -1,4 +1,5 @@
|
||||
use crate::def::{AstPtr, BindingValue, Expr, NameKind};
|
||||
use crate::ty::AttrSource;
|
||||
use crate::{FileId, FilePos, TyDatabase};
|
||||
use builtin::{BuiltinKind, ALL_BUILTINS};
|
||||
use either::Either::{Left, Right};
|
||||
@ -61,14 +62,13 @@ impl From<BuiltinKind> for CompletionItemKind {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NameKind> for CompletionItemKind {
|
||||
type Error = ();
|
||||
fn try_from(k: NameKind) -> Result<Self, Self::Error> {
|
||||
impl From<NameKind> for CompletionItemKind {
|
||||
fn from(k: NameKind) -> Self {
|
||||
match k {
|
||||
NameKind::LetIn => Ok(Self::LetBinding),
|
||||
NameKind::RecAttrset => Ok(Self::Field),
|
||||
NameKind::Param | NameKind::PatField => Ok(Self::Param),
|
||||
NameKind::PlainAttrset => Err(()),
|
||||
NameKind::LetIn => Self::LetBinding,
|
||||
NameKind::RecAttrset => Self::Field,
|
||||
NameKind::Param | NameKind::PatField => Self::Param,
|
||||
NameKind::PlainAttrset => Self::Field,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -203,10 +203,7 @@ fn complete_expr(
|
||||
label: text.clone(),
|
||||
source_range,
|
||||
replace: text.clone(),
|
||||
kind: module[*name]
|
||||
.kind
|
||||
.try_into()
|
||||
.expect("NonRecAttrset names are not definitions"),
|
||||
kind: module[*name].kind.into(),
|
||||
brief: None,
|
||||
doc: None,
|
||||
})
|
||||
@ -342,12 +339,15 @@ fn complete_attrpath(
|
||||
set.iter()
|
||||
// We should not report current incomplete definition.
|
||||
// This is covered by `no_incomplete_field`.
|
||||
.filter(|(name, _)| **name != current_input)
|
||||
.map(|(name, ty)| CompletionItem {
|
||||
.filter(|(name, _, _)| **name != current_input)
|
||||
.map(|(name, ty, src)| CompletionItem {
|
||||
label: name.clone(),
|
||||
source_range,
|
||||
replace: name.clone(),
|
||||
kind: CompletionItemKind::Field,
|
||||
kind: match src {
|
||||
AttrSource::Unknown => CompletionItemKind::Field,
|
||||
AttrSource::Name(name) => module[name].kind.into(),
|
||||
},
|
||||
brief: Some(infer.display_ty(ty).to_string()),
|
||||
doc: None,
|
||||
}),
|
||||
@ -506,7 +506,7 @@ mod tests {
|
||||
check(
|
||||
"{ foo }@b: b.f$0",
|
||||
"foo",
|
||||
expect!["(Field) { foo }@b: b.foo"],
|
||||
expect!["(Param) { foo }@b: b.foo"],
|
||||
);
|
||||
}
|
||||
|
||||
@ -619,12 +619,12 @@ mod tests {
|
||||
check(
|
||||
"let f = { foo }: foo.bar; in f { f$0 }",
|
||||
"foo",
|
||||
expect!["(Field) let f = { foo }: foo.bar; in f { foo }"],
|
||||
expect!["(Param) let f = { foo }: foo.bar; in f { foo }"],
|
||||
);
|
||||
check(
|
||||
"let f = { foo }: foo.bar; in f { f$0.bar }",
|
||||
"foo",
|
||||
expect!["(Field) let f = { foo }: foo.bar; in f { foo.bar }"],
|
||||
expect!["(Param) let f = { foo }: foo.bar; in f { foo.bar }"],
|
||||
);
|
||||
check(
|
||||
"let f = { foo }: foo.bar; in f { foo.b$0 }",
|
||||
|
@ -78,7 +78,7 @@ impl fmt::Display for TyDisplay<'_> {
|
||||
} else {
|
||||
"{".fmt(f)?;
|
||||
let mut first = true;
|
||||
for (name, ty) in set.iter().take(MAX_FIELD_CNT) {
|
||||
for (name, ty, _src) in set.iter().take(MAX_FIELD_CNT) {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
|
@ -52,7 +52,7 @@ impl TyKind {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct Attrset(BTreeMap<SmolStr, Ty>);
|
||||
pub struct Attrset(BTreeMap<SmolStr, (Ty, AttrSource)>);
|
||||
|
||||
impl Attrset {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
@ -64,11 +64,33 @@ impl Attrset {
|
||||
}
|
||||
|
||||
pub fn get(&self, field: &str) -> Option<Ty> {
|
||||
self.0.get(field).copied()
|
||||
Some(self.0.get(field)?.0)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&SmolStr, Ty)> + '_ {
|
||||
self.0.iter().map(|(k, &v)| (k, v))
|
||||
pub fn get_src(&self, field: &str) -> Option<AttrSource> {
|
||||
Some(self.0.get(field)?.1)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&SmolStr, Ty, AttrSource)> + '_ {
|
||||
self.0.iter().map(|(k, (ty, src))| (k, *ty, *src))
|
||||
}
|
||||
}
|
||||
|
||||
/// The source of an Attr.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AttrSource {
|
||||
/// Unknown source, possibly generated or referenced.
|
||||
Unknown,
|
||||
/// Defined by a name.
|
||||
Name(NameId),
|
||||
// TODO: Builtins.
|
||||
}
|
||||
|
||||
impl AttrSource {
|
||||
fn unify(&mut self, rhs: Self) {
|
||||
if *self == Self::Unknown {
|
||||
*self = rhs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +213,8 @@ impl<'db> InferCtx<'db> {
|
||||
self.unify(name_ty, default_ty);
|
||||
}
|
||||
let field_text = self.module[name].text.clone();
|
||||
let param_field_ty = self.infer_set_field(param_ty, field_text);
|
||||
let param_field_ty =
|
||||
self.infer_set_field(param_ty, field_text, AttrSource::Name(name));
|
||||
self.unify(param_field_ty, name_ty);
|
||||
}
|
||||
}
|
||||
@ -298,7 +321,7 @@ impl<'db> InferCtx<'db> {
|
||||
self.unify_kind(attr_ty, TyKind::String);
|
||||
match &self.module[attr] {
|
||||
Expr::Literal(Literal::String(key)) => {
|
||||
self.infer_set_field(set_ty, key.clone())
|
||||
self.infer_set_field(set_ty, key.clone(), AttrSource::Unknown)
|
||||
}
|
||||
_ => {
|
||||
self.unify_kind(set_ty, TyKind::Attrset(Attrset::default()));
|
||||
@ -348,7 +371,7 @@ impl<'db> InferCtx<'db> {
|
||||
Expr::LetAttrset(bindings) => {
|
||||
let set = self.infer_bindings(bindings);
|
||||
let set_ty = TyKind::Attrset(set).intern(self);
|
||||
self.infer_set_field(set_ty, "body".into())
|
||||
self.infer_set_field(set_ty, "body".into(), AttrSource::Unknown)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -366,11 +389,12 @@ impl<'db> InferCtx<'db> {
|
||||
BindingValue::Inherit(e) | BindingValue::Expr(e) => self.infer_expr(e),
|
||||
BindingValue::InheritFrom(from_expr) => {
|
||||
let from_ty = self.ty_for_expr(from_expr);
|
||||
self.infer_set_field(from_ty, name_text.clone())
|
||||
self.infer_set_field(from_ty, name_text.clone(), AttrSource::Name(name))
|
||||
}
|
||||
};
|
||||
self.unify(name_ty, value_ty);
|
||||
fields.insert(name_text, value_ty);
|
||||
let src = AttrSource::Name(name);
|
||||
fields.insert(name_text, (value_ty, src));
|
||||
}
|
||||
|
||||
for &(k, v) in bindings.dynamics.iter() {
|
||||
@ -382,17 +406,21 @@ impl<'db> InferCtx<'db> {
|
||||
Attrset(fields)
|
||||
}
|
||||
|
||||
fn infer_set_field(&mut self, set_ty: Ty, field: SmolStr) -> Ty {
|
||||
fn infer_set_field(&mut self, set_ty: Ty, field: SmolStr, src: AttrSource) -> Ty {
|
||||
let next_ty = Ty(self.table.len() as u32);
|
||||
match self.table.get_mut(set_ty.0) {
|
||||
TyKind::Attrset(set) => match set.0.entry(field) {
|
||||
Entry::Occupied(ent) => return *ent.get(),
|
||||
Entry::Occupied(mut ent) => {
|
||||
let (ty, prev_src) = ent.get_mut();
|
||||
prev_src.unify(src);
|
||||
return *ty;
|
||||
}
|
||||
Entry::Vacant(ent) => {
|
||||
ent.insert(next_ty);
|
||||
ent.insert((next_ty, src));
|
||||
}
|
||||
},
|
||||
k @ TyKind::Unknown => {
|
||||
*k = TyKind::Attrset(Attrset([(field, next_ty)].into_iter().collect()));
|
||||
*k = TyKind::Attrset(Attrset([(field, (next_ty, src))].into_iter().collect()));
|
||||
}
|
||||
TyKind::Bool
|
||||
| TyKind::Int
|
||||
@ -438,13 +466,15 @@ impl<'db> InferCtx<'db> {
|
||||
self.unify(a2, b2);
|
||||
}
|
||||
(TyKind::Attrset(a), TyKind::Attrset(b)) => {
|
||||
for (field, ty) in b.0 {
|
||||
for (field, (ty2, src2)) in b.0 {
|
||||
match a.0.entry(field) {
|
||||
Entry::Vacant(ent) => {
|
||||
ent.insert(ty);
|
||||
ent.insert((ty2, src2));
|
||||
}
|
||||
Entry::Occupied(ent) => {
|
||||
self.unify(*ent.get(), ty);
|
||||
Entry::Occupied(mut ent) => {
|
||||
let (ty1, src1) = ent.get_mut();
|
||||
src1.unify(src2);
|
||||
self.unify(*ty1, ty2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -533,7 +563,7 @@ impl<'a> TableCompresser<'a> {
|
||||
*b = self.intern(*b);
|
||||
}
|
||||
TyKind::Attrset(set) => {
|
||||
for ty in set.0.values_mut() {
|
||||
for (ty, _) in set.0.values_mut() {
|
||||
*ty = self.intern(*ty);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::{DefDatabase, FileId};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use fmt::TyDisplay;
|
||||
pub use infer::{Attrset, InferenceResult, Ty, TyKind};
|
||||
pub use infer::{AttrSource, Attrset, InferenceResult, Ty, TyKind};
|
||||
|
||||
#[salsa::query_group(TyDatabaseStorage)]
|
||||
pub trait TyDatabase: DefDatabase {
|
||||
|
Loading…
Reference in New Issue
Block a user