@@ -85,6 +85,11 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
85
85
/// machinery, since we don't particularly care about, for example, similarly named
86
86
/// candidates if we're *reporting* similarly named candidates.
87
87
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 ,
88
93
}
89
94
90
95
impl < ' a , ' tcx > Deref for ProbeContext < ' a , ' tcx > {
@@ -99,6 +104,7 @@ pub(crate) struct Candidate<'tcx> {
99
104
pub ( crate ) item : ty:: AssocItem ,
100
105
pub ( crate ) kind : CandidateKind < ' tcx > ,
101
106
pub ( crate ) import_ids : SmallVec < [ LocalDefId ; 1 ] > ,
107
+ receiver_trait_derefs : usize ,
102
108
}
103
109
104
110
#[ derive( Debug , Clone ) ]
@@ -170,6 +176,30 @@ struct PickDiagHints<'a, 'tcx> {
170
176
) > ,
171
177
}
172
178
179
+ /// Criteria to apply when searching for a given Pick. This is used during
180
+ /// the search for potentially shadowed methods to ensure we don't search
181
+ /// more candidates than strictly necessary.
182
+ #[ derive( Debug ) ]
183
+ struct PickConstraintsForShadowed {
184
+ autoderefs : usize ,
185
+ receiver_trait_derefs : usize ,
186
+ def_id : DefId ,
187
+ }
188
+
189
+ impl PickConstraintsForShadowed {
190
+ fn may_shadow_based_on_autoderefs ( & self , autoderefs : usize ) -> bool {
191
+ autoderefs == self . autoderefs
192
+ }
193
+
194
+ fn may_shadow_based_on_receiver_trait_derefs ( & self , receiver_trait_derefs : usize ) -> bool {
195
+ receiver_trait_derefs != self . receiver_trait_derefs
196
+ }
197
+
198
+ fn may_shadow_based_on_defid ( & self , def_id : DefId ) -> bool {
199
+ def_id != self . def_id
200
+ }
201
+ }
202
+
173
203
#[ derive( Debug , Clone ) ]
174
204
pub ( crate ) struct Pick < ' tcx > {
175
205
pub item : ty:: AssocItem ,
@@ -189,6 +219,10 @@ pub(crate) struct Pick<'tcx> {
189
219
190
220
/// Unstable candidates alongside the stable ones.
191
221
unstable_candidates : Vec < ( Candidate < ' tcx > , Symbol ) > ,
222
+
223
+ /// Number of jumps along the `Receiver::Target` chain we followed
224
+ /// to identify this method. Used only for deshadowing errors.
225
+ pub receiver_trait_derefs : usize ,
192
226
}
193
227
194
228
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -673,6 +707,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
673
707
static_candidates : RefCell :: new ( Vec :: new ( ) ) ,
674
708
scope_expr_id,
675
709
is_suggestion,
710
+ receiver_trait_derefs : 0usize ,
676
711
}
677
712
}
678
713
@@ -705,7 +740,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
705
740
import_ids : SmallVec < [ LocalDefId ; 1 ] > ,
706
741
is_inherent : bool ,
707
742
) {
708
- let candidate = Candidate { item, kind, import_ids } ;
743
+ let candidate =
744
+ Candidate { item, kind, import_ids, receiver_trait_derefs : self . receiver_trait_derefs } ;
709
745
let is_accessible = if let Some ( name) = self . method_name {
710
746
let item = candidate. item ;
711
747
let hir_id = self . tcx . local_def_id_to_hir_id ( self . body_id ) ;
@@ -728,6 +764,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
728
764
729
765
fn assemble_inherent_candidates ( & mut self ) {
730
766
for step in self . steps . iter ( ) {
767
+ self . receiver_trait_derefs = step. autoderefs ;
731
768
self . assemble_probe ( & step. self_ty ) ;
732
769
}
733
770
}
@@ -1195,8 +1232,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1195
1232
return Some ( by_value_pick) ;
1196
1233
}
1197
1234
1198
- let autoref_pick =
1199
- self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Not , pick_diag_hints) ;
1235
+ let autoref_pick = self . pick_autorefd_method (
1236
+ step,
1237
+ self_ty,
1238
+ hir:: Mutability :: Not ,
1239
+ pick_diag_hints,
1240
+ None ,
1241
+ ) ;
1200
1242
// Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing)
1201
1243
if let Some ( autoref_pick) = autoref_pick {
1202
1244
if let Ok ( autoref_pick) = autoref_pick. as_ref ( ) {
@@ -1237,9 +1279,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1237
1279
// in the pointee. In practice, methods taking raw pointers
1238
1280
// are rare, and it seems that it should be easily possible
1239
1281
// to avoid such compatibility breaks.
1240
- self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Mut , pick_diag_hints)
1241
- . or_else ( || self . pick_const_ptr_method ( step, self_ty, pick_diag_hints) )
1242
- . or_else ( || self . pick_reborrow_pin_method ( step, self_ty, pick_diag_hints) )
1282
+ self . pick_autorefd_method (
1283
+ step,
1284
+ self_ty,
1285
+ hir:: Mutability :: Mut ,
1286
+ pick_diag_hints,
1287
+ None ,
1288
+ )
1289
+ . or_else ( || self . pick_const_ptr_method ( step, self_ty, pick_diag_hints) )
1290
+ . or_else ( || self . pick_reborrow_pin_method ( step, self_ty, pick_diag_hints) )
1243
1291
} )
1244
1292
}
1245
1293
@@ -1260,7 +1308,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1260
1308
/// Report an error in this case.
1261
1309
fn check_for_shadowed_autorefd_method (
1262
1310
& self ,
1263
- _possible_shadower : & Pick < ' tcx > ,
1311
+ possible_shadower : & Pick < ' tcx > ,
1264
1312
step : & CandidateStep < ' tcx > ,
1265
1313
self_ty : Ty < ' tcx > ,
1266
1314
mutbl : hir:: Mutability ,
@@ -1274,8 +1322,54 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1274
1322
unstable_candidates : if track_unstable_candidates { Some ( Vec :: new ( ) ) } else { None } ,
1275
1323
unsatisfied_predicates : & mut Vec :: new ( ) ,
1276
1324
} ;
1277
- let _potentially_shadowed_pick =
1278
- self . pick_autorefd_method ( step, self_ty, mutbl, & mut pick_diag_hints) ;
1325
+ // Set criteria for how we find methods possibly shadowed by 'possible_shadower'
1326
+ let pick_constraints = PickConstraintsForShadowed {
1327
+ // It's the same `self` type...
1328
+ autoderefs : possible_shadower. autoderefs ,
1329
+ // ... but the method was found in an impl block determined
1330
+ // by searching further along the Receiver chain than the other,
1331
+ // showing that it's a smart pointer type causing the problem...
1332
+ receiver_trait_derefs : possible_shadower. receiver_trait_derefs ,
1333
+ // ... and they don't end up pointing to the same item in the
1334
+ // first place (could happen with things like blanket impls for T)
1335
+ def_id : possible_shadower. item . def_id ,
1336
+ } ;
1337
+ // A note on the autoderefs above. Within pick_by_value_method, an extra
1338
+ // autoderef may be applied in order to reborrow a reference with
1339
+ // a different lifetime. That seems as though it would break the
1340
+ // logic of these constraints, since the number of autoderefs could
1341
+ // no longer be used to identify the fundamental type of the receiver.
1342
+ // However, this extra autoderef is applied only to by-value calls
1343
+ // where the receiver is already a reference. So this situation would
1344
+ // only occur in cases where the shadowing looks like this:
1345
+ // ```
1346
+ // struct A;
1347
+ // impl A {
1348
+ // fn foo(self: &&NonNull<A>) {}
1349
+ // // note this is by DOUBLE reference
1350
+ // }
1351
+ // ```
1352
+ // then we've come along and added this method to `NonNull`:
1353
+ // ```
1354
+ // fn foo(&self) // note this is by single reference
1355
+ // ```
1356
+ // and the call is:
1357
+ // ```
1358
+ // let bar = NonNull<Foo>;
1359
+ // let bar = &foo;
1360
+ // bar.foo();
1361
+ // ```
1362
+ // In these circumstances, the logic is wrong, and we wouldn't spot
1363
+ // the shadowing, because the autoderef-based maths wouldn't line up.
1364
+ // This is a niche case and we can live without generating an error
1365
+ // in the case of such shadowing.
1366
+ let _potentially_shadowed_pick = self . pick_autorefd_method (
1367
+ step,
1368
+ self_ty,
1369
+ mutbl,
1370
+ & mut pick_diag_hints,
1371
+ Some ( & pick_constraints) ,
1372
+ ) ;
1279
1373
1280
1374
// At the moment, this function does no checks. A future
1281
1375
// commit will fill out the body here.
@@ -1298,7 +1392,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1298
1392
return None ;
1299
1393
}
1300
1394
1301
- self . pick_method ( self_ty, pick_diag_hints) . map ( |r| {
1395
+ self . pick_method ( self_ty, pick_diag_hints, None ) . map ( |r| {
1302
1396
r. map ( |mut pick| {
1303
1397
pick. autoderefs = step. autoderefs ;
1304
1398
@@ -1337,14 +1431,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1337
1431
self_ty : Ty < ' tcx > ,
1338
1432
mutbl : hir:: Mutability ,
1339
1433
pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1434
+ pick_constraints : Option < & PickConstraintsForShadowed > ,
1340
1435
) -> Option < PickResult < ' tcx > > {
1341
1436
let tcx = self . tcx ;
1342
1437
1438
+ if let Some ( pick_constraints) = pick_constraints {
1439
+ if !pick_constraints. may_shadow_based_on_autoderefs ( step. autoderefs ) {
1440
+ return None ;
1441
+ }
1442
+ }
1443
+
1343
1444
// In general, during probing we erase regions.
1344
1445
let region = tcx. lifetimes . re_erased ;
1345
1446
1346
1447
let autoref_ty = Ty :: new_ref ( tcx, region, self_ty, mutbl) ;
1347
- self . pick_method ( autoref_ty, pick_diag_hints) . map ( |r| {
1448
+ self . pick_method ( autoref_ty, pick_diag_hints, pick_constraints ) . map ( |r| {
1348
1449
r. map ( |mut pick| {
1349
1450
pick. autoderefs = step. autoderefs ;
1350
1451
pick. autoref_or_ptr_adjustment =
@@ -1381,7 +1482,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1381
1482
1382
1483
let region = self . tcx . lifetimes . re_erased ;
1383
1484
let autopin_ty = Ty :: new_pinned_ref ( self . tcx , region, inner_ty, hir:: Mutability :: Not ) ;
1384
- self . pick_method ( autopin_ty, pick_diag_hints) . map ( |r| {
1485
+ self . pick_method ( autopin_ty, pick_diag_hints, None ) . map ( |r| {
1385
1486
r. map ( |mut pick| {
1386
1487
pick. autoderefs = step. autoderefs ;
1387
1488
pick. autoref_or_ptr_adjustment =
@@ -1410,7 +1511,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1410
1511
} ;
1411
1512
1412
1513
let const_ptr_ty = Ty :: new_imm_ptr ( self . tcx , ty) ;
1413
- self . pick_method ( const_ptr_ty, pick_diag_hints) . map ( |r| {
1514
+ self . pick_method ( const_ptr_ty, pick_diag_hints, None ) . map ( |r| {
1414
1515
r. map ( |mut pick| {
1415
1516
pick. autoderefs = step. autoderefs ;
1416
1517
pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: ToConstPtr ) ;
@@ -1423,22 +1524,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1423
1524
& self ,
1424
1525
self_ty : Ty < ' tcx > ,
1425
1526
pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1527
+ pick_constraints : Option < & PickConstraintsForShadowed > ,
1426
1528
) -> Option < PickResult < ' tcx > > {
1427
1529
debug ! ( "pick_method(self_ty={})" , self . ty_to_string( self_ty) ) ;
1428
1530
1429
1531
for ( kind, candidates) in
1430
1532
[ ( "inherent" , & self . inherent_candidates ) , ( "extension" , & self . extension_candidates ) ]
1431
1533
{
1432
1534
debug ! ( "searching {} candidates" , kind) ;
1433
- let res = self . consider_candidates ( self_ty, candidates, pick_diag_hints) ;
1535
+ let res =
1536
+ self . consider_candidates ( self_ty, candidates, pick_diag_hints, pick_constraints) ;
1434
1537
if let Some ( pick) = res {
1435
1538
return Some ( pick) ;
1436
1539
}
1437
1540
}
1438
1541
1439
1542
if self . private_candidate . get ( ) . is_none ( ) {
1440
1543
if let Some ( Ok ( pick) ) =
1441
- self . consider_candidates ( self_ty, & self . private_candidates , pick_diag_hints)
1544
+ self . consider_candidates ( self_ty, & self . private_candidates , pick_diag_hints, None )
1442
1545
{
1443
1546
self . private_candidate . set ( Some ( ( pick. item . kind . as_def_kind ( ) , pick. item . def_id ) ) ) ;
1444
1547
}
@@ -1451,9 +1554,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1451
1554
self_ty : Ty < ' tcx > ,
1452
1555
candidates : & [ Candidate < ' tcx > ] ,
1453
1556
pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1557
+ pick_constraints : Option < & PickConstraintsForShadowed > ,
1454
1558
) -> Option < PickResult < ' tcx > > {
1455
1559
let mut applicable_candidates: Vec < _ > = candidates
1456
1560
. iter ( )
1561
+ . filter ( |candidate| {
1562
+ pick_constraints
1563
+ . map ( |pick_constraints| {
1564
+ pick_constraints. may_shadow_based_on_defid ( candidate. item . def_id )
1565
+ && pick_constraints. may_shadow_based_on_receiver_trait_derefs (
1566
+ candidate. receiver_trait_derefs ,
1567
+ )
1568
+ } )
1569
+ . unwrap_or ( true )
1570
+ } )
1457
1571
. map ( |probe| {
1458
1572
(
1459
1573
probe,
@@ -1527,6 +1641,7 @@ impl<'tcx> Pick<'tcx> {
1527
1641
autoref_or_ptr_adjustment : _,
1528
1642
self_ty,
1529
1643
unstable_candidates : _,
1644
+ receiver_trait_derefs : _,
1530
1645
} = * self ;
1531
1646
self_ty != other. self_ty || def_id != other. item . def_id
1532
1647
}
@@ -1899,10 +2014,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1899
2014
item : probes[ 0 ] . 0 . item ,
1900
2015
kind : TraitPick ,
1901
2016
import_ids : probes[ 0 ] . 0 . import_ids . clone ( ) ,
1902
- autoderefs : 0 ,
2017
+ autoderefs : probes [ 0 ] . 0 . receiver_trait_derefs ,
1903
2018
autoref_or_ptr_adjustment : None ,
1904
2019
self_ty,
1905
2020
unstable_candidates : vec ! [ ] ,
2021
+ receiver_trait_derefs : 0 ,
1906
2022
} )
1907
2023
}
1908
2024
@@ -2196,6 +2312,7 @@ impl<'tcx> Candidate<'tcx> {
2196
2312
autoref_or_ptr_adjustment : None ,
2197
2313
self_ty,
2198
2314
unstable_candidates,
2315
+ receiver_trait_derefs : self . receiver_trait_derefs ,
2199
2316
}
2200
2317
}
2201
2318
}
0 commit comments