Skip to content

Commit d7db38f

Browse files
bors[bot]cynecx
andauthored
Merge #7907
7907: Autoderef with visibility r=cynecx a=cynecx Fixes #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: https://github.com/rust-lang/rust/blob/66ec64ccf31883cd2c28d045912a76179c0c6ed2/compiler/rustc_typeck/src/check/expr.rs#L1610 r? @flodiebold Co-authored-by: cynecx <[email protected]>
2 parents 9d81618 + d1156bb commit d7db38f

File tree

10 files changed

+250
-37
lines changed

10 files changed

+250
-37
lines changed

crates/hir/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,7 @@ impl Type {
19991999
env,
20002000
krate,
20012001
traits_in_scope,
2002+
None,
20022003
name,
20032004
method_resolution::LookupMode::MethodCall,
20042005
|ty, it| match it {
@@ -2031,6 +2032,7 @@ impl Type {
20312032
env,
20322033
krate,
20332034
traits_in_scope,
2035+
None,
20342036
name,
20352037
method_resolution::LookupMode::Path,
20362038
|ty, it| callback(ty, it.into()),

crates/hir_def/src/db.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
item_tree::ItemTree,
1717
lang_item::{LangItemTarget, LangItems},
1818
nameres::DefMap,
19+
visibility::{self, Visibility},
1920
AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId,
2021
FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId,
2122
StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
@@ -131,6 +132,12 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
131132

132133
#[salsa::invoke(ImportMap::import_map_query)]
133134
fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
135+
136+
#[salsa::invoke(visibility::field_visibilities_query)]
137+
fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>;
138+
139+
#[salsa::invoke(visibility::function_visibility_query)]
140+
fn function_visibility(&self, def: FunctionId) -> Visibility;
134141
}
135142

136143
fn crate_def_map_wait(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {

crates/hir_def/src/visibility.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
//! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`).
22
3+
use std::sync::Arc;
4+
35
use hir_expand::{hygiene::Hygiene, InFile};
6+
use la_arena::ArenaMap;
47
use syntax::ast;
58

69
use crate::{
710
db::DefDatabase,
811
nameres::DefMap,
912
path::{ModPath, PathKind},
10-
ModuleId,
13+
resolver::HasResolver,
14+
FunctionId, HasModule, LocalFieldId, ModuleDefId, ModuleId, VariantId,
1115
};
1216

1317
/// Visibility of an item, not yet resolved.
@@ -190,3 +194,29 @@ impl Visibility {
190194
}
191195
}
192196
}
197+
198+
/// Resolve visibility of all specific fields of a struct or union variant.
199+
pub(crate) fn field_visibilities_query(
200+
db: &dyn DefDatabase,
201+
variant_id: VariantId,
202+
) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
203+
let var_data = match variant_id {
204+
VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
205+
VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
206+
VariantId::EnumVariantId(it) => {
207+
db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
208+
}
209+
};
210+
let resolver = variant_id.module(db).resolver(db);
211+
let mut res = ArenaMap::default();
212+
for (field_id, field_data) in var_data.fields().iter() {
213+
res.insert(field_id, field_data.visibility.resolve(db, &resolver))
214+
}
215+
Arc::new(res)
216+
}
217+
218+
/// Resolve visibility of a function.
219+
pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
220+
let resolver = ModuleDefId::from(def).module(db).unwrap().resolver(db);
221+
db.function_data(def).visibility.resolve(db, &resolver)
222+
}

