Skip to content

Commit bc46b88

Browse files
committed
generic_const_args: allow paths to non type consts
1 parent fcce4d1 commit bc46b88

17 files changed

Lines changed: 251 additions & 47 deletions

File tree

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3031,7 +3031,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
30313031
span: Span,
30323032
) -> Result<(), ErrorGuaranteed> {
30333033
let tcx = self.tcx();
3034-
if tcx.is_type_const(def_id) {
3034+
// FIXME(gca): Intentionally disallowing paths to inherent associated non-type constants
3035+
// until a refactoring for how generic args for IACs are represented has been landed.
3036+
let is_inherent_assoc_const = tcx.def_kind(def_id)
3037+
== DefKind::AssocConst { is_type_const: false }
3038+
&& tcx.def_kind(tcx.parent(def_id)) == DefKind::Impl { of_trait: false };
3039+
if tcx.is_type_const(def_id)
3040+
|| tcx.features().generic_const_args() && !is_inherent_assoc_const
3041+
{
30353042
Ok(())
30363043
} else {
30373044
let mut err = self.dcx().struct_span_err(

compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,8 @@ where
1414
&mut self,
1515
goal: Goal<I, ty::NormalizesTo<I>>,
1616
) -> QueryResult<I> {
17-
if let Some(normalized_const) = self.evaluate_const(
18-
goal.param_env,
19-
ty::UnevaluatedConst::new(
20-
goal.predicate.alias.def_id.try_into().unwrap(),
21-
goal.predicate.alias.args,
22-
),
23-
) {
17+
let uv = goal.predicate.alias.expect_ct(self.cx());
18+
if let Some(normalized_const) = self.evaluate_const(goal.param_env, uv) {
2419
self.instantiate_normalizes_to_term(goal, normalized_const.into());
2520
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
2621
} else {

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,24 @@ where
2929
.map(|pred| goal.with(cx, pred)),
3030
);
3131

32-
let actual = if free_alias.kind(cx).is_type() {
33-
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into()
34-
} else {
35-
cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into()
32+
let actual = match free_alias.kind(cx) {
33+
ty::AliasTermKind::FreeTy => {
34+
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into()
35+
}
36+
ty::AliasTermKind::FreeConst { is_type_const: true } => {
37+
cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into()
38+
}
39+
ty::AliasTermKind::FreeConst { is_type_const: false } => {
40+
if let Some(normalized_const) =
41+
self.evaluate_const(goal.param_env, free_alias.expect_ct(cx))
42+
{
43+
normalized_const.into()
44+
} else {
45+
return self
46+
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
47+
}
48+
}
49+
kind => panic!("expected free alias, found {kind:?}"),
3650
};
3751

3852
self.instantiate_normalizes_to_term(goal, actual);

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,23 @@ where
5151
.map(|pred| goal.with(cx, pred)),
5252
);
5353

54-
let normalized = if inherent.kind(cx).is_type() {
55-
cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into()
56-
} else {
57-
cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into()
54+
let normalized = match inherent.kind(cx) {
55+
ty::AliasTermKind::InherentTy => {
56+
cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into()
57+
}
58+
ty::AliasTermKind::InherentConst { is_type_const: true } => {
59+
cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into()
60+
}
61+
ty::AliasTermKind::InherentConst { is_type_const: false } => {
62+
// FIXME(gca): This is dead code at the moment. It should eventually call
63+
// self.evaluate_const like projected consts do in consider_impl_candidate in
64+
// normalizes_to/mod.rs. However, how generic args are represented for IACs is up in
65+
// the air right now.
66+
// Will self.evaluate_const eventually take the inherent_args or the impl_args form
67+
// of args? It might be either.
68+
panic!("References to inherent associated consts should have been blocked");
69+
}
70+
kind => panic!("expected inherent alias, found {kind:?}"),
5871
};
5972
self.instantiate_normalizes_to_term(goal, normalized);
6073
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,15 +380,28 @@ where
380380
// Finally we construct the actual value of the associated type.
381381
let term = match goal.predicate.alias.kind(cx) {
382382
ty::AliasTermKind::ProjectionTy => {
383-
cx.type_of(target_item_def_id).map_bound(|ty| ty.into())
383+
cx.type_of(target_item_def_id).instantiate(cx, target_args).into()
384384
}
385-
ty::AliasTermKind::ProjectionConst { .. } => {
386-
cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into())
385+
ty::AliasTermKind::ProjectionConst { is_type_const: true } => {
386+
cx.const_of_item(target_item_def_id).instantiate(cx, target_args).into()
387+
}
388+
ty::AliasTermKind::ProjectionConst { is_type_const: false } => {
389+
let uv = ty::UnevaluatedConst::new(
390+
target_item_def_id.try_into().unwrap(),
391+
target_args,
392+
);
393+
if let Some(eval) = ecx.evaluate_const(goal.param_env, uv) {
394+
eval.into()
395+
} else {
396+
return ecx.evaluate_added_goals_and_make_canonical_response(
397+
Certainty::AMBIGUOUS,
398+
);
399+
}
387400
}
388401
kind => panic!("expected projection, found {kind:?}"),
389402
};
390403

391-
ecx.instantiate_normalizes_to_term(goal, term.instantiate(cx, target_args));
404+
ecx.instantiate_normalizes_to_term(goal, term);
392405
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
393406
})
394407
}

compiler/rustc_trait_selection/src/traits/normalize.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,15 +331,24 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
331331
),
332332
);
333333
self.depth += 1;
334-
let res = if free.kind(infcx.tcx).is_type() {
335-
infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into()
336-
} else {
337-
infcx
334+
let res = match free.kind(infcx.tcx) {
335+
ty::AliasTermKind::FreeTy => infcx
336+
.tcx
337+
.type_of(free.def_id)
338+
.instantiate(infcx.tcx, free.args)
339+
.fold_with(self)
340+
.into(),
341+
ty::AliasTermKind::FreeConst { is_type_const: true } => infcx
338342
.tcx
339343
.const_of_item(free.def_id)
340344
.instantiate(infcx.tcx, free.args)
341345
.fold_with(self)
342-
.into()
346+
.into(),
347+
ty::AliasTermKind::FreeConst { is_type_const: false } => {
348+
super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env)
349+
.into()
350+
}
351+
kind => panic!("expected free alias, found {kind:?}"),
343352
};
344353
self.depth -= 1;
345354
res

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -545,10 +545,22 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
545545
));
546546
}
547547

