aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-03-24 22:37:48 +0000
committerGitHub <[email protected]>2021-03-24 22:37:48 +0000
commitd7db38fff9c251c36d0796309b43678bdf9e5bd8 (patch)
tree83b422d45c28e3ae9a2eac550ce8a6048bf5fd71 /crates/hir_ty
parent9d81618f11eb403cc0644a22f30648393ec77cf6 (diff)
parentd1156bb52e900c015afd490f509d744c7a5adf10 (diff)
Merge #7907
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: https://github.com/rust-lang/rust/blob/66ec64ccf31883cd2c28d045912a76179c0c6ed2/compiler/rustc_typeck/src/check/expr.rs#L1610 r? @flodiebold Co-authored-by: cynecx <[email protected]>
Diffstat (limited to 'crates/hir_ty')
-rw-r--r--crates/hir_ty/src/infer/expr.rs45
-rw-r--r--crates/hir_ty/src/infer/path.rs1
-rw-r--r--crates/hir_ty/src/method_resolution.rs41
-rw-r--r--crates/hir_ty/src/tests/macros.rs4
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs119
-rw-r--r--crates/hir_ty/src/tests/simple.rs32
-rw-r--r--crates/hir_ty/src/tests/traits.rs4
7 files changed, 210 insertions, 36 deletions
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 19249973c..3f3187ea2 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -443,27 +443,47 @@ impl<'a> InferenceContext<'a> {
443 }, 443 },
444 ) 444 )
445 .find_map(|derefed_ty| { 445 .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 };
446 match canonicalized.decanonicalize_ty(derefed_ty.value).interned(&Interner) { 456 match canonicalized.decanonicalize_ty(derefed_ty.value).interned(&Interner) {
447 TyKind::Tuple(_, substs) => { 457 TyKind::Tuple(_, substs) => {
448 name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned()) 458 name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned())
449 } 459 }
450 TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => { 460 TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
451 self.db.struct_data(*s).variant_data.field(name).map(|local_id| { 461 let local_id = self.db.struct_data(*s).variant_data.field(name)?;
452 let field = FieldId { parent: (*s).into(), local_id }; 462 let field = FieldId { parent: (*s).into(), local_id };
463 if is_visible(&field) {
453 self.write_field_resolution(tgt_expr, field); 464 self.write_field_resolution(tgt_expr, field);
454 self.db.field_types((*s).into())[field.local_id] 465 Some(
455 .clone() 466 self.db.field_types((*s).into())[field.local_id]
456 .subst(&parameters) 467 .clone()
457 }) 468 .subst(&parameters),
469 )
470 } else {
471 None
472 }
458 } 473 }
459 TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => { 474 TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
460 self.db.union_data(*u).variant_data.field(name).map(|local_id| { 475 let local_id = self.db.union_data(*u).variant_data.field(name)?;
461 let field = FieldId { parent: (*u).into(), local_id }; 476 let field = FieldId { parent: (*u).into(), local_id };
477 if is_visible(&field) {
462 self.write_field_resolution(tgt_expr, field); 478 self.write_field_resolution(tgt_expr, field);
463 self.db.field_types((*u).into())[field.local_id] 479 Some(
464 .clone() 480 self.db.field_types((*u).into())[field.local_id]
465 .subst(&parameters) 481 .clone()
466 }) 482 .subst(&parameters),
483 )
484 } else {
485 None
486 }
467 } 487 }
468 _ => None, 488 _ => None,
469 } 489 }
@@ -828,6 +848,7 @@ impl<'a> InferenceContext<'a> {
828 self.trait_env.clone(), 848 self.trait_env.clone(),
829 krate, 849 krate,
830 &traits_in_scope, 850 &traits_in_scope,
851 self.resolver.module(),
831 method_name, 852 method_name,
832 ) 853 )
833 }); 854 });
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 58cce56ab..cefa38509 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -230,6 +230,7 @@ impl<'a> InferenceContext<'a> {
230 self.trait_env.clone(), 230 self.trait_env.clone(),
231 krate, 231 krate,
232 &traits_in_scope, 232 &traits_in_scope,
233 None,
233 Some(name), 234 Some(name),
234 method_resolution::LookupMode::Path, 235 method_resolution::LookupMode::Path,
235 move |_ty, item| { 236 move |_ty, item| {
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 8e986ddde..84d9a1e18 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -296,6 +296,7 @@ pub(crate) fn lookup_method(
296 env: Arc<TraitEnvironment>, 296 env: Arc<TraitEnvironment>,
297 krate: CrateId, 297 krate: CrateId,
298 traits_in_scope: &FxHashSet<TraitId>, 298 traits_in_scope: &FxHashSet<TraitId>,
299 visible_from_module: Option<ModuleId>,
299 name: &Name, 300 name: &Name,
300) -> Option<(Ty, FunctionId)> { 301) -> Option<(Ty, FunctionId)> {
301 iterate_method_candidates( 302 iterate_method_candidates(
@@ -304,6 +305,7 @@ pub(crate) fn lookup_method(
304 env, 305 env,
305 krate, 306 krate,
306 &traits_in_scope, 307 &traits_in_scope,
308 visible_from_module,
307 Some(name), 309 Some(name),
308 LookupMode::MethodCall, 310 LookupMode::MethodCall,
309 |ty, f| match f { 311 |ty, f| match f {
@@ -334,6 +336,7 @@ pub fn iterate_method_candidates<T>(
334 env: Arc<TraitEnvironment>, 336 env: Arc<TraitEnvironment>,
335 krate: CrateId, 337 krate: CrateId,
336 traits_in_scope: &FxHashSet<TraitId>, 338 traits_in_scope: &FxHashSet<TraitId>,
339 visible_from_module: Option<ModuleId>,
337 name: Option<&Name>, 340 name: Option<&Name>,
338 mode: LookupMode, 341 mode: LookupMode,
339 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 342 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
@@ -345,6 +348,7 @@ pub fn iterate_method_candidates<T>(
345 env, 348 env,
346 krate, 349 krate,
347 traits_in_scope, 350 traits_in_scope,
351 visible_from_module,
348 name, 352 name,
349 mode, 353 mode,
350 &mut |ty, item| { 354 &mut |ty, item| {
@@ -362,6 +366,7 @@ fn iterate_method_candidates_impl(
362 env: Arc<TraitEnvironment>, 366 env: Arc<TraitEnvironment>,
363 krate: CrateId, 367 krate: CrateId,
364 traits_in_scope: &FxHashSet<TraitId>, 368 traits_in_scope: &FxHashSet<TraitId>,
369 visible_from_module: Option<ModuleId>,
365 name: Option<&Name>, 370 name: Option<&Name>,
366 mode: LookupMode, 371 mode: LookupMode,
367 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 372 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
@@ -399,6 +404,7 @@ fn iterate_method_candidates_impl(
399 env.clone(), 404 env.clone(),
400 krate, 405 krate,
401 traits_in_scope, 406 traits_in_scope,
407 visible_from_module,
402 name, 408 name,
403 callback, 409 callback,
404 ) { 410 ) {
@@ -415,6 +421,7 @@ fn iterate_method_candidates_impl(
415 env, 421 env,
416 krate, 422 krate,
417 traits_in_scope, 423 traits_in_scope,
424 visible_from_module,
418 name, 425 name,
419 callback, 426 callback,
420 ) 427 )
@@ -428,6 +435,7 @@ fn iterate_method_candidates_with_autoref(
428 env: Arc<TraitEnvironment>, 435 env: Arc<TraitEnvironment>,
429 krate: CrateId, 436 krate: CrateId,
430 traits_in_scope: &FxHashSet<TraitId>, 437 traits_in_scope: &FxHashSet<TraitId>,
438 visible_from_module: Option<ModuleId>,
431 name: Option<&Name>, 439 name: Option<&Name>,
432 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 440 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
433) -> bool { 441) -> bool {
@@ -438,6 +446,7 @@ fn iterate_method_candidates_with_autoref(
438 env.clone(), 446 env.clone(),
439 krate, 447 krate,
440 &traits_in_scope, 448 &traits_in_scope,
449 visible_from_module,
441 name, 450 name,
442 &mut callback, 451 &mut callback,
443 ) { 452 ) {
@@ -454,6 +463,7 @@ fn iterate_method_candidates_with_autoref(
454 env.clone(), 463 env.clone(),
455 krate, 464 krate,
456 &traits_in_scope, 465 &traits_in_scope,
466 visible_from_module,
457 name, 467 name,
458 &mut callback, 468 &mut callback,
459 ) { 469 ) {
@@ -470,6 +480,7 @@ fn iterate_method_candidates_with_autoref(
470 env, 480 env,
471 krate, 481 krate,
472 &traits_in_scope, 482 &traits_in_scope,
483 visible_from_module,
473 name, 484 name,
474 &mut callback, 485 &mut callback,
475 ) { 486 ) {
@@ -485,6 +496,7 @@ fn iterate_method_candidates_by_receiver(
485 env: Arc<TraitEnvironment>, 496 env: Arc<TraitEnvironment>,
486 krate: CrateId, 497 krate: CrateId,
487 traits_in_scope: &FxHashSet<TraitId>, 498 traits_in_scope: &FxHashSet<TraitId>,
499 visible_from_module: Option<ModuleId>,
488 name: Option<&Name>, 500 name: Option<&Name>,
489 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 501 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
490) -> bool { 502) -> bool {
@@ -492,7 +504,15 @@ fn iterate_method_candidates_by_receiver(
492 // be found in any of the derefs of receiver_ty, so we have to go through 504 // be found in any of the derefs of receiver_ty, so we have to go through
493 // that. 505 // that.
494 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { 506 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 ) {
496 return true; 516 return true;
497 } 517 }
498 } 518 }
@@ -519,10 +539,12 @@ fn iterate_method_candidates_for_self_ty(
519 env: Arc<TraitEnvironment>, 539 env: Arc<TraitEnvironment>,
520 krate: CrateId, 540 krate: CrateId,
521 traits_in_scope: &FxHashSet<TraitId>, 541 traits_in_scope: &FxHashSet<TraitId>,
542 visible_from_module: Option<ModuleId>,
522 name: Option<&Name>, 543 name: Option<&Name>,
523 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 544 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
524) -> bool { 545) -> 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 {
526 return true; 548 return true;
527 } 549 }
528 iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) 550 iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback)
@@ -559,7 +581,9 @@ fn iterate_trait_method_candidates(
559 // iteration 581 // iteration
560 let mut known_implemented = false; 582 let mut known_implemented = false;
561 for (_name, item) in data.items.iter() { 583 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) {
563 continue; 587 continue;
564 } 588 }
565 if !known_implemented { 589 if !known_implemented {
@@ -583,6 +607,7 @@ fn iterate_inherent_methods(
583 name: Option<&Name>, 607 name: Option<&Name>,
584 receiver_ty: Option<&Canonical<Ty>>, 608 receiver_ty: Option<&Canonical<Ty>>,
585 krate: CrateId, 609 krate: CrateId,
610 visible_from_module: Option<ModuleId>,
586 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 611 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
587) -> bool { 612) -> bool {
588 let def_crates = match self_ty.value.def_crates(db, krate) { 613 let def_crates = match self_ty.value.def_crates(db, krate) {
@@ -594,7 +619,7 @@ fn iterate_inherent_methods(
594 619
595 for &impl_def in impls.for_self_ty(&self_ty.value) { 620 for &impl_def in impls.for_self_ty(&self_ty.value) {
596 for &item in db.impl_data(impl_def).items.iter() { 621 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) {
598 continue; 623 continue;
599 } 624 }
600 // we have to check whether the self type unifies with the type 625 // we have to check whether the self type unifies with the type
@@ -639,6 +664,7 @@ fn is_valid_candidate(
639 receiver_ty: Option<&Canonical<Ty>>, 664 receiver_ty: Option<&Canonical<Ty>>,
640 item: AssocItemId, 665 item: AssocItemId,
641 self_ty: &Canonical<Ty>, 666 self_ty: &Canonical<Ty>,
667 visible_from_module: Option<ModuleId>,
642) -> bool { 668) -> bool {
643 match item { 669 match item {
644 AssocItemId::FunctionId(m) => { 670 AssocItemId::FunctionId(m) => {
@@ -660,6 +686,13 @@ fn is_valid_candidate(
660 return false; 686 return false;
661 } 687 }
662 } 688 }
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
663 true 696 true
664 } 697 }
665 AssocItemId::ConstId(c) => { 698 AssocItemId::ConstId(c) => {
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 12951fb16..7eda51866 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -31,12 +31,12 @@ struct S;
31 31
32#[cfg(not(test))] 32#[cfg(not(test))]
33impl S { 33impl S {
34 fn foo3(&self) -> i32 { 0 } 34 pub fn foo3(&self) -> i32 { 0 }
35} 35}
36 36
37#[cfg(test)] 37#[cfg(test)]
38impl S { 38impl S {
39 fn foo4(&self) -> i32 { 0 } 39 pub fn foo4(&self) -> i32 { 0 }
40} 40}
41"#, 41"#,
42 ); 42 );
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 4e3f9a9b6..61f18b0d2 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1173,3 +1173,122 @@ fn main() {
1173"#, 1173"#,
1174 ); 1174 );
1175} 1175}
1176
1177#[test]
1178fn autoderef_visibility_field() {
1179 check_infer(
1180 r#"
1181#[lang = "deref"]
1182pub trait Deref {
1183 type Target;
1184 fn deref(&self) -> &Self::Target;
1185}
1186mod a {
1187 pub struct Foo(pub char);
1188 pub struct Bar(i32);
1189 impl Bar {
1190 pub fn new() -> Self {
1191 Self(0)
1192 }
1193 }
1194 impl super::Deref for Bar {
1195 type Target = Foo;
1196 fn deref(&self) -> &Foo {
1197 &Foo('z')
1198 }
1199 }
1200}
1201mod b {
1202 fn foo() {
1203 let x = super::a::Bar::new().0;
1204 }
1205}
1206 "#,
1207 expect![[r#"
1208 67..71 'self': &Self
1209 200..231 '{ ... }': Bar
1210 214..218 'Self': Bar(i32) -> Bar
1211 214..221 'Self(0)': Bar
1212 219..220 '0': i32
1213 315..319 'self': &Bar
1214 329..362 '{ ... }': &Foo
1215 343..352 '&Foo('z')': &Foo
1216 344..347 'Foo': Foo(char) -> Foo
1217 344..352 'Foo('z')': Foo
1218 348..351 ''z'': char
1219 392..439 '{ ... }': ()
1220 406..407 'x': char
1221 410..428 'super:...r::new': fn new() -> Bar
1222 410..430 'super:...:new()': Bar
1223 410..432 'super:...ew().0': char
1224 "#]],
1225 )
1226}
1227
1228#[test]
1229fn autoderef_visibility_method() {
1230 cov_mark::check!(autoderef_candidate_not_visible);
1231 check_infer(
1232 r#"
1233#[lang = "deref"]
1234pub trait Deref {
1235 type Target;
1236 fn deref(&self) -> &Self::Target;
1237}
1238mod a {
1239 pub struct Foo(pub char);
1240 impl Foo {
1241 pub fn mango(&self) -> char {
1242 self.0
1243 }
1244 }
1245 pub struct Bar(i32);
1246 impl Bar {
1247 pub fn new() -> Self {
1248 Self(0)
1249 }
1250 fn mango(&self) -> i32 {
1251 self.0
1252 }
1253 }
1254 impl super::Deref for Bar {
1255 type Target = Foo;
1256 fn deref(&self) -> &Foo {
1257 &Foo('z')
1258 }
1259 }
1260}
1261mod b {
1262 fn foo() {
1263 let x = super::a::Bar::new().mango();
1264 }
1265}
1266 "#,
1267 expect![[r#"
1268 67..71 'self': &Self
1269 168..172 'self': &Foo
1270 182..212 '{ ... }': char
1271 196..200 'self': &Foo
1272 196..202 'self.0': char
1273 288..319 '{ ... }': Bar
1274 302..306 'Self': Bar(i32) -> Bar
1275 302..309 'Self(0)': Bar
1276 307..308 '0': i32
1277 338..342 'self': &Bar
1278 351..381 '{ ... }': i32
1279 365..369 'self': &Bar
1280 365..371 'self.0': i32
1281 465..469 'self': &Bar
1282 479..512 '{ ... }': &Foo
1283 493..502 '&Foo('z')': &Foo
1284 494..497 'Foo': Foo(char) -> Foo
1285 494..502 'Foo('z')': Foo
1286 498..501 ''z'': char
1287 542..595 '{ ... }': ()
1288 556..557 'x': char
1289 560..578 'super:...r::new': fn new() -> Bar
1290 560..580 'super:...:new()': Bar
1291 560..588 'super:...ango()': char
1292 "#]],
1293 )
1294}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index bcc43ed70..361cd6302 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1103,7 +1103,7 @@ fn infer_inherent_method() {
1103 1103
1104 mod b { 1104 mod b {
1105 impl super::A { 1105 impl super::A {
1106 fn bar(&self, x: u64) -> i64 {} 1106 pub fn bar(&self, x: u64) -> i64 {}
1107 } 1107 }
1108 } 1108 }
1109 1109
@@ -1117,21 +1117,21 @@ fn infer_inherent_method() {
1117 31..35 'self': A 1117 31..35 'self': A
1118 37..38 'x': u32 1118 37..38 'x': u32
1119 52..54 '{}': () 1119 52..54 '{}': ()
1120 102..106 'self': &A 1120 106..110 'self': &A
1121 108..109 'x': u64 1121 112..113 'x': u64
1122 123..125 '{}': () 1122 127..129 '{}': ()
1123 143..144 'a': A 1123 147..148 'a': A
1124 149..197 '{ ...(1); }': () 1124 153..201 '{ ...(1); }': ()
1125 155..156 'a': A 1125 159..160 'a': A
1126 155..163 'a.foo(1)': i32 1126 159..167 'a.foo(1)': i32
1127 161..162 '1': u32 1127 165..166 '1': u32
1128 169..180 '(&a).bar(1)': i64 1128 173..184 '(&a).bar(1)': i64
1129 170..172 '&a': &A 1129 174..176 '&a': &A
1130 171..172 'a': A 1130 175..176 'a': A
1131 178..179 '1': u64 1131 182..183 '1': u64
1132 186..187 'a': A 1132 190..191 'a': A
1133 186..194 'a.bar(1)': i64 1133 190..198 'a.bar(1)': i64
1134 192..193 '1': u64 1134 196..197 '1': u64
1135 "#]], 1135 "#]],
1136 ); 1136 );
1137} 1137}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 45a1958e3..2ba97f814 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -187,8 +187,8 @@ mod iter {
187mod collections { 187mod collections {
188 struct Vec<T> {} 188 struct Vec<T> {}
189 impl<T> Vec<T> { 189 impl<T> Vec<T> {
190 fn new() -> Self { Vec {} } 190 pub fn new() -> Self { Vec {} }
191 fn push(&mut self, t: T) { } 191 pub fn push(&mut self, t: T) { }
192 } 192 }
193 193
194 impl<T> IntoIterator for Vec<T> { 194 impl<T> IntoIterator for Vec<T> {