Skip to content

Commit 9864a2f

Browse files
committed
add const_of_item query and use it in normalization
1 parent 0515aa5 commit 9864a2f

File tree

16 files changed

+171
-122
lines changed

16 files changed

+171
-122
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub(crate) fn provide(providers: &mut Providers) {
9696
rendered_precise_capturing_args,
9797
const_param_default,
9898
anon_const_kind,
99+
const_of_item,
99100
..*providers
100101
};
101102
}
@@ -1543,3 +1544,38 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
15431544
_ => ty::AnonConstKind::NonTypeSystem,
15441545
}
15451546
}
1547+
1548+
#[instrument(level = "debug", skip(tcx), ret)]
1549+
fn const_of_item<'tcx>(
1550+
tcx: TyCtxt<'tcx>,
1551+
def_id: LocalDefId,
1552+
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
1553+
let ct_rhs = match tcx.hir_node_by_def_id(def_id) {
1554+
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => *ct,
1555+
hir::Node::TraitItem(hir::TraitItem {
1556+
kind: hir::TraitItemKind::Const(.., ct), ..
1557+
}) => ct.expect("no default value for trait assoc const"),
1558+
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => *ct,
1559+
_ => {
1560+
span_bug!(tcx.def_span(def_id), "`const_of_item` expected a const or assoc const item")
1561+
}
1562+
};
1563+
let ct_arg = match ct_rhs {
1564+
hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg,
1565+
hir::ConstItemRhs::Body(body_id) => {
1566+
bug!("cannot call const_of_item on a non-type_const {body_id:?}")
1567+
}
1568+
};
1569+
let icx = ItemCtxt::new(tcx, def_id);
1570+
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
1571+
let ct = icx
1572+
.lowerer()
1573+
.lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args));
1574+
if let Err(e) = icx.check_tainted_by_errors()
1575+
&& !ct.references_error()
1576+
{
1577+
ty::EarlyBinder::bind(Const::new_error(tcx, e))
1578+
} else {
1579+
ty::EarlyBinder::bind(ct)
1580+
}
1581+
}

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ provide! { tcx, def_id, other, cdata,
403403
tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
404404
}
405405
anon_const_kind => { table }
406+
const_of_item => { table }
406407
}
407408

408409
pub(in crate::rmeta) fn provide(providers: &mut Providers) {

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,21 @@ fn should_encode_const(def_kind: DefKind) -> bool {
13831383
}
13841384
}
13851385

1386+
fn should_encode_const_of_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool {
1387+
matches!(def_kind, DefKind::Const | DefKind::AssocConst)
1388+
&& find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_))
1389+
// AssocConst ==> assoc item has value
1390+
&& (!matches!(def_kind, DefKind::AssocConst) || assoc_item_has_value(tcx, def_id))
1391+
}
1392+
1393+
fn assoc_item_has_value<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
1394+
let assoc_item = tcx.associated_item(def_id);
1395+
match assoc_item.container {
1396+
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
1397+
ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
1398+
}
1399+
}
1400+
13861401
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
13871402
fn encode_attrs(&mut self, def_id: LocalDefId) {
13881403
let tcx = self.tcx;
@@ -1604,6 +1619,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16041619
if let DefKind::AnonConst = def_kind {
16051620
record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
16061621
}
1622+
if should_encode_const_of_item(self.tcx, def_id, def_kind) {
1623+
record!(self.tables.const_of_item[def_id] <- self.tcx.const_of_item(def_id));
1624+
}
16071625
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
16081626
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
16091627
{

compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ define_tables! {
471471
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
472472
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
473473
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
474+
const_of_item: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
474475
associated_types_for_impl_traits_in_trait_or_impl: Table<DefIndex, LazyValue<DefIdMap<Vec<DefId>>>>,
475476
}
476477

compiler/rustc_middle/src/query/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,19 @@ rustc_queries! {
293293
separate_provide_extern
294294
}
295295

296+
/// Returns the const of the RHS of a (free or assoc) const item, if it is a `#[type_const]`.
297+
///
298+
/// When a const item is used in a type-level expression, like in equality for an assoc const
299+
/// projection, this allows us to retrieve the typesystem-appropriate representation of the
300+
/// const value.
301+
///
302+
/// This query will ICE if given a const that is not marked with `#[type_const]`.
303+
query const_of_item(def_id: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> {
304+
desc { |tcx| "computing the type-level value for `{}`", tcx.def_path_str(def_id) }
305+
cache_on_disk_if { def_id.is_local() }
306+
separate_provide_extern
307+
}
308+
296309
/// Returns the *type* of the definition given by `DefId`.
297310
///
298311
/// For type aliases (whether eager or lazy) and associated types, this returns

compiler/rustc_middle/src/ty/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
242242
fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
243243
self.type_of_opaque_hir_typeck(def_id)
244244
}
245+
fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
246+
self.const_of_item(def_id)
247+
}
245248

246249
type AdtDef = ty::AdtDef<'tcx>;
247250
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,12 @@ where
3030
);
3131

