Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ed128eb

Browse files
committedMay 1, 2025·
Set groundwork for proper const normalization
1 parent 6e23095 commit ed128eb

File tree

18 files changed

+450
-325
lines changed

18 files changed

+450
-325
lines changed
 
Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use rustc_middle::traits::ObligationCause;
2-
use rustc_middle::ty::{self, Ty};
2+
use rustc_middle::ty;
33

44
use super::InferCtxt;
5+
use crate::infer::Term;
56
use crate::traits::{Obligation, PredicateObligations};
67

78
impl<'tcx> InferCtxt<'tcx> {
@@ -11,24 +12,32 @@ impl<'tcx> InferCtxt<'tcx> {
1112
/// of the given projection. This allows us to proceed with projections
1213
/// while they cannot be resolved yet due to missing information or
1314
/// simply due to the lack of access to the trait resolution machinery.
14-
pub fn projection_ty_to_infer(
15+
pub fn projection_term_to_infer(
1516
&self,
1617
param_env: ty::ParamEnv<'tcx>,
17-
projection_ty: ty::AliasTy<'tcx>,
18+
alias_term: ty::AliasTerm<'tcx>,
1819
cause: ObligationCause<'tcx>,
1920
recursion_depth: usize,
2021
obligations: &mut PredicateObligations<'tcx>,
21-
) -> Ty<'tcx> {
22+
) -> Term<'tcx> {
2223
debug_assert!(!self.next_trait_solver());
23-
let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
24+
25+
let span = self.tcx.def_span(alias_term.def_id);
26+
let infer_var = if alias_term.kind(self.tcx).is_type() {
27+
self.next_ty_var(span).into()
28+
} else {
29+
self.next_const_var(span).into()
30+
};
31+
2432
let projection =
2533
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
26-
projection_term: projection_ty.into(),
27-
term: ty_var.into(),
34+
projection_term: alias_term,
35+
term: infer_var,
2836
}));
2937
let obligation =
3038
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
3139
obligations.push(obligation);
32-
ty_var
40+
41+
infer_var
3342
}
3443
}

‎compiler/rustc_middle/src/ty/context.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
243243
ty::AliasTermKind::ProjectionTy
244244
}
245245
}
246+
DefKind::AssocConst => {
247+
if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
248+
{
249+
ty::AliasTermKind::InherentConst
250+
} else {
251+
ty::AliasTermKind::ProjectionConst
252+
}
253+
}
246254
DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
247255
DefKind::TyAlias => ty::AliasTermKind::FreeTy,
248-
DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
249-
DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => {
256+
DefKind::Const => ty::AliasTermKind::FreeConst,
257+
DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => {
250258
ty::AliasTermKind::UnevaluatedConst
251259
}
252260
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),

‎compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3195,7 +3195,7 @@ define_print! {
31953195

31963196
ty::AliasTerm<'tcx> {
31973197
match self.kind(cx.tcx()) {
3198-
ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
3198+
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p!(pretty_print_inherent_projection(*self)),
31993199
ty::AliasTermKind::ProjectionTy => {
32003200
if !(cx.should_print_verbose() || with_reduced_queries())
32013201
&& cx.tcx().is_impl_trait_in_trait(self.def_id)
@@ -3205,7 +3205,8 @@ define_print! {
32053205
p!(print_def_path(self.def_id, self.args));
32063206
}
32073207
}
3208-
| ty::AliasTermKind::FreeTy
3208+
ty::AliasTermKind::FreeTy
3209+
| ty::AliasTermKind::FreeConst
32093210
| ty::AliasTermKind::OpaqueTy
32103211
| ty::AliasTermKind::UnevaluatedConst
32113212
| ty::AliasTermKind::ProjectionConst => {

‎compiler/rustc_middle/src/ty/util.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,9 @@ impl<'tcx> TyCtxt<'tcx> {
966966
}
967967
ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)),
968968
ty::AliasTermKind::InherentTy
969+
| ty::AliasTermKind::InherentConst
969970
| ty::AliasTermKind::FreeTy
971+
| ty::AliasTermKind::FreeConst
970972
| ty::AliasTermKind::UnevaluatedConst
971973
| ty::AliasTermKind::ProjectionConst => None,
972974
}

