Rollup merge of #149320 - ShoyuVanilla:normalized-fudge, r=lcnr

-Znext-solver: normalize expected function input types when fudging

Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/252

r? lcnr
This commit is contained in:
Matthias Krüger
2025-11-27 20:07:11 +01:00
committed by GitHub
16 changed files with 499 additions and 13 deletions
@@ -243,6 +243,11 @@ pub(in super::super) fn check_argument_types(
let expected_input_tys: Option<Vec<_>> = expectation
.only_has_type(self)
.and_then(|expected_output| {
// FIXME(#149379): This operation results in expected input
// types which are potentially not well-formed or for whom the
// function where-bounds don't actually hold. This results
// in weird bugs when later treating these expectations as if
// they were actually correct.
self.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new(self);
@@ -252,6 +257,39 @@ pub(in super::super) fn check_argument_types(
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
ocx.sup(&origin, self.param_env, expected_output, formal_output)?;
let formal_input_tys_ns;
let formal_input_tys = if self.next_trait_solver() {
// In the new solver, the normalizations are done lazily.
// Because of this, if we encounter unnormalized alias types inside this
// fudge scope, we might lose the relationships between them and other vars
// when fudging inference variables created here.
// So, we utilize generalization to normalize aliases by adding a new
// inference var and equating it with the type we want to pull out of the
// fudge scope.
formal_input_tys_ns = formal_input_tys
.iter()
.map(|&ty| {
// If we replace a (unresolved) inference var with a new inference
// var, it will be eventually resolved to itself and this will
// weaken type inferences as the new inference var will be fudged
// out and lose all relationships with other vars while the former
// will not be fudged.
if ty.is_ty_var() {
return ty;
}
let generalized_ty = self.next_ty_var(call_span);
ocx.eq(&origin, self.param_env, ty, generalized_ty).unwrap();
generalized_ty
})
.collect_vec();
formal_input_tys_ns.as_slice()
} else {
formal_input_tys
};
if !ocx.try_evaluate_obligations().is_empty() {
return Err(TypeError::Mismatch);
}
@@ -0,0 +1,32 @@
error[E0308]: mismatched types
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:33
|
LL | let _: Box<dyn Send> = foo(((), ()));
| ^^ expected trait object, found `()`
|
= note: expected trait object `dyn Send`
found unit type `()`
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:32
|
LL | let _: Box<dyn Send> = foo(((), ()));
| --- ^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `foo`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:10:8
|
LL | fn foo<T>(x: (T, ())) -> Box<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `foo`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn foo<T: ?Sized>(x: (T, ())) -> Box<T> {
| ++++++++
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
@@ -0,0 +1,32 @@
error[E0308]: mismatched types
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:33
|
LL | let _: Box<dyn Send> = foo(((), ()));
| ^^ expected trait object, found `()`
|
= note: expected trait object `dyn Send`
found unit type `()`
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:16:32
|
LL | let _: Box<dyn Send> = foo(((), ()));
| --- ^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `foo`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-1.rs:10:8
|
LL | fn foo<T>(x: (T, ())) -> Box<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `foo`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn foo<T: ?Sized>(x: (T, ())) -> Box<T> {
| ++++++++
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
@@ -0,0 +1,19 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// FIXME(#149379): This should pass, but fails due to fudged expactation
// types which are potentially not well-formed or for whom the function
// where-bounds don't actually hold. And this results in weird bugs when
// later treating these expectations as if they were actually correct..
fn foo<T>(x: (T, ())) -> Box<T> {
Box::new(x.0)
}
fn main() {
// Uses expectation as its struct tail is sized, resulting in `(dyn Send, ())`
let _: Box<dyn Send> = foo(((), ()));
//~^ ERROR mismatched types
//~| ERROR the size for values of type `dyn Send` cannot be known at compilation time
}
@@ -0,0 +1,22 @@
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:15:38
|
LL | let _: Box<dyn Send> = sized_box(Box::new(1));
| --------- ^^^^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `sized_box`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:10:14
|
LL | fn sized_box<T>(x: Box<T>) -> Box<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `sized_box`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn sized_box<T: ?Sized>(x: Box<T>) -> Box<T> {
| ++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
@@ -0,0 +1,22 @@
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:15:38
|
LL | let _: Box<dyn Send> = sized_box(Box::new(1));
| --------- ^^^^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `sized_box`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:10:14
|
LL | fn sized_box<T>(x: Box<T>) -> Box<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `sized_box`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn sized_box<T: ?Sized>(x: Box<T>) -> Box<T> {
| ++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
@@ -0,0 +1,17 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// FIXME(#149379): This should pass, but fails due to fudged expactation
// types which are potentially not well-formed or for whom the function
// where-bounds don't actually hold. And this results in weird bugs when
// later treating these expectations as if they were actually correct..
fn sized_box<T>(x: Box<T>) -> Box<T> {
x
}
fn main() {
let _: Box<dyn Send> = sized_box(Box::new(1));
//~^ ERROR the size for values of type `dyn Send` cannot be known at compilation time
}
@@ -0,0 +1,87 @@
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
|
LL | let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
| ^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `Foo`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
|
LL | struct Foo<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `Foo`
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
|
LL | struct Foo<T> {
| ^ this could be changed to `T: ?Sized`...
LL | field: T,
| - ...if indirection were used here: `Box<T>`
error[E0308]: mismatched types
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
|
LL | let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
| ^ expected trait object, found integer
|
= note: expected trait object `dyn Send`
found type `{integer}`
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:42
|
LL | let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `field_to_box1`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:19:18
|
LL | fn field_to_box1<T>(x: Foo<T>) -> Box<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box1`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn field_to_box1<T: ?Sized>(x: Foo<T>) -> Box<T> {
| ++++++++
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:36:38
|
LL | let _: &dyn Send = field_to_box2(&Bar { field: 1 });
| ------------- ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `field_to_box2`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:23:18
|
LL | fn field_to_box2<T>(x: &Bar<T>) -> &T {
| ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box2`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn field_to_box2<T: ?Sized>(x: &Bar<T>) -> &T {
| ++++++++
error[E0308]: mismatched types
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:38:38
|
LL | let _: &dyn Send = field_to_box3(&(1,));
| ------------- ^^^^^ expected `&(dyn Send,)`, found `&({integer},)`
| |
| arguments to this function are incorrect
|
= note: expected reference `&(dyn Send,)`
found reference `&({integer},)`
note: function defined here
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:27:4
|
LL | fn field_to_box3<T>(x: &(T,)) -> &T {
| ^^^^^^^^^^^^^ --------
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
@@ -0,0 +1,87 @@
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
|
LL | let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
| ^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `Foo`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
|
LL | struct Foo<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `Foo`
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:10:12
|
LL | struct Foo<T> {
| ^ this could be changed to `T: ?Sized`...
LL | field: T,
| - ...if indirection were used here: `Box<T>`
error[E0308]: mismatched types
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:55
|
LL | let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
| ^ expected trait object, found integer
|
= note: expected trait object `dyn Send`
found type `{integer}`
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:32:42
|
LL | let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `field_to_box1`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:19:18
|
LL | fn field_to_box1<T>(x: Foo<T>) -> Box<T> {
| ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box1`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn field_to_box1<T: ?Sized>(x: Foo<T>) -> Box<T> {
| ++++++++
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:36:38
|
LL | let _: &dyn Send = field_to_box2(&Bar { field: 1 });
| ------------- ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Send`
note: required by an implicit `Sized` bound in `field_to_box2`
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:23:18
|
LL | fn field_to_box2<T>(x: &Bar<T>) -> &T {
| ^ required by the implicit `Sized` requirement on this type parameter in `field_to_box2`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn field_to_box2<T: ?Sized>(x: &Bar<T>) -> &T {
| ++++++++
error[E0308]: mismatched types
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:38:38
|
LL | let _: &dyn Send = field_to_box3(&(1,));
| ------------- ^^^^^ expected `&(dyn Send,)`, found `&({integer},)`
| |
| arguments to this function are incorrect
|
= note: expected reference `&(dyn Send,)`
found reference `&({integer},)`
note: function defined here
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-3.rs:27:4
|
LL | fn field_to_box3<T>(x: &(T,)) -> &T {
| ^^^^^^^^^^^^^ --------
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
@@ -0,0 +1,40 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// FIXME(#149379): This should pass, but fails due to fudged expactation
// types which are potentially not well-formed or for whom the function
// where-bounds don't actually hold. And this results in weird bugs when
// later treating these expectations as if they were actually correct..
struct Foo<T> {
field: T,
tail: (),
}
struct Bar<T> {
field: T,
}
fn field_to_box1<T>(x: Foo<T>) -> Box<T> {
Box::new(x.field)
}
fn field_to_box2<T>(x: &Bar<T>) -> &T {
&x.field
}
fn field_to_box3<T>(x: &(T,)) -> &T {
&x.0
}
fn main() {
let _: Box<dyn Send> = field_to_box1(Foo { field: 1, tail: () });
//~^ ERROR the size for values of type `dyn Send` cannot be known at compilation time
//~| ERROR the size for values of type `dyn Send` cannot be known at compilation time
//~| ERROR mismatched types
let _: &dyn Send = field_to_box2(&Bar { field: 1 });
//~^ ERROR the size for values of type `dyn Send` cannot be known at compilation time
let _: &dyn Send = field_to_box3(&(1,));
//~^ ERROR mismatched types
}
@@ -26,10 +26,9 @@ impl Foo for () {
fn main() {
let x = String::from("hello, world");
let _ = identity(<() as Foo>::copy_me(&x));
//~^ ERROR overflow evaluating the requirement `String <: <() as Foo>::Item`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed`
//~^ ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed`
//~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == String`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
@@ -12,7 +12,7 @@ LL | trait Foo {
LL | type Item: Copy
| ^^^^ this trait's associated type doesn't have the requirement `String: Copy`
error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item`
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == String`
--> $DIR/alias-bound-unsound.rs:28:43
|
LL | let _ = identity(<() as Foo>::copy_me(&x));
@@ -52,12 +52,6 @@ LL | let _ = identity(<() as Foo>::copy_me(&x));
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
--> $DIR/alias-bound-unsound.rs:28:43
|
LL | let _ = identity(<() as Foo>::copy_me(&x));
| ^^
error: aborting due to 8 previous errors
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0275`.
@@ -0,0 +1,26 @@
//@ compile-flags: -Znext-solver
//@ check-pass
// A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/252.
// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to normalize
// them inside the fudge scope.
trait Trait {
type Assoc;
}
impl<T: Trait> Trait for W<T> {
type Assoc = T::Assoc;
}
impl Trait for i32 {
type Assoc = i32;
}
struct W<T>(T);
fn foo<T: Trait>(_: <T as Trait>::Assoc) -> T {
todo!()
}
fn main() {
let x: W<_> = foo(1);
let _: W<i32> = x;
}
@@ -0,0 +1,40 @@
//@ compile-flags: -Znext-solver
//@ check-pass
// A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/252.
// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to normalize
// them inside the fudge scope.
enum Either<L, R> {
Left(L),
Right(R),
}
impl<L, R> Iterator for Either<L, R>
where
L: Iterator,
R: Iterator<Item = L::Item>,
{
type Item = L::Item;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
pub enum OneOrMany<I: Iterator> {
One(I::Item),
Many(I),
}
pub fn repro<T>(iter: impl IntoIterator<Item = T>) -> OneOrMany<impl Iterator<Item = T>> {
let mut iter = iter.into_iter();
// if the order of two ifs is reversed: no error
if true {
return OneOrMany::Many(Either::Left(iter));
}
if let Some(first) = iter.next() {
return OneOrMany::One(first);
}
OneOrMany::Many(Either::Right(iter))
}
fn main() {}
@@ -0,0 +1,31 @@
//@ compile-flags: -Znext-solver
//@ check-pass
// A regression test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/252.
// `fn fudge_inference_if_ok` might lose relationships between ty vars so we need to normalize
// them inside the fudge scope.
pub struct Error;
trait Throw {
type Error;
fn from_error(error: Self::Error) -> Self;
}
impl<T, E> Throw for Result<T, E> {
type Error = E;
fn from_error(_: Self::Error) -> Self {
unimplemented!()
}
}
fn op<F, T>(_: F) -> Result<T, Error>
where
F: FnOnce() -> Result<T, Error>,
{
unimplemented!()
}
pub fn repro() -> Result<(), Error> {
op(|| Throw::from_error(Error))?
}
fn main() {}
@@ -1,8 +1,8 @@
error[E0271]: type mismatch resolving `A == B`
--> $DIR/more-object-bound.rs:12:5
--> $DIR/more-object-bound.rs:12:17
|
LL | foo::<A, B, dyn Trait<A = A, B = B>>(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
| ^^^^^^^^^^^^^^^^^^^^^^^ types differ
|
= note: required because it appears within the type `dyn Trait<A = A, B = B>`
note: required by a bound in `foo`