crates/hir_ty/src/infer/expr.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -443,27 +443,47 @@ impl<'a> InferenceContext<'a> {
443443
},
444444
)
445445
.find_map(|derefed_ty| {
446+
let def_db = self.db.upcast();
447+
let module = self.resolver.module();
448+
let is_visible = |field_id: &FieldId| {
449+
module
450+
.map(|mod_id| {
451+
self.db.field_visibilities(field_id.parent)[field_id.local_id]
452+
.is_visible_from(def_db, mod_id)
453+
})
454+
.unwrap_or(true)
455+
};
446456
match canonicalized.decanonicalize_ty(derefed_ty.value).interned(&Interner) {
447457
TyKind::Tuple(_, substs) => {
448458
name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned())
449459
}
450460
TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
451-
self.db.struct_data(*s).variant_data.field(name).map(|local_id| {
452-
let field = FieldId { parent: (*s).into(), local_id };
461+
let local_id = self.db.struct_data(*s).variant_data.field(name)?;
462+
let field = FieldId { parent: (*s).into(), local_id };
463+
if is_visible(&field) {
453464
self.write_field_resolution(tgt_expr, field);
454-
self.db.field_types((*s).into())[field.local_id]
455-
.clone()
456-
.subst(&parameters)
457-
})
465+
Some(
466+
self.db.field_types((*s).into())[field.local_id]
467+
.clone()
468+
.subst(&parameters),
469+
)
470+
} else {
471+
None
472+
}
458473
}
459474
TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
460-
self.db.union_data(*u).variant_data.field(name).map(|local_id| {
461-
let field = FieldId { parent: (*u).into(), local_id };
475+
let local_id = self.db.union_data(*u).variant_data.field(name)?;
476+
let field = FieldId { parent: (*u).into(), local_id };
477+
if is_visible(&field) {
462478
self.write_field_resolution(tgt_expr, field);
463-
self.db.field_types((*u).into())[field.local_id]
464-
.clone()
465-
.subst(&parameters)
466-
})
479+
Some(
480+
self.db.field_types((*u).into())[field.local_id]
481+
.clone()
482+
.subst(&parameters),
483+
)
484+
} else {
485+
None
486+
}
467487
}
468488
_ => None,
469489
}
@@ -828,6 +848,7 @@ impl<'a> InferenceContext<'a> {
828848
self.trait_env.clone(),
829849
krate,
830850
&traits_in_scope,
851+
self.resolver.module(),
831852
method_name,
832853
)
833854
});

