Skip to content

Commit 5b56a2a

Browse files
authored
Unrolled build for rust-lang#133610
Rollup merge of rust-lang#133610 - camelid:move-from_anon_const, r=BoxyUwU Move `Const::{from_anon_const,try_from_lit}` to hir_ty_lowering Fixes rust-lang#128176. This accomplishes one of the followup items from rust-lang#131081. These operations are much more about lowering the HIR than about `Const`s themselves. They fit better in hir_ty_lowering with `lower_const_arg` (formerly `Const::from_const_arg`) and the rest. To accomplish this, `const_evaluatable_predicates_of` had to be changed to not use `from_anon_const` anymore. Instead of visiting the HIR and lowering anon consts on the fly, it now visits the `rustc_middle::ty` data structures instead and directly looks for `UnevaluatedConst`s. This approach was proposed in: rust-lang#131081 (comment) r? `@BoxyUwU`
2 parents 42b4b9c + dcf332b commit 5b56a2a

File tree

11 files changed

+241
-164
lines changed

11 files changed

+241
-164
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_hir::lang_items::LangItem;
1313
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1414
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
1515
use rustc_macros::LintDiagnostic;
16+
use rustc_middle::mir::interpret::ErrorHandled;
1617
use rustc_middle::query::Providers;
1718
use rustc_middle::ty::print::with_no_trimmed_paths;
1819
use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -1170,19 +1171,13 @@ fn check_type_defn<'tcx>(
11701171

11711172
// Explicit `enum` discriminant values must const-evaluate successfully.
11721173
if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
1173-
let cause = traits::ObligationCause::new(
1174-
tcx.def_span(discr_def_id),
1175-
wfcx.body_def_id,
1176-
ObligationCauseCode::Misc,
1177-
);
1178-
wfcx.register_obligation(Obligation::new(
1179-
tcx,
1180-
cause,
1181-
wfcx.param_env,
1182-
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(
1183-
ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
1184-
))),
1185-
));
1174+
match tcx.const_eval_poly(discr_def_id) {
1175+
Ok(_) => {}
1176+
Err(ErrorHandled::Reported(..)) => {}
1177+
Err(ErrorHandled::TooGeneric(sp)) => {
1178+
span_bug!(sp, "enum variant discr was too generic to eval")
1179+
}
1180+
}
11861181
}
11871182
}
11881183

compiler/rustc_hir_analysis/src/collect/dump.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
22
use rustc_hir::intravisit;
3-
use rustc_middle::hir::nested_filter::OnlyBodies;
3+
use rustc_middle::hir::nested_filter;
44
use rustc_middle::ty::TyCtxt;
55
use rustc_span::sym;
66

@@ -42,15 +42,16 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
4242
}
4343

4444
pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
45-
for did in tcx.hir().body_owners() {
45+
for iid in tcx.hir().items() {
46+
let did = iid.owner_id.def_id;
4647
if tcx.has_attr(did, sym::rustc_dump_def_parents) {
4748
struct AnonConstFinder<'tcx> {
4849
tcx: TyCtxt<'tcx>,
4950
anon_consts: Vec<LocalDefId>,
5051
}
5152

5253
impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
53-
type NestedFilter = OnlyBodies;
54+
type NestedFilter = nested_filter::All;
5455

5556
fn nested_visit_map(&mut self) -> Self::Map {
5657
self.tcx.hir()
@@ -62,11 +63,11 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
6263
}
6364
}
6465

65-
// Look for any anon consts inside of this body owner as there is no way to apply
66+
// Look for any anon consts inside of this item as there is no way to apply
6667
// the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
6768
// to see what its def parent is.
6869
let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] };
69-
intravisit::walk_expr(&mut anon_ct_finder, tcx.hir().body_owned_by(did).value);
70+
intravisit::walk_item(&mut anon_ct_finder, tcx.hir().item(iid));
7071

7172
for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
7273
let span = tcx.def_span(did);

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+58-38
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use std::assert_matches::assert_matches;
22

3-
use hir::{HirId, Node};
3+
use hir::Node;
44
use rustc_data_structures::fx::FxIndexSet;
55
use rustc_hir as hir;
66
use rustc_hir::def::DefKind;
77
use rustc_hir::def_id::{DefId, LocalDefId};
8-
use rustc_hir::intravisit::{self, Visitor};
9-
use rustc_middle::ty::{self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, Upcast};
8+
use rustc_middle::ty::{
9+
self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast,
10+
};
1011
use rustc_middle::{bug, span_bug};
1112
use rustc_span::symbol::Ident;
1213
use rustc_span::{DUMMY_SP, Span};
@@ -305,7 +306,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
305306
}
306307

