Skip to content

Commit 19ca569

Browse files
committedMay 19, 2023
Auto merge of #110100 - compiler-errors:no-infer-pred-must-hold, r=jackh726
do not allow inference in `predicate_must_hold` (alternative approach) See the FCP description for more info, but tl;dr is that we should not return `EvaluatedToOkModuloRegions` if an obligation may hold only with some choice of inference vars being constrained. Attempts to solve this in the approach laid out by lcnr here: #109558 (comment), rather than by eagerly replacing infer vars with placeholders which is a bit too restrictive. r? `@ghost`
2 parents 92f5dea + c06e611 commit 19ca569

File tree

4 files changed

+47
-25
lines changed

4 files changed

+47
-25
lines changed
 

‎compiler/rustc_trait_selection/src/traits/mod.rs

+21-20
Original file line numberDiff line numberDiff line change
@@ -143,35 +143,36 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
143143
fn pred_known_to_hold_modulo_regions<'tcx>(
144144
infcx: &InferCtxt<'tcx>,
145145
param_env: ty::ParamEnv<'tcx>,
146-
pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>,
146+
pred: impl ToPredicate<'tcx>,
147147
) -> bool {
148-
let has_non_region_infer = pred.has_non_region_infer();
149148
let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
150149

151150
let result = infcx.evaluate_obligation_no_overflow(&obligation);
152151
debug!(?result);
153152

154-
if result.must_apply_modulo_regions() && !has_non_region_infer {
153+
if result.must_apply_modulo_regions() {
155154
true
156155
} else if result.may_apply() {
157-
// Because of inference "guessing", selection can sometimes claim
158-
// to succeed while the success requires a guess. To ensure
159-
// this function's result remains infallible, we must confirm
160-
// that guess. While imperfect, I believe this is sound.
161-
162-
// The handling of regions in this area of the code is terrible,
163-
// see issue #29149. We should be able to improve on this with
164-
// NLL.
165-
let ocx = ObligationCtxt::new(infcx);
166-
ocx.register_obligation(obligation);
167-
let errors = ocx.select_all_or_error();
168-
match errors.as_slice() {
169-
[] => true,
170-
errors => {
171-
debug!(?errors);
172-
false
156+
// Sometimes obligations are ambiguous because the recursive evaluator
157+
// is not smart enough, so we fall back to fulfillment when we're not certain
158+
// that an obligation holds or not. Even still, we must make sure that
159+
// the we do no inference in the process of checking this obligation.
160+
let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
161+
infcx.probe(|_| {
162+
let ocx = ObligationCtxt::new_in_snapshot(infcx);
163+
ocx.register_obligation(obligation);
164+
165+
let errors = ocx.select_all_or_error();
166+
match errors.as_slice() {
167+
// Only known to hold if we did no inference.
168+
[] => infcx.shallow_resolve(goal) == goal,
169+
170+
errors => {
171+
debug!(?errors);
172+
false
173+
}
173174
}
174-
}
175+
})
175176
} else {
176177
false
177178
}

‎compiler/rustc_trait_selection/src/traits/select/mod.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -537,14 +537,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
537537
obligation: &PredicateObligation<'tcx>,
538538
) -> Result<EvaluationResult, OverflowError> {
539539
self.evaluation_probe(|this| {
540-
if this.tcx().trait_solver_next() {
541-
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])
540+
let goal =
541+
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
542+
let mut result = if this.tcx().trait_solver_next() {
543+
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
542544
} else {
543545
this.evaluate_predicate_recursively(
544546
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
545547
obligation.clone(),
546-
)
548+
)?
549+
};
550+
// If the predicate has done any inference, then downgrade the
551+
// result to ambiguous.
552+
if this.infcx.shallow_resolve(goal) != goal {
553+
result = result.max(EvaluatedToAmbig);
547554
}
555+
Ok(result)
548556
})
549557
}
550558

‎tests/ui/traits/copy-guessing.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// run-pass
2-
31
#![allow(dead_code)]
42
#![allow(drop_copy)]
53

@@ -20,6 +18,7 @@ fn assert_impls_fn<R,T: Fn()->R>(_: &T){}
2018

2119
fn main() {
2220
let n = None;
21+
//~^ ERROR type annotations needed for `Option<T>`
2322
let e = S(&n);
2423
let f = || {
2524
// S being copy is critical for this to work

‎tests/ui/traits/copy-guessing.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0282]: type annotations needed for `Option<T>`
2+
--> $DIR/copy-guessing.rs:20:9
3+
|
4+
LL | let n = None;
5+
| ^
6+
|
7+
help: consider giving `n` an explicit type, where the type for type parameter `T` is specified
8+
|
9+
LL | let n: Option<T> = None;
10+
| +++++++++++
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0282`.

0 commit comments

Comments
 (0)