3232
let actual = if free_alias.kind(cx).is_type() {
33-
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args)
33+
cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into()
3434
} 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");
35+
cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into()
3836
};
3937

40-
self.instantiate_normalizes_to_term(goal, actual.into());
38+
self.instantiate_normalizes_to_term(goal, actual);
4139
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
4240
}
4341
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ where
5454
let normalized = if inherent.kind(cx).is_type() {
5555
cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into()
5656
} else {
57-
// FIXME(mgca): Properly handle IACs in the type system
58-
panic!("normalizing inherent associated consts in the type system is unsupported");
57+
cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into()
5958
};
6059
self.instantiate_normalizes_to_term(goal, normalized);
6160
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)

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

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -366,19 +366,7 @@ where
366366
cx.type_of(target_item_def_id).map_bound(|ty| ty.into())
367367
}
368368
ty::AliasTermKind::ProjectionConst => {
369-
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
370-
// this should instead return that.
371-
if cx.features().associated_const_equality() {
372-
panic!("associated const projection is not supported yet")
373-
} else {
374-
ty::EarlyBinder::bind(
375-
Const::new_error_with_message(
376-
cx,
377-
"associated const projection is not supported yet",
378-
)
379-
.into(),
380-
)
381-
}
369+
cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into())
382370
}
383371
kind => panic!("expected projection, found {kind:?}"),
384372
};

compiler/rustc_trait_selection/src/traits/normalize.rs

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
333333
let res = if free.kind(infcx.tcx).is_type() {
334334
infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into()
335335
} else {
336-
// FIXME(mgca): once const items are actual aliases defined as equal to type system consts
337-
// this should instead use that rather than evaluating.
338-
super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env)
339-
.super_fold_with(self)
336+
infcx
337+
.tcx
338+
.const_of_item(free.def_id)
339+
.instantiate(infcx.tcx, free.args)
340+
.fold_with(self)
340341
.into()
341342
};
342343
self.depth -= 1;
@@ -436,51 +437,47 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
436437
return ct;
437438
}
438439

439-
// Doing "proper" normalization of const aliases is inherently cyclic until const items
440-
// are real aliases instead of having bodies. We gate proper const alias handling behind
441-
// mgca to avoid breaking stable code, though this should become the "main" codepath long
442-
// before mgca is stabilized.
440+
let uv = match ct.kind() {
441+
ty::ConstKind::Unevaluated(uv) => uv,
442+
_ => return ct.super_fold_with(self),
443+
};
444+
445+
// Note that the AssocConst and Const cases are unreachable on stable,
446+
// unless a `min_generic_const_args` feature gate error has already
447+
// been emitted earlier in compilation.
443448
//
444-
// FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items
445-
// are represented.
446-
if tcx.features().min_generic_const_args() {
447-
let uv = match ct.kind() {
448-
ty::ConstKind::Unevaluated(uv) => uv,
449-
_ => return ct.super_fold_with(self),
450-
};
451-
452-
let ct = match tcx.def_kind(uv.def) {
453-
DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
454-
DefKind::Trait => self.normalize_trait_projection(uv.into()),
455-
DefKind::Impl { of_trait: false } => {
456-
self.normalize_inherent_projection(uv.into())
457-
}
458-
kind => unreachable!(
459-
"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
460-
kind
461-
),
462-
},
463-
DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()),
464-
kind => {
465-
unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
449+
// That's because we can only end up with an Unevaluated ty::Const for a const item
450+
// if it was marked with `#[type_const]`. Using this attribute without the mgca
451+
// feature gate causes a parse error.
452+
let ct = match tcx.def_kind(uv.def) {
453+
DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
454+
DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(),
455+
DefKind::Impl { of_trait: false } => {
456+
self.normalize_inherent_projection(uv.into()).expect_const()
466457
}
467-
};
458+
kind => unreachable!(
459+
"unexpected `DefKind` for const alias' resolution's parent def: {:?}",
460+
kind
461+
),
462+
},
463+
DefKind::Const => self.normalize_free_alias(uv.into()).expect_const(),
464+
DefKind::AnonConst => {
465+
let ct = ct.super_fold_with(self);
466+
super::with_replaced_escaping_bound_vars(
467+
self.selcx.infcx,
468+
&mut self.universes,
469+
ct,
470+
|ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
471+
)
472+
}
473+
kind => {
474+
unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
475+
}
476+
};
468477

469-
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
470-
// unnormalized after const evaluation returns.
471-
ct.expect_const().super_fold_with(self)
472-
} else {
473-
let ct = ct.super_fold_with(self);
474-
return super::with_replaced_escaping_bound_vars(
475-
self.selcx.infcx,
476-
&mut self.universes,
477-
ct,
478-
|ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
479-
)
480-
.super_fold_with(self);
481-
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
482-
// unnormalized after const evaluation returns.
483-
}
478+
// We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be
479+
// unnormalized after const evaluation returns.
480+
ct.super_fold_with(self)
484481
}
485482

486483
#[inline]

0 commit comments

Comments
 (0)