307308
if tcx.features().generic_const_exprs() {
308-
predicates.extend(const_evaluatable_predicates_of(tcx, def_id));
309+
predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates));
309310
}
310311

311312
let mut predicates: Vec<_> = predicates.into_iter().collect();
@@ -369,61 +370,80 @@ fn compute_bidirectional_outlives_predicates<'tcx>(
369370
}
370371
}
371372

372-
fn const_evaluatable_predicates_of(
373-
tcx: TyCtxt<'_>,
373+
#[instrument(level = "debug", skip(tcx, predicates), ret)]
374+
fn const_evaluatable_predicates_of<'tcx>(
375+
tcx: TyCtxt<'tcx>,
374376
def_id: LocalDefId,
375-
) -> FxIndexSet<(ty::Clause<'_>, Span)> {
377+
predicates: &FxIndexSet<(ty::Clause<'tcx>, Span)>,
378+
) -> FxIndexSet<(ty::Clause<'tcx>, Span)> {
376379
struct ConstCollector<'tcx> {
377380
tcx: TyCtxt<'tcx>,
378381
preds: FxIndexSet<(ty::Clause<'tcx>, Span)>,
379382
}
380383

381-
impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
382-
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
383-
let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
384-
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
385-
let span = self.tcx.def_span(c.def_id);
386-
self.preds.insert((ty::ClauseKind::ConstEvaluatable(ct).upcast(self.tcx), span));
387-
}
388-
}
384+
fn is_const_param_default(tcx: TyCtxt<'_>, def: LocalDefId) -> bool {
385+
let hir_id = tcx.local_def_id_to_hir_id(def);
386+
let (_, parent_node) = tcx
387+
.hir()
388+
.parent_iter(hir_id)
389+
.skip_while(|(_, n)| matches!(n, Node::ConstArg(..)))
390+
.next()
391+
.unwrap();
392+
matches!(
393+
parent_node,
394+
Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { .. }, .. })
395+
)
396+
}
389397

390-
fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::ConstArg<'tcx>) {
391-
// Do not look into const param defaults,
392-
// these get checked when they are actually instantiated.
393-
//
394-
// We do not want the following to error:
395-
//
396-
// struct Foo<const N: usize, const M: usize = { N + 1 }>;
397-
// struct Bar<const N: usize>(Foo<N, 3>);
398+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ConstCollector<'tcx> {
399+
fn visit_const(&mut self, c: ty::Const<'tcx>) {
400+
if let ty::ConstKind::Unevaluated(uv) = c.kind() {
401+
if is_const_param_default(self.tcx, uv.def.expect_local()) {
402+
// Do not look into const param defaults,
403+
// these get checked when they are actually instantiated.
404+
//
405+
// We do not want the following to error:
406+
//
407+
// struct Foo<const N: usize, const M: usize = { N + 1 }>;
408+
// struct Bar<const N: usize>(Foo<N, 3>);
409+
return;
410+
}
411+
412+
let span = self.tcx.def_span(uv.def);
413+
self.preds.insert((ty::ClauseKind::ConstEvaluatable(c).upcast(self.tcx), span));
414+
}
398415
}
399416
}
400417

401418
let hir_id = tcx.local_def_id_to_hir_id(def_id);
402419
let node = tcx.hir_node(hir_id);
403420

