diff options
| author | bors <bors@rust-lang.org> | 2024-07-19 08:44:51 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-07-19 08:44:51 +0000 |
| commit | 8c3a94a1c79c67924558a4adf7fb6d98f5f0f741 (patch) | |
| tree | 38c82dbbb0ab3f8513f0965761bb13006c8f433e /compiler/rustc_hir_analysis/src | |
| parent | 3d68afc9e821b00d59058abc9bda670b07639955 (diff) | |
| parent | c8457e60e8a1bbade7f8aa34d3646c392a4237b6 (diff) | |
| download | rust-8c3a94a1c79c67924558a4adf7fb6d98f5f0f741.tar.gz rust-8c3a94a1c79c67924558a4adf7fb6d98f5f0f741.zip | |
Auto merge of #125915 - camelid:const-arg-refactor, r=BoxyUwU
Represent type-level consts with new-and-improved `hir::ConstArg` ### Summary This is a step toward `min_generic_const_exprs`. We now represent all const generic arguments using an enum that differentiates between const *paths* (temporarily just bare const params) and arbitrary anon consts that may perform computations. This will enable us to cleanly implement the `min_generic_const_args` plan of allowing the use of generics in paths used as const args, while disallowing their use in arbitrary anon consts. Here is a summary of the salient aspects of this change: - Add `current_def_id_parent` to `LoweringContext` This is needed to track anon const parents properly once we implement `ConstArgKind::Path` (which requires moving anon const def-creation outside of `DefCollector`). - Create `hir::ConstArgKind` enum with `Path` and `Anon` variants. Use it in the existing `hir::ConstArg` struct, replacing the previous `hir::AnonConst` field. - Use `ConstArg` for all instances of const args. Specifically, use it instead of `AnonConst` for assoc item constraints, array lengths, and const param defaults. - Some `ast::AnonConst`s now have their `DefId`s created in rustc_ast_lowering rather than `DefCollector`. This is because in some cases they will end up becoming a `ConstArgKind::Path` instead, which has no `DefId`. We have to solve this in a hacky way where we guess whether the `AnonConst` could end up as a path const since we can't know for sure until after name resolution (`N` could refer to a free const or a nullary struct). If it has no chance as being a const param, then we create a `DefId` in `DefCollector` -- otherwise we decide during ast_lowering. This will have to be updated once all path consts use `ConstArgKind::Path`. - We explicitly use `ConstArgHasType` for array lengths, rather than implicitly relying on anon const type feeding -- this is due to the addition of `ConstArgKind::Path`. - Some tests have their outputs changed, but the changes are for the most part minor (including removing duplicate or almost-duplicate errors). One test now ICEs, but it is for an incomplete, unstable feature and is now tracked at https://github.com/rust-lang/rust/issues/127009. ### Followup items post-merge - Use `ConstArgKind::Path` for all const paths, not just const params. - Fix (no github dont close this issue) #127009 - If a path in generic args doesn't resolve as a type, try to resolve as a const instead (do this in rustc_resolve). Then remove the special-casing from `rustc_ast_lowering`, so that all params will automatically be lowered as `ConstArgKind::Path`. - (?) Consider making `const_evaluatable_unchecked` a hard error, or at least trying it in crater r? `@BoxyUwU`
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
9 files changed, 100 insertions, 55 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e0aad299163..5e23d473274 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -304,7 +304,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { self.tcx.ensure().type_of(param.def_id); if let Some(default) = default { // need to store default and type of default - self.tcx.ensure().type_of(default.def_id); + if let hir::ConstArgKind::Anon(ac) = default.kind { + self.tcx.ensure().type_of(ac.def_id); + } self.tcx.ensure().const_param_default(param.def_id); } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 22d465c8e62..690423421b9 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -13,7 +13,7 @@ use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -#[instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx), ret)] pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -102,6 +102,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { None } else if tcx.features().generic_const_exprs { let parent_node = tcx.parent_hir_node(hir_id); + debug!(?parent_node); if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node && constant.hir_id == hir_id { @@ -164,13 +165,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } else { let parent_node = tcx.parent_hir_node(hir_id); + let parent_node = match parent_node { + Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id), + _ => parent_node, + }; match parent_node { // HACK(eddyb) this provides the correct generics for repeat // expressions' count (i.e. `N` in `[x; N]`), and explicit // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), // as they shouldn't be able to cause query cycle errors. - Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) - if constant.hir_id() == hir_id => + Node::Expr(Expr { kind: ExprKind::Repeat(_, ArrayLen::Body(ct)), .. }) + if ct.anon_const_hir_id() == Some(hir_id) => { Some(parent_did) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index b89d034fc2e..9e430c83e20 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -388,7 +388,7 @@ fn const_evaluatable_predicates_of( } } - fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) { + fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::ConstArg<'tcx>) { // Do not look into const param defaults, // these get checked when they are actually instantiated. // diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index cad7870a0a1..7930f54038d 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -954,7 +954,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { GenericParamKind::Const { ty, default, .. } => { self.visit_ty(ty); if let Some(default) = default { - self.visit_body(self.tcx.hir().body(default.body)); + self.visit_const_arg(default); } } } @@ -1594,7 +1594,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { i += 1; } GenericArg::Const(ct) => { - self.visit_anon_const(&ct.value); + self.visit_const_arg(ct); i += 1; } GenericArg::Infer(inf) => { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 974dd415f46..9affd654366 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -35,16 +35,32 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let parent_node_id = tcx.parent_hir_id(hir_id); let parent_node = tcx.hir_node(parent_node_id); - let (generics, arg_idx) = match parent_node { - // Easy case: arrays repeat expressions. - Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) - | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id() == hir_id => + match parent_node { + // Anon consts "inside" the type system. + Node::ConstArg(&ConstArg { + hir_id: arg_hir_id, + kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }), + .. + }) if anon_hir_id == hir_id => const_arg_anon_type_of(tcx, arg_hir_id, span), + + // Anon consts outside the type system. + Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) + | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) + if asm.operands.iter().any(|(op, _op_sp)| match op { + hir::InlineAsmOperand::Const { anon_const } + | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, + _ => false, + }) => { - return tcx.types.usize; + tcx.typeck(def_id).node_type(hir_id) + } + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) } + // Sort of affects the type system, but only for the purpose of diagnostics + // so no need for ConstArg. Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), span, .. }) if e.hir_id == hir_id => { - let ty = tcx.typeck(def_id).node_type(e.hir_id); + let ty = tcx.typeck(def_id).node_type(tcx.local_def_id_to_hir_id(def_id)); let ty = tcx.fold_regions(ty, |r, _| { if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r } }); @@ -56,24 +72,35 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg }); return ty; } - Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) - if asm.operands.iter().any(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, - _ => false, - }) => + + _ => Ty::new_error_with_message( + tcx, + span, + format!("unexpected anon const parent in type_of(): {parent_node:?}"), + ), + } +} + +fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> { + use hir::*; + use rustc_middle::ty::Ty; + + let parent_node_id = tcx.parent_hir_id(arg_hir_id); + let parent_node = tcx.hir_node(parent_node_id); + + let (generics, arg_idx) = match parent_node { + // Easy case: arrays repeat expressions. + Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) + | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + if constant.hir_id() == arg_hir_id => { - return tcx.typeck(def_id).node_type(hir_id); - } - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { - return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx); + return tcx.types.usize; } Node::GenericParam(&GenericParam { def_id: param_def_id, kind: GenericParamKind::Const { default: Some(ct), .. }, .. - }) if ct.hir_id == hir_id => { + }) if ct.hir_id == arg_hir_id => { return tcx .type_of(param_def_id) .no_bound_vars() @@ -104,7 +131,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // to a ty::Alias(ty::Projection, `<Self as Foo>::Assoc<3>`). let item_def_id = tcx .hir() - .parent_owner_iter(hir_id) + .parent_owner_iter(arg_hir_id) .find(|(_, node)| matches!(node, OwnerNode::Item(_))) .unwrap() .0 @@ -124,7 +151,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) + .position(|arg| arg.hir_id() == arg_hir_id) }) .unwrap_or_else(|| { bug!("no arg matching AnonConst in segment"); @@ -145,7 +172,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)), .. }) => { - let body_owner = tcx.hir().enclosing_body_owner(hir_id); + let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id); let tables = tcx.typeck(body_owner); // This may fail in case the method/path does not actually exist. // As there is no relevant param for `def_id`, we simply return @@ -163,10 +190,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) + .position(|arg| arg.hir_id() == arg_hir_id) }) .unwrap_or_else(|| { - bug!("no arg matching AnonConst in segment"); + bug!("no arg matching ConstArg in segment"); }); (tcx.generics_of(type_dependent_def), idx) @@ -185,18 +212,18 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { | ExprKind::Struct(&QPath::Resolved(_, path), ..), .. }) => { - let body_owner = tcx.hir().enclosing_body_owner(hir_id); + let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id); let _tables = tcx.typeck(body_owner); &*path } Node::Pat(pat) => { - if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { + if let Some(path) = get_path_containing_arg_in_pat(pat, arg_hir_id) { path } else { return Ty::new_error_with_message( tcx, span, - format!("unable to find const parent for {hir_id} in pat {pat:?}"), + format!("unable to find const parent for {arg_hir_id} in pat {pat:?}"), ); } } @@ -217,14 +244,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) + .position(|arg| arg.hir_id() == arg_hir_id) .map(|index| (index, seg)) .or_else(|| { args.constraints .iter() .copied() .filter_map(AssocItemConstraint::ct) - .position(|ct| ct.hir_id == hir_id) + .position(|ct| ct.hir_id == arg_hir_id) .map(|idx| (idx, seg)) }) }) else { @@ -249,7 +276,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { return Ty::new_error_with_message( tcx, span, - format!("unexpected const parent in type_of(): {parent_node:?}"), + format!("unexpected const arg parent in type_of(): {parent_node:?}"), ); } }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index a1feef9e15b..6f9c481650b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -413,12 +413,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); // Provide the resolved type of the associated constant to `type_of(AnonConst)`. - if let Some(anon_const) = constraint.ct() { - let ty = alias_term - .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); - let ty = - check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id); - tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); + if let Some(const_arg) = constraint.ct() { + if let hir::ConstArgKind::Anon(anon_const) = const_arg.kind { + let ty = alias_term + .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); + let ty = check_assoc_const_binding_type( + self, + constraint.ident, + ty, + constraint.hir_id, + ); + tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); + } } alias_term @@ -435,7 +441,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), - hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(), + hir::Term::Const(ct) => { + ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into() + } }; // Find any late-bound regions declared in `ty` that are not diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 968f38cf05d..8ff6ced8b39 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -340,7 +340,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { let span = match term { hir::Term::Ty(ty) => ty.span, - hir::Term::Const(ct) => tcx.def_span(ct.def_id), + hir::Term::Const(ct) => ct.span(), }; (span, Some(ident.span), assoc_item.kind, assoc_kind) } else { @@ -1294,8 +1294,7 @@ pub fn prohibit_assoc_item_constraint( hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) }, GenericParamDefKind::Const { .. }, ) => { - let span = tcx.hir().span(c.hir_id); - suggest_direct_use(&mut err, span); + suggest_direct_use(&mut err, c.span()); } (hir::AssocItemConstraintKind::Bound { bounds }, _) => { // Suggest `impl<T: Bound> Trait<T> for Foo` when finding diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index b1c77db9f37..abe2cff321f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -113,8 +113,12 @@ fn generic_arg_mismatch_err( } } (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => { - let body = tcx.hir().body(cnst.value.body); - if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind + // FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too, + // this should match against that instead of ::Anon + if let hir::ConstArgKind::Anon(anon) = cnst.kind + && let body = tcx.hir().body(anon.body) + && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = + body.value.kind { if let Res::Def(DefKind::Fn { .. }, id) = path.res { err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a665306f2c6..7b8a03def86 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -471,11 +471,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - let did = ct.value.def_id; - tcx.feed_anon_const_type(did, tcx.type_of(param.def_id)); - ty::Const::from_anon_const(tcx, did).into() + ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id)) + .into() } - (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => { + (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.lowerer.ct_infer(Some(param), inf.span).into() } (kind, arg) => span_bug!( @@ -912,7 +911,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - ty::Const::from_anon_const(tcx, ct.def_id).into() + ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No) + .into() } }; // FIXME(#97583): This isn't syntactically well-formed! @@ -2140,7 +2140,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let length = match length { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { - ty::Const::from_anon_const(tcx, constant.def_id) + ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No) } }; |
