Skip to content

Commit 3e3e207

Browse files
committed
use alias-relate to structurally normalize in the solver
1 parent bbe2f6c commit 3e3e207

16 files changed

+136
-119
lines changed

compiler/rustc_hir_typeck/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ fn typeck_with_fallback<'tcx>(
304304

305305
let typeck_results = fcx.resolve_type_vars_in_body(body);
306306

307+
// We clone the defined opaque types during writeback in the new solver
308+
// because we have to use them during normalization.
307309
let _ = fcx.infcx.take_opaque_types();
308310

309311
// Consistency check our TypeckResults instance can hold all ItemLocalIds

compiler/rustc_hir_typeck/src/writeback.rs

+6
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
564564
fn visit_opaque_types(&mut self) {
565565
// We clone the opaques instead of stealing them here as they are still used for
566566
// normalization in the next generation trait solver.
567+
//
568+
// FIXME(-Znext-solver): Opaque types defined after this would simply get dropped
569+
// at the end of typeck. While this seems unlikely to happen in practice this
570+
// should still get fixed. Either by preventing writeback from defining new opaque
571+
// types or by using this function at the end of writeback and running it as a
572+
// fixpoint.
567573
let opaque_types = self.fcx.infcx.clone_opaque_types();
568574
for (opaque_type_key, decl) in opaque_types {
569575
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);

compiler/rustc_trait_selection/src/solve/alias_relate.rs

+34-7
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@
2121
//! `NormalizesTo` goal, at which point the opaque is actually defined.
2222
2323
use super::{EvalCtxt, GoalSource};
24-
use rustc_infer::infer::DefineOpaqueTypes;
2524
use rustc_infer::traits::query::NoSolution;
2625
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
27-
use rustc_middle::ty;
26+
use rustc_middle::ty::{self, Ty};
2827

2928
impl<'tcx> EvalCtxt<'_, 'tcx> {
3029
#[instrument(level = "debug", skip(self), ret)]
@@ -79,7 +78,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
7978
}
8079

8180
// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
82-
/// Normalize the `term` to equate it later. This does not define opaque types.
81+
/// Normalize the `term` to equate it later.
8382
#[instrument(level = "debug", skip(self, param_env), ret)]
8483
fn try_normalize_term(
8584
&mut self,
@@ -88,10 +87,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
8887
) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
8988
match term.unpack() {
9089
ty::TermKind::Ty(ty) => {
91-
// We do no define opaque types here but instead do so in `relate_rigid_alias_or_opaque`.
92-
Ok(self
93-
.try_normalize_ty_recur(param_env, DefineOpaqueTypes::No, 0, ty)
94-
.map(Into::into))
90+
Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into))
9591
}
9692
ty::TermKind::Const(_) => {
9793
if let Some(alias) = term.to_alias_ty(self.tcx()) {
@@ -108,4 +104,35 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
108104
}
109105
}
110106
}
107+
108+
fn try_normalize_ty_recur(
109+
&mut self,
110+
param_env: ty::ParamEnv<'tcx>,
111+
depth: usize,
112+
ty: Ty<'tcx>,
113+
) -> Option<Ty<'tcx>> {
114+
if !self.tcx().recursion_limit().value_within_limit(depth) {
115+
return None;
116+
}
117+
118+
let ty::Alias(_, alias) = *ty.kind() else {
119+
return Some(ty);
120+
};
121+
122+
match self.commit_if_ok(|this| {
123+
let normalized_ty = this.next_ty_infer();
124+
let normalizes_to_goal = Goal::new(
125+
this.tcx(),
126+
param_env,
127+
ty::NormalizesTo { alias, term: normalized_ty.into() },
128+
);
129+
this.add_goal(GoalSource::Misc, normalizes_to_goal);
130+
this.try_evaluate_added_goals()?;
131+
let ty = this.resolve_vars_if_possible(normalized_ty);
132+
Ok(this.try_normalize_ty_recur(param_env, depth + 1, ty))
133+
}) {
134+
Ok(ty) => ty,
135+
Err(NoSolution) => Some(ty),
136+
}
137+
}
111138
}

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+12-28
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
276276
&mut self,
277277
goal: Goal<'tcx, G>,
278278
) -> Vec<Candidate<'tcx>> {
279-
let Some(normalized_self_ty) =
280-
self.try_normalize_ty(goal.param_env, goal.predicate.self_ty())
279+
let Ok(normalized_self_ty) =
280+
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
281281
else {
282-
debug!("overflow while evaluating self type");
283-
return self.forced_ambiguity(MaybeCause::Overflow);
282+
return vec![];
284283
};
285284

286285
if normalized_self_ty.is_ty_var() {
@@ -635,19 +634,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
635634
return;
636635
}
637636