‎compiler/rustc_mir_build/src/thir/pattern/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
568568

569569
// Lower the named constant to a THIR pattern.
570570
let args = self.typeck_results.node_args(id);
571+
// FIXME(mgca): we will need to special case IACs here to have type system compatible
572+
// generic args, instead of how we represent them in body expressions.
571573
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
572574
let mut pattern = self.const_to_pat(c, ty, id, span);
573575

‎compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,25 @@ where
1919
goal: Goal<I, ty::NormalizesTo<I>>,
2020
) -> QueryResult<I> {
2121
let cx = self.cx();
22-
let free_ty = goal.predicate.alias;
22+
let free_alias = goal.predicate.alias;
2323

2424
// Check where clauses
2525
self.add_goals(
2626
GoalSource::Misc,
27-
cx.predicates_of(free_ty.def_id)
28-
.iter_instantiated(cx, free_ty.args)
27+
cx.predicates_of(free_alias.def_id)
28+
.iter_instantiated(cx, free_alias.args)
2929
.map(|pred| goal.with(cx, pred)),
3030
);
3131

32-
let actual = cx.type_of(free_ty.def_id).instantiate(cx, free_ty.args);
33-
self.instantiate_normalizes_to_term(goal, actual.into());
32+
let actual = if free_alias.kind(cx).is_type() {
33+
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args)
34+
} else {
35+
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
36+
// this should instead return that.
37+
panic!("normalizing free const aliases in the type system is unsupported");
38+
};
3439

40+
self.instantiate_normalizes_to_term(goal, actual.into());
3541
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
3642
}
3743
}

‎compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ where
1515
D: SolverDelegate<Interner = I>,
1616
I: Interner,
1717
{
18-
pub(super) fn normalize_inherent_associated_type(
18+
pub(super) fn normalize_inherent_associated_term(
1919
&mut self,
2020
goal: Goal<I, ty::NormalizesTo<I>>,
2121
) -> QueryResult<I> {
2222
let cx = self.cx();
23-
let inherent = goal.predicate.alias.expect_ty(cx);
23+
let inherent = goal.predicate.alias;
2424

2525
let impl_def_id = cx.parent(inherent.def_id);
2626
let impl_args = self.fresh_args_for_item(impl_def_id);
@@ -48,8 +48,13 @@ where
4848
.map(|pred| goal.with(cx, pred)),
4949
);
5050

51-
let normalized = cx.type_of(inherent.def_id).instantiate(cx, inherent_args);
52-
self.instantiate_normalizes_to_term(goal, normalized.into());
51+
let normalized = if inherent.kind(cx).is_type() {
52+
cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into()
53+
} else {
54+
// FIXME(mgca): Properly handle IACs in the type system
55+
panic!("normalizing inherent associated consts in the type system is unsupported");
56+
};
57+
self.instantiate_normalizes_to_term(goal, normalized);
5358
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
5459
}
5560
}

