Skip to content

Commit ffb4c08

Browse files
committed
implement and use NormalizesTo
1 parent 3978f54 commit ffb4c08

21 files changed

+135
-125
lines changed

Diff for: compiler/rustc_infer/src/infer/combine.rs

+40-26
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVa
3434
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
3535
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3636
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
37-
use rustc_middle::ty::TyVar;
3837
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
38+
use rustc_middle::ty::{AliasRelationDirection, TyVar};
3939
use rustc_middle::ty::{IntType, UintType};
4040
use rustc_span::DUMMY_SP;
4141

@@ -490,31 +490,47 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
490490
// cyclic type. We instead delay the unification in case
491491
// the alias can be normalized to something which does not
492492
// mention `?0`.
493-
494-
// FIXME(-Ztrait-solver=next): replace this with `AliasRelate`
495-
let &ty::Alias(kind, data) = a_ty.kind() else {
496-
bug!("generalization should only result in infer vars for aliases");
497-
};
498-
if !self.infcx.next_trait_solver() {
499-
// The old solver only accepts projection predicates for associated types.
500-
match kind {
501-
ty::AliasKind::Projection => {}
502-
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque => {
503-
return Err(TypeError::CyclicTy(a_ty));
493+
if self.infcx.next_trait_solver() {
494+
let (lhs, rhs, direction) = match ambient_variance {
495+
ty::Variance::Invariant => {
496+
(a_ty.into(), b_ty.into(), AliasRelationDirection::Equate)
497+
}
498+
ty::Variance::Covariant => {
499+
(a_ty.into(), b_ty.into(), AliasRelationDirection::Subtype)
500+
}
501+
ty::Variance::Contravariant => {
502+
(b_ty.into(), a_ty.into(), AliasRelationDirection::Subtype)
504503
}
504+
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
505+
};
506+
self.obligations.push(Obligation::new(
507+
self.tcx(),
508+
self.trace.cause.clone(),
509+
self.param_env,
510+
ty::PredicateKind::AliasRelate(lhs, rhs, direction),
511+
));
512+
} else {
513+
match a_ty.kind() {
514+
&ty::Alias(ty::AliasKind::Projection, data) => {
515+
// FIXME: This does not handle subtyping correctly, we should switch to
516+
// alias-relate in the new solver and could instead create a new inference
517+
// variable for `a_ty`, emitting `Projection(a_ty, a_infer)` and
518+
// `a_infer <: b_ty`.
519+
self.obligations.push(Obligation::new(
520+
self.tcx(),
521+
self.trace.cause.clone(),
522+
self.param_env,
523+
ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
524+
))
525+
}
526+
// The old solver only accepts projection predicates for associated types.
527+
ty::Alias(
528+
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
529+
_,
530+
) => return Err(TypeError::CyclicTy(a_ty)),
531+
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
505532
}
506533
}
507-
508-
// FIXME: This does not handle subtyping correctly, we should switch to
509-
// alias-relate in the new solver and could instead create a new inference
510-
// variable for `a_ty`, emitting `Projection(a_ty, a_infer)` and
511-
// `a_infer <: b_ty`.
512-
self.obligations.push(Obligation::new(
513-
self.tcx(),
514-
self.trace.cause.clone(),
515-
self.param_env,
516-
ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
517-
))
518534
} else {
519535
match ambient_variance {
520536
ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
@@ -525,9 +541,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
525541
a_ty,
526542
b_ty,
527543
),
528-
ty::Variance::Bivariant => {
529-
unreachable!("no code should be generalizing bivariantly (currently)")
530-
}
544+
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
531545
}?;
532546
}
533547

Diff for: compiler/rustc_middle/src/ty/print/pretty.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2814,7 +2814,7 @@ define_print! {
28142814
p!("the constant `", print(c1), "` equals `", print(c2), "`")
28152815
}
28162816
ty::PredicateKind::Ambiguous => p!("ambiguous"),
2817-
ty::PredicateKind::NormalizesTo(data) => p!(print(data.alias), " normalizes-to ", print(data.term)),
2817+
ty::PredicateKind::NormalizesTo(data) => p!(print(data)),
28182818
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
28192819
}
28202820
}
@@ -2946,6 +2946,12 @@ define_print_and_forward_display! {
29462946
p!(print(self.term))
29472947
}
29482948