638-
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
639-
// Recurse on the self type of the projection.
640-
Some(next_self_ty) => {
641-
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates);
642-
}
643-
// Bail if we overflow when normalizing, adding an ambiguous candidate.
644-
None => {
645-
if let Ok(result) =
646-
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
647-
{
648-
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
649-
}
637+
// Recurse on the self type of the projection.
638+
match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
639+
Ok(next_self_ty) => {
640+
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates)
650641
}
642+
Err(NoSolution) => {}
651643
}
652644
}
653645

@@ -857,19 +849,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
857849
let tcx = self.tcx();
858850
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
859851
let trait_ref = goal.predicate.trait_ref(tcx);
860-
#[derive(Debug)]
861-
struct Overflow;
862-
let lazily_normalize_ty = |ty| match ecx.try_normalize_ty(goal.param_env, ty) {
863-
Some(ty) => Ok(ty),
864-
None => Err(Overflow),
865-
};
852+
let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
866853

867-
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty) {
868-
Err(Overflow) => {
869-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
870-
}
871-
Ok(Ok(())) => Err(NoSolution),
872-
Ok(Err(_)) => {
854+
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
855+
Ok(()) => Err(NoSolution),
856+
Err(_) => {
873857
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
874858
}
875859
}

compiler/rustc_trait_selection/src/solve/mod.rs

+19-37
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@
1515
//! about it on zulip.
1616
use rustc_hir::def_id::DefId;
1717
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
18-
use rustc_infer::infer::DefineOpaqueTypes;
1918
use rustc_infer::traits::query::NoSolution;
2019
use rustc_middle::infer::canonical::CanonicalVarInfos;
2120
use rustc_middle::traits::solve::{
2221
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
2322
QueryResult, Response,
2423
};
25-
use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
24+
use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex};
2625
use rustc_middle::ty::{
2726
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
2827
};
@@ -266,49 +265,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
266265
Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
267266
}
268267

269-
/// Normalize a type when it is structually matched on.
268+
/// Normalize a type for when it is structurally matched on.
270269
///
271-
/// In nearly all cases this function must be used before matching on a type.
270+
/// This function is necessary in nearly all cases before matching on a type.
272271
/// Not doing so is likely to be incomplete and therefore unsound during
273272
/// coherence.
274-
#[instrument(level = "debug", skip(self), ret)]
275-
fn try_normalize_ty(
276-
&mut self,
277-
param_env: ty::ParamEnv<'tcx>,
278-
ty: Ty<'tcx>,
279-
) -> Option<Ty<'tcx>> {
280-
self.try_normalize_ty_recur(param_env, DefineOpaqueTypes::Yes, 0, ty)
281-
}
282-
283-
fn try_normalize_ty_recur(
273+
fn structurally_normalize_ty(
284274
&mut self,
285275
param_env: ty::ParamEnv<'tcx>,
286-
define_opaque_types: DefineOpaqueTypes,
287-
depth: usize,
288276
ty: Ty<'tcx>,
289-
) -> Option<Ty<'tcx>> {
290-
if !self.tcx().recursion_limit().value_within_limit(depth) {
291-
return None;
292-
}
293-
294-
let ty::Alias(_, alias) = *ty.kind() else {
295-
return Some(ty);
296-
};
297-
298-
match self.commit_if_ok(|this| {
299-
let normalized_ty = this.next_ty_infer();
300-
let normalizes_to_goal = Goal::new(
301-
this.tcx(),
277+
) -> Result<Ty<'tcx>, NoSolution> {
278+
if let ty::Alias(..) = ty.kind() {
279+
let normalized_ty = self.next_ty_infer();
280+
let alias_relate_goal = Goal::new(
281+
self.tcx(),
302282
param_env,
303-
ty::NormalizesTo { alias, term: normalized_ty.into() },
283+
ty::PredicateKind::AliasRelate(
284+
ty.into(),
285+
normalized_ty.into(),
286+
AliasRelationDirection::Equate,
287+
),
304288
);
305-
this.add_goal(GoalSource::Misc, normalizes_to_goal);
306-
this.try_evaluate_added_goals()?;
307-
let ty = this.resolve_vars_if_possible(normalized_ty);
308-
Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty))
309-
}) {
310-
Ok(ty) => ty,
311-
Err(NoSolution) => Some(ty),
289+
self.add_goal(GoalSource::Misc, alias_relate_goal);
290+
self.try_evaluate_added_goals()?;
291+
Ok(self.resolve_vars_if_possible(normalized_ty))
292+
} else {
293+
Ok(ty)
312294
}
313295
}
314296
}

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

+5-15
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
5858
}
5959
}
6060

