Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let param_env = self.infcx.param_env;
// Upcast to a `Clause`, then to a `Predicate`.
let predicate = clause.upcast(self.tcx()).upcast(self.tcx());
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
let _: Result<(), ErrorGuaranteed> = self.fully_perform_op(
locations,
category,
param_env.and(type_op::prove_predicate::ProvePredicate { predicate }),
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_borrowck/src/type_check/free_region_relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,10 +508,16 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
}

let MirBorrowckImpliedOutlivesBounds {
outlives_bounds,
normalized_inputs_and_output,
} = value;
let (
MirBorrowckImpliedOutlivesBounds {
outlives_bounds,
normalized_inputs_and_output,
},
certainty,
) = value;

// FIXME: We're implicitly ignoring the certainty here.
let _ = certainty;

// Because of #109628, we may have unexpected placeholders. Ignore them!
// FIXME(#109628): panic in this case once the issue is fixed.
Expand Down
21 changes: 13 additions & 8 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl<'tcx> InferCtxt<'tcx> {
original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
) -> InferResult<'tcx, R>
) -> InferResult<'tcx, (R, Certainty)>
where
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
Expand Down Expand Up @@ -324,9 +324,17 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

let QueryResponse {
var_values: _,
ref region_constraints,
certainty,
opaque_types: _,
ref value,
} = query_response.value;