‎compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,13 @@ where
4848
})
4949
})
5050
}
51-
ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal),
51+
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
52+
self.normalize_inherent_associated_term(goal)
53+
}
5254
ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal),
53-
ty::AliasTermKind::FreeTy => self.normalize_free_alias(goal),
55+
ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => {
56+
self.normalize_free_alias(goal)
57+
}
5458
ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal),
5559
}
5660
}
@@ -333,6 +337,8 @@ where
333337
cx.type_of(target_item_def_id).map_bound(|ty| ty.into())
334338
}
335339
ty::AliasTermKind::ProjectionConst => {
340+
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
341+
// this should instead return that.
336342
if cx.features().associated_const_equality() {
337343
panic!("associated const projection is not supported yet")
338344
} else {

‎compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub use self::dyn_compatibility::{
5151
pub use self::engine::{ObligationCtxt, TraitEngineExt};
5252
pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation};
5353
pub use self::normalize::NormalizeExt;
54-
pub use self::project::{normalize_inherent_projection, normalize_projection_ty};
54+
pub use self::project::{normalize_inherent_projection, normalize_projection_term};
5555
pub use self::select::{
5656
EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache,
5757
SelectionContext,

‎compiler/rustc_trait_selection/src/traits/normalize.rs

Lines changed: 209 additions & 178 deletions
Large diffs are not rendered by default.

‎compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 87 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::ops::ControlFlow;
55
use rustc_data_structures::sso::SsoHashSet;
66
use rustc_data_structures::stack::ensure_sufficient_stack;
77
use rustc_errors::ErrorGuaranteed;
8-
use rustc_hir::def::DefKind;
98
use rustc_hir::lang_items::LangItem;
109
use rustc_infer::infer::DefineOpaqueTypes;
1110
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
@@ -258,34 +257,27 @@ fn project_and_unify_term<'cx, 'tcx>(
258257
/// there are unresolved type variables in the projection, we will
259258
/// instantiate it with a fresh type variable `$X` and generate a new
260259
/// obligation `<T as Trait>::Item == $X` for later.
261-
pub fn normalize_projection_ty<'a, 'b, 'tcx>(
260+
pub fn normalize_projection_term<'a, 'b, 'tcx>(
262261
selcx: &'a mut SelectionContext<'b, 'tcx>,
263262
param_env: ty::ParamEnv<'tcx>,
264-
projection_ty: ty::AliasTy<'tcx>,
263+
alias_term: ty::AliasTerm<'tcx>,
265264
cause: ObligationCause<'tcx>,
266265
depth: usize,
267266
obligations: &mut PredicateObligations<'tcx>,
268267
) -> Term<'tcx> {
269-
opt_normalize_projection_term(
270-
selcx,
271-
param_env,
272-
projection_ty.into(),
273-
cause.clone(),
274-
depth,
275-
obligations,
276-
)
277-
.ok()
278-
.flatten()
279-
.unwrap_or_else(move || {
280-
// if we bottom out in ambiguity, create a type variable
281-
// and a deferred predicate to resolve this when more type
282-
// information is available.
283-
284-
selcx
285-
.infcx
286-
.projection_ty_to_infer(param_env, projection_ty, cause, depth + 1, obligations)
287-
.into()
288-
})
268+
opt_normalize_projection_term(selcx, param_env, alias_term, cause.clone(), depth, obligations)
269+
.ok()
270+
.flatten()
271+
.unwrap_or_else(move || {
272+
// if we bottom out in ambiguity, create a type variable
273+
// and a deferred predicate to resolve this when more type
274+
// information is available.
275+
276+
selcx
277+
.infcx
278+
.projection_term_to_infer(param_env, alias_term, cause, depth + 1, obligations)
279+
.into()
280+
})
289281
}
290282

291283
/// The guts of `normalize`: normalize a specific projection like `<T
@@ -469,9 +461,10 @@ fn normalize_to_error<'a, 'tcx>(
469461
| ty::AliasTermKind::InherentTy
470462
| ty::AliasTermKind::OpaqueTy
471463
| ty::AliasTermKind::FreeTy => selcx.infcx.next_ty_var(cause.span).into(),
472-
ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => {
473-
selcx.infcx.next_const_var(cause.span).into()
474-
}
464+
ty::AliasTermKind::FreeConst
465+
| ty::AliasTermKind::InherentConst
466+
| ty::AliasTermKind::UnevaluatedConst
467+
| ty::AliasTermKind::ProjectionConst => selcx.infcx.next_const_var(cause.span).into(),
475468
};
476469
let mut obligations = PredicateObligations::new();
477470
obligations.push(Obligation {
@@ -488,32 +481,32 @@ fn normalize_to_error<'a, 'tcx>(
488481
pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
489482
selcx: &'a mut SelectionContext<'b, 'tcx>,
490483
param_env: ty::ParamEnv<'tcx>,
491-
alias_ty: ty::AliasTy<'tcx>,
484+
alias_term: ty::AliasTerm<'tcx>,
492485
cause: ObligationCause<'tcx>,
493486
depth: usize,
494487
obligations: &mut PredicateObligations<'tcx>,
495-
) -> Ty<'tcx> {
488+
) -> ty::Term<'tcx> {
496489
let tcx = selcx.tcx();
497490

498491
if !tcx.recursion_limit().value_within_limit(depth) {
499492
// Halt compilation because it is important that overflows never be masked.
500493
tcx.dcx().emit_fatal(InherentProjectionNormalizationOverflow {
501494
span: cause.span,
502-
ty: alias_ty.to_string(),
495+
ty: alias_term.to_string(),
503496
});
504497
}
505498

506-
let args = compute_inherent_assoc_ty_args(
499+
let args = compute_inherent_assoc_term_args(
507500
selcx,
508501
param_env,
509-
alias_ty,
502+
alias_term,
510503
cause.clone(),
511504
depth,
512505
obligations,
513506
);
514507

515508
// Register the obligations arising from the impl and from the associated type itself.
516-
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, args);
509+
let predicates = tcx.predicates_of(alias_term.def_id).instantiate(tcx, args);
517510
for (predicate, span) in predicates {
518511
let predicate = normalize_with_depth_to(
519512
selcx,
@@ -531,7 +524,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
531524
// cause code, inherent projections will be printed with identity instantiation in
532525
// diagnostics which is not ideal.
533526
// Consider creating separate cause codes for this specific situation.
534-
ObligationCauseCode::WhereClause(alias_ty.def_id, span),
527+
ObligationCauseCode::WhereClause(alias_term.def_id, span),
535528
);
536529

537530
obligations.push(Obligation::with_depth(
@@ -543,27 +536,32 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
543536
));
544537
}
545538

546-
let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args);
539+
let term: Term<'tcx> = if alias_term.kind(tcx).is_type() {
540+
tcx.type_of(alias_term.def_id).instantiate(tcx, args).into()
541+
} else {
542+
get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into()
543+
};
547544

548-
let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
549-
if ty.has_aliases() {
550-
ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
545+
let mut term = selcx.infcx.resolve_vars_if_possible(term);
546+
if term.has_aliases() {
547+
term =
548+
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, term, obligations);
551549
}
552550

553-
ty
551+
term
554552
}
555553

