mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-03 18:29:00 +00:00
fix: attribute completion
This commit is contained in:
parent
37f026bb0c
commit
ac0ca49724
6 changed files with 175 additions and 8 deletions
|
@ -2,4 +2,6 @@
|
|||
|
||||
.x = 1
|
||||
|
||||
.C = Class { .x = Int }
|
||||
.C = Class { .a = Int }
|
||||
.C.
|
||||
func self = self
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue