Skip to content

Commit 02aefd4

Browse files
Normalize opaques before defining them in the new solver
1 parent 09df610 commit 02aefd4

19 files changed

+137
-18
lines changed

compiler/rustc_trait_selection/src/solve/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{
2222
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult,
2323
Response,
2424
};
25+
use rustc_middle::traits::Reveal;
2526
use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
2627
use rustc_middle::ty::{
2728
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
@@ -302,10 +303,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
302303
mut ty: Ty<'tcx>,
303304
) -> Result<Option<Ty<'tcx>>, NoSolution> {
304305
for _ in 0..self.local_overflow_limit() {
305-
let ty::Alias(_, projection_ty) = *ty.kind() else {
306+
let ty::Alias(kind, projection_ty) = *ty.kind() else {
306307
return Ok(Some(ty));
307308
};
308309

310+
// Don't try normalizing an opaque that is not in the defining scope
311+
if kind == ty::Opaque
312+
&& param_env.reveal() == Reveal::UserFacing
313+
&& !projection_ty
314+
.def_id
315+
.as_local()
316+
.is_some_and(|def_id| self.can_define_opaque_ty(def_id))
317+
{
318+
return Ok(Some(ty));
319+
}
320+
309321
let normalized_ty = self.next_ty_infer();
310322
let normalizes_to_goal = Goal::new(
311323
self.tcx(),

compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
2323
let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else {
2424
return Err(NoSolution);
2525
};
26+
2627
// FIXME: at some point we should call queries without defining
2728
// new opaque types but having the existing opaque type definitions.
2829
// This will require moving this below "Prefer opaques registered already".
2930
if !self.can_define_opaque_ty(opaque_ty_def_id) {
3031
return Err(NoSolution);
3132
}
33+
3234
// FIXME: This may have issues when the args contain aliases...
3335
match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) {
3436
Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
@@ -41,6 +43,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
4143
}
4244
Ok(()) => {}
4345
}
46+
4447
// Prefer opaques registered already.
4548
let opaque_type_key =
4649
ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args };
@@ -53,6 +56,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
5356
return self.flounder(&matches);
5457
}
5558
}
59+
60+
// Try normalizing the opaque's hidden type. If it's a ty var,
61+
// then refuse to define the opaque type yet. This allows us to
62+
// avoid inferring opaque cycles so eagerly.
63+
let expected = match self.try_normalize_ty(goal.param_env, expected) {
64+
Ok(Some(ty)) if !ty.is_ty_var() => ty,
65+
Ok(_) => {
66+
return self.evaluate_added_goals_and_make_canonical_response(
67+
Certainty::AMBIGUOUS,
68+
);
69+
}
70+
Err(_) => {
71+
return Err(NoSolution);
72+
}
73+
};
74+
5675
// Otherwise, define a new opaque type
5776
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
5877
self.add_item_bounds_for_hidden_type(

tests/ui/impl-trait/issues/issue-83919.stderr renamed to tests/ui/impl-trait/issues/issue-83919.current.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: `{integer}` is not a future
2-
--> $DIR/issue-83919.rs:21:26
2+
--> $DIR/issue-83919.rs:23:26
33
|
44
LL | fn get_fut(&self) -> Self::Fut {
55
| ^^^^^^^^^ `{integer}` is not a future
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-83919.rs:25:9
3+
|
4+
LL | fn get_fut(&self) -> Self::Fut {
5+
| --------- expected `<Implementor as Foo>::Fut` because of return type
6+
LL |
7+
LL | / async move {
8+
LL | |
9+
LL | | 42
10+
LL | | // 42 does not impl Future and rustc does actually point out the error,
11+
LL | | // but rustc used to panic.
12+
LL | | // Putting a valid Future here always worked fine.
13+
LL | | }
14+
| |_________^ types differ
15+
|
16+
= note: expected associated type `<Implementor as Foo>::Fut`
17+
found `async` block `{async block@$DIR/issue-83919.rs:25:9: 31:10}`
18+
= help: consider constraining the associated type `<Implementor as Foo>::Fut` to `{async block@$DIR/issue-83919.rs:25:9: 31:10}` or calling a method that returns `<Implementor as Foo>::Fut`
19+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
20+
21+
error: aborting due to previous error
22+
23+
For more information about this error, try `rustc --explain E0308`.

tests/ui/impl-trait/issues/issue-83919.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
#![feature(impl_trait_in_assoc_type)]
2-
1+
// revisions: current next
2+
//[next] compile-flags: -Ztrait-solver=next
33
// edition:2021
44

5+
#![feature(impl_trait_in_assoc_type)]
6+
57
use std::future::Future;
68

79
trait Foo {
@@ -19,8 +21,9 @@ impl Foo for Implementor {
1921
type Fut = impl Future<Output = Self::Fut2>;
2022

2123
fn get_fut(&self) -> Self::Fut {
22-
//~^ ERROR `{integer}` is not a future
24+
//[current]~^ ERROR `{integer}` is not a future
2325
async move {
26+
//[next]~^ ERROR mismatched types
2427
42
2528
// 42 does not impl Future and rustc does actually point out the error,
2629
// but rustc used to panic.

tests/ui/impl-trait/recursive-generator.stderr renamed to tests/ui/impl-trait/recursive-generator.current.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0720]: cannot resolve opaque type
2-
--> $DIR/recursive-generator.rs:5:13
2+
--> $DIR/recursive-generator.rs:8:13
33
|
44
LL | fn foo() -> impl Generator<Yield = (), Return = ()> {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0720]: cannot resolve opaque type
2+
--> $DIR/recursive-generator.rs:8:13
3+
|
4+
LL | fn foo() -> impl Generator<Yield = (), Return = ()> {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
6+
...
7+
LL | let mut gen = Box::pin(foo());
8+
| ------- generator captures itself here
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0720`.

tests/ui/impl-trait/recursive-generator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// revisions: current next
2+
//[next] compile-flags: -Ztrait-solver=next
3+
14
#![feature(generators, generator_trait)]
25

36
use std::ops::{Generator, GeneratorState};

tests/ui/impl-trait/two_tait_defining_each_other.stderr renamed to tests/ui/impl-trait/two_tait_defining_each_other.current.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
error: opaque type's hidden type cannot be another opaque type from the same scope
2-
--> $DIR/two_tait_defining_each_other.rs:12:5
2+
--> $DIR/two_tait_defining_each_other.rs:16:5
33
|
44
LL | x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
55
| ^ one of the two opaque types used here has to be outside its defining scope
66
|
77
note: opaque type whose hidden type is being assigned
8-
--> $DIR/two_tait_defining_each_other.rs:4:10
8+
--> $DIR/two_tait_defining_each_other.rs:8:10
99
|
1010
LL | type B = impl Foo;
1111
| ^^^^^^^^
1212
note: opaque type being used as hidden type
13-
--> $DIR/two_tait_defining_each_other.rs:3:10
13+
--> $DIR/two_tait_defining_each_other.rs:7:10
1414
|
1515
LL | type A = impl Foo;
1616
| ^^^^^^^^

tests/ui/impl-trait/two_tait_defining_each_other.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// revisions: current next
2+
//[next] compile-flags: -Ztrait-solver=next
3+
//[next] check-pass
4+
15
#![feature(type_alias_impl_trait)]
26

37
type A = impl Foo;
@@ -10,7 +14,7 @@ fn muh(x: A) -> B {
1014
return Bar; // B's hidden type is Bar
1115
}
1216
x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
13-
//~^ ERROR opaque type's hidden type cannot be another opaque type
17+
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type
1418
}
1519

1620
struct Bar;

0 commit comments

Comments
 (0)