548-
let term: Term<'tcx> = if alias_term.kind(tcx).is_type() {
549-
tcx.type_of(alias_term.def_id).instantiate(tcx, args).into()
550-
} else {
551-
tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into()
548+
let term: Term<'tcx> = match alias_term.kind(tcx) {
549+
ty::AliasTermKind::InherentTy => {
550+
tcx.type_of(alias_term.def_id).instantiate(tcx, args).into()
551+
}
552+
ty::AliasTermKind::InherentConst { is_type_const: true } => {
553+
tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into()
554+
}
555+
ty::AliasTermKind::InherentConst { is_type_const: false } => {
556+
// FIXME(gca): This is dead code at the moment. It should eventually call
557+
// super::evaluate_const like projected consts do in confirm_impl_candidate in this
558+
// file. However, how generic args are represented for IACs is up in the air right now.
559+
// Will super::evaluate_const eventually take the inherent_args or the impl_args form of
560+
// args? It might be either.
561+
panic!("References to inherent associated consts should have been blocked");
562+
}
563+
kind => panic!("expected inherent alias, found {kind:?}"),
552564
};
553565

554566
let mut term = selcx.infcx.resolve_vars_if_possible(term);
@@ -2046,12 +2058,6 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20462058
let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args);
20472059
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_term.defining_node);
20482060

