Skip to content

Commit 429d6b2

Browse files
committed
Arbitrary self types v2: probe for more methods.
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.
1 parent 5367673 commit 429d6b2

File tree

1 file changed

+120
-19
lines changed
  • compiler/rustc_hir_typeck/src/method

1 file changed

+120
-19
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 120 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,33 +1071,133 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10711071
.unwrap_or_else(|_| {
10721072
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
10731073
});
1074-
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
1075-
.or_else(|| {
1076-
self.pick_autorefd_method(
1077-
step,
1078-
self_ty,
1079-
hir::Mutability::Not,
1080-
unstable_candidates.as_deref_mut(),
1081-
)
1082-
.or_else(|| {
1083-
self.pick_autorefd_method(
1074+
1075+
let by_value_pick =
1076+
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut());
1077+
1078+
// Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
1079+
if let Some(by_value_pick) = by_value_pick {
1080+
if let Ok(by_value_pick) = by_value_pick.as_ref() {
1081+
if by_value_pick.kind == PickKind::InherentImplPick {
1082+
if let Err(e) = self.check_for_shadowed_autorefd_method(
1083+
by_value_pick,
1084+
step,
1085+
self_ty,
1086+
hir::Mutability::Not,
1087+
unstable_candidates.is_some(),
1088+
) {
1089+
return Some(Err(e));
1090+
}
1091+
if let Err(e) = self.check_for_shadowed_autorefd_method(
1092+
by_value_pick,
10841093
step,
10851094
self_ty,
10861095
hir::Mutability::Mut,
1087-
unstable_candidates.as_deref_mut(),
1088-
)
1089-
})
1090-
.or_else(|| {
1091-
self.pick_const_ptr_method(
1096+
unstable_candidates.is_some(),
1097+
) {
1098+
return Some(Err(e));
1099+
}
1100+
}
1101+
}
1102+
return Some(by_value_pick);
1103+
}
1104+
1105+
let autoref_pick = self.pick_autorefd_method(
1106+
step,
1107+
self_ty,
1108+
hir::Mutability::Not,
1109+
unstable_candidates.as_deref_mut(),
1110+
);
1111+
// Check for shadowing of a by-mut-ref method by a by-reference method (see comments on check_for_shadowing)
1112+
if let Some(autoref_pick) = autoref_pick {
1113+
if let Ok(autoref_pick) = autoref_pick.as_ref() {
1114+
// Check we're not shadowing others
1115+
if autoref_pick.kind == PickKind::InherentImplPick {
1116+
if let Err(e) = self.check_for_shadowed_autorefd_method(
1117+
autoref_pick,
10921118
step,
10931119
self_ty,
1094-
unstable_candidates.as_deref_mut(),
1095-
)
1096-
})
1097-
})
1120+
hir::Mutability::Mut,
1121+
unstable_candidates.is_some(),
1122+
) {
1123+
return Some(Err(e));
1124+
}
1125+
}
1126+
}
1127+
return Some(autoref_pick);
1128+
}
1129+
1130+
// Note that no shadowing errors are produced from here on,
1131+
// as we consider const ptr methods.
1132+
// We allow new methods that take *mut T to shadow
1133+
// methods which took *const T, so there is no entry in
1134+
// this list for the results of `pick_const_ptr_method`.
1135+
// The reason is that the standard pointer cast method
1136+
// (on a mutable pointer) always already shadows the
1137+
// cast method (on a const pointer). So, if we added
1138+
// `pick_const_ptr_method` to this method, the anti-
1139+
// shadowing algorithm would always complain about
1140+
// the conflict between *const::cast and *mut::cast.
1141+
// In practice therefore this does constrain us:
1142+
// we cannot add new
1143+
// self: *mut Self
1144+
// methods to types such as NonNull or anything else
1145+
// which implements Receiver, because this might in future
1146+
// shadow existing methods taking
1147+
// self: *const NonNull<Self>
1148+
// in the pointee. In practice, methods taking raw pointers
1149+
// are rare, and it seems that it should be easily possible
1150+
// to avoid such compatibility breaks.
1151+
self.pick_autorefd_method(
1152+
step,
1153+
self_ty,
1154+
hir::Mutability::Mut,
1155+
unstable_candidates.as_deref_mut(),
1156+
)
1157+
.or_else(|| {
1158+
self.pick_const_ptr_method(step, self_ty, unstable_candidates.as_deref_mut())
1159+
})
10981160
})
10991161
}
11001162

1163+
/// Check for cases where arbitrary self types allows shadowing
1164+
/// of methods that might be a compatibility break. Specifically,
1165+
/// we have something like:
1166+
/// ```compile_fail
1167+
/// # use std::ptr::NonNull;
1168+
/// struct A;
1169+
/// impl A {
1170+
/// fn foo(self: &NonNull<A>) {}
1171+
/// // note this is by reference
1172+
/// }
1173+
/// ```
1174+
/// then we've come along and added this method to `NonNull`:
1175+
/// ```
1176+
/// # struct NonNull;
1177+
/// # impl NonNull {
1178+
/// fn foo(self) {} // note this is by value
1179+
/// # }
1180+
/// ```
1181+
/// Report an error in this case.
1182+
fn check_for_shadowed_autorefd_method(
1183+
&self,
1184+
_possible_shadower: &Pick<'tcx>,
1185+
step: &CandidateStep<'tcx>,
1186+
self_ty: Ty<'tcx>,
1187+
mutbl: hir::Mutability,
1188+
tracking_unstable_candidates: bool,
1189+
) -> Result<(), MethodError<'tcx>> {
1190+
let mut empty_vec = vec![];
1191+
let unstable_candidates_for_shadow_probe =
1192+
if tracking_unstable_candidates { Some(&mut empty_vec) } else { None };
1193+
let _potentially_shadowed_pick =
1194+
self.pick_autorefd_method(step, self_ty, mutbl, unstable_candidates_for_shadow_probe);
1195+
1196+
// At the moment, this function does no checks. A future
1197+
// commit will fill out the body here.
1198+
Ok(())
1199+
}
1200+
11011201
/// For each type `T` in the step list, this attempts to find a method where
11021202
/// the (transformed) self type is exactly `T`. We do however do one
11031203
/// transformation on the adjustment: if we are passing a region pointer in,
@@ -1217,6 +1317,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12171317

12181318
// `pick_method` may be called twice for the same self_ty if no stable methods
12191319
// match. Only extend once.
1320+
// FIXME: this shouldn't be done when we're probing just for shadowing possibilities.
12201321
if unstable_candidates.is_some() {
12211322
self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
12221323
}

0 commit comments

Comments
 (0)