Skip to content

Commit c14d5fa

Browse files
committed
Properly generalize unevaluated consts
1 parent a3903b1 commit c14d5fa

9 files changed

Lines changed: 135 additions & 61 deletions

File tree

compiler/rustc_infer/src/infer/relate/generalize.rs

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -212,29 +212,41 @@ impl<'tcx> InferCtxt<'tcx> {
212212
source_ct,
213213
)?;
214214

215-
debug_assert!(!generalized_ct.is_ct_infer());
216-
217-
self.inner
218-
.borrow_mut()
219-
.const_unification_table()
220-
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
221-
222-
// Make sure that the order is correct when relating the
223-
// generalized const and the source.
224-
if target_is_expected {
225-
relation.relate_with_variance(
226-
ty::Invariant,
227-
ty::VarianceDiagInfo::default(),
228-
generalized_ct,
229-
source_ct,
230-
)?;
215+
if let ty::ConstKind::Infer(ty::InferConst::Var(generalized_vid)) = generalized_ct.kind() {
216+
self.inner.borrow_mut().const_unification_table().union(target_vid, generalized_vid);
217+
218+
if self.next_trait_solver() {
219+
relation.register_predicates([ty::PredicateKind::AliasRelate(
220+
generalized_ct.into(),
221+
source_ct.into(),
222+
AliasRelationDirection::Equate,
223+
)]);
224+
} else {
225+
return Err(TypeError::CyclicConst(source_ct));
226+
}
231227
} else {
232-
relation.relate_with_variance(
233-
ty::Invariant,
234-
ty::VarianceDiagInfo::default(),
235-
source_ct,
236-
generalized_ct,
237-
)?;
228+
self.inner
229+
.borrow_mut()
230+
.const_unification_table()
231+
.union_value(target_vid, ConstVariableValue::Known { value: generalized_ct });
232+
233+
// Make sure that the order is correct when relating the
234+
// generalized const and the source.
235+
if target_is_expected {
236+
relation.relate_with_variance(
237+
ty::Invariant,
238+
ty::VarianceDiagInfo::default(),
239+
generalized_ct,
240+
source_ct,
241+
)?;
242+
} else {
243+
relation.relate_with_variance(
244+
ty::Invariant,
245+
ty::VarianceDiagInfo::default(),
246+
source_ct,
247+
generalized_ct,
248+
)?;
249+
}
238250
}
239251

240252
Ok(())
@@ -377,8 +389,12 @@ impl<'tcx> Generalizer<'_, 'tcx> {
377389

378390
/// Create a new type variable in the universe of the target when
379391
/// generalizing an alias.
380-
fn next_ty_var_for_alias(&self) -> Ty<'tcx> {
381-
self.infcx.next_ty_var_in_universe(self.span, self.for_universe)
392+
fn next_var_for_alias_of_kind(&self, alias: ty::AliasTerm<'tcx>) -> ty::Term<'tcx> {
393+
if alias.kind(self.cx()).is_type() {
394+
self.infcx.next_ty_var_in_universe(self.span, self.for_universe).into()
395+
} else {
396+
self.infcx.next_const_var_in_universe(self.span, self.for_universe).into()
397+
}
382398
}
383399

384400
/// An occurs check failure inside of an alias does not mean
@@ -399,23 +415,23 @@ impl<'tcx> Generalizer<'_, 'tcx> {
399415
/// continue generalizing the alias. This ends up pulling down the universe of the
400416
/// inference variable and is incomplete in case the alias would normalize to a type
401417
/// which does not mention that inference variable.
402-
fn generalize_alias_ty(
418+
fn generalize_alias_term(
403419
&mut self,
404-
alias: ty::AliasTy<'tcx>,
405-
) -> Result<Ty<'tcx>, TypeError<'tcx>> {
420+
alias: ty::AliasTerm<'tcx>,
421+
) -> Result<ty::Term<'tcx>, TypeError<'tcx>> {
406422
// We do not eagerly replace aliases with inference variables if they have
407423
// escaping bound vars, see the method comment for details. However, when we
408424
// are inside of an alias with escaping bound vars replacing nested aliases
409425
// with inference variables can cause incorrect ambiguity.
410426
//
411427
// cc trait-system-refactor-initiative#110
412428
if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
413-
return Ok(self.next_ty_var_for_alias());
429+
return Ok(self.next_var_for_alias_of_kind(alias));
414430
}
415431

416432
let is_nested_alias = mem::replace(&mut self.in_alias, true);
417433
let result = match self.relate(alias, alias) {
418-
Ok(alias) => Ok(alias.to_ty(self.cx())),
434+
Ok(alias) => Ok(alias.to_term(self.cx())),
419435
Err(e) => {
420436
if is_nested_alias {
421437
return Err(e);
@@ -430,7 +446,7 @@ impl<'tcx> Generalizer<'_, 'tcx> {
430446
}
431447

432448
debug!("generalization failure in alias");
433-
Ok(self.next_ty_var_for_alias())
449+
Ok(self.next_var_for_alias_of_kind(alias))
434450
}
435451
}
436452
};
@@ -507,13 +523,13 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
507523
if TermVid::Ty(vid) == self.root_vid {
508524
// If sub-roots are equal, then `root_vid` and
509525
// `vid` are related via subtyping.
510-
Err(self.cyclic_term_error())
526+
return Err(self.cyclic_term_error());
511527
} else {
512528
let probe = inner.type_variables().probe(vid);
513529
match probe {
514530
TypeVariableValue::Known { value: u } => {
515531
drop(inner);
516-
self.relate(u, u)
532+
self.relate(u, u)?
517533
}
518534
TypeVariableValue::Unknown { universe } => {
519535
match self.ambient_variance {
@@ -559,7 +575,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
559575
}
560576

561577
debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
562-
Ok(Ty::new_var(self.cx(), new_var_id))
578+
Ty::new_var(self.cx(), new_var_id)
563579
}
564580
}
565581
}
@@ -569,28 +585,30 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
569585
// No matter what mode we are in,
570586
// integer/floating-point types must be equal to be
571587
// relatable.
572-
Ok(t)
588+
t
573589
}
574590

575591
ty::Placeholder(placeholder) => {
576592
if self.for_universe.can_name(placeholder.universe) {
577-
Ok(t)
593+
t
578594
} else {
579595
debug!(
580596
"root universe {:?} cannot name placeholder in universe {:?}",
581597
self.for_universe, placeholder.universe
582598
);
583-
Err(TypeError::Mismatch)
599+
return Err(TypeError::Mismatch);
584600
}
585601
}
586602

587603
ty::Alias(_, data) => match self.structurally_relate_aliases {
588-
StructurallyRelateAliases::No => self.generalize_alias_ty(data),
589-
StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
604+
StructurallyRelateAliases::No => {
605+
self.generalize_alias_term(data.into())?.expect_type()
606+
}
607+
StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t)?,
590608
},
591609

592-
_ => relate::structurally_relate_tys(self, t, t),
593-
}?;
610+
_ => relate::structurally_relate_tys(self, t, t)?,
611+
};
594612

595613
self.cache.insert((t, self.ambient_variance, self.in_alias), g);
596614
Ok(g)
@@ -695,17 +713,26 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
695713
// FIXME: Unevaluated constants are also not rigid, so the current
696714
// approach of always relating them structurally is incomplete.
697715
//
698-
// FIXME: remove this branch once `structurally_relate_consts` is fully
699-
// structural.
700-
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
701-
let args = self.relate_with_variance(
702-
ty::Invariant,
703-
ty::VarianceDiagInfo::default(),
704-
args,
705-
args,
706-
)?;
707-
Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args }))
708-
}
716+
// FIXME: replace the StructurallyRelateAliases::Yes branch with
717+
// `structurally_relate_consts` once it is fully structural.
718+
ty::ConstKind::Unevaluated(uv) => match self.structurally_relate_aliases {
719+
// Hack: Fall back to old behavior if GCE is enabled (it used to just be the Yes
720+
// path), as doing this new No path breaks some GCE things. I expect GCE to be
721+
// ripped out soon so this shouldn't matter soon.
722+
StructurallyRelateAliases::No if !self.cx().features().generic_const_exprs() => {
723+
Ok(self.generalize_alias_term(uv.into())?.expect_const())
724+
}
725+
_ => {
726+
let ty::UnevaluatedConst { def, args } = uv;
727+
let args = self.relate_with_variance(
728+
ty::Invariant,
729+
ty::VarianceDiagInfo::default(),
730+
args,
731+
args,
732+
)?;
733+
Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args }))
734+
}
735+
},
709736
ty::ConstKind::Placeholder(placeholder) => {
710737
if self.for_universe.can_name(placeholder.universe) {
711738
Ok(c)

tests/ui/coherence/occurs-check/associated-type.next.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
2-
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
1+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
2+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
33
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
44
--> $DIR/associated-type.rs:32:1
55
|

tests/ui/coherence/occurs-check/associated-type.old.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
2-
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
1+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
2+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), .. }
33
error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())`
44
--> $DIR/associated-type.rs:32:1
55
|
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/153831>
2+
//@ check-fail
3+
//@compile-flags: -Znext-solver=globally --emit=obj
4+
#![feature(min_generic_const_args)]
5+
#![expect(incomplete_features)]
6+
7+
type const A: () = A;
8+
//~^ ERROR type mismatch resolving `A normalizes-to _`
9+
//~| ERROR the constant `A` is not of type `()`
10+
11+
fn main() {
12+
A;
13+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0271]: type mismatch resolving `A normalizes-to _`
2+
--> $DIR/free-type-alias-recursive.rs:7:1
3+
|
4+
LL | type const A: () = A;
5+
| ^^^^^^^^^^^^^^^^ types differ
6+
7+
error: the constant `A` is not of type `()`
8+
--> $DIR/free-type-alias-recursive.rs:7:1
9+
|
10+
LL | type const A: () = A;
11+
| ^^^^^^^^^^^^^^^^ expected `()`, found a different `()`
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0271`.