2049-
let term = if obligation.predicate.kind(tcx).is_type() {
2050-
tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into())
2051-
} else {
2052-
tcx.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into())
2053-
};
2054-
20552061
let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) {
20562062
let msg = "impl item and trait item have different parameters";
20572063
let span = obligation.cause.span;
@@ -2063,7 +2069,23 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20632069
Progress { term: err, obligations: nested }
20642070
} else {
20652071
assoc_term_own_obligations(selcx, obligation, &mut nested);
2066-
Progress { term: term.instantiate(tcx, args), obligations: nested }
2072+
2073+
let term = match obligation.predicate.kind(tcx) {
2074+
ty::AliasTermKind::ProjectionTy => {
2075+
tcx.type_of(assoc_term.item.def_id).instantiate(tcx, args).into()
2076+
}
2077+
ty::AliasTermKind::ProjectionConst { is_type_const: true } => {
2078+
tcx.const_of_item(assoc_term.item.def_id).instantiate(tcx, args).into()
2079+
}
2080+
ty::AliasTermKind::ProjectionConst { is_type_const: false } => {
2081+
let uv = ty::UnevaluatedConst::new(assoc_term.item.def_id, args);
2082+
let ct = ty::Const::new_unevaluated(tcx, uv);
2083+
super::evaluate_const(selcx.infcx, ct, param_env).into()
2084+
}
2085+
kind => panic!("expected projection alias, found {kind:?}"),
2086+
};
2087+
2088+
Progress { term, obligations: nested }
20672089
};
20682090
Ok(Projected::Progress(progress))
20692091
}

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
10591059
ty::ConstKind::Unevaluated(uv) => {
10601060
if !c.has_escaping_bound_vars() {
10611061
// Skip type consts as mGCA doesn't support evaluatable clauses
1062-
if !tcx.is_type_const(uv.def) {
1062+
if !tcx.is_type_const(uv.def) && !tcx.features().generic_const_args() {
10631063
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
10641064
ty::ClauseKind::ConstEvaluatable(c),
10651065
));

compiler/rustc_type_ir/src/predicate.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -529,15 +529,17 @@ impl AliasTermKind {
529529
pub fn descr(self) -> &'static str {
530530
match self {
531531
AliasTermKind::ProjectionTy => "associated type",
532-
AliasTermKind::ProjectionConst { is_type_const: true } => "associated const",
533-
AliasTermKind::ProjectionConst { is_type_const: false } => "associated const",
532+
AliasTermKind::ProjectionConst { is_type_const: true } => "associated constant",
533+
AliasTermKind::ProjectionConst { is_type_const: false } => "associated type constant",
534534
AliasTermKind::InherentTy => "inherent associated type",
535-
AliasTermKind::InherentConst { is_type_const: true } => "inherent associated const",
536-
AliasTermKind::InherentConst { is_type_const: false } => "inherent associated const",
535+
AliasTermKind::InherentConst { is_type_const: true } => {
536+
"inherent associated type constant"
537+
}
538+
AliasTermKind::InherentConst { is_type_const: false } => "inherent associated constant",
537539
AliasTermKind::OpaqueTy => "opaque type",
538540
AliasTermKind::FreeTy => "type alias",
539-
AliasTermKind::FreeConst { is_type_const: true } => "unevaluated constant",
540-
AliasTermKind::FreeConst { is_type_const: false } => "unevaluated constant",
541+
AliasTermKind::FreeConst { is_type_const: true } => "free type constant",
542+
AliasTermKind::FreeConst { is_type_const: false } => "free constant",
541543
AliasTermKind::UnevaluatedConst => "unevaluated constant",
542544
}
543545
}
@@ -642,6 +644,22 @@ impl<I: Interner> AliasTerm<I> {
642644
ty::AliasTy { kind, args: self.args, _use_alias_ty_new_instead: () }
643645
}
644646

647+
pub fn expect_ct(self, interner: I) -> ty::UnevaluatedConst<I> {
648+
match self.kind(interner) {
649+
AliasTermKind::InherentConst { .. }
650+
| AliasTermKind::FreeConst { .. }
651+
| AliasTermKind::UnevaluatedConst
652+
| AliasTermKind::ProjectionConst { .. } => {}
653+
kind @ (AliasTermKind::ProjectionTy
654+
| AliasTermKind::InherentTy
655+
| AliasTermKind::OpaqueTy
656+
| AliasTermKind::FreeTy) => {
657+
panic!("Cannot turn `{}` into `UnevaluatedConst`", kind.descr())
658+
}
659+
}
660+
ty::UnevaluatedConst { def: self.def_id.try_into().unwrap(), args: self.args }
661+
}
662+
645663
pub fn kind(self, interner: I) -> AliasTermKind {
646664
interner.alias_term_kind(self)
647665
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//@ check-pass
2+
//@ revisions: old next
3+
//@[next] compile-flags: -Znext-solver
4+
5+
#![feature(min_generic_const_args)]
6+
#![feature(generic_const_args)]
7+
#![expect(incomplete_features)]
8+
9+
trait Trait {
10+
const PROJECTED: usize;
11+
}
12+
13+
struct StructImpl;
14+
struct GenericStructImpl<const A: usize>;
15+
16+
const FREE: usize = 1;
17+
18+
impl Trait for StructImpl {
19+
const PROJECTED: usize = 1;
20+
}
21+
22+
impl<const A: usize> Trait for GenericStructImpl<A> {
23+
const PROJECTED: usize = A;
24+
}
25+
26+
struct Struct<const N: usize>;
27+
28+
fn f<T: Trait>() {
29+
let _ = Struct::<{ T::PROJECTED }>;
30+
}
31+
32+
fn main() {
33+
let _ = Struct::<FREE>;
34+
let _ = Struct::<{ <StructImpl as Trait>::PROJECTED }>;
35+
let _ = Struct::<{ <GenericStructImpl<2> as Trait>::PROJECTED }>;
36+
}

0 commit comments

Comments
 (0)