556-
pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
554+
pub fn compute_inherent_assoc_term_args<'a, 'b, 'tcx>(
557555
selcx: &'a mut SelectionContext<'b, 'tcx>,
558556
param_env: ty::ParamEnv<'tcx>,
559-
alias_ty: ty::AliasTy<'tcx>,
557+
alias_term: ty::AliasTerm<'tcx>,
560558
cause: ObligationCause<'tcx>,
561559
depth: usize,
562560
obligations: &mut PredicateObligations<'tcx>,
563561
) -> ty::GenericArgsRef<'tcx> {
564562
let tcx = selcx.tcx();
565563

566-
let impl_def_id = tcx.parent(alias_ty.def_id);
564+
let impl_def_id = tcx.parent(alias_term.def_id);
567565
let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id);
568566

569567
let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args);
@@ -580,7 +578,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
580578

581579
// Infer the generic parameters of the impl by unifying the
582580
// impl type with the self type of the projection.
583-
let mut self_ty = alias_ty.self_ty();
581+
let mut self_ty = alias_term.self_ty();
584582
if !selcx.infcx.next_trait_solver() {
585583
self_ty = normalize_with_depth_to(
586584
selcx,
@@ -602,7 +600,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
602600
}
603601
}
604602

605-
alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx)
603+
alias_term.rebase_inherent_args_onto_impl(impl_args, tcx)
606604
}
607605

608606
enum Projected<'tcx> {
@@ -896,7 +894,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
896894
ImplSource::UserDefined(impl_data) => {
897895
// We have to be careful when projecting out of an
898896
// impl because of specialization. If we are not in
899-
// codegen (i.e., projection mode is not "any"), and the
897+
// codegen (i.e., `TypingMode` is not `PostAnalysis`), and the
900898
// impl's type is declared as default, then we disable
901899
// projection (even if the trait ref is fully
902900
// monomorphic). In the case where trait ref is not
@@ -1926,9 +1924,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
19261924
) {
19271925
Ok(InferOk { value: _, obligations }) => {
19281926
nested_obligations.extend(obligations);
1929-
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
1930-
// FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
1931-
// a term instead.
1927+
assoc_term_own_obligations(selcx, obligation, &mut nested_obligations);
19321928
Progress { term: cache_entry.term, obligations: nested_obligations }
19331929
}
19341930
Err(e) => {
@@ -1955,8 +1951,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
19551951
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
19561952

19571953
let param_env = obligation.param_env;
1958-
let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
1959-
Ok(assoc_ty) => assoc_ty,
1954+
let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
1955+
Ok(assoc_term) => assoc_term,
19601956
Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))),
19611957
};
19621958

@@ -1965,10 +1961,10 @@ fn confirm_impl_candidate<'cx, 'tcx>(
19651961
// has impossible-to-satisfy predicates (since those were
19661962
// allowed in <https://github.com/rust-lang/rust/pull/135480>),
19671963
// or because the impl is literally missing the definition.
1968-
if !assoc_ty.item.defaultness(tcx).has_value() {
1964+
if !assoc_term.item.defaultness(tcx).has_value() {
19691965
debug!(
19701966
"confirm_impl_candidate: no associated type {:?} for {:?}",
1971-
assoc_ty.item.name(),
1967+
assoc_term.item.name(),
19721968
obligation.predicate
19731969
);
19741970
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
@@ -1979,7 +1975,11 @@ fn confirm_impl_candidate<'cx, 'tcx>(
19791975
return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx)));
19801976
} else {
19811977
return Ok(Projected::Progress(Progress {
1982-
term: Ty::new_misc_error(tcx).into(),
1978+
term: if obligation.predicate.kind(tcx).is_type() {
1979+
Ty::new_misc_error(tcx).into()
1980+
} else {
1981+
ty::Const::new_misc_error(tcx).into()
1982+
},
19831983
obligations: nested,
19841984
}));
19851985
}
@@ -1992,35 +1992,40 @@ fn confirm_impl_candidate<'cx, 'tcx>(
19921992
// * `args` is `[u32]`
19931993
// * `args` ends up as `[u32, S]`
19941994
let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args);
1995-
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node);
1996-
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
1997-
1998-
let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const {
1999-
let did = assoc_ty.item.def_id;
2000-
let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did);
2001-
let uv = ty::UnevaluatedConst::new(did, identity_args);
2002-
ty::EarlyBinder::bind(ty::Const::new_unevaluated(tcx, uv).into())
1995+
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_term.defining_node);
1996+
1997+
let term = if obligation.predicate.kind(tcx).is_type() {
1998+
tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into())
20031999
} else {
2004-
tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into())
2000+
ty::EarlyBinder::bind(
2001+
get_associated_const_value(
2002+
selcx,
2003+
obligation.predicate.to_term(tcx).expect_const(),
2004+
param_env,
2005+
)
2006+
.into(),
2007+
)
20052008
};
20062009

2007-
let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
2008-
let err = Ty::new_error_with_message(
2009-
tcx,
2010-
obligation.cause.span,
2011-
"impl item and trait item have different parameters",
2012-
);
2013-
Progress { term: err.into(), obligations: nested }
2010+
let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) {
2011+
let msg = "impl item and trait item have different parameters";
2012+
let span = obligation.cause.span;
2013+
let err = if obligation.predicate.kind(tcx).is_type() {
2014+
Ty::new_error_with_message(tcx, span, msg).into()
2015+
} else {
2016+
ty::Const::new_error_with_message(tcx, span, msg).into()
2017+
};
2018+
Progress { term: err, obligations: nested }
20142019
} else {
2015-
assoc_ty_own_obligations(selcx, obligation, &mut nested);
2020+
assoc_term_own_obligations(selcx, obligation, &mut nested);
20162021
Progress { term: term.instantiate(tcx, args), obligations: nested }
20172022
};
20182023
Ok(Projected::Progress(progress))
20192024
}
20202025

20212026
// Get obligations corresponding to the predicates from the where-clause of the
20222027
// associated type itself.
2023-
fn assoc_ty_own_obligations<'cx, 'tcx>(
2028+
fn assoc_term_own_obligations<'cx, 'tcx>(
20242029
selcx: &mut SelectionContext<'cx, 'tcx>,
20252030
obligation: &ProjectionTermObligation<'tcx>,
20262031
nested: &mut PredicateObligations<'tcx>,
@@ -2090,3 +2095,15 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> {
20902095
})
20912096
}
20922097
}
2098+
2099+
fn get_associated_const_value<'tcx>(
2100+
selcx: &mut SelectionContext<'_, 'tcx>,
2101+
alias_ct: ty::Const<'tcx>,
2102+
param_env: ty::ParamEnv<'tcx>,
2103+
) -> ty::Const<'tcx> {
2104+
// FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type
2105+
// system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the
2106+
// constant is "close enough" to getting the actual rhs of the const item for now even if it might
2107+
// lead to some cycles
2108+
super::evaluate_const(selcx.infcx, alias_ct, param_env)
2109+
}

‎compiler/rustc_trait_selection/src/traits/select/confirmation.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
406406
let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
407407

408408
let mut assume = predicate.trait_ref.args.const_at(2);
409-
// FIXME(mgca): We should shallowly normalize this.
410409
if self.tcx().features().generic_const_exprs() {
411410
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
412411
}

‎compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use std::iter;
77

88
use rustc_hir as hir;
9+
use rustc_hir::def::DefKind;
910
use rustc_hir::lang_items::LangItem;
1011
use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
1112
use rustc_middle::bug;
@@ -486,7 +487,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
486487
/// Pushes the obligations required for an inherent alias to be WF
487488
/// into `self.out`.
488489
// FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
489-
fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
490+
fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTerm<'tcx>) {
490491
// An inherent projection is well-formed if
491492
//
492493
// (a) its predicates hold (*)
@@ -498,7 +499,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
498499
if !data.self_ty().has_escaping_bound_vars() {
499500
// FIXME(inherent_associated_types): Should this happen inside of a snapshot?
500501
// FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm!
501-
let args = traits::project::compute_inherent_assoc_ty_args(
502+
let args = traits::project::compute_inherent_assoc_term_args(
502503
&mut traits::SelectionContext::new(self.infcx),
503504
self.param_env,
504505
data,
@@ -776,7 +777,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
776777
self.out.extend(obligations);
777778
}
778779
ty::Alias(ty::Inherent, data) => {
779-
self.add_wf_preds_for_inherent_projection(data);
780+
self.add_wf_preds_for_inherent_projection(data.into());
780781
return; // Subtree handled by compute_inherent_projection.
781782
}
782783

@@ -961,9 +962,6 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
961962
match c.kind() {
962963
ty::ConstKind::Unevaluated(uv) => {
963964
if !c.has_escaping_bound_vars() {
964-
let obligations = self.nominal_obligations(uv.def, uv.args);
965-
self.out.extend(obligations);
966-
967965
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
968966
ty::ClauseKind::ConstEvaluatable(c),
969967
));
@@ -975,6 +973,16 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
975973
self.param_env,
976974
predicate,
977975
));
976+
977+
if tcx.def_kind(uv.def) == DefKind::AssocConst
978+
&& tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false })
979+
{
980+
self.add_wf_preds_for_inherent_projection(uv.into());
981+
return; // Subtree is handled by above function
982+
} else {
983+
let obligations = self.nominal_obligations(uv.def, uv.args);
984+
self.out.extend(obligations);
985+
}
978986
}
979987
}
980988
ty::ConstKind::Infer(_) => {

‎compiler/rustc_traits/src/normalize_projection_ty.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,14 @@ fn normalize_canonicalized_projection_ty<'tcx>(
3232
let selcx = &mut SelectionContext::new(ocx.infcx);
3333
let cause = ObligationCause::dummy();
3434
let mut obligations = PredicateObligations::new();
35-
let answer =
36-
traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations);
35+
let answer = traits::normalize_projection_term(
36+
selcx,
37+
param_env,
38+
goal.into(),
39+
cause,
40+
0,
41+
&mut obligations,
42+
);
3743
ocx.register_obligations(obligations);
3844
// #112047: With projections and opaques, we are able to create opaques that
3945
// are recursive (given some generic parameters of the opaque's type variables).
@@ -104,14 +110,14 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>(
104110
let answer = traits::normalize_inherent_projection(
105111
selcx,
106112
param_env,
107-
goal,
113+
goal.into(),
108114
cause,
109115
0,
110116
&mut obligations,
111117
);
112118
ocx.register_obligations(obligations);
113119

114-
Ok(NormalizationResult { normalized_ty: answer })
120+
Ok(NormalizationResult { normalized_ty: answer.expect_type() })
115121
},
116122
)
117123
}

‎compiler/rustc_type_ir/src/predicate.rs

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -474,10 +474,15 @@ pub enum AliasTermKind {
474474
/// Currently only used if the type alias references opaque types.
475475
/// Can always be normalized away.
476476
FreeTy,
477-
/// An unevaluated const coming from a generic const expression.
477+
478+
/// An unevaluated anonymous constants.
478479
UnevaluatedConst,
479480
/// An unevaluated const coming from an associated const.
480481
ProjectionConst,
482+
/// A top level const item not part of a trait or impl.
483+
FreeConst,
484+
/// An associated const in an inherent `impl`
485+
InherentConst,
481486
}
482487

483488
impl AliasTermKind {
@@ -486,11 +491,27 @@ impl AliasTermKind {
486491
AliasTermKind::ProjectionTy => "associated type",
487492
AliasTermKind::ProjectionConst => "associated const",
488493
AliasTermKind::InherentTy => "inherent associated type",
494+
AliasTermKind::InherentConst => "inherent associated const",
489495
AliasTermKind::OpaqueTy => "opaque type",
490496
AliasTermKind::FreeTy => "type alias",
497+
AliasTermKind::FreeConst => "unevaluated constant",
491498
AliasTermKind::UnevaluatedConst => "unevaluated constant",
492499
}
493500
}
501+
502+
pub fn is_type(self) -> bool {
503+
match self {
504+
AliasTermKind::ProjectionTy
505+
| AliasTermKind::InherentTy
506+
| AliasTermKind::OpaqueTy
507+
| AliasTermKind::FreeTy => true,
508+
509+
AliasTermKind::UnevaluatedConst
510+
| AliasTermKind::ProjectionConst
511+
| AliasTermKind::InherentConst
512+
| AliasTermKind::FreeConst => false,
513+
}
514+
}
494515
}
495516

496517
impl From<ty::AliasTyKind> for AliasTermKind {
@@ -566,7 +587,10 @@ impl<I: Interner> AliasTerm<I> {
566587
| AliasTermKind::InherentTy
567588
| AliasTermKind::OpaqueTy
568589
| AliasTermKind::FreeTy => {}
569-
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
590+
AliasTermKind::InherentConst
591+
| AliasTermKind::FreeConst
592+
| AliasTermKind::UnevaluatedConst
593+
| AliasTermKind::ProjectionConst => {
570594
panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
571595
}
572596
}
@@ -603,18 +627,19 @@ impl<I: Interner> AliasTerm<I> {
603627
ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
604628
)
605629
.into(),
606-
AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
607-
I::Const::new_unevaluated(
608-
interner,
609-
ty::UnevaluatedConst::new(self.def_id, self.args),
610-
)
611-
.into()
612-
}
630+
AliasTermKind::FreeConst
631+
| AliasTermKind::InherentConst
632+
| AliasTermKind::UnevaluatedConst
633+
| AliasTermKind::ProjectionConst => I::Const::new_unevaluated(
634+
interner,
635+
ty::UnevaluatedConst::new(self.def_id, self.args),
636+
)
637+
.into(),
613638
}
614639
}
615640
}
616641

