7907: Autoderef with visibility r=cynecx a=cynecx

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/7841.

I am not sure about the general approach here. Right now this simply tries to check whether the autoderef candidate is reachable from the current module. ~~However this doesn't exactly work with traits (see the `tests::macros::infer_derive_clone_in_core` test, which fails right now).~~ see comment below

Refs:

- `rustc_typeck` checking fields: 66ec64ccf3/compiler/rustc_typeck/src/check/expr.rs (L1610) 


r? @flodiebold

Co-authored-by: cynecx <me@cynecx.net>
This commit is contained in:
bors[bot] 2021-03-24 22:37:48 +00:00 committed by GitHub
commit d7db38fff9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 250 additions and 37 deletions

View file

@ -443,27 +443,47 @@ impl<'a> InferenceContext<'a> {
},
)
.find_map(|derefed_ty| {
let def_db = self.db.upcast();
let module = self.resolver.module();
let is_visible = |field_id: &FieldId| {
module
.map(|mod_id| {
self.db.field_visibilities(field_id.parent)[field_id.local_id]
.is_visible_from(def_db, mod_id)
})
.unwrap_or(true)
};
match canonicalized.decanonicalize_ty(derefed_ty.value).interned(&Interner) {
TyKind::Tuple(_, substs) => {
name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned())
}
TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
self.db.struct_data(*s).variant_data.field(name).map(|local_id| {
let field = FieldId { parent: (*s).into(), local_id };
let local_id = self.db.struct_data(*s).variant_data.field(name)?;
let field = FieldId { parent: (*s).into(), local_id };
if is_visible(&field) {
self.write_field_resolution(tgt_expr, field);
self.db.field_types((*s).into())[field.local_id]
.clone()
.subst(&parameters)
})
Some(
self.db.field_types((*s).into())[field.local_id]
.clone()
.subst(&parameters),
)
} else {
None
}
}
TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
self.db.union_data(*u).variant_data.field(name).map(|local_id| {
let field = FieldId { parent: (*u).into(), local_id };
let local_id = self.db.union_data(*u).variant_data.field(name)?;
let field = FieldId { parent: (*u).into(), local_id };
if is_visible(&field) {
self.write_field_resolution(tgt_expr, field);
self.db.field_types((*u).into())[field.local_id]
.clone()
.subst(&parameters)
})
Some(
self.db.field_types((*u).into())[field.local_id]
.clone()
.subst(&parameters),
)
} else {
None
}
}
_ => None,
}
@ -828,6 +848,7 @@ impl<'a> InferenceContext<'a> {
self.trait_env.clone(),
krate,
&traits_in_scope,
self.resolver.module(),
method_name,
)
});