Skip to content

Commit

Permalink
Rollup merge of #119091 - compiler-errors:alias-eq-in-structural-norm…
Browse files Browse the repository at this point in the history
…alize, r=lcnr

Use alias-eq in structural normalization

We don't need to register repeated normalizes-to goals in a loop in structural normalize, but instead we can piggyback on the fact that alias-eq will already normalize aliases until they are rigid.

This fixes rust-lang/trait-system-refactor-initiative#78.

r? lcnr
  • Loading branch information
matthiaskrgr authored Dec 19, 2023
2 parents d1e52a8 + 132a288 commit 9a72b7d
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 50 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1498,7 +1498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.resolve_vars_with_obligations(ty);

if self.next_trait_solver()
&& let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind()
&& let ty::Alias(..) = ty.kind()
{
match self
.at(&self.misc(sp), self.param_env)
Expand Down
61 changes: 31 additions & 30 deletions compiler/rustc_trait_selection/src/traits/structural_normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::traits::{FulfillmentError, TraitEngine};
use rustc_middle::ty::{self, Ty};

use crate::traits::{query::evaluate_obligation::InferCtxtExt, NormalizeExt, Obligation};
use crate::traits::{NormalizeExt, Obligation};

pub trait StructurallyNormalizeExt<'tcx> {
fn structurally_normalize(
Expand All @@ -16,42 +16,43 @@ pub trait StructurallyNormalizeExt<'tcx> {
impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
fn structurally_normalize(
&self,
mut ty: Ty<'tcx>,
ty: Ty<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
assert!(!ty.is_ty_var(), "should have resolved vars before calling");

if self.infcx.next_trait_solver() {
// FIXME(-Znext-solver): correctly handle
// overflow here.
for _ in 0..256 {
let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, alias) = *ty.kind() else {
break;
};

let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.cause.span,
});
let obligation = Obligation::new(
self.infcx.tcx,
self.cause.clone(),
self.param_env,
ty::NormalizesTo { alias, term: new_infer_ty.into() },
);
if self.infcx.predicate_may_hold(&obligation) {
fulfill_cx.register_predicate_obligation(self.infcx, obligation);
let errors = fulfill_cx.select_where_possible(self.infcx);
if !errors.is_empty() {
return Err(errors);
}
ty = self.infcx.resolve_vars_if_possible(new_infer_ty);
} else {
break;
}
// FIXME(-Znext-solver): Should we resolve opaques here?
let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = *ty.kind() else {
return Ok(ty);
};

let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.cause.span,
});

// We simply emit an `alias-eq` goal here, since that will take care of
// normalizing the LHS of the projection until it is a rigid projection
// (or a not-yet-defined opaque in scope).
let obligation = Obligation::new(
self.infcx.tcx,
self.cause.clone(),
self.param_env,
ty::PredicateKind::AliasRelate(
ty.into(),
new_infer_ty.into(),
ty::AliasRelationDirection::Equate,
),
);

fulfill_cx.register_predicate_obligation(self.infcx, obligation);
let errors = fulfill_cx.select_where_possible(self.infcx);
if !errors.is_empty() {
return Err(errors);
}

Ok(ty)
Ok(self.infcx.resolve_vars_if_possible(new_infer_ty))
} else {
Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/traits/next-solver/alias-bound-unsound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn main() {
let x = String::from("hello, world");
drop(<() as Foo>::copy_me(&x));
//~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item normalizes-to _`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed`
//~| ERROR overflow evaluating the requirement `String <: <() as Foo>::Item`
//~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed`
Expand Down
3 changes: 1 addition & 2 deletions tests/ui/traits/next-solver/alias-bound-unsound.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ LL | drop(<() as Foo>::copy_me(&x));
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)

error[E0275]: overflow evaluating the requirement `<() as Foo>::Item normalizes-to _`
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
--> $DIR/alias-bound-unsound.rs:24:10
|
LL | drop(<() as Foo>::copy_me(&x));
Expand Down Expand Up @@ -59,7 +59,6 @@ LL | drop(<() as Foo>::copy_me(&x));
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 7 previous errors

Expand Down
15 changes: 15 additions & 0 deletions tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// compile-flags: -Znext-solver
// check-pass

trait Trait {
type Assoc;
}

fn call<T: Trait>(_: <T as Trait>::Assoc, _: T) {}

fn foo<T: Trait>(rigid: <T as Trait>::Assoc, t: T) {
// Check that we can coerce `<?0 as Trait>::Assoc` to `<T as Trait>::Assoc`.
call::<_ /* ?0 */>(rigid, t);
}

fn main() {}
1 change: 0 additions & 1 deletion tests/ui/traits/next-solver/object-unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pub fn copy_any<T>(t: &T) -> T {
//~^ ERROR the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
//~| ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
//~| ERROR the size for values of type `<dyn Setup<From = T> as Setup>::From` cannot be known at compilation time

Expand Down
16 changes: 1 addition & 15 deletions tests/ui/traits/next-solver/object-unsafety.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,6 @@ note: function defined here
LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
| ^^^^ --------------

error[E0308]: mismatched types
--> $DIR/object-unsafety.rs:12:5
|
LL | pub fn copy_any<T>(t: &T) -> T {
| - - expected `T` because of return type
| |
| expected this type parameter
LL | copy::<dyn Setup<From=T>>(t)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
|
= note: expected type parameter `T`
found associated type `<dyn Setup<From = T> as Setup>::From`
= note: you might be missing a type parameter or trait bound

error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
--> $DIR/object-unsafety.rs:12:5
|
Expand All @@ -72,7 +58,7 @@ help: consider further restricting the associated type
LL | pub fn copy_any<T>(t: &T) -> T where <dyn Setup<From = T> as Setup>::From: Sized {
| +++++++++++++++++++++++++++++++++++++++++++++++++

error: aborting due to 6 previous errors
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 comments on commit 9a72b7d

Please sign in to comment.