404421
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
422+
423+
for (clause, _sp) in predicates {
424+
clause.visit_with(&mut collector);
425+
}
426+
405427
if let hir::Node::Item(item) = node
406-
&& let hir::ItemKind::Impl(impl_) = item.kind
428+
&& let hir::ItemKind::Impl(_) = item.kind
407429
{
408-
if let Some(of_trait) = &impl_.of_trait {
409-
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
410-
collector.visit_trait_ref(of_trait);
430+
if let Some(of_trait) = tcx.impl_trait_ref(def_id) {
431+
debug!("visit impl trait_ref");
432+
of_trait.instantiate_identity().visit_with(&mut collector);
411433
}
412434

413-
debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
414-
collector.visit_ty(impl_.self_ty);
415-
}
416-
417-
if let Some(generics) = node.generics() {
418-
debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
419-
collector.visit_generics(generics);
435+
debug!("visit self_ty");
436+
let self_ty = tcx.type_of(def_id);
437+
self_ty.instantiate_identity().visit_with(&mut collector);
420438
}
421439

422-
if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
423-
debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
424-
collector.visit_fn_decl(fn_sig.decl);
440+
if let Some(_) = tcx.hir().fn_sig_by_hir_id(hir_id) {
441+
debug!("visit fn sig");
442+
let fn_sig = tcx.fn_sig(def_id);
443+
let fn_sig = fn_sig.instantiate_identity();
444+
debug!(?fn_sig);
445+
fn_sig.visit_with(&mut collector);
425446
}
426-
debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
427447

428448
collector.preds
429449
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
703703
///
704704
/// It might actually be possible that we can already support early-bound generic params
705705
/// in such types if we just lifted some more checks in other places, too, for example
706-
/// inside [`ty::Const::from_anon_const`]. However, even if that were the case, we should
706+
/// inside `HirTyLowerer::lower_anon_const`. However, even if that were the case, we should
707707
/// probably gate this behind another feature flag.
708708
///
709709
/// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>.

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+87-1
Original file line numberDiff line numberDiff line change
@@ -2089,7 +2089,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
20892089
qpath.span(),
20902090
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
20912091
),
2092-
hir::ConstArgKind::Anon(anon) => Const::from_anon_const(tcx, anon.def_id),
2092+
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon.def_id),
20932093
hir::ConstArgKind::Infer(span) => self.ct_infer(None, span),
20942094
}
20952095
}
@@ -2177,6 +2177,92 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21772177
}
21782178
}
21792179

2180+
/// Literals and const generic parameters are eagerly converted to a constant, everything else
2181+
/// becomes `Unevaluated`.
2182+
#[instrument(skip(self), level = "debug")]
2183+
fn lower_anon_const(&self, def: LocalDefId) -> Const<'tcx> {
2184+
let tcx = self.tcx();
2185+
2186+
let body_id = match tcx.hir_node_by_def_id(def) {
2187+
hir::Node::AnonConst(ac) => ac.body,
2188+
node => span_bug!(
2189+
tcx.def_span(def.to_def_id()),
2190+
"from_anon_const can only process anonymous constants, not {node:?}"
2191+
),
2192+
};
2193+
2194+
let expr = &tcx.hir().body(body_id).value;
2195+
debug!(?expr);
2196+
2197+
let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
2198+
2199+
match self.try_lower_anon_const_lit(ty, expr) {
2200+
Some(v) => v,
2201+
None => ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst {
2202+
def: def.to_def_id(),
2203+
args: ty::GenericArgs::identity_for_item(tcx, def.to_def_id()),
2204+
}),
2205+
}
2206+
}
2207+
2208+
#[instrument(skip(self), level = "debug")]
2209+
fn try_lower_anon_const_lit(
2210+
&self,
2211+
ty: Ty<'tcx>,
2212+
expr: &'tcx hir::Expr<'tcx>,
2213+
) -> Option<Const<'tcx>> {
2214+
let tcx = self.tcx();
2215+
2216+
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
2217+
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
2218+
let expr = match &expr.kind {
2219+
hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
2220+
block.expr.as_ref().unwrap()
2221+
}
2222+
_ => expr,
2223+
};
2224+
2225+
if let hir::ExprKind::Path(hir::QPath::Resolved(
2226+
_,
2227+
&hir::Path { res: Res::Def(DefKind::ConstParam, _), .. },
2228+
)) = expr.kind
2229+
{
2230+
span_bug!(
2231+
expr.span,
2232+
"try_lower_anon_const_lit: received const param which shouldn't be possible"
2233+
);
2234+
};
2235+
2236+
let lit_input = match expr.kind {
2237+
hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
2238+
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
2239+
hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }),
2240+
_ => None,
2241+
},
2242+
_ => None,
2243+
};
2244+
2245+
if let Some(lit_input) = lit_input {
2246+
// If an error occurred, ignore that it's a literal and leave reporting the error up to
2247+
// mir.
2248+
match tcx.at(expr.span).lit_to_const(lit_input) {
2249+
Ok(c) => return Some(c),
2250+
Err(_) if lit_input.ty.has_aliases() => {
2251+
// allow the `ty` to be an alias type, though we cannot handle it here
2252+
return None;
2253+
}
2254+
Err(e) => {
2255+
tcx.dcx().span_delayed_bug(
2256+
expr.span,
2257+
format!("try_lower_anon_const_lit: couldn't lit_to_const {e:?}"),
2258+
);
2259+
}
2260+
}
2261+
}
2262+
2263+
None
2264+
}
2265+
21802266
fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
21812267
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
21822268
match idx {

0 commit comments

Comments
 (0)