tests/ui/const-generics/ogca/coherence-ambiguous.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// FIXME(ogca): this should ERROR not pass!!
2-
//@ check-pass
1+
//@ check-fail
32

43
#![feature(generic_const_items, min_generic_const_args, opaque_generic_const_args)]
54
#![expect(incomplete_features)]
@@ -12,8 +11,8 @@ trait Trait {}
1211

1312
impl Trait for [(); FOO::<1>] {}
1413
impl Trait for [(); BAR::<1>] {}
15-
// FIXME(ogca): this should ERROR!
14+
//~^ ERROR conflicting implementations of trait `Trait` for type `[(); FOO::<1>]`
1615
impl Trait for [(); BAR::<2>] {}
17-
// FIXME(ogca): this should ERROR!
16+
//~^ ERROR conflicting implementations of trait `Trait` for type `[(); FOO::<1>]`
1817

1918
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0119]: conflicting implementations of trait `Trait` for type `[(); FOO::<1>]`
2+
--> $DIR/coherence-ambiguous.rs:13:1
3+
|
4+
LL | impl Trait for [(); FOO::<1>] {}
5+
| ----------------------------- first implementation here
6+
LL | impl Trait for [(); BAR::<1>] {}
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); FOO::<1>]`
8+
9+
error[E0119]: conflicting implementations of trait `Trait` for type `[(); FOO::<1>]`
10+
--> $DIR/coherence-ambiguous.rs:15:1
11+
|
12+
LL | impl Trait for [(); FOO::<1>] {}
13+
| ----------------------------- first implementation here
14+
...
15+
LL | impl Trait for [(); BAR::<2>] {}
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); FOO::<1>]`
17+
18+
error: aborting due to 2 previous errors
19+
20+
For more information about this error, try `rustc --explain E0119`.

tests/ui/higher-ranked/structually-relate-aliases.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. }
1+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), .. }
22
error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
33
--> $DIR/structually-relate-aliases.rs:13:36
44
|

tests/ui/traits/next-solver/issue-118950-root-region.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ help: this trait has no implementations, consider adding one
2525
LL | trait ToUnit<'a> {
2626
| ^^^^^^^^^^^^^^^^
2727

28-
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. }
28+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a)), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. }
2929
error: aborting due to 2 previous errors; 1 warning emitted
3030

3131
Some errors have detailed explanations: E0277, E0425.

0 commit comments

Comments
 (0)