Skip to content

Commit 4c7af42

Browse files
committed
Auto merge of #113336 - compiler-errors:new-solver-iat, r=lcnr
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)
2 parents f1eab64 + c9ce51b commit 4c7af42

File tree

9 files changed

+154
-13
lines changed

9 files changed

+154
-13
lines changed

compiler/rustc_middle/src/ty/sty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ impl<'tcx> AliasTy<'tcx> {
13131313
/// I_i impl subst
13141314
/// P_j GAT subst
13151315
/// ```
1316-
pub fn rebase_args_onto_impl(
1316+
pub fn rebase_inherent_args_onto_impl(
13171317
self,
13181318
impl_args: ty::GenericArgsRef<'tcx>,
13191319
tcx: TyCtxt<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
2+
use rustc_middle::ty;
3+
4+
use super::EvalCtxt;
5+
6+
impl<'tcx> EvalCtxt<'_, 'tcx> {
7+
pub(super) fn normalize_inherent_associated_type(
8+
&mut self,
9+
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
10+
) -> QueryResult<'tcx> {
11+
let tcx = self.tcx();
12+
let inherent = goal.predicate.projection_ty;
13+
let expected = goal.predicate.term.ty().expect("inherent consts are treated separately");
14+
15+
let impl_def_id = tcx.parent(inherent.def_id);
16+
let impl_substs = self.fresh_args_for_item(impl_def_id);
17+
18+
// Equate impl header and add impl where clauses
19+
self.eq(
20+
goal.param_env,
21+
inherent.self_ty(),
22+
tcx.type_of(impl_def_id).instantiate(tcx, impl_substs),
23+
)?;
24+
25+
// Equate IAT with the RHS of the project goal
26+
let inherent_substs = inherent.rebase_inherent_args_onto_impl(impl_substs, tcx);
27+
self.eq(
28+
goal.param_env,
29+
expected,
30+
tcx.type_of(inherent.def_id).instantiate(tcx, inherent_substs),
31+
)
32+
.expect("expected goal term to be fully unconstrained");
33+
34+
// Check both where clauses on the impl and IAT
35+
self.add_goals(
36+
tcx.predicates_of(inherent.def_id)
37+
.instantiate(tcx, inherent_substs)
38+
.into_iter()
39+
.map(|(pred, _)| goal.with(tcx, pred)),
40+
);
41+
42+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
43+
}
44+
}

compiler/rustc_trait_selection/src/solve/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mod assembly;
2525
mod canonicalize;
2626
mod eval_ctxt;
2727
mod fulfill;
28+
mod inherent_projection;
2829
pub mod inspect;
2930
mod normalize;
3031
mod opaques;

compiler/rustc_trait_selection/src/solve/project_goals.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
4848
self.merge_candidates(candidates)
4949
}
5050
ty::AssocItemContainer::ImplContainer => {
51-
bug!("IATs not supported here yet")
51+
self.normalize_inherent_associated_type(goal)
5252
}
5353
}
5454
} else {
@@ -112,6 +112,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
112112
) -> QueryResult<'tcx> {
113113
if let Some(projection_pred) = assumption.as_projection_clause() {
114114
if projection_pred.projection_def_id() == goal.predicate.def_id() {
115+
let tcx = ecx.tcx();
115116
ecx.probe_candidate("assumption").enter(|ecx| {
116117
let assumption_projection_pred =
117118
ecx.instantiate_binder_with_infer(projection_pred);
@@ -122,6 +123,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
122123
)?;
123124
ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
124125
.expect("expected goal term to be fully unconstrained");
126+
127+
// Add GAT where clauses from the trait's definition
128+
ecx.add_goals(
129+
tcx.predicates_of(goal.predicate.def_id())
130+
.instantiate_own(tcx, goal.predicate.projection_ty.args)
131+
.map(|(pred, _)| goal.with(tcx, pred)),
132+
);
133+
125134
then(ecx)
126135
})
127136
} else {
@@ -160,6 +169,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
160169
.map(|pred| goal.with(tcx, pred));
161170
ecx.add_goals(where_clause_bounds);
162171

172+
// Add GAT where clauses from the trait's definition
173+
ecx.add_goals(
174+
tcx.predicates_of(goal.predicate.def_id())
175+
.instantiate_own(tcx, goal.predicate.projection_ty.args)
176+
.map(|(pred, _)| goal.with(tcx, pred)),
177+
);
178+
163179
// In case the associated item is hidden due to specialization, we have to
164180
// return ambiguity this would otherwise be incomplete, resulting in
165181
// unsoundness during coherence (#105782).

compiler/rustc_trait_selection/src/solve/weak_types.rs

+10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
1414

1515
let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args);
1616
self.eq(goal.param_env, expected, actual)?;
17+
18+
// Check where clauses
19+
self.add_goals(
20+
tcx.predicates_of(weak_ty.def_id)
21+
.instantiate(tcx, weak_ty.args)
22+
.predicates
23+
.into_iter()
24+
.map(|pred| goal.with(tcx, pred)),
25+
);
26+
1727
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1828
}
1929
}