61-
let expected = match self.try_normalize_ty(goal.param_env, expected) {
62-
Some(ty) => {
63-
if ty.is_ty_var() {
64-
return self.evaluate_added_goals_and_make_canonical_response(
65-
Certainty::AMBIGUOUS,
66-
);
67-
} else {
68-
ty
69-
}
70-
}
71-
None => {
72-
return self
73-
.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
74-
}
75-
};
61+
let expected = self.structurally_normalize_ty(goal.param_env, expected)?;
62+
if expected.is_ty_var() {
63+
return self
64+
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
65+
}
7666

7767
// Otherwise, define a new opaque type
7868
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
581581
let a_ty = goal.predicate.self_ty();
582582
// We need to normalize the b_ty since it's matched structurally
583583
// in the other functions below.
584-
let b_ty = match ecx
585-
.try_normalize_ty(goal.param_env, goal.predicate.trait_ref.args.type_at(1))
586-
{
587-
Some(b_ty) => b_ty,
588-
None => return vec![misc_candidate(ecx, Certainty::OVERFLOW)],
584+
let Ok(b_ty) = ecx.structurally_normalize_ty(
585+
goal.param_env,
586+
goal.predicate.trait_ref.args.type_at(1),
587+
) else {
588+
return vec![];
589589
};
590590

591591
let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/recursive-coroutine-boxed.rs:10:23
3+
|
4+
LL | let mut gen = Box::pin(foo());
5+
| ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
6+
...
7+
LL | let mut r = gen.as_mut().resume(());
8+
| ------ type must be known at this point
9+
|
10+
help: consider specifying the generic argument
11+
|
12+
LL | let mut gen = Box::<T>::pin(foo());
13+
| +++++
14+
15+
error[E0282]: type annotations needed
16+
--> $DIR/recursive-coroutine-boxed.rs:10:32
17+
|
18+
LL | let mut gen = Box::pin(foo());
19+
| ^^^^^ cannot infer type for opaque type `impl Coroutine<Yield = (), Return = ()>`
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0282`.

tests/ui/impl-trait/recursive-coroutine-boxed.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// check-pass
21
// revisions: current next
2+
//[current] check-pass
33
//[next] compile-flags: -Znext-solver
44
#![feature(coroutines, coroutine_trait)]
55

@@ -8,6 +8,8 @@ use std::ops::{Coroutine, CoroutineState};
88
fn foo() -> impl Coroutine<Yield = (), Return = ()> {
99
|| {
1010
let mut gen = Box::pin(foo());
11+
//[next]~^ ERROR type annotations needed
12+
//[next]~| ERROR type annotations needed
1113
let mut r = gen.as_mut().resume(());
1214
while let CoroutineState::Yielded(v) = r {
1315
yield v;

tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0284]: type annotations needed: cannot satisfy `A <: B`
1+
error[E0284]: type annotations needed: cannot satisfy `A == B`
22
--> $DIR/two_tait_defining_each_other2.rs:11:5
33
|
44
LL | x // B's hidden type is A (opaquely)
5-
| ^ cannot satisfy `A <: B`
5+
| ^ cannot satisfy `A == B`
66

77
error: aborting due to 1 previous error
88

tests/ui/impl-trait/two_tait_defining_each_other2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ trait Foo {}
1010
fn muh(x: A) -> B {
1111
x // B's hidden type is A (opaquely)
1212
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type
13-
//[next]~^^ ERROR type annotations needed: cannot satisfy `A <: B`
13+
//[next]~^^ ERROR type annotations needed: cannot satisfy `A == B`
1414
}
1515

1616
struct Bar;

tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// compile-flags: -Znext-solver
2-
// check-pass
3-
2+
// FIXME(-Znext-solver): This test is currently broken because the `deduce_closure_signature`
3+
// is unable to look at nested obligations.
44
trait Foo {
55
fn test() -> impl Fn(u32) -> u32 {
66
|x| x.count_ones()
7+
//~^ ERROR type annotations needed
78
}
89
}
910

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/deduce-closure-signature-after-normalization.rs:6:10
3+
|
4+
LL | |x| x.count_ones()
5+
| ^ - type must be known at this point
6+
|
7+
help: consider giving this closure parameter an explicit type
8+
|
9+
LL | |x: /* Type */| x.count_ones()
10+
| ++++++++++++
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0282`.
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
1+
error[E0284]: type annotations needed: cannot satisfy `Foo == _`
22
--> $DIR/dont-type_of-tait-in-defining-scope.rs:15:18
33
|
44
LL | needs_send::<Foo>();
5-
| ^^^
6-
|
7-
= note: cannot satisfy `Foo: Send`
8-
note: required by a bound in `needs_send`
9-
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
10-
|
11-
LL | fn needs_send<T: Send>() {}
12-
| ^^^^ required by this bound in `needs_send`
5+
| ^^^ cannot satisfy `Foo == _`
136

147
error: aborting due to 1 previous error
158

16-
For more information about this error, try `rustc --explain E0283`.
9+
For more information about this error, try `rustc --explain E0284`.

0 commit comments

Comments
 (0)