2949+
ty::NormalizesTo<'tcx> {
2950+
p!(print(self.alias), " normalizes-to ");
2951+
cx.reset_type_limit();
2952+
p!(print(self.term))
2953+
}
2954+
29492955
ty::Term<'tcx> {
29502956
match self.unpack() {
29512957
ty::TermKind::Ty(ty) => p!(print(ty)),

Diff for: compiler/rustc_trait_selection/src/solve/alias_relate.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
9292
self.add_goal(Goal::new(
9393
self.tcx(),
9494
param_env,
95-
ty::ProjectionPredicate { projection_ty: alias, term },
95+
ty::NormalizesTo { alias, term },
9696
));
9797
self.try_evaluate_added_goals()?;
9898
Ok(Some(self.resolve_vars_if_possible(term)))
@@ -109,11 +109,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
109109
opaque: ty::AliasTy<'tcx>,
110110
term: ty::Term<'tcx>,
111111
) -> QueryResult<'tcx> {
112-
self.add_goal(Goal::new(
113-
self.tcx(),
114-
param_env,
115-
ty::ProjectionPredicate { projection_ty: opaque, term },
116-
));
112+
self.add_goal(Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }));
117113
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
118114
}
119115

Diff for: compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -352,15 +352,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
352352
num_steps: usize,
353353
) {
354354
let tcx = self.tcx();
355-
let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else { return };
355+
let &ty::Alias(_, alias) = goal.predicate.self_ty().kind() else { return };
356356

357357
candidates.extend(self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
358358
if tcx.recursion_limit().value_within_limit(num_steps) {
359359
let normalized_ty = ecx.next_ty_infer();
360-
let normalizes_to_goal = goal.with(
361-
tcx,
362-
ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() },
363-
);
360+
let normalizes_to_goal =
361+
goal.with(tcx, ty::NormalizesTo { alias, term: normalized_ty.into() });
364362
ecx.add_goal(normalizes_to_goal);
365363
if let Err(NoSolution) = ecx.try_evaluate_added_goals() {
366364
debug!("self type normalization failed");

Diff for: compiler/rustc_trait_selection/src/solve/canonicalize.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
6969
};
7070

7171
let value = value.fold_with(&mut canonicalizer);
72-
assert!(!value.has_infer());
73-
assert!(!value.has_placeholders());
72+
assert!(!value.has_infer(), "unexpected infer in {value:?}");
73+
assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
7474

7575
let (max_universe, variables) = canonicalizer.finalize();
7676

Diff for: compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub(super) struct NestedGoals<'tcx> {
103103
/// with a fresh inference variable when we evaluate this goal. That can result
104104
/// in a trait solver cycle. This would currently result in overflow but can be
105105
/// can be unsound with more powerful coinduction in the future.
106-
pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::ProjectionPredicate<'tcx>>>,
106+
pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::NormalizesTo<'tcx>>>,
107107
/// The rest of the goals which have not yet processed or remain ambiguous.
108108
pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
109109
}
@@ -423,7 +423,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
423423
ty::PredicateKind::ConstEquate(_, _) => {
424424
bug!("ConstEquate should not be emitted when `-Ztrait-solver=next` is active")
425425
}
426-
ty::PredicateKind::NormalizesTo(_) => unimplemented!(),
426+
ty::PredicateKind::NormalizesTo(predicate) => {
427+
self.compute_normalizes_to_goal(Goal { param_env, predicate })
428+
}
427429
ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
428430
.compute_alias_relate_goal(Goal {
429431
param_env,
@@ -493,10 +495,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
493495
let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term);
494496
let unconstrained_goal = goal.with(
495497
tcx,
496-
ty::ProjectionPredicate {
497-
projection_ty: goal.predicate.projection_ty,
498-
term: unconstrained_rhs,
499-
},
498+
ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs },
500499
);
501500

502501
let (_, certainty, instantiate_goals) = self.evaluate_goal(
@@ -518,9 +517,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
518517
// looking at the "has changed" return from evaluate_goal,
519518
// because we expect the `unconstrained_rhs` part of the predicate
520519
// to have changed -- that means we actually normalized successfully!
521-
if goal.predicate.projection_ty
522-
!= self.resolve_vars_if_possible(goal.predicate.projection_ty)
523-
{
520+
if goal.predicate.alias != self.resolve_vars_if_possible(goal.predicate.alias) {
524521
unchanged_certainty = None;
525522
}
526523

@@ -590,9 +587,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
590587
///
591588
/// This is the case if the `term` is an inference variable in the innermost universe
592589
/// and does not occur in any other part of the predicate.
590+
#[instrument(level = "debug", skip(self), ret)]
593591
pub(super) fn term_is_fully_unconstrained(
594592
&self,
595-
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
593+
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
596594
) -> bool {
597595
let term_is_infer = match goal.predicate.term.unpack() {
598596
ty::TermKind::Ty(ty) => {
@@ -656,7 +654,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
656654
let mut visitor = ContainsTerm { infcx: self.infcx, term: goal.predicate.term };
657655

658656
term_is_infer
659-
&& goal.predicate.projection_ty.visit_with(&mut visitor).is_continue()
657+
&& goal.predicate.alias.visit_with(&mut visitor).is_continue()
660658
&& goal.param_env.visit_with(&mut visitor).is_continue()
661659
}
662660

Diff for: compiler/rustc_trait_selection/src/solve/mod.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ mod eval_ctxt;
3535
mod fulfill;
3636
pub mod inspect;
3737
mod normalize;
38+
mod normalizes_to;
3839
mod project_goals;
3940
mod search_graph;
4041
mod trait_goals;
@@ -216,7 +217,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
216217

217218
impl<'tcx> EvalCtxt<'_, 'tcx> {
218219
#[instrument(level = "debug", skip(self))]
219-
fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>) {
220+
fn set_normalizes_to_hack_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
220221
assert!(
221222
self.nested_goals.normalizes_to_hack_goal.is_none(),
222223
"attempted to set the projection eq hack goal when one already exists"
@@ -310,17 +311,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
310311
return None;
311312
}
312313

313-
let ty::Alias(kind, projection_ty) = *ty.kind() else {
314+
let ty::Alias(kind, alias) = *ty.kind() else {
314315
return Some(ty);
315316
};
316317

317318
// We do no always define opaque types eagerly to allow non-defining uses in the defining scope.
318319
if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
319-
if let Some(def_id) = projection_ty.def_id.as_local() {
320+
if let Some(def_id) = alias.def_id.as_local() {
320321
if self
321322
.unify_existing_opaque_tys(
322323
param_env,
323-
OpaqueTypeKey { def_id, args: projection_ty.args },
324+
OpaqueTypeKey { def_id, args: alias.args },
324325
self.next_ty_infer(),
325326
)
326327
.is_empty()
@@ -335,7 +336,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
335336
let normalizes_to_goal = Goal::new(
336337
this.tcx(),
337338
param_env,
338-
ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() },
339+
ty::NormalizesTo { alias, term: normalized_ty.into() },
339340
);
340341
this.add_goal(normalizes_to_goal);
341342
this.try_evaluate_added_goals()?;

Diff for: compiler/rustc_trait_selection/src/solve/normalize.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
7676
tcx,
7777
self.at.cause.clone(),
7878
self.at.param_env,
79-
ty::ProjectionPredicate { projection_ty: alias, term: new_infer_ty.into() },
79+
ty::NormalizesTo { alias, term: new_infer_ty.into() },
8080
);
8181

8282
// Do not emit an error if normalization is known to fail but instead
@@ -129,8 +129,8 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
129129
tcx,
130130
self.at.cause.clone(),
131131
self.at.param_env,
132-
ty::ProjectionPredicate {
133-
projection_ty: AliasTy::new(tcx, uv.def, uv.args),
132+
ty::NormalizesTo {
133+
alias: AliasTy::new(tcx, uv.def, uv.args),
134134
term: new_infer_ct.into(),
135135
},
136136
);

Diff for: compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs renamed to compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use super::EvalCtxt;
1212
impl<'tcx> EvalCtxt<'_, 'tcx> {
1313
pub(super) fn normalize_inherent_associated_type(
1414
&mut self,
15-
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
15+
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
1616
) -> QueryResult<'tcx> {
1717
let tcx = self.tcx();
18-
let inherent = goal.predicate.projection_ty;
18+
let inherent = goal.predicate.alias;
1919
let expected = goal.predicate.term.ty().expect("inherent consts are treated separately");
2020

2121
let impl_def_id = tcx.parent(inherent.def_id);

0 commit comments

Comments
 (0)