compiler/rustc_trait_selection/src/traits/project.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -1402,9 +1402,17 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
14021402
let impl_def_id = tcx.parent(alias_ty.def_id);
14031403
let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id);
14041404

1405-
let impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
1406-
let impl_ty =
1407-
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
1405+
let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
1406+
if !selcx.infcx.next_trait_solver() {
1407+
impl_ty = normalize_with_depth_to(
1408+
selcx,
1409+
param_env,
1410+
cause.clone(),
1411+
depth + 1,
1412+
impl_ty,
1413+
obligations,
1414+
);
1415+
}
14081416

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

1424-
alias_ty.rebase_args_onto_impl(impl_args, tcx)
1432+
alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx)
14251433
}
14261434

14271435
enum Projected<'tcx> {

tests/ui/associated-inherent-types/inference.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Testing inference capabilities.
22
// check-pass
3+
// revisions: current next
4+
//[next] compile-flags: -Ztrait-solver=next
35

46
#![feature(inherent_associated_types)]
57
#![allow(incomplete_features)]

tests/ui/traits/new-solver/alias-bound-unsound.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@ trait Foo {
1616

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

2122
fn main() {
2223
let x = String::from("hello, world");
2324
drop(<() as Foo>::copy_me(&x));
24-
//~^ ERROR the type `&<() as Foo>::Item` is not well-formed
25-
//~| ERROR `<() as Foo>::Item` is not well-formed
25+
//~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized`
26+
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _`
27+
//~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed`
28+
//~| ERROR overflow evaluating the requirement `String <: <() as Foo>::Item`
29+
//~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed`
30+
//~| ERROR type annotations needed
2631
println!("{x}");
2732
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,69 @@
1-
error: the type `&<() as Foo>::Item` is not well-formed
2-
--> $DIR/alias-bound-unsound.rs:23:31
1+
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy`
2+
--> $DIR/alias-bound-unsound.rs:18:17
3+
|
4+
LL | type Item = String where String: Copy;
5+
| ^^^^^^
6+
|
7+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
8+
note: required by a bound in `Foo::Item`
9+
--> $DIR/alias-bound-unsound.rs:8:16
10+
|
11+
LL | type Item: Copy
12+
| ^^^^ required by this bound in `Foo::Item`
13+
14+
error[E0282]: type annotations needed
15+
--> $DIR/alias-bound-unsound.rs:24:5
16+
|
17+
LL | drop(<() as Foo>::copy_me(&x));
18+
| ^^^^ cannot infer type of the type parameter `T` declared on the function `drop`
19+
|
20+
help: consider specifying the generic argument
21+
|
22+
LL | drop::<T>(<() as Foo>::copy_me(&x));
23+
| +++++
24+
25+
error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed`
26+
--> $DIR/alias-bound-unsound.rs:24:31
327
|
428
LL | drop(<() as Foo>::copy_me(&x));
529
| ^^
30+
|
31+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
632

7-
error: the type `<() as Foo>::Item` is not well-formed
8-
--> $DIR/alias-bound-unsound.rs:23:10
33+
error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item`
34+
--> $DIR/alias-bound-unsound.rs:24:31
35+
|
36+
LL | drop(<() as Foo>::copy_me(&x));
37+
| ^^
38+
|
39+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
40+
41+
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item well-formed`
42+
--> $DIR/alias-bound-unsound.rs:24:10
43+
|
44+
LL | drop(<() as Foo>::copy_me(&x));
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^
46+
|
47+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
48+
49+
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _`
50+
--> $DIR/alias-bound-unsound.rs:24:10
951
|
1052
LL | drop(<() as Foo>::copy_me(&x));
1153
| ^^^^^^^^^^^^^^^^^^^^^^^^
54+
|
55+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
56+
57+
error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Sized`
58+
--> $DIR/alias-bound-unsound.rs:24:10
59+
|
60+
LL | drop(<() as Foo>::copy_me(&x));
61+
| ^^^^^^^^^^^^^^^^^^^^
62+
|
63+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`)
64+
= note: the return type of a function must have a statically known size
1265

13-
error: aborting due to 2 previous errors
66+
error: aborting due to 7 previous errors
1467

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

0 commit comments

Comments
 (0)