Skip to content

Commit f313d8b

Browse files
committed
Auto merge of #127812 - adetaylor:receiver_trait_with_target_deshadowing_probes, r=<try>
Arbitrary self types v2: probe for more methods. This PR is one of the first steps towards arbitrary self types v2, RFC [3519](rust-lang/rfcs#3519) (#44874). Specifically, it is [step 2 of the plan outlined here](#44874 (comment)). That says: > 1. **Search for potentially conflicting method candidates** per the [deshadowing part of the RFC](https://github.com/rust-lang/rfcs/blob/master/text/3519-arbitrary-self-types-v2.md#compiler-changes-deshadowing). This is the riskiest part - per > the production of errors requires us to interrogate more candidates to look for potential conflicts, so this could have a compile-time performance penalty which we should measure > let's attempt to land this first and see if performance issues show up. If so, it's back to the drawing board. So - this commit isn't useful in itself but we need to determine its performance and any unexpected compatibility problems. That's what this PR is for. We shouldn't necessarily merge it. Here's what this commit does. Rust prioritizes method candidates in this order: 1. By value; 2. By reference; 3. By mutable reference; 4. By const ptr. Previously, if a suitable candidate was found in one of these earlier categories, Rust wouldn't even move onto probing the other categories. As part of the arbitrary self types work, we're going to need to change that - even if we choose a method from one of the earlier categories, we will sometimes need to probe later categories to search for methods that we may be shadowing. This commit adds those extra searches for shadowing, but it does not yet produce an error when such shadowing problems are found. That will come in a subsequent commit, by filling out the 'check_for_shadowing' method. We're adding the extra searches in a preliminary commit because they are the risky bit. We want to find any functional or performance problems from these extra searches before we proceed with the actual work on arbitrary self types and specifically on extra deshadowing errors.
2 parents a91f7d7 + 4740759 commit f313d8b

File tree

1 file changed

+104
-17
lines changed
  • compiler/rustc_hir_typeck/src/method

1 file changed

+104
-17
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

+104-17
Original file line numberDiff line numberDiff line change
@@ -1056,33 +1056,120 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10561056
.unwrap_or_else(|_| {
10571057
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
10581058
});
1059-
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
1060-
.or_else(|| {
1061-
self.pick_autorefd_method(
1062-
step,
1063-
self_ty,
1064-
hir::Mutability::Not,
1065-
unstable_candidates.as_deref_mut(),
1066-
)
1067-
.or_else(|| {
1068-
self.pick_autorefd_method(
1059+
1060+
let by_value_pick =
1061+
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut());
1062+
1063+
// Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
1064+
if let Some(by_value_pick) = by_value_pick {
1065+
if let Ok(by_value_pick) = by_value_pick.as_ref() {
1066+
if by_value_pick.kind == PickKind::InherentImplPick {
1067+
let autoref_pick = self.pick_autorefd_method(
1068+
step,
1069+
self_ty,
1070+
hir::Mutability::Not,
1071+
unstable_candidates.as_deref_mut(),
1072+
);
1073+
if let Err(e) = self.check_for_shadowing(by_value_pick, autoref_pick) {
1074+
return Some(Err(e));
1075+
}
1076+
1077+
let autoref_mut_pick = self.pick_autorefd_method(
10691078
step,
10701079
self_ty,
10711080
hir::Mutability::Mut,
10721081
unstable_candidates.as_deref_mut(),
1073-
)
1074-
})
1075-
.or_else(|| {
1076-
self.pick_const_ptr_method(
1082+
);
1083+
if let Err(e) =
1084+
self.check_for_shadowing(by_value_pick, autoref_mut_pick)
1085+
{
1086+
return Some(Err(e));
1087+
}
1088+
}
1089+
}
1090+
return Some(by_value_pick);
1091+
}
1092+
1093+
let autoref_pick = self.pick_autorefd_method(
1094+
step,
1095+
self_ty,
1096+
hir::Mutability::Not,
1097+
unstable_candidates.as_deref_mut(),
1098+
);
1099+
// Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing)
1100+
if let Some(autoref_pick) = autoref_pick {
1101+
if let Ok(autoref_pick) = autoref_pick.as_ref() {
1102+
// Check we're not shadowing others
1103+
if autoref_pick.kind == PickKind::InherentImplPick {
1104+
let autoref_mut_pick = self.pick_autorefd_method(
10771105
step,
10781106
self_ty,
1107+
hir::Mutability::Mut,
10791108
unstable_candidates.as_deref_mut(),
1080-
)
1081-
})
1082-
})
1109+
);
1110+
if let Err(e) = self.check_for_shadowing(autoref_pick, autoref_mut_pick)
1111+
{
1112+
return Some(Err(e));
1113+
}
1114+
}
1115+
}
1116+
return Some(autoref_pick);
1117+
}
1118+
1119+
// Note that no shadowing errors are produced from here on,
1120+
// as we consider const ptr methods.
1121+
// We allow new methods that take *mut T to shadow
1122+
// methods which took *const T, so there is no entry in
1123+
// this list for the results of `pick_const_ptr_method`.
1124+
// The reason is that the standard pointer cast method
1125+
// (on a mutable pointer) always already shadows the
1126+
// cast method (on a const pointer). So, if we added
1127+
// `pick_const_ptr_method` to this method, the anti-
1128+
// shadowing algorithm would always complain about
1129+
// the conflict between *const::cast and *mut::cast.
1130+
// In practice therefore this does constrain us:
1131+
// we cannot add new
1132+
// self: *mut Self
1133+
// methods to types such as NonNull or anything else
1134+
// which implements Receiver, because this might in future
1135+
// shadow existing methods taking
1136+
// self: *const NonNull<Self>
1137+
// in the pointee. In practice, methods taking raw pointers
1138+
// are rare, and it seems that it should be easily possible
1139+
// to avoid such compatibility breaks.
1140+
self.pick_autorefd_method(
1141+
step,
1142+
self_ty,
1143+
hir::Mutability::Mut,
1144+
unstable_candidates.as_deref_mut(),
1145+
)
1146+
.or_else(|| {
1147+
self.pick_const_ptr_method(step, self_ty, unstable_candidates.as_deref_mut())
1148+
})
10831149
})
10841150
}
10851151

1152+
/// Check for cases where arbitrary self types allows shadowing
1153+
/// of methods that might be a compatibility break. Specifically,
1154+
/// we have something like:
1155+
/// struct A;
1156+
/// impl A {
1157+
/// fn foo(self: &NonNull<A>) {}
1158+
/// // note this is by reference
1159+
/// }
1160+
/// then we've come along and added this method to NonNull:
1161+
/// fn foo(self) // note this is by value
1162+
/// Report an error in this case.
1163+
fn check_for_shadowing(
1164+
&self,
1165+
_possible_shadower: &Pick<'tcx>,
1166+
_possible_shadowed: Option<Result<Pick<'tcx>, MethodError<'tcx>>>,
1167+
) -> Result<(), MethodError<'tcx>> {
1168+
// At the moment, this function does nothing. A future
1169+
// commit will fill out the body here.
1170+
Ok(())
1171+
}
1172+
10861173
/// For each type `T` in the step list, this attempts to find a method where
10871174
/// the (transformed) self type is exactly `T`. We do however do one
10881175
/// transformation on the adjustment: if we are passing a region pointer in,

0 commit comments

Comments
 (0)