Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

analyse visitor: build proof tree in probe #124936

Merged
merged 2 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>
/// This currently assumes that unifying the var values trivially succeeds.
/// Adding any inference constraints which weren't present when originally
/// computing the canonical query can result in bugs.
#[instrument(level = "debug", skip(infcx, span, param_env))]
pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
infcx: &InferCtxt<'tcx>,
span: Span,
Expand Down
44 changes: 33 additions & 11 deletions compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
/// inference constraints, and optionally the args of an impl if this candidate
/// came from a `CandidateSource::Impl`. This function modifies the state of the
/// `infcx`.
#[instrument(
level = "debug",
skip_all,
fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals)
)]
pub fn instantiate_nested_goals_and_opt_impl_args(
&self,
span: Span,
Expand Down Expand Up @@ -213,10 +218,23 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
};
let goal =
goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
let proof_tree = EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal)
})
.1;
// We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
// expected term. This means that candidates which only fail due to nested goals
// and which normalize to a different term then the final result could ICE: when
// building their proof tree, the expected term was unconstrained, but when
// instantiating the candidate it is already constrained to the result of another
// candidate.
let proof_tree = infcx
.probe(|_| {
EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
ecx.evaluate_goal_raw(
GoalEvaluationKind::Root,
GoalSource::Misc,
goal,
)
})
})
.1;
InspectGoal::new(
infcx,
self.goal.depth + 1,
Expand All @@ -225,13 +243,17 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
source,
)
}
_ => InspectGoal::new(
infcx,
self.goal.depth + 1,
infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1.unwrap(),
None,
source,
),
_ => {
// We're using a probe here as evaluating a goal could constrain
// inference variables by choosing one candidate. If we then recurse
// into another candidate who ends up with different inference
// constraints, we get an ICE if we already applied the constraints
// from the chosen candidate.
let proof_tree = infcx
.probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
.unwrap();
InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
}
})
.collect();

Expand Down
14 changes: 0 additions & 14 deletions tests/crashes/124702.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//@ compile-flags: -Znext-solver=coherence
//@ check-pass

// A regression test for #124791. Computing ambiguity causes
// for the overlap of the `ToString` impls caused an ICE.
#![crate_type = "lib"]
#![feature(min_specialization)]
trait Display {}

trait ToOwned {
type Owned;
}

impl<T> ToOwned for T {
type Owned = T;
}

struct Cow<B: ?Sized>(B);

impl<B: ?Sized> Display for Cow<B>
where
B: ToOwned,
B::Owned: Display,
{
}

impl Display for () {}

trait ToString {
fn to_string();
}

impl<T: Display + ?Sized> ToString for T {
default fn to_string() {}
}

impl ToString for Cow<str> {
fn to_string() {}
}

impl ToOwned for str {
type Owned = ();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ compile-flags: -Znext-solver=coherence

// A regression test for #124791. Computing ambiguity causes
// for the overlap of the `ToString` impls caused an ICE.
#![crate_type = "lib"]
trait ToOwned {
type Owned;
}
impl<T> ToOwned for T {
type Owned = u8;
}
impl ToOwned for str {
type Owned = i8;
}

trait Overlap {}
impl<T: ToOwned<Owned = i8> + ?Sized> Overlap for T {}
impl Overlap for str {}
//~^ ERROR conflicting implementations of trait `Overlap`
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0119]: conflicting implementations of trait `Overlap` for type `str`
--> $DIR/ambiguity-causes-canonical-state-ice-2.rs:18:1
|
LL | impl<T: ToOwned<Owned = i8> + ?Sized> Overlap for T {}
| --------------------------------------------------- first implementation here
LL | impl Overlap for str {}
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `str`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0119`.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ where
// entering the cycle from `A` fails, but would work if we were to use the cache
// result of `B<X>`.
impls_trait::<A<X>, _, _, _>();
//~^ ERROR the trait bound `A<X>: Trait<i32, u8, u8>` is not satisfied
//~^ ERROR the trait bound `A<X>: Trait<_, _, _>` is not satisfied
}

fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
error[E0277]: the trait bound `A<X>: Trait<i32, u8, u8>` is not satisfied
error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
--> $DIR/incompleteness-unstable-result.rs:63:19
|
LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `Trait<i32, u8, u8>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
| ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
|
note: required for `A<X>` to implement `Trait<i32, u8, u8>`
= help: the trait `Trait<U, V, D>` is implemented for `A<T>`
note: required for `A<X>` to implement `Trait<_, _, _>`
--> $DIR/incompleteness-unstable-result.rs:32:50
|
LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
Expand All @@ -13,16 +14,12 @@ LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
LL | A<T>: Trait<U, D, V>,
| -------------- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<i32, u8, u8>`
= note: required for `A<X>` to implement `Trait<_, _, _>`
note: required by a bound in `impls_trait`
--> $DIR/incompleteness-unstable-result.rs:51:28
|
LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
|
LL | X: IncompleteGuidance<u32, i16>, A<X>: Trait<i32, u8, u8>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~

error: aborting due to 1 previous error

Expand Down