crates/hir_ty/src/infer/path.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ impl<'a> InferenceContext<'a> {
230230
self.trait_env.clone(),
231231
krate,
232232
&traits_in_scope,
233+
None,
233234
Some(name),
234235
method_resolution::LookupMode::Path,
235236
move |_ty, item| {

crates/hir_ty/src/method_resolution.rs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ pub(crate) fn lookup_method(
296296
env: Arc<TraitEnvironment>,
297297
krate: CrateId,
298298
traits_in_scope: &FxHashSet<TraitId>,
299+
visible_from_module: Option<ModuleId>,
299300
name: &Name,
300301
) -> Option<(Ty, FunctionId)> {
301302
iterate_method_candidates(
@@ -304,6 +305,7 @@ pub(crate) fn lookup_method(
304305
env,
305306
krate,
306307
&traits_in_scope,
308+
visible_from_module,
307309
Some(name),
308310
LookupMode::MethodCall,
309311
|ty, f| match f {
@@ -334,6 +336,7 @@ pub fn iterate_method_candidates<T>(
334336
env: Arc<TraitEnvironment>,
335337
krate: CrateId,
336338
traits_in_scope: &FxHashSet<TraitId>,
339+
visible_from_module: Option<ModuleId>,
337340
name: Option<&Name>,
338341
mode: LookupMode,
339342
mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
@@ -345,6 +348,7 @@ pub fn iterate_method_candidates<T>(
345348
env,
346349
krate,
347350
traits_in_scope,
351+
visible_from_module,
348352
name,
349353
mode,
350354
&mut |ty, item| {
@@ -362,6 +366,7 @@ fn iterate_method_candidates_impl(
362366
env: Arc<TraitEnvironment>,
363367
krate: CrateId,
364368
traits_in_scope: &FxHashSet<TraitId>,
369+
visible_from_module: Option<ModuleId>,
365370
name: Option<&Name>,
366371
mode: LookupMode,
367372
callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
@@ -399,6 +404,7 @@ fn iterate_method_candidates_impl(
399404
env.clone(),
400405
krate,
401406
traits_in_scope,
407+
visible_from_module,
402408
name,
403409
callback,
404410
) {
@@ -415,6 +421,7 @@ fn iterate_method_candidates_impl(
415421
env,
416422
krate,
417423
traits_in_scope,
424+
visible_from_module,
418425
name,
419426
callback,
420427
)
@@ -428,6 +435,7 @@ fn iterate_method_candidates_with_autoref(
428435
env: Arc<TraitEnvironment>,
429436
krate: CrateId,
430437
traits_in_scope: &FxHashSet<TraitId>,
438+
visible_from_module: Option<ModuleId>,
431439
name: Option<&Name>,
432440
mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
433441
) -> bool {
@@ -438,6 +446,7 @@ fn iterate_method_candidates_with_autoref(
438446
env.clone(),
439447
krate,
440448
&traits_in_scope,
449+
visible_from_module,
441450
name,
442451
&mut callback,
443452
) {
@@ -454,6 +463,7 @@ fn iterate_method_candidates_with_autoref(
454463
env.clone(),
455464
krate,
456465
&traits_in_scope,
466+
visible_from_module,
457467
name,
458468
&mut callback,
459469
) {
@@ -470,6 +480,7 @@ fn iterate_method_candidates_with_autoref(
470480
env,
471481
krate,
472482
&traits_in_scope,
483+
visible_from_module,
473484
name,
474485
&mut callback,
475486
) {
@@ -485,14 +496,23 @@ fn iterate_method_candidates_by_receiver(
485496
env: Arc<TraitEnvironment>,
486497
krate: CrateId,
487498
traits_in_scope: &FxHashSet<TraitId>,
499+
visible_from_module: Option<ModuleId>,
488500
name: Option<&Name>,
489501
mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
490502
) -> bool {
491503
// We're looking for methods with *receiver* type receiver_ty. These could
492504
// be found in any of the derefs of receiver_ty, so we have to go through
493505
// that.
494506
for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
495-
if iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) {
507+
if iterate_inherent_methods(
508+
self_ty,
509+
db,
510+
name,
511+
Some(receiver_ty),
512+
krate,
513+
visible_from_module,
514+
&mut callback,
515+
) {
496516
return true;
497517
}
498518
}
@@ -519,10 +539,12 @@ fn iterate_method_candidates_for_self_ty(
519539
env: Arc<TraitEnvironment>,
520540
krate: CrateId,
521541
traits_in_scope: &FxHashSet<TraitId>,
542+
visible_from_module: Option<ModuleId>,
522543
name: Option<&Name>,
523544
mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
524545
) -> bool {
525-
if iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
546+
if iterate_inherent_methods(self_ty, db, name, None, krate, visible_from_module, &mut callback)
547+
{
526548
return true;
527549
}
528550
iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback)
@@ -559,7 +581,9 @@ fn iterate_trait_method_candidates(
559581
// iteration
560582
let mut known_implemented = false;
561583
for (_name, item) in data.items.iter() {
562-
if !is_valid_candidate(db, name, receiver_ty, *item, self_ty) {
584+
// Don't pass a `visible_from_module` down to `is_valid_candidate`,
585+
// since only inherent methods should be included into visibility checking.
586+
if !is_valid_candidate(db, name, receiver_ty, *item, self_ty, None) {
563587
continue;
564588
}
565589
if !known_implemented {
@@ -583,6 +607,7 @@ fn iterate_inherent_methods(
583607
name: Option<&Name>,
584608
receiver_ty: Option<&Canonical<Ty>>,
585609
krate: CrateId,
610+
visible_from_module: Option<ModuleId>,
586611
callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
587612
) -> bool {
588613
let def_crates = match self_ty.value.def_crates(db, krate) {
@@ -594,7 +619,7 @@ fn iterate_inherent_methods(
594619

595620
for &impl_def in impls.for_self_ty(&self_ty.value) {
596621
for &item in db.impl_data(impl_def).items.iter() {
597-
if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
622+
if !is_valid_candidate(db, name, receiver_ty, item, self_ty, visible_from_module) {
598623
continue;
599624
}
600625
// we have to check whether the self type unifies with the type
@@ -639,6 +664,7 @@ fn is_valid_candidate(
639664
receiver_ty: Option<&Canonical<Ty>>,
640665
item: AssocItemId,
641666
self_ty: &Canonical<Ty>,
667+
visible_from_module: Option<ModuleId>,
642668
) -> bool {
643669
match item {
644670
AssocItemId::FunctionId(m) => {
@@ -660,6 +686,13 @@ fn is_valid_candidate(
660686
return false;
661687
}
662688
}
689+
if let Some(from_module) = visible_from_module {
690+
if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) {
691+
cov_mark::hit!(autoderef_candidate_not_visible);
692+
return false;
693+
}
694+
}
695+
663696
true
664697
}
665698
AssocItemId::ConstId(c) => {

crates/hir_ty/src/tests/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ struct S;
3131
3232
#[cfg(not(test))]
3333
impl S {
34-
fn foo3(&self) -> i32 { 0 }
34+
pub fn foo3(&self) -> i32 { 0 }
3535
}
3636
3737
#[cfg(test)]
3838
impl S {
39-
fn foo4(&self) -> i32 { 0 }
39+
pub fn foo4(&self) -> i32 { 0 }
4040
}
4141
"#,
4242
);

0 commit comments

Comments
 (0)