Skip to content

Commit

Permalink
Auto merge of #113336 - compiler-errors:new-solver-iat, r=lcnr
Browse files Browse the repository at this point in the history
Add support for inherent projections in new solver

Not hard to support these, and it cuts out a really big chunk of failing UI tests with `--compare-mode=next-solver`

r? `@lcnr` (feel free to reassign, anyone can review this)
  • Loading branch information
bors committed Jul 17, 2023
2 parents f1eab64 + c9ce51b commit 4c7af42
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 13 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ impl<'tcx> AliasTy<'tcx> {
/// I_i impl subst
/// P_j GAT subst
/// ```
pub fn rebase_args_onto_impl(
pub fn rebase_inherent_args_onto_impl(
self,
impl_args: ty::GenericArgsRef<'tcx>,
tcx: TyCtxt<'tcx>,
Expand Down
44 changes: 44 additions & 0 deletions compiler/rustc_trait_selection/src/solve/inherent_projection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty;

use super::EvalCtxt;

impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn normalize_inherent_associated_type(
&mut self,
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
let inherent = goal.predicate.projection_ty;
let expected = goal.predicate.term.ty().expect("inherent consts are treated separately");

let impl_def_id = tcx.parent(inherent.def_id);
let impl_substs = self.fresh_args_for_item(impl_def_id);

// Equate impl header and add impl where clauses
self.eq(
goal.param_env,
inherent.self_ty(),
tcx.type_of(impl_def_id).instantiate(tcx, impl_substs),
)?;

// Equate IAT with the RHS of the project goal
let inherent_substs = inherent.rebase_inherent_args_onto_impl(impl_substs, tcx);
self.eq(
goal.param_env,
expected,
tcx.type_of(inherent.def_id).instantiate(tcx, inherent_substs),
)
.expect("expected goal term to be fully unconstrained");

// Check both where clauses on the impl and IAT
self.add_goals(
tcx.predicates_of(inherent.def_id)
.instantiate(tcx, inherent_substs)
.into_iter()
.map(|(pred, _)| goal.with(tcx, pred)),
);

self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ mod assembly;
mod canonicalize;
mod eval_ctxt;
mod fulfill;
mod inherent_projection;
pub mod inspect;
mod normalize;
mod opaques;
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_trait_selection/src/solve/project_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.merge_candidates(candidates)
}
ty::AssocItemContainer::ImplContainer => {
bug!("IATs not supported here yet")
self.normalize_inherent_associated_type(goal)
}
}
} else {
Expand Down Expand Up @@ -112,6 +112,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
) -> QueryResult<'tcx> {
if let Some(projection_pred) = assumption.as_projection_clause() {
if projection_pred.projection_def_id() == goal.predicate.def_id() {
let tcx = ecx.tcx();
ecx.probe_candidate("assumption").enter(|ecx| {
let assumption_projection_pred =
ecx.instantiate_binder_with_infer(projection_pred);
Expand All @@ -122,6 +123,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
)?;
ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
.expect("expected goal term to be fully unconstrained");

// Add GAT where clauses from the trait's definition
ecx.add_goals(
tcx.predicates_of(goal.predicate.def_id())
.instantiate_own(tcx, goal.predicate.projection_ty.args)
.map(|(pred, _)| goal.with(tcx, pred)),
);

then(ecx)
})
} else {
Expand Down Expand Up @@ -160,6 +169,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
.map(|pred| goal.with(tcx, pred));
ecx.add_goals(where_clause_bounds);

// Add GAT where clauses from the trait's definition
ecx.add_goals(
tcx.predicates_of(goal.predicate.def_id())
.instantiate_own(tcx, goal.predicate.projection_ty.args)
.map(|(pred, _)| goal.with(tcx, pred)),
);

// In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782).
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_trait_selection/src/solve/weak_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {

let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args);
self.eq(goal.param_env, expected, actual)?;

// Check where clauses
self.add_goals(
tcx.predicates_of(weak_ty.def_id)
.instantiate(tcx, weak_ty.args)
.predicates
.into_iter()
.map(|pred| goal.with(tcx, pred)),
);

self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
16 changes: 12 additions & 4 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1402,9 +1402,17 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
let impl_def_id = tcx.parent(alias_ty.def_id);
let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id);

let impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
let impl_ty =
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
if !selcx.infcx.next_trait_solver() {
impl_ty = normalize_with_depth_to(
selcx,
param_env,
cause.clone(),
depth + 1,
impl_ty,
obligations,
);
}

// Infer the generic parameters of the impl by unifying the
// impl type with the self type of the projection.
Expand All @@ -1421,7 +1429,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
}
}

alias_ty.rebase_args_onto_impl(impl_args, tcx)
alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx)
}

enum Projected<'tcx> {
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/associated-inherent-types/inference.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Testing inference capabilities.
// check-pass
// revisions: current next
//[next] compile-flags: -Ztrait-solver=next

#![feature(inherent_associated_types)]
#![allow(incomplete_features)]
Expand Down
9 changes: 7 additions & 2 deletions tests/ui/traits/new-solver/alias-bound-unsound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ trait Foo {

impl Foo for () {
type Item = String where String: Copy;
//~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Copy`
}

fn main() {
let x = String::from("hello, world");
drop(<() as Foo>::copy_me(&x));
//~^ ERROR the type `&<() as Foo>::Item` is not well-formed
//~| ERROR `<() as Foo>::Item` is not well-formed
//~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized`
//~| 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`
//~| ERROR type annotations needed
println!("{x}");
}
65 changes: 60 additions & 5 deletions tests/ui/traits/new-solver/alias-bound-unsound.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,69 @@
error: the type `&<() as Foo>::Item` is not well-formed
--> $DIR/alias-bound-unsound.rs:23:31
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy`
--> $DIR/alias-bound-unsound.rs:18:17
|
LL | type Item = String where String: Copy;
| ^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
note: required by a bound in `Foo::Item`
--> $DIR/alias-bound-unsound.rs:8:16
|
LL | type Item: Copy
| ^^^^ required by this bound in `Foo::Item`

error[E0282]: type annotations needed
--> $DIR/alias-bound-unsound.rs:24:5
|
LL | drop(<() as Foo>::copy_me(&x));
| ^^^^ cannot infer type of the type parameter `T` declared on the function `drop`
|
help: consider specifying the generic argument
|
LL | drop::<T>(<() as Foo>::copy_me(&x));
| +++++

error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed`
--> $DIR/alias-bound-unsound.rs:24:31
|
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: the type `<() as Foo>::Item` is not well-formed
--> $DIR/alias-bound-unsound.rs:23:10
error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item`
--> $DIR/alias-bound-unsound.rs:24:31
|
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 well-formed`
--> $DIR/alias-bound-unsound.rs:24:10
|
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 == _`
--> $DIR/alias-bound-unsound.rs:24:10
|
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: Sized`
--> $DIR/alias-bound-unsound.rs:24:10
|
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: the return type of a function must have a statically known size

error: aborting due to 2 previous errors
error: aborting due to 7 previous errors

Some errors have detailed explanations: E0275, E0282.
For more information about an error, try `rustc --explain E0275`.

0 comments on commit 4c7af42

Please sign in to comment.