@@ -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 ) ]
@@ -171,6 +177,30 @@ struct PickDiagHints<'a, 'tcx> {
171
177
) > ,
172
178
}
173
179
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
+
174
204
#[ derive( Debug , Clone ) ]
175
205
pub ( crate ) struct Pick < ' tcx > {
176
206
pub item : ty:: AssocItem ,
@@ -190,6 +220,10 @@ pub(crate) struct Pick<'tcx> {
190
220
191
221
/// Unstable candidates alongside the stable ones.
192
222
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 ,
193
227
}
194
228
195
229
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -674,6 +708,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
674
708
static_candidates : RefCell :: new ( Vec :: new ( ) ) ,
675
709
scope_expr_id,
676
710
is_suggestion,
711
+ receiver_trait_derefs : 0usize ,
677
712
}
678
713
}
679
714
@@ -706,7 +741,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
706
741
import_ids : SmallVec < [ LocalDefId ; 1 ] > ,
707
742
is_inherent : bool ,
708
743
) {
709
- let candidate = Candidate { item, kind, import_ids } ;
744
+ let candidate =
745
+ Candidate { item, kind, import_ids, receiver_trait_derefs : self . receiver_trait_derefs } ;
710
746
let is_accessible = if let Some ( name) = self . method_name {
711
747
let item = candidate. item ;
712
748
let hir_id = self . tcx . local_def_id_to_hir_id ( self . body_id ) ;
@@ -729,6 +765,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
729
765
730
766
fn assemble_inherent_candidates ( & mut self ) {
731
767
for step in self . steps . iter ( ) {
768
+ self . receiver_trait_derefs = step. autoderefs ;
732
769
self . assemble_probe ( & step. self_ty ) ;
733
770
}
734
771
}
@@ -1196,8 +1233,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1196
1233
return Some ( by_value_pick) ;
1197
1234
}
1198
1235
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
+ ) ;
1201
1243
// Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing)
1202
1244
if let Some ( autoref_pick) = autoref_pick {
1203
1245
if let Ok ( autoref_pick) = autoref_pick. as_ref ( ) {
@@ -1238,9 +1280,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1238
1280
// in the pointee. In practice, methods taking raw pointers
1239
1281
// are rare, and it seems that it should be easily possible
1240
1282
// 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) )
1244
1292
} )
1245
1293
}
1246
1294
@@ -1261,7 +1309,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1261
1309
/// Report an error in this case.
1262
1310
fn check_for_shadowed_autorefd_method (
1263
1311
& self ,
1264
- _possible_shadower : & Pick < ' tcx > ,
1312
+ possible_shadower : & Pick < ' tcx > ,
1265
1313
step : & CandidateStep < ' tcx > ,
1266
1314
self_ty : Ty < ' tcx > ,
1267
1315
mutbl : hir:: Mutability ,
@@ -1275,8 +1323,54 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1275
1323
unstable_candidates : if track_unstable_candidates { Some ( Vec :: new ( ) ) } else { None } ,
1276
1324
unsatisfied_predicates : & mut Vec :: new ( ) ,
1277
1325
} ;
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
+ ) ;
1280
1374
1281
1375
// At the moment, this function does no checks. A future
1282
1376
// commit will fill out the body here.
@@ -1299,7 +1393,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1299
1393
return None ;
1300
1394
}
1301
1395
1302
- self . pick_method ( self_ty, pick_diag_hints) . map ( |r| {
1396
+ self . pick_method ( self_ty, pick_diag_hints, None ) . map ( |r| {
1303
1397
r. map ( |mut pick| {
1304
1398
pick. autoderefs = step. autoderefs ;
1305
1399
@@ -1338,14 +1432,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1338
1432
self_ty : Ty < ' tcx > ,
1339
1433
mutbl : hir:: Mutability ,
1340
1434
pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1435
+ pick_constraints : Option < & PickConstraintsForShadowed > ,
1341
1436
) -> Option < PickResult < ' tcx > > {
1342
1437
let tcx = self . tcx ;
1343
1438
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
+
1344
1445
// In general, during probing we erase regions.
1345
1446
let region = tcx. lifetimes . re_erased ;
1346
1447
1347
1448
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| {
1349
1450
r. map ( |mut pick| {
1350
1451
pick. autoderefs = step. autoderefs ;
1351
1452
pick. autoref_or_ptr_adjustment =
@@ -1382,7 +1483,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1382
1483
1383
1484
let region = self . tcx . lifetimes . re_erased ;
1384
1485
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| {
1386
1487
r. map ( |mut pick| {
1387
1488
pick. autoderefs = step. autoderefs ;
1388
1489
pick. autoref_or_ptr_adjustment =
@@ -1411,7 +1512,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1411
1512
} ;
1412
1513
1413
1514
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| {
1415
1516
r. map ( |mut pick| {
1416
1517
pick. autoderefs = step. autoderefs ;
1417
1518
pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: ToConstPtr ) ;
@@ -1424,22 +1525,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1424
1525
& self ,
1425
1526
self_ty : Ty < ' tcx > ,
1426
1527
pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1528
+ pick_constraints : Option < & PickConstraintsForShadowed > ,
1427
1529
) -> Option < PickResult < ' tcx > > {
1428
1530
debug ! ( "pick_method(self_ty={})" , self . ty_to_string( self_ty) ) ;
1429
1531
1430
1532
for ( kind, candidates) in
1431
1533
[ ( "inherent" , & self . inherent_candidates ) , ( "extension" , & self . extension_candidates ) ]
1432
1534
{
1433
1535
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) ;
1435
1538
if let Some ( pick) = res {
1436
1539
return Some ( pick) ;
1437
1540
}
1438
1541
}
1439
1542
1440
1543
if self . private_candidate . get ( ) . is_none ( ) {
1441
1544
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 )
1443
1546
{
1444
1547
self . private_candidate . set ( Some ( ( pick. item . kind . as_def_kind ( ) , pick. item . def_id ) ) ) ;
1445
1548
}
@@ -1452,9 +1555,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1452
1555
self_ty : Ty < ' tcx > ,
1453
1556
candidates : & [ Candidate < ' tcx > ] ,
1454
1557
pick_diag_hints : & mut PickDiagHints < ' b , ' tcx > ,
1558
+ pick_constraints : Option < & PickConstraintsForShadowed > ,
1455
1559
) -> Option < PickResult < ' tcx > > {
1456
1560
let mut applicable_candidates: Vec < _ > = candidates
1457
1561
. 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
+ } )
1458
1572
. map ( |probe| {
1459
1573
(
1460
1574
probe,
@@ -1528,6 +1642,7 @@ impl<'tcx> Pick<'tcx> {
1528
1642
autoref_or_ptr_adjustment : _,
1529
1643
self_ty,
1530
1644
unstable_candidates : _,
1645
+ receiver_trait_derefs : _,
1531
1646
} = * self ;
1532
1647
self_ty != other. self_ty || def_id != other. item . def_id
1533
1648
}
@@ -1900,10 +2015,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1900
2015
item : probes[ 0 ] . 0 . item ,
1901
2016
kind : TraitPick ,
1902
2017
import_ids : probes[ 0 ] . 0 . import_ids . clone ( ) ,
1903
- autoderefs : 0 ,
2018
+ autoderefs : probes [ 0 ] . 0 . receiver_trait_derefs ,
1904
2019
autoref_or_ptr_adjustment : None ,
1905
2020
self_ty,
1906
2021
unstable_candidates : vec ! [ ] ,
2022
+ receiver_trait_derefs : 0 ,
1907
2023
} )
1908
2024
}
1909
2025
@@ -2197,6 +2313,7 @@ impl<'tcx> Candidate<'tcx> {
2197
2313
autoref_or_ptr_adjustment : None ,
2198
2314
self_ty,
2199
2315
unstable_candidates,
2316
+ receiver_trait_derefs : self . receiver_trait_derefs ,
2200
2317
}
2201
2318
}
2202
2319
}
0 commit comments