// ...also include the other query region constraints from the query.
output_query_region_constraints.constraints.extend(
query_response.value.region_constraints.constraints.iter().filter_map(|&r_c| {
region_constraints.constraints.iter().filter_map(|&r_c| {
let r_c = instantiate_value(self.tcx, &result_args, r_c);

// Screen out `'a: 'a` or `'a == 'a` cases.
Expand All @@ -338,18 +346,15 @@ impl<'tcx> InferCtxt<'tcx> {
// at once, rather than calling `instantiate_value` repeatedly which may
// create more universes.
output_query_region_constraints.assumptions.extend(
query_response
.value
.region_constraints
region_constraints
.assumptions
.iter()
.map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)),
);

let user_result: R =
query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
let user_result: R = instantiate_value(self.tcx, &result_args, value.clone());

Ok(InferOk { value: user_result, obligations })
Ok(InferOk { value: (user_result, certainty), obligations })
}

/// Given the original values and the (canonicalized) result from
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn implied_outlives_bounds<'a, 'tcx>(

let mut constraints = QueryRegionConstraints::default();
let span = infcx.tcx.def_span(body_def_id);
let Ok(InferOk { value: mut bounds, obligations }) = infcx
let Ok(InferOk { value: (mut bounds, certainty), obligations }) = infcx
.instantiate_nll_query_response_and_region_obligations(
&ObligationCause::dummy_with_span(span),
param_env,
Expand All @@ -72,6 +72,9 @@ fn implied_outlives_bounds<'a, 'tcx>(
};
assert_eq!(obligations.len(), 0);

// FIXME: We're silently ignoring the certainty here, this feels off.
let _ = certainty;

// Because of #109628, we may have unexpected placeholders. Ignore them!
// FIXME(#109628): panic in this case once the issue is fixed.
bounds.retain(|bound| !bound.has_placeholders());
Expand Down
18 changes: 14 additions & 4 deletions compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rustc_infer::traits::{PredicateObligations, ScrubbedTraitError};
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt, TypeFoldable};
use rustc_span::Span;
use tracing::debug;

use crate::infer::canonical::{
CanonicalQueryInput, CanonicalQueryResponse, Certainty, OriginalQueryValues,
Expand Down Expand Up @@ -93,7 +94,6 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
Self::QueryResponse,
Option<CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>>,
PredicateObligations<'tcx>,
Certainty,
),
NoSolution,
> {
Expand All @@ -102,7 +102,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
let canonical_self = infcx.canonicalize_query(query_key, &mut canonical_var_values);
let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;

let InferOk { value, obligations } = infcx
let InferOk { value: (value, certainty), obligations } = infcx
.instantiate_nll_query_response_and_region_obligations(
&ObligationCause::dummy_with_span(span),
old_param_env,
Expand All @@ -111,7 +111,17 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
output_query_region_constraints,
)?;

Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
if infcx.next_trait_solver() {
match certainty {
Certainty::Proven => {}
Certainty::Ambiguous => {
debug!("TypeOp resulted in unexpected ambiguity: {query_key:?}");
return Err(NoSolution);
}
}
}

Ok((value, Some(canonical_self), obligations))
}
}

Expand Down Expand Up @@ -150,7 +160,7 @@ where
"fully_perform",
span,
|ocx| {
let (output, ei, obligations, _) =
let (output, ei, obligations) =
Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
error_info = ei;

Expand Down
11 changes: 8 additions & 3 deletions src/tools/miri/tests/pass/dyn-upcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,9 +499,14 @@ fn modulo_binder() {
}
impl<T, U> Trait<T, U> for () {}

(&() as &'static dyn for<'a> Trait<&'static (), &'a ()>
as &'static dyn Trait<&'static (), &'static ()>)
.say_hello(&0);
// We can't have `dyn Trait<&'static (), &'static ()>` directly here
// as that results in an ambiguity error in MIR borrowck.
fn generic<T: 'static>() {
(&() as &'static dyn for<'a> Trait<T, &'a ()> as &'static dyn Trait<T, &'static ()>)
.say_hello(&0);
}

generic::<&'static ()>();
Comment on lines -502 to +509

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. Breaking MIRI does not bode well for the fallout here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

proving dyn Trait<&'x (), &'y ()>: Supertrait<&'z ()> is ambiguous as it either requires 'z = 'x or 'z = 'y. The reason this previously compiled with -Znext-solver is that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your last sentence cut off I think.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proving dyn Trait<&'x (), &'y ()>: Supertrait<&'z ()> is ambiguous as it either requires 'z = 'x or 'z = 'y. The reason this previously compiled with -Znext-solver is that during HIR typeck succeeds as it has Trait<&'static (), &'static ()> while MIR borrowck proves it for Trait<&'x (), &'y ()> and the resulting ambiguity got ignored.

The explanation here is in #164055 (comment)

}

// Test for <https://github.com/rust-lang/rust/issues/135315>.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0283]: type annotations needed: cannot satisfy `dyn D<&(), &()>: B<&()>`
--> $DIR/ambiguity-due-to-uniquification-1.rs:15:31
|
LL | (&() as &dyn D<&(), &()>).f()
| ^
|
= note: cannot satisfy `dyn D<&(), &()>: B<&()>`
help: the trait `B<C>` is implemented for `()`
--> $DIR/ambiguity-due-to-uniquification-1.rs:9:1
|
LL | impl<C> B<C> for () {}
| ^^^^^^^^^^^^^^^^^^^
note: required by a bound in `D::f`
--> $DIR/ambiguity-due-to-uniquification-1.rs:10:16
|
LL | trait D<C, E>: B<C> + B<E> {
| ^^^^ required by this bound in `D::f`
LL | fn f(&self) {}
|

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0283`.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@ check-pass
//@[current] check-pass

// Regression test for #139409 and trait-system-refactor-initiative#27.

Expand All @@ -13,4 +13,5 @@ trait D<C, E>: B<C> + B<E> {
impl<C, E> D<C, E> for () {}
fn main() {
(&() as &dyn D<&(), &()>).f()
//[next]~^ ERROR: type annotations needed: cannot satisfy `dyn D<&(), &()>: B<&()>`
Comment on lines 15 to +16

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So...this on first glance this really doesn't seem to me like it should fail. I guess from a technical perspective, I can probably see why it does (lack of OR constraints) but even that I'm unsure about, because I would expect that D<C, E>: B<C> and D<C, E>: B<E> to be able to be solved separately without region constraints.

Given that I would expect that this test be marked as known-bug under the next-solver.

@lcnr lcnr Nov 2, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is odd because it should also just be ambiguous during HIR typeck already.

For dyn D<&'a (), &'b ()> HIR typeck explicitly proves B<&'a ()> and B<&'b ()>, both of which work as one of the candidates has no region constraints. The MIR body has the function item <dyn D<&'a (), &'b ()> as D<&'c (), &'d ()>>::f, proving dyn D<&'a (), &'b ()>: D<&'c (), &'d ()> for that one is ambiguous.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0283]: type annotations needed: cannot satisfy `impl Trait<'_> + Trait<'_>: Trait<'_>`
--> $DIR/ambiguity-due-to-uniquification-2.rs:16:5
|
LL | impls_trait::<'y, _>(foo::<'x, 'y>());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: cannot satisfy `impl Trait<'_> + Trait<'_>: Trait<'_>`
help: the trait `Trait<'t>` is implemented for `()`
--> $DIR/ambiguity-due-to-uniquification-2.rs:9:1
|
LL | impl<'t> Trait<'t> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `impls_trait`
--> $DIR/ambiguity-due-to-uniquification-2.rs:13:23
|
LL | fn impls_trait<'x, T: Trait<'x>>(_: T) {}
| ^^^^^^^^^ required by this bound in `impls_trait`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0283`.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@ check-pass
//@[current] check-pass

// Regression test from trait-system-refactor-initiative#27.

Expand All @@ -14,6 +14,7 @@ fn impls_trait<'x, T: Trait<'x>>(_: T) {}

fn bar<'x, 'y>() {
impls_trait::<'y, _>(foo::<'x, 'y>());
//[next]~^ ERROR: type annotations needed: cannot satisfy `impl Trait<'_> + Trait<'_>: Trait<'_>`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar point to above.

}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0283]: type annotations needed: cannot satisfy `dyn Object<&(), &()>: Trait<&()>`
--> $DIR/ambiguity-due-to-uniquification-3.rs:30:5
|
LL | impls_trait(obj, t);
| ^^^^^^^^^^^^^^^^^^^
|
= note: cannot satisfy `dyn Object<&(), &()>: Trait<&()>`
help: the trait `Trait<T>` is implemented for `()`
--> $DIR/ambiguity-due-to-uniquification-3.rs:17:1
|
LL | impl<T> Trait<T> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `impls_trait`
--> $DIR/ambiguity-due-to-uniquification-3.rs:26:19
|
LL | fn impls_trait<T: Trait<U>, U>(_: Inv<T>, _: Inv<U>) {}
| ^^^^^^^^ required by this bound in `impls_trait`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0283`.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@ check-pass
//@[current] check-pass

// Regression test from trait-system-refactor-initiative#27.
//
Expand All @@ -28,6 +28,7 @@ fn impls_trait<T: Trait<U>, U>(_: Inv<T>, _: Inv<U>) {}
fn bar() {
let (obj, t) = foo();
impls_trait(obj, t);
//[next]~^ ERROR: type annotations needed: cannot satisfy `dyn Object<&(), &()>: Trait<&()>`
let _: Inv<dyn Object<&(), &()>> = obj;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0283]: type annotations needed: cannot satisfy `dyn D<&(), &()>: B<&()>`
--> $DIR/ambiguity-due-to-uniquification-old-solver.rs:15:31
|
LL | (&() as &dyn D<&(), &()>).f()
| ^
|
= note: cannot satisfy `dyn D<&(), &()>: B<&()>`
help: the trait `B<C>` is implemented for `()`
--> $DIR/ambiguity-due-to-uniquification-old-solver.rs:9:1
|
LL | impl<C> B<C> for () {}
| ^^^^^^^^^^^^^^^^^^^
note: required by a bound in `D::f`
--> $DIR/ambiguity-due-to-uniquification-old-solver.rs:10:16
|
LL | trait D<C, E>: B<C> + B<E> {
| ^^^^ required by this bound in `D::f`
LL | fn f(&self) {}
|

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0283`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[current] check-pass

// Regression test for #139409 and trait-system-refactor-initiative#27.

trait B<C> {}
impl<C> B<C> for () {}
trait D<C, E>: B<C> + B<E> {
fn f(&self) {}
}
impl<C, E> D<C, E> for () {}
fn main() {
(&() as &dyn D<&(), &()>).f()
//[next]~^ ERROR: type annotations needed: cannot satisfy `dyn D<&(), &()>: B<&()>`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0283]: type annotations needed: cannot satisfy `dyn Tr<'a, 'a, (), ()>: Sup<'a, ()>`
--> $DIR/ambiguity-due-to-uniquification-unsound-old.rs:37:7
|
LL | x.hide_me()
| ^^^^^^^
|
= note: cannot satisfy `dyn Tr<'a, 'a, (), ()>: Sup<'a, ()>`
help: the trait `Sup<'a, ()>` is implemented for `&'a str`
--> $DIR/ambiguity-due-to-uniquification-unsound-old.rs:15:1
|
LL | impl<'a> Sup<'a, ()> for &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required for `dyn Tr<'a, 'a, (), ()>` to implement `HideMe`
--> $DIR/ambiguity-due-to-uniquification-unsound-old.rs:31:57
|
LL | impl<'a, T: Sup<'a, (), Assoc = &'static str> + ?Sized> HideMe for T {
| --------------------------------- ^^^^^^ ^
| |
| unsatisfied trait bound introduced here

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0283`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// A regression test for trait-system-refactor-initiative#307 affecting
// the old solver instead. The old solver only cares about region identity
// inside of `project` when merging candidates. This means this unsoundness
// also affects the old solver.

//@ revisions: current next
//@[next] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[current] build-pass
//@[current] known-bug: unknown
trait Sup<'a, T> {
type Assoc;
fn to_assoc(&self) -> Self::Assoc;
}
impl<'a> Sup<'a, ()> for &'a str {
type Assoc = &'a str;
fn to_assoc(&self) -> Self::Assoc { self }
}

// Need the trait arguments to pass WF-checking
trait Tr<'a, 'b, T, U>: Sup<'a, T, Assoc = &'a str> + Sup<'b, U, Assoc = &'b str> {}
impl<'a> Tr<'a, 'a, (), ()> for &'a str {}

trait HideMe {
fn hide_me(&self) -> &'static str;
}

// Need the ambiguous `T: Sup<'a, (), Assoc = &'static str>` bound to only be
// used inside of the trait impl, as otherwise we also encounter ambiguity
// during normalization, which ICEs instead of ignoring it.
impl<'a, T: Sup<'a, (), Assoc = &'static str> + ?Sized> HideMe for T {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this one clearly should not pass.

fn hide_me(&self) -> &'static str {
self.to_assoc()
}
}
fn yeet<'a>(x: &dyn Tr<'a, 'a, (), ()>) -> &'static str {
x.hide_me()
//[next]~^ ERROR: type annotations needed: cannot satisfy `dyn Tr<'a, 'a, (), ()>: Sup<'a, ()>`
}

fn main() {
let s = String::from("hello");
let r = yeet(&s.as_str());
drop(s);
println!("{r}");
}
Loading
Loading