@@ -85,6 +85,11 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
8585 /// machinery, since we don't particularly care about, for example, similarly named
8686 /// candidates if we're *reporting* similarly named candidates.
8787 is_suggestion : IsSuggestion ,
88+
89+ /// Number of times we've hopped along the chain of `Receiver::Target`.
90+ /// Used to spot cases where an "outer" method in a smart pointer might
91+ /// "shadow" a pre-existing method in the pointee.
92+ receiver_trait_derefs : usize ,
8893}
8994
9095impl < ' a , ' tcx > Deref for ProbeContext < ' a , ' tcx > {
@@ -99,6 +104,7 @@ pub(crate) struct Candidate<'tcx> {
99104 pub ( crate ) item : ty:: AssocItem ,
100105 pub ( crate ) kind : CandidateKind < ' tcx > ,
101106 pub ( crate ) import_ids : SmallVec < [ LocalDefId ; 1 ] > ,
107+ receiver_trait_derefs : usize ,
102108}
103109
104110#[ derive( Debug , Clone ) ]
@@ -171,6 +177,30 @@ struct PickDiagHints<'a, 'tcx> {
171177 ) > ,
172178}
173179
180+ /// Criteria to apply when searching for a given Pick. This is used during
181+ /// the search for potentially shadowed methods to ensure we don't search
182+ /// more candidates than strictly necessary.
183+ #[ derive( Debug ) ]
184+ struct PickConstraintsForShadowed {
185+ autoderefs : usize ,
186+ receiver_trait_derefs : usize ,
187+ def_id : DefId ,
188+ }
189+
190+ impl PickConstraintsForShadowed {
191+ fn may_shadow_based_on_autoderefs ( & self , autoderefs : usize ) -> bool {
192+ autoderefs == self . autoderefs
193+ }
194+
195+ fn may_shadow_based_on_receiver_trait_derefs ( & self , receiver_trait_derefs : usize ) -> bool {
196+ receiver_trait_derefs != self . receiver_trait_derefs
197+ }
198+
199+ fn may_shadow_based_on_defid ( & self , def_id : DefId ) -> bool {
200+ def_id != self . def_id
201+ }
202+ }
203+
174204#[ derive( Debug , Clone ) ]
175205pub ( crate ) struct Pick < ' tcx > {
176206 pub item : ty:: AssocItem ,
@@ -190,6 +220,10 @@ pub(crate) struct Pick<'tcx> {
190220
191221 /// Unstable candidates alongside the stable ones.
192222 unstable_candidates : Vec < ( Candidate < ' tcx > , Symbol ) > ,
223+
224+ /// Number of jumps along the `Receiver::Target` chain we followed
225+ /// to identify this method. Used only for deshadowing errors.
226+ pub receiver_trait_derefs : usize ,
193227}
194228
195229#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -674,6 +708,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
674708 static_candidates : RefCell :: new ( Vec :: new ( ) ) ,
675709 scope_expr_id,
676710 is_suggestion,
711+ receiver_trait_derefs : 0usize ,
677712 }
678713 }
679714
@@ -706,7 +741,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
706741 import_ids : SmallVec < [ LocalDefId ; 1 ] > ,
707742 is_inherent : bool ,
708743 ) {
709- let candidate = Candidate { item, kind, import_ids } ;
744+ let candidate =
745+ Candidate { item, kind, import_ids, receiver_trait_derefs : self . receiver_trait_derefs } ;
710746 let is_accessible = if let Some ( name) = self . method_name {
711747 let item = candidate. item ;
712748 let hir_id = self . tcx . local_def_id_to_hir_id ( self . body_id ) ;
@@ -729,6 +765,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
729765
730766 fn assemble_inherent_candidates ( & mut self ) {
731767 for step in self . steps . iter ( ) {
768+ self . receiver_trait_derefs = step. autoderefs ;
732769 self . assemble_probe ( & step. self_ty ) ;
733770 }
734771 }
@@ -1196,8 +1233,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11961233 return Some ( by_value_pick) ;
11971234 }
11981235
1199- let autoref_pick =
1200- self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Not , pick_diag_hints) ;
1236+ let autoref_pick = self . pick_autorefd_method (
1237+ step,
1238+ self_ty,
1239+ hir:: Mutability :: Not ,
1240+ pick_diag_hints,
1241+ None ,
1242+ ) ;
12011243 // Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing)
12021244 if let Some ( autoref_pick) = autoref_pick {
12031245 if let Ok ( autoref_pick) = autoref_pick. as_ref ( ) {
@@ -1238,9 +1280,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12381280 // in the pointee. In practice, methods taking raw pointers
12391281 // are rare, and it seems that it should be easily possible
12401282 // to avoid such compatibility breaks.
1241- self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Mut , pick_diag_hints)
1242- . or_else ( || self . pick_const_ptr_method ( step, self_ty, pick_diag_hints) )
1243- . or_else ( || self . pick_reborrow_pin_method ( step, self_ty, pick_diag_hints) )
1283+ self . pick_autorefd_method (
1284+ step,
1285+ self_ty,
1286+ hir:: Mutability :: Mut ,
1287+ pick_diag_hints,
1288+ None ,
1289+ )
1290+ . or_else ( || self . pick_const_ptr_method ( step, self_ty, pick_diag_hints) )
1291+ . or_else ( || self . pick_reborrow_pin_method ( step, self_ty, pick_diag_hints) )
12441292 } )
12451293 }
12461294
@@ -1261,7 +1309,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12611309 /// Report an error in this case.
12621310 fn check_for_shadowed_autorefd_method (
12631311 & self ,
1264- _possible_shadower : & Pick < ' tcx > ,
1312+ possible_shadower : & Pick < ' tcx > ,
12651313 step : & CandidateStep < ' tcx > ,
12661314 self_ty : Ty < ' tcx > ,
12671315 mutbl : hir:: Mutability ,
@@ -1275,8 +1323,54 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12751323 unstable_candidates : if track_unstable_candidates { Some ( Vec :: new ( ) ) } else { None } ,
12761324 unsatisfied_predicates : & mut Vec :: new ( ) ,
12771325 } ;
1278- let _potentially_shadowed_pick =
1279- self . pick_autorefd_method ( step, self_ty, mutbl, & mut pick_diag_hints) ;
1326+ // Set criteria for how we find methods possibly shadowed by 'possible_shadower'
1327+ let pick_constraints = PickConstraintsForShadowed {
1328+ // It's the same `self` type...
1329+ autoderefs : possible_shadower. autoderefs ,
1330+ // ... but the method was found in an impl block determined
1331+ // by searching further along the Receiver chain than the other,
1332+ // showing that it's a smart pointer type causing the problem...
1333+ receiver_trait_derefs : possible_shadower. receiver_trait_derefs ,
1334+ // ... and they don't end up pointing to the same item in the
1335+ // first place (could happen with things like blanket impls for T)
1336+ def_id : possible_shadower. item . def_id ,
1337+ } ;
1338+ // A note on the autoderefs above. Within pick_by_value_method, an extra
1339+ // autoderef may be applied in order to reborrow a reference with
1340+ // a different lifetime. That seems as though it would break the
1341+ // logic of these constraints, since the number of autoderefs could
1342+ // no longer be used to identify the fundamental type of the receiver.
1343+ // However, this extra autoderef is applied only to by-value calls
1344+ // where the receiver is already a reference. So this situation would
1345+ // only occur in cases where the shadowing looks like this:
1346+ // ```
1347+ // struct A;
1348+ // impl A {
1349+ // fn foo(self: &&NonNull<A>) {}
1350+ // // note this is by DOUBLE reference
1351+ // }
1352+ // ```
1353+ // then we've come along and added this method to `NonNull`:
1354+ // ```
1355+ // fn foo(&self) // note this is by single reference
1356+ // ```
1357+ // and the call is:
1358+ // ```
1359+ // let bar = NonNull<Foo>;
1360+ // let bar = &foo;
1361+ // bar.foo();
1362+ // ```
1363+ // In these circumstances, the logic is wrong, and we wouldn't spot
1364+ // the shadowing, because the autoderef-based maths wouldn't line up.
1365+ // This is a niche case and we can live without generating an error
1366+ // in the case of such shadowing.
1367+ let _potentially_shadowed_pick = self . pick_autorefd_method (
1368+ step,
1369+ self_ty,
1370+ mutbl,
1371+ & mut pick_diag_hints,
1372+ Some ( & pick_constraints) ,
1373+ ) ;
12801374
12811375 // At the moment, this function does no checks. A future
12821376 // commit will fill out the body here.
@@ -1299,7 +1393,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12991393 return None ;
13001394 }
13011395
1302- self . pick_method ( self_ty, pick_diag_hints) . map ( |r| {
1396+ self . pick_method ( self_ty, pick_diag_hints, None ) . map ( |r| {
13031397 r. map ( |mut pick| {
13041398 pick. autoderefs = step. autoderefs ;
13051399
@@ -1338,14 +1432,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13381432 self_ty : Ty < ' tcx > ,
13391433 mutbl : hir:: Mutability ,
13401434 pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1435+ pick_constraints : Option < & PickConstraintsForShadowed > ,
13411436 ) -> Option < PickResult < ' tcx > > {
13421437 let tcx = self . tcx ;
13431438
1439+ if let Some ( pick_constraints) = pick_constraints {
1440+ if !pick_constraints. may_shadow_based_on_autoderefs ( step. autoderefs ) {
1441+ return None ;
1442+ }
1443+ }
1444+
13441445 // In general, during probing we erase regions.
13451446 let region = tcx. lifetimes . re_erased ;
13461447
13471448 let autoref_ty = Ty :: new_ref ( tcx, region, self_ty, mutbl) ;
1348- self . pick_method ( autoref_ty, pick_diag_hints) . map ( |r| {
1449+ self . pick_method ( autoref_ty, pick_diag_hints, pick_constraints ) . map ( |r| {
13491450 r. map ( |mut pick| {
13501451 pick. autoderefs = step. autoderefs ;
13511452 pick. autoref_or_ptr_adjustment =
@@ -1382,7 +1483,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13821483
13831484 let region = self . tcx . lifetimes . re_erased ;
13841485 let autopin_ty = Ty :: new_pinned_ref ( self . tcx , region, inner_ty, hir:: Mutability :: Not ) ;
1385- self . pick_method ( autopin_ty, pick_diag_hints) . map ( |r| {
1486+ self . pick_method ( autopin_ty, pick_diag_hints, None ) . map ( |r| {
13861487 r. map ( |mut pick| {
13871488 pick. autoderefs = step. autoderefs ;
13881489 pick. autoref_or_ptr_adjustment =
@@ -1411,7 +1512,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14111512 } ;
14121513
14131514 let const_ptr_ty = Ty :: new_imm_ptr ( self . tcx , ty) ;
1414- self . pick_method ( const_ptr_ty, pick_diag_hints) . map ( |r| {
1515+ self . pick_method ( const_ptr_ty, pick_diag_hints, None ) . map ( |r| {
14151516 r. map ( |mut pick| {
14161517 pick. autoderefs = step. autoderefs ;
14171518 pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: ToConstPtr ) ;
@@ -1424,22 +1525,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14241525 & self ,
14251526 self_ty : Ty < ' tcx > ,
14261527 pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1528+ pick_constraints : Option < & PickConstraintsForShadowed > ,
14271529 ) -> Option < PickResult < ' tcx > > {
14281530 debug ! ( "pick_method(self_ty={})" , self . ty_to_string( self_ty) ) ;
14291531
14301532 for ( kind, candidates) in
14311533 [ ( "inherent" , & self . inherent_candidates ) , ( "extension" , & self . extension_candidates ) ]
14321534 {
14331535 debug ! ( "searching {} candidates" , kind) ;
1434- let res = self . consider_candidates ( self_ty, candidates, pick_diag_hints) ;
1536+ let res =
1537+ self . consider_candidates ( self_ty, candidates, pick_diag_hints, pick_constraints) ;
14351538 if let Some ( pick) = res {
14361539 return Some ( pick) ;
14371540 }
14381541 }
14391542
14401543 if self . private_candidate . get ( ) . is_none ( ) {
14411544 if let Some ( Ok ( pick) ) =
1442- self . consider_candidates ( self_ty, & self . private_candidates , pick_diag_hints)
1545+ self . consider_candidates ( self_ty, & self . private_candidates , pick_diag_hints, None )
14431546 {
14441547 self . private_candidate . set ( Some ( ( pick. item . kind . as_def_kind ( ) , pick. item . def_id ) ) ) ;
14451548 }
@@ -1452,9 +1555,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14521555 self_ty : Ty < ' tcx > ,
14531556 candidates : & [ Candidate < ' tcx > ] ,
14541557 pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1558+ pick_constraints : Option < & PickConstraintsForShadowed > ,
14551559 ) -> Option < PickResult < ' tcx > > {
14561560 let mut applicable_candidates: Vec < _ > = candidates
14571561 . iter ( )
1562+ . filter ( |candidate| {
1563+ pick_constraints
1564+ . map ( |pick_constraints| {
1565+ pick_constraints. may_shadow_based_on_defid ( candidate. item . def_id )
1566+ && pick_constraints. may_shadow_based_on_receiver_trait_derefs (
1567+ candidate. receiver_trait_derefs ,
1568+ )
1569+ } )
1570+ . unwrap_or ( true )
1571+ } )
14581572 . map ( |probe| {
14591573 (
14601574 probe,
@@ -1528,6 +1642,7 @@ impl<'tcx> Pick<'tcx> {
15281642 autoref_or_ptr_adjustment : _,
15291643 self_ty,
15301644 unstable_candidates : _,
1645+ receiver_trait_derefs : _,
15311646 } = * self ;
15321647 self_ty != other. self_ty || def_id != other. item . def_id
15331648 }
@@ -1900,10 +2015,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
19002015 item : probes[ 0 ] . 0 . item ,
19012016 kind : TraitPick ,
19022017 import_ids : probes[ 0 ] . 0 . import_ids . clone ( ) ,
1903- autoderefs : 0 ,
2018+ autoderefs : probes [ 0 ] . 0 . receiver_trait_derefs ,
19042019 autoref_or_ptr_adjustment : None ,
19052020 self_ty,
19062021 unstable_candidates : vec ! [ ] ,
2022+ receiver_trait_derefs : 0 ,
19072023 } )
19082024 }
19092025
@@ -2197,6 +2313,7 @@ impl<'tcx> Candidate<'tcx> {
21972313 autoref_or_ptr_adjustment : None ,
21982314 self_ty,
21992315 unstable_candidates,
2316+ receiver_trait_derefs : self . receiver_trait_derefs ,
22002317 }
22012318 }
22022319}
0 commit comments