Skip to content

Commit ce0ebd8

Browse files
committed
analyse visitor: build proof tree in probe
1 parent 8c7c151 commit ce0ebd8

File tree

3 files changed

+78
-11
lines changed

3 files changed

+78
-11
lines changed

compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs

+1
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>
409409
/// This currently assumes that unifying the var values trivially succeeds.
410410
/// Adding any inference constraints which weren't present when originally
411411
/// computing the canonical query can result in bugs.
412+
#[instrument(level = "debug", skip(infcx, span, param_env))]
412413
pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
413414
infcx: &InferCtxt<'tcx>,
414415
span: Span,

compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
146146
/// inference constraints, and optionally the args of an impl if this candidate
147147
/// came from a `CandidateSource::Impl`. This function modifies the state of the
148148
/// `infcx`.
149+
#[instrument(
150+
level = "debug",
151+
skip_all,
152+
fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals)
153+
)]
149154
pub fn instantiate_nested_goals_and_opt_impl_args(
150155
&self,
151156
span: Span,
@@ -213,10 +218,23 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
213218
};
214219
let goal =
215220
goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
216-
let proof_tree = EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
217-
ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal)
218-
})
219-
.1;
221+
// We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
222+
// expected term. This means that candidates which only fail due to nested goals
223+
// and which normalize to a different term then the final result could ICE: when
224+
// building their proof tree, the expected term was unconstrained, but when
225+
// instantiating the candidate it is already constrained to the result of another
226+
// candidate.
227+
let proof_tree = infcx
228+
.probe(|_| {
229+
EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
230+
ecx.evaluate_goal_raw(
231+
GoalEvaluationKind::Root,
232+
GoalSource::Misc,
233+
goal,
234+
)
235+
})
236+
})
237+
.1;
220238
InspectGoal::new(
221239
infcx,
222240
self.goal.depth + 1,
@@ -225,13 +243,17 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
225243
source,
226244
)
227245
}
228-
_ => InspectGoal::new(
229-
infcx,
230-
self.goal.depth + 1,
231-
infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1.unwrap(),
232-
None,
233-
source,
234-
),
246+
_ => {
247+
// We're using a probe here as evaluating a goal could constrain
248+
// inference variables by choosing one candidate. If we then recurse
249+
// into another candidate who ends up with different inference
250+
// constraints, we get an ICE if we already applied the constraints
251+
// from the chosen candidate.
252+
let proof_tree = infcx
253+
.probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
254+
.unwrap();
255+
InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
256+
}
235257
})
236258
.collect();
237259

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//@ compile-flags: -Znext-solver=coherence
2+
//@ check-pass
3+
#![crate_type = "lib"]
4+
#![feature(min_specialization)]
5+
6+
// A regression test for #124791. Computing ambiguity causes
7+
// for the overlap of the `ToString` impls caused an ICE.
8+
9+
trait Display {}
10+
11+
trait ToOwned {
12+
type Owned;
13+
}
14+
15+
impl<T> ToOwned for T {
16+
type Owned = T;
17+
}
18+
19+
struct Cow<B: ?Sized>(B);
20+
21+
impl<B: ?Sized> Display for Cow<B>
22+
where
23+
B: ToOwned,
24+
B::Owned: Display,
25+
{
26+
}
27+
28+
impl Display for () {}
29+
30+
trait ToString {
31+
fn to_string();
32+
}
33+
34+
impl<T: Display + ?Sized> ToString for T {
35+
default fn to_string() {}
36+
}
37+
38+
impl ToString for Cow<str> {
39+
fn to_string() {}
40+
}
41+
42+
impl ToOwned for str {
43+
type Owned = ();
44+
}

0 commit comments

Comments
 (0)