fix: attribute completion

This commit is contained in:
Shunsuke Shibayama 2023-10-22 14:48:35 +09:00
parent 37f026bb0c
commit ac0ca49724
6 changed files with 175 additions and 8 deletions

View file

@ -2,4 +2,6 @@
.x = 1
.C = Class { .x = Int }
.C = Class { .a = Int }
.C.
func self = self

View file

@ -1,4 +1,4 @@
b = import "b"
{neighbor;} = import "b"
print! neighbor, b.x, b.C.new({ .x = 1 }).x
print! neighbor, b.x, b.C.new({ .a = 1 }).a

View file

@ -35,18 +35,27 @@ fn test_completion() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Server::bind_fake_client();
client.request_initialize()?;
client.notify_initialized()?;
let uri = NormalizedUrl::from_file_path(Path::new(FILE_A).canonicalize()?)?;
let uri_a = NormalizedUrl::from_file_path(Path::new(FILE_A).canonicalize()?)?;
let uri_b = NormalizedUrl::from_file_path(Path::new(FILE_B).canonicalize()?)?;
client.notify_open(FILE_A)?;
client.notify_change(uri.clone().raw(), add_char(2, 0, "x"))?;
client.notify_change(uri.clone().raw(), add_char(2, 1, "."))?;
let resp = client.request_completion(uri.raw(), 2, 2, ".")?;
client.notify_change(uri_a.clone().raw(), add_char(2, 0, "x"))?;
client.notify_change(uri_a.clone().raw(), add_char(2, 1, "."))?;
let resp = client.request_completion(uri_a.raw(), 2, 2, ".")?;
if let Some(CompletionResponse::Array(items)) = resp {
assert!(items.len() >= 40);
assert!(items.iter().any(|item| item.label == "abs"));
Ok(())
} else {
Err(format!("not items: {resp:?}").into())
return Err(format!("not items: {resp:?}").into());
}
client.notify_open(FILE_B)?;
client.notify_change(uri_b.clone().raw(), add_char(6, 20, "."))?;
let resp = client.request_completion(uri_b.raw(), 6, 21, ".")?;
if let Some(CompletionResponse::Array(items)) = resp {
assert!(items.iter().any(|item| item.label == "a"));
} else {
return Err(format!("not items: {resp:?}").into());
}
Ok(())
}
#[test]

View file

@ -1110,6 +1110,8 @@ impl Context {
let t = mem::take(acc.ref_mut_t().unwrap());
let mut dereferencer = Dereferencer::simple(self, qnames, acc);
*acc.ref_mut_t().unwrap() = dereferencer.deref_tyvar(t)?;
} else {
acc.ref_mut_t().unwrap().dereference();
}
if let hir::Accessor::Attr(attr) = acc {
self.resolve_expr_t(&mut attr.obj, qnames)?;

View file

@ -3757,6 +3757,90 @@ impl Type {
_ => set! { self.clone() },
}
}
pub fn dereference(&mut self) {
match self {
Self::FreeVar(fv) if fv.is_linked() => {
let new = fv.crack().clone();
*self = new;
self.dereference();
}
Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init();
}
// TODO: T(:> X, <: Y).dereference()
Self::Refinement(refine) => refine.t.dereference(),
Self::Ref(t) => {
t.dereference();
}
Self::RefMut { before, after } => {
before.dereference();
if let Some(after) = after.as_mut() {
after.dereference();
}
}
Self::Subr(sub) => {
for nd in sub.non_default_params.iter_mut() {
nd.typ_mut().dereference();
}
if let Some(var) = sub.var_params.as_mut() {
var.typ_mut().dereference();
}
for d in sub.default_params.iter_mut() {
d.typ_mut().dereference();
}
sub.return_t.dereference();
}
Self::Callable { param_ts, return_t } => {
for t in param_ts.iter_mut() {
t.dereference();
}
return_t.dereference();
}
Self::And(l, r) | Self::Or(l, r) => {
l.dereference();
r.dereference();
}
Self::Not(ty) => {
ty.dereference();
}
Self::Bounded { sub, sup } => {
sub.dereference();
sup.dereference();
}
Self::Quantified(ty) | Self::Structural(ty) => {
ty.dereference();
}
Self::Record(rec) => {
for v in rec.values_mut() {
v.dereference();
}
}
Self::NamedTuple(r) => {
for (_, v) in r.iter_mut() {
v.dereference();
}
}
Self::Proj { lhs, .. } => {
lhs.dereference();
}
Self::ProjCall { lhs, args, .. } => {
lhs.dereference();
for arg in args.iter_mut() {
arg.dereference();
}
}
Self::Poly { params, .. } => {
for param in params.iter_mut() {
param.dereference();
}
}
Self::Guard(guard) => {
guard.to.dereference();
}
_ => {}
}
}
}
pub struct ReplaceTable<'t> {

View file

@ -1543,6 +1543,76 @@ impl TyParam {
_ => set! {},
}
}
pub fn dereference(&mut self) {
match self {
Self::FreeVar(fv) if fv.is_linked() => {
let new = fv.crack().clone();
*self = new;
self.dereference();
}
Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init();
}
Self::Type(t) => t.dereference(),
Self::Value(ValueObj::Type(t)) => t.typ_mut().dereference(),
Self::App { args, .. } => {
for arg in args {
arg.dereference();
}
}
Self::Proj { obj, .. } => obj.dereference(),
Self::ProjCall { obj, args, .. } => {
obj.dereference();
for arg in args {
arg.dereference();
}
}
Self::Array(ts) | Self::Tuple(ts) => {
for t in ts {
t.dereference();
}
}
Self::Set(ts) => {
let ts_ = std::mem::take(ts);
*ts = ts_
.into_iter()
.map(|mut t| {
t.dereference();
t
})
.collect();
}
Self::Dict(ts) => {
let ts_ = std::mem::take(ts);
*ts = ts_
.into_iter()
.map(|(mut k, mut v)| {
k.dereference();
v.dereference();
(k, v)
})
.collect();
}
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
for (_, t) in rec.iter_mut() {
t.dereference();
}
}
Self::Lambda(lambda) => {
for t in &mut lambda.body {
t.dereference();
}
}
Self::UnaryOp { val, .. } => val.dereference(),
Self::BinOp { lhs, rhs, .. } => {
lhs.dereference();
rhs.dereference();
}
Self::Erased(t) => t.dereference(),
_ => {}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]