617-
/// The following methods work only with (trait) associated type projections.
642+
/// The following methods work only with (trait) associated term projections.
618643
impl<I: Interner> AliasTerm<I> {
619644
pub fn self_ty(self) -> I::Ty {
620645
self.args.type_at(0)
@@ -659,6 +684,31 @@ impl<I: Interner> AliasTerm<I> {
659684
}
660685
}
661686

687+
/// The following methods work only with inherent associated term projections.
688+
impl<I: Interner> AliasTerm<I> {
689+
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
690+
///
691+
/// Does the following transformation:
692+
///
693+
/// ```text
694+
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
695+
///
696+
/// I_i impl args
697+
/// P_j GAT args
698+
/// ```
699+
pub fn rebase_inherent_args_onto_impl(
700+
self,
701+
impl_args: I::GenericArgs,
702+
interner: I,
703+
) -> I::GenericArgs {
704+
debug_assert!(matches!(
705+
self.kind(interner),
706+
AliasTermKind::InherentTy | AliasTermKind::InherentConst
707+
));
708+
interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1)))
709+
}
710+
}
711+
662712
impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> {
663713
fn from(ty: ty::AliasTy<I>) -> Self {
664714
AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }

‎compiler/rustc_type_ir/src/relate.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,10 @@ impl<I: Interner> Relate<I> for ty::AliasTerm<I> {
273273
false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
274274
)?,
275275
ty::AliasTermKind::ProjectionTy
276+
| ty::AliasTermKind::FreeConst
276277
| ty::AliasTermKind::FreeTy
277278
| ty::AliasTermKind::InherentTy
279+
| ty::AliasTermKind::InherentConst
278280
| ty::AliasTermKind::UnevaluatedConst
279281
| ty::AliasTermKind::ProjectionConst => {
280282
relate_args_invariantly(relation, a.args, b.args)?

‎compiler/rustc_type_ir/src/ty_kind.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -514,28 +514,6 @@ impl<I: Interner> AliasTy<I> {
514514
}
515515
}
516516

517-
/// The following methods work only with inherent associated type projections.
518-
impl<I: Interner> AliasTy<I> {
519-
/// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
520-
///
521-
/// Does the following transformation:
522-
///
523-
/// ```text
524-
/// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
525-
///
526-
/// I_i impl args
527-
/// P_j GAT args
528-
/// ```
529-
pub fn rebase_inherent_args_onto_impl(
530-
self,
531-
impl_args: I::GenericArgs,
532-
interner: I,
533-
) -> I::GenericArgs {
534-
debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent);
535-
interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1)))
536-
}
537-
}
538-
539517
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
540518
#[cfg_attr(
541519
feature = "nightly",

‎tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@ error: unconstrained generic constant
3939
LL | let _ = const_evaluatable_lib::test1::<T>();
4040
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4141
|
42-
note: required by a bound in `test1`
43-
--> $DIR/auxiliary/const_evaluatable_lib.rs:5:10
44-
|
45-
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
46-
| ----- required by a bound in this function
47-
LL | where
48-
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
49-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1`
5042
help: try adding a `where` bound
5143
|
5244
LL | fn user<T>() where [(); std::mem::size_of::<T>() - 1]: {
@@ -59,10 +51,13 @@ LL | let _ = const_evaluatable_lib::test1::<T>();
5951
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6052
|
6153
note: required by a bound in `test1`
62-
--> $DIR/auxiliary/const_evaluatable_lib.rs:3:27
54+
--> $DIR/auxiliary/const_evaluatable_lib.rs:5:10
6355
|
6456
LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
65-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1`
57+
| ----- required by a bound in this function
58+
LL | where
59+
LL | [u8; std::mem::size_of::<T>() - 1]: Sized,
60+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1`
6661
help: try adding a `where` bound
6762
|
6863
LL | fn user<T>() where [(); std::mem::size_of::<T>() - 1]: {

0 commit comments

Comments
 (0)
Please sign in to comment.