From 4b4f8cdf18d7d2d0de5024425a0bd6c684c8c992 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 10 Apr 2025 21:34:30 -0400 Subject: [PATCH 01/19] Centralize const item lowering logic --- compiler/rustc_ast_lowering/src/item.rs | 42 +++++++++++++++---------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e98d6c50ee791..68e97d1b30b7c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -170,15 +170,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::Static(box ast::StaticItem { ident, - ty: t, + ty, safety: _, mutability: m, expr: e, define_opaque, }) => { let ident = self.lower_ident(*ident); - let (ty, body_id) = - self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); + let ty = + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let body_id = self.lower_const_body(span, e.as_deref()); self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(ident, ty, *m, body_id) } @@ -196,7 +197,9 @@ impl<'hir> LoweringContext<'_, 'hir> { id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + (ty, this.lower_const_item(span, expr.as_deref())) }, ); self.lower_define_opaque(hir_id, &define_opaque); @@ -480,15 +483,23 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_const_item( - &mut self, - ty: &Ty, - span: Span, - body: Option<&Expr>, - impl_trait_position: ImplTraitPosition, - ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position)); - (ty, self.lower_const_body(span, body)) + fn lower_const_item(&mut self, span: Span, body: Option<&Expr>) -> hir::BodyId { + self.lower_const_body(span, body) + // TODO: code to add next + // let ct_arg = if self.tcx.features().min_generic_const_args() + // && let Some(expr) = body + // { + // self.try_lower_as_const_path(expr) + // } else { + // None + // }; + // let body_id = if body.is_some() && ct_arg.is_none() { + // // TODO: lower as const block instead + // self.lower_const_body(span, body) + // } else { + // self.lower_const_body(span, body) + // }; + // (body_id, ct_arg) } #[instrument(level = "debug", skip(self))] @@ -797,8 +808,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x))); - + let body = expr.as_deref().map(|e| this.lower_const_item(i.span, Some(e))); hir::TraitItemKind::Const(ty, body) }, ); @@ -990,8 +1000,8 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = this.lower_const_body(i.span, expr.as_deref()); this.lower_define_opaque(hir_id, &define_opaque); + let body = this.lower_const_item(i.span, expr.as_deref()); hir::ImplItemKind::Const(ty, body) }, ), From 54b9a85c73b5559048707375534d671c784a3a4f Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 17 Apr 2025 22:21:24 -0400 Subject: [PATCH 02/19] Add dummy NodeId to AST const item for mgca lowering --- compiler/rustc_ast/src/ast.rs | 5 ++++ compiler/rustc_ast/src/mut_visit.rs | 3 +- compiler/rustc_ast/src/visit.rs | 2 ++ compiler/rustc_ast_lowering/src/item.rs | 29 +++++++++++-------- .../rustc_ast_pretty/src/pprust/state/item.rs | 2 ++ compiler/rustc_builtin_macros/src/test.rs | 1 + compiler/rustc_expand/src/build.rs | 1 + compiler/rustc_parse/src/parser/item.rs | 2 ++ compiler/rustc_resolve/src/def_collector.rs | 16 +++++++++- .../clippy/clippy_utils/src/ast_utils/mod.rs | 4 +++ 10 files changed, 51 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a16219361c051..54f6b57391f79 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3617,6 +3617,11 @@ pub struct ConstItem { pub ident: Ident, pub generics: Generics, pub ty: P, + /// A [`NodeId`] that can be used for the body of the const, independently of the ID + /// of the body's root expression. + // HACK(mgca): this is potentially temporary, tbd, in order to create defs for const bodies. + // FIXME(mgca): maybe merge this with expr since their Options should be in sync + pub body_id: Option, pub expr: Option>, pub define_opaque: Option>, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a90349f318c09..609437e6881a9 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1307,11 +1307,12 @@ impl WalkItemKind for AssocItemKind { } fn walk_const_item(vis: &mut T, item: &mut ConstItem) { - let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; + let ConstItem { defaultness, ident, generics, ty, body_id, expr, define_opaque } = item; visit_defaultness(vis, defaultness); vis.visit_ident(ident); vis.visit_generics(generics); vis.visit_ty(ty); + visit_opt(body_id, |body_id| vis.visit_id(body_id)); visit_opt(expr, |expr| vis.visit_expr(expr)); walk_define_opaques(vis, define_opaque); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e43d7ae065d9e..43046aee93deb 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -448,6 +448,7 @@ impl WalkItemKind for ItemKind { ident, generics, ty, + body_id: _, expr, define_opaque, }) => { @@ -1044,6 +1045,7 @@ impl WalkItemKind for AssocItemKind { ident, generics, ty, + body_id: _, expr, define_opaque, }) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 68e97d1b30b7c..751de58c05282 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -187,6 +187,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, + body_id, expr, define_opaque, .. @@ -199,7 +200,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - (ty, this.lower_const_item(span, expr.as_deref())) + (ty, this.lower_const_item(span, body_id.zip(expr.as_deref()))) }, ); self.lower_define_opaque(hir_id, &define_opaque); @@ -483,21 +484,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_const_item(&mut self, span: Span, body: Option<&Expr>) -> hir::BodyId { - self.lower_const_body(span, body) + fn lower_const_item(&mut self, span: Span, body: Option<(NodeId, &Expr)>) -> hir::BodyId { + self.lower_const_body(span, body.map(|b| b.1)) // TODO: code to add next - // let ct_arg = if self.tcx.features().min_generic_const_args() - // && let Some(expr) = body - // { + // let mgca = self.tcx.features().min_generic_const_args(); + // let ct_arg = if mgca && let Some((_, expr)) = body { // self.try_lower_as_const_path(expr) // } else { // None // }; - // let body_id = if body.is_some() && ct_arg.is_none() { - // // TODO: lower as const block instead - // self.lower_const_body(span, body) + // let body_id = if mgca && ct_arg.is_none() { + // self.lower_const_body_with_const_block(span, body) // } else { - // self.lower_const_body(span, body) + // self.lower_const_body(span, body.map(|(_, e)| e)) // }; // (body_id, ct_arg) } @@ -797,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, + body_id, expr, define_opaque, .. @@ -808,7 +808,9 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = expr.as_deref().map(|e| this.lower_const_item(i.span, Some(e))); + let body = expr + .as_deref() + .map(|e| this.lower_const_item(i.span, Some((body_id.unwrap(), e)))); hir::TraitItemKind::Const(ty, body) }, ); @@ -988,6 +990,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, + body_id, expr, define_opaque, .. @@ -1001,7 +1004,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); this.lower_define_opaque(hir_id, &define_opaque); - let body = this.lower_const_item(i.span, expr.as_deref()); + let body = this.lower_const_item(i.span, body_id.zip(expr.as_deref())); hir::ImplItemKind::Const(ty, body) }, ), @@ -1278,6 +1281,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) } + // TODO: add lower_const_body_with_const_block + pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { self.lower_body(|this| { ( diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 70cf2f2a45982..eadf0e2c6b1f8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -214,6 +214,7 @@ impl<'a> State<'a> { ident, generics, ty, + body_id: _, expr, define_opaque, }) => { @@ -563,6 +564,7 @@ impl<'a> State<'a> { ident, generics, ty, + body_id: _, expr, define_opaque, }) => { diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1cef4f9514cd7..27b7dad21cad0 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -293,6 +293,7 @@ pub(crate) fn expand_test_or_bench( generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), define_opaque: None, + body_id: Some(ast::DUMMY_NODE_ID), // test::TestDescAndFn { expr: Some( cx.expr_struct( diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 14b8cc90d97d6..8c630f1f4c7c2 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -724,6 +724,7 @@ impl<'a> ExtCtxt<'a> { // FIXME(generic_const_items): Pass the generics as a parameter. generics: ast::Generics::default(), ty, + body_id: Some(ast::DUMMY_NODE_ID), expr: Some(expr), define_opaque: None, } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index babc55ccc0f9e..54c8a8843a8d2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -258,6 +258,7 @@ impl<'a> Parser<'a> { ident, generics, ty, + body_id: expr.is_some().then_some(DUMMY_NODE_ID), expr, define_opaque: None, })) @@ -973,6 +974,7 @@ impl<'a> Parser<'a> { ident, generics: Generics::default(), ty, + body_id: expr.is_some().then_some(DUMMY_NODE_ID), expr, define_opaque, })) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 13dfb59f27fc0..113cf3e8b56eb 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -174,6 +174,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ); } } + // HACK(mgca): see lower_const_body_with_const_block in ast_lowering + ItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) + if this.resolver.tcx.features().min_generic_const_args() => + { + this.create_def(body_id, None, DefKind::InlineConst, i.span); + } _ => {} } visit::walk_item(this, i); @@ -334,7 +340,15 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { }; let def = self.create_def(i.id, Some(ident.name), def_kind, i.span); - self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); + self.with_parent(def, |this| { + // HACK(mgca): see lower_const_body_with_const_block in ast_lowering + if let AssocItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) = i.kind + && this.resolver.tcx.features().min_generic_const_args() + { + this.create_def(body_id, None, DefKind::InlineConst, i.span); + } + visit::walk_assoc_item(this, i, ctxt) + }); } fn visit_pat(&mut self, pat: &'a Pat) { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 8996b694ed8f7..8dad0411f8b0c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -355,6 +355,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: li, generics: lg, ty: lt, + body_id: _, expr: le, define_opaque: _, }), @@ -363,6 +364,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: ri, generics: rg, ty: rt, + body_id: _, expr: re, define_opaque: _, }), @@ -595,6 +597,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ident: li, generics: lg, ty: lt, + body_id: _, expr: le, define_opaque: _, }), @@ -603,6 +606,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ident: ri, generics: rg, ty: rt, + body_id: _, expr: re, define_opaque: _, }), From 04047539d762f0f140a55c197b50f03257c1eb43 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 28 Apr 2025 18:04:02 -0400 Subject: [PATCH 03/19] wip on using ConstArg for const item bodies --- compiler/rustc_ast_lowering/src/item.rs | 58 +++++++++++-------- compiler/rustc_ast_lowering/src/lib.rs | 16 +++++ compiler/rustc_hir/src/hir.rs | 54 ++++++++++++----- compiler/rustc_hir/src/intravisit.rs | 6 +- .../rustc_hir_analysis/src/collect/type_of.rs | 24 ++++---- compiler/rustc_hir_pretty/src/lib.rs | 8 +-- compiler/rustc_lint/src/context.rs | 12 +++- compiler/rustc_passes/src/reachable.rs | 10 ++-- compiler/rustc_resolve/src/def_collector.rs | 12 ++-- src/librustdoc/clean/mod.rs | 20 +++++-- .../src/undocumented_unsafe_blocks.rs | 15 ++++- 11 files changed, 152 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 751de58c05282..485371726814d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -193,18 +193,20 @@ impl<'hir> LoweringContext<'_, 'hir> { .. }) => { let ident = self.lower_ident(*ident); - let (generics, (ty, body_id)) = self.lower_generics( + let (generics, (ty, body)) = self.lower_generics( generics, id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - (ty, this.lower_const_item(span, body_id.zip(expr.as_deref()))) + let body = + this.lower_const_item(span, body_id.unwrap(), expr.as_deref().unwrap()); + (ty, body) }, ); self.lower_define_opaque(hir_id, &define_opaque); - hir::ItemKind::Const(ident, ty, generics, body_id) + hir::ItemKind::Const(ident, ty, generics, body) } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, @@ -484,21 +486,27 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_const_item(&mut self, span: Span, body: Option<(NodeId, &Expr)>) -> hir::BodyId { - self.lower_const_body(span, body.map(|b| b.1)) - // TODO: code to add next - // let mgca = self.tcx.features().min_generic_const_args(); - // let ct_arg = if mgca && let Some((_, expr)) = body { - // self.try_lower_as_const_path(expr) - // } else { - // None - // }; - // let body_id = if mgca && ct_arg.is_none() { - // self.lower_const_body_with_const_block(span, body) - // } else { - // self.lower_const_body(span, body.map(|(_, e)| e)) - // }; - // (body_id, ct_arg) + fn lower_const_item( + &mut self, + span: Span, + body_id: NodeId, + body_expr: &Expr, + ) -> &'hir hir::ConstArg<'hir> { + let mgca = self.tcx.features().min_generic_const_args(); + if mgca && let Some(ct_arg) = self.try_lower_as_const_path(body_expr) { + return ct_arg; + } + let anon = self.arena.alloc(self.with_new_scopes(span, |this| { + let body = this.lower_const_body(span, Some(body_expr)); + hir::AnonConst { + hir_id: this.lower_node_id(body_id), + def_id: this.local_def_id(body_id), + body, + span, + } + })); + self.arena + .alloc(hir::ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(anon) }) } #[instrument(level = "debug", skip(self))] @@ -808,9 +816,9 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = expr - .as_deref() - .map(|e| this.lower_const_item(i.span, Some((body_id.unwrap(), e)))); + let body = body_id + .zip(expr.as_deref()) + .map(|(b_id, b_ex)| this.lower_const_item(i.span, b_id, b_ex)); hir::TraitItemKind::Const(ty, body) }, ); @@ -1004,7 +1012,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); this.lower_define_opaque(hir_id, &define_opaque); - let body = this.lower_const_item(i.span, body_id.zip(expr.as_deref())); + let body = this.lower_const_item( + i.span, + body_id.unwrap(), + expr.as_deref().unwrap(), + ); hir::ImplItemKind::Const(ty, body) }, ), @@ -1281,8 +1293,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) } - // TODO: add lower_const_body_with_const_block - pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { self.lower_body(|this| { ( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 422e79ca82ffd..72feb11cc79a1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2084,6 +2084,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + /// Assumes mgca feature is enabled. + fn try_lower_as_const_path(&mut self, expr: &Expr) -> Option<&'hir hir::ConstArg<'hir>> { + let ExprKind::Path(qself, path) = &expr.kind else { return None }; + let qpath = self.lower_qpath( + expr.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + let ct_kind = hir::ConstArgKind::Path(qpath); + Some(self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })) + } + /// Used when lowering a type argument that turned out to actually be a const argument. /// /// Only use for that purpose since otherwise it will create a duplicate def. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f63ab30368914..1a7c0e68c66a0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3096,7 +3096,7 @@ impl<'hir> TraitItem<'hir> { } expect_methods_self_kind! { - expect_const, (&'hir Ty<'hir>, Option), + expect_const, (&'hir Ty<'hir>, Option<&'hir ConstArg<'hir>>), TraitItemKind::Const(ty, body), (ty, *body); expect_fn, (&FnSig<'hir>, &TraitFn<'hir>), @@ -3121,7 +3121,7 @@ pub enum TraitFn<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TraitItemKind<'hir> { /// An associated constant with an optional value (otherwise `impl`s must contain a value). - Const(&'hir Ty<'hir>, Option), + Const(&'hir Ty<'hir>, Option<&'hir ConstArg<'hir>>), /// An associated function with an optional body. Fn(FnSig<'hir>, TraitFn<'hir>), /// An associated type with (possibly empty) bounds and optional concrete @@ -3171,9 +3171,9 @@ impl<'hir> ImplItem<'hir> { } expect_methods_self_kind! { - expect_const, (&'hir Ty<'hir>, BodyId), ImplItemKind::Const(ty, body), (ty, *body); - expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body); - expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty; + expect_const, (&'hir Ty<'hir>, &'hir ConstArg<'hir>), ImplItemKind::Const(ty, body), (ty, body); + expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body); + expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty; } } @@ -3182,7 +3182,7 @@ impl<'hir> ImplItem<'hir> { pub enum ImplItemKind<'hir> { /// An associated constant of the given type, set to the constant result /// of the expression. - Const(&'hir Ty<'hir>, BodyId), + Const(&'hir Ty<'hir>, &'hir ConstArg<'hir>), /// An associated function implementation with the given signature and body. Fn(FnSig<'hir>, BodyId), /// An associated type. @@ -4109,8 +4109,8 @@ impl<'hir> Item<'hir> { expect_static, (Ident, &'hir Ty<'hir>, Mutability, BodyId), ItemKind::Static(ident, ty, mutbl, body), (*ident, ty, *mutbl, *body); - expect_const, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), - ItemKind::Const(ident, ty, generics, body), (*ident, ty, generics, *body); + expect_const, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, &'hir ConstArg<'hir>), + ItemKind::Const(ident, ty, generics, ct_arg), (*ident, ty, generics, ct_arg); expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body); @@ -4280,7 +4280,7 @@ pub enum ItemKind<'hir> { /// A `static` item. Static(Ident, &'hir Ty<'hir>, Mutability, BodyId), /// A `const` item. - Const(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), + Const(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, &'hir ConstArg<'hir>), /// A function declaration. Fn { ident: Ident, @@ -4578,17 +4578,29 @@ impl<'hir> OwnerNode<'hir> { OwnerNode::Item(Item { kind: ItemKind::Static(_, _, _, body) - | ItemKind::Const(_, _, _, body) + | ItemKind::Const( + .., + ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }, + ) | ItemKind::Fn { body, .. }, .. }) | OwnerNode::TraitItem(TraitItem { kind: - TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)), + TraitItemKind::Fn(_, TraitFn::Provided(body)) + | TraitItemKind::Const( + _, + Some(ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }), + ), .. }) | OwnerNode::ImplItem(ImplItem { - kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body), + kind: + ImplItemKind::Fn(_, body) + | ImplItemKind::Const( + _, + ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }, + ), .. }) => Some(*body), _ => None, @@ -4835,7 +4847,10 @@ impl<'hir> Node<'hir> { Node::Item(Item { owner_id, kind: - ItemKind::Const(_, _, _, body) + ItemKind::Const( + .., + ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }, + ) | ItemKind::Static(.., body) | ItemKind::Fn { body, .. }, .. @@ -4843,12 +4858,21 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { owner_id, kind: - TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), + TraitItemKind::Const( + _, + Some(ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }), + ) + | TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) | Node::ImplItem(ImplItem { owner_id, - kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), + kind: + ImplItemKind::Const( + _, + ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }, + ) + | ImplItemKind::Fn(_, body), .. }) => Some((owner_id.def_id, *body)), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index a60de4b1fc31b..36e0b6e7d9f8a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -554,7 +554,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_nested_body(body)); + try_visit!(visitor.visit_const_arg_unambig(body)); } ItemKind::Fn { ident, sig, generics, body: body_id, .. } => { try_visit!(visitor.visit_ident(ident)); @@ -1168,7 +1168,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( match *kind { TraitItemKind::Const(ref ty, default) => { try_visit!(visitor.visit_ty_unambig(ty)); - visit_opt!(visitor, visit_nested_body, default); + visit_opt!(visitor, visit_const_arg_unambig, default); } TraitItemKind::Fn(ref sig, TraitFn::Required(param_idents)) => { try_visit!(visitor.visit_fn_decl(sig.decl)); @@ -1226,7 +1226,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( match *kind { ImplItemKind::Const(ref ty, body) => { try_visit!(visitor.visit_ty_unambig(ty)); - visitor.visit_nested_body(body) + visitor.visit_const_arg_unambig(body) } ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn( FnKind::Method(impl_item.ident, sig), diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c20b14df7704b..1b92ac97c5516 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -157,13 +157,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - TraitItemKind::Const(ty, body_id) => body_id - .and_then(|body_id| { + TraitItemKind::Const(ty, body) => body + .and_then(|ct_arg| { ty.is_suggestable_infer_ty().then(|| { infer_placeholder_type( icx.lowerer(), def_id, - body_id, + ct_arg.hir_id, ty.span, item.ident, "associated constant", @@ -182,12 +182,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ImplItemKind::Const(ty, body_id) => { + ImplItemKind::Const(ty, ct_arg) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), def_id, - body_id, + ct_arg.hir_id, ty.span, item.ident, "associated constant", @@ -211,7 +211,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ infer_placeholder_type( icx.lowerer(), def_id, - body_id, + body_id.hir_id, ty.span, ident, "static variable", @@ -220,12 +220,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ icx.lower_ty(ty) } } - ItemKind::Const(ident, ty, _, body_id) => { + ItemKind::Const(ident, ty, _, body) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), def_id, - body_id, + body.hir_id, ty.span, ident, "constant", @@ -406,13 +406,13 @@ pub(super) fn type_of_opaque_hir_typeck( fn infer_placeholder_type<'tcx>( cx: &dyn HirTyLowerer<'tcx>, def_id: LocalDefId, - body_id: hir::BodyId, + hir_id: HirId, span: Span, item_ident: Ident, kind: &'static str, ) -> Ty<'tcx> { let tcx = cx.tcx(); - let ty = tcx.typeck(def_id).node_type(body_id.hir_id); + let ty = tcx.typeck(def_id).node_type(hir_id); // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. @@ -440,7 +440,7 @@ fn infer_placeholder_type<'tcx>( ); } else { with_forced_trimmed_paths!(err.span_note( - tcx.hir_body(body_id).value.span, + tcx.hir_span(hir_id), format!("however, the inferred type `{ty}` cannot be named"), )); } @@ -483,7 +483,7 @@ fn infer_placeholder_type<'tcx>( ); } else { with_forced_trimmed_paths!(diag.span_note( - tcx.hir_body(body_id).value.span, + tcx.hir_span(hir_id), format!("however, the inferred type `{ty}` cannot be named"), )); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 04f9c831b0ac0..895186d6d2f01 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -516,17 +516,17 @@ impl<'a> State<'a> { ident: Ident, generics: &hir::Generics<'_>, ty: &hir::Ty<'_>, - default: Option, + default: Option<&'_ hir::ConstArg<'_>>, ) { self.word_space("const"); self.print_ident(ident); self.print_generic_params(generics.params); self.word_space(":"); self.print_type(ty); - if let Some(expr) = default { + if let Some(ct_arg) = default { self.space(); self.word_space("="); - self.ann.nested(self, Nested::Body(expr)); + self.print_const_arg(ct_arg); } self.print_where_clause(generics); self.word(";") @@ -619,7 +619,7 @@ impl<'a> State<'a> { self.end(ib); self.word_space("="); - self.ann.nested(self, Nested::Body(expr)); + self.print_const_arg(expr); self.print_where_clause(generics); self.word(";"); self.end(cb); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5679d4566dcd4..42416086daabb 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -932,9 +932,15 @@ impl<'tcx> LateContext<'tcx> { .. }) => *init, hir::Node::Item(item) => match item.kind { - hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { - Some(self.tcx.hir_body(body_id).value) - } + // TODO(mgca): figure out how to handle ConstArgKind::Path (or don't but add warning in docs here) + hir::ItemKind::Const( + .., + &hir::ConstArg { + kind: hir::ConstArgKind::Anon(&hir::AnonConst { body: body_id, .. }), + .. + }, + ) + | hir::ItemKind::Static(.., body_id) => Some(self.tcx.hir_body(body_id).value), _ => None, }, _ => None, diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 7e15267a953ba..fe83dc81238d8 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -28,7 +28,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; @@ -217,7 +217,7 @@ impl<'tcx> ReachableContext<'tcx> { // We can't figure out which value the constant will evaluate to. In // lieu of that, we have to consider everything mentioned in the const // initializer reachable, since it *may* end up in the final value. - Err(ErrorHandled::TooGeneric(_)) => self.visit_nested_body(init), + Err(ErrorHandled::TooGeneric(_)) => self.visit_const_arg_unambig(init), // If there was an error evaluating the const, nothing can be reachable // via it, and anyway compilation will fail. Err(ErrorHandled::Reported(..)) => {} @@ -253,8 +253,8 @@ impl<'tcx> ReachableContext<'tcx> { | hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => { // Keep going, nothing to get exported } - hir::TraitItemKind::Const(_, Some(body_id)) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => { + hir::TraitItemKind::Const(_, Some(body)) => self.visit_const_arg_unambig(body), + hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => { self.visit_nested_body(body_id); } hir::TraitItemKind::Type(..) => {} @@ -262,7 +262,7 @@ impl<'tcx> ReachableContext<'tcx> { } Node::ImplItem(impl_item) => match impl_item.kind { hir::ImplItemKind::Const(_, body) => { - self.visit_nested_body(body); + self.visit_const_arg_unambig(body); } hir::ImplItemKind::Fn(_, body) => { if recursively_reachable(self.tcx, impl_item.hir_id().owner.to_def_id()) { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 113cf3e8b56eb..c42ecdae6c8a4 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -174,10 +174,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ); } } - // HACK(mgca): see lower_const_body_with_const_block in ast_lowering - ItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) - if this.resolver.tcx.features().min_generic_const_args() => - { + // HACK(mgca): see lower_const_item in ast_lowering + ItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) => { this.create_def(body_id, None, DefKind::InlineConst, i.span); } _ => {} @@ -341,10 +339,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let def = self.create_def(i.id, Some(ident.name), def_kind, i.span); self.with_parent(def, |this| { - // HACK(mgca): see lower_const_body_with_const_block in ast_lowering - if let AssocItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) = i.kind - && this.resolver.tcx.features().min_generic_const_args() - { + // HACK(mgca): see lower_const_item in ast_lowering + if let AssocItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) = i.kind { this.create_def(body_id, None, DefKind::InlineConst, i.span); } visit::walk_assoc_item(this, i, ctxt) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 28dfa01534ead..efc12e02cee5a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -306,13 +306,21 @@ pub(crate) fn clean_precise_capturing_arg( pub(crate) fn clean_const<'tcx>( constant: &hir::ConstArg<'tcx>, + // Used for mgca representation of const item bodies. + parent_if_item_body: Option, _cx: &mut DocContext<'tcx>, ) -> ConstantKind { match &constant.kind { hir::ConstArgKind::Path(qpath) => { ConstantKind::Path { path: qpath_to_string(qpath).into() } } - hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, + hir::ConstArgKind::Anon(anon) => { + if let Some(def_id) = parent_if_item_body { + ConstantKind::Local { def_id, body: anon.body } + } else { + ConstantKind::Anonymous { body: anon.body } + } + } hir::ConstArgKind::Infer(..) => ConstantKind::Infer, } } @@ -1231,7 +1239,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext hir::TraitItemKind::Const(ty, Some(default)) => { ProvidedAssocConstItem(Box::new(Constant { generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)), - kind: ConstantKind::Local { def_id: local_did, body: default }, + kind: clean_const(default, Some(local_did), cx), type_: clean_ty(ty, cx), })) } @@ -1281,7 +1289,7 @@ pub(crate) fn clean_impl_item<'tcx>( let inner = match impl_.kind { hir::ImplItemKind::Const(ty, expr) => ImplAssocConstItem(Box::new(Constant { generics: clean_generics(impl_.generics, cx), - kind: ConstantKind::Local { def_id: local_did, body: expr }, + kind: clean_const(expr, Some(local_did), cx), type_: clean_ty(ty, cx), })), hir::ImplItemKind::Fn(ref sig, body) => { @@ -2539,7 +2547,7 @@ fn clean_generic_args<'tcx>( hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)), hir::GenericArg::Const(ct) => { - GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx))) + GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), None, cx))) } hir::GenericArg::Infer(_inf) => GenericArg::Infer, }) @@ -2808,10 +2816,10 @@ fn clean_maybe_renamed_item<'tcx>( mutability, expr: Some(body_id), }), - ItemKind::Const(_, ty, generics, body_id) => ConstantItem(Box::new(Constant { + ItemKind::Const(_, ty, generics, body) => ConstantItem(Box::new(Constant { generics: clean_generics(generics, cx), type_: clean_ty(ty, cx), - kind: ConstantKind::Local { body: body_id, def_id }, + kind: clean_const(body, Some(def_id), cx), })), ItemKind::TyAlias(_, hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index a2938c86c76a9..b46a7f02ddf94 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -7,8 +7,7 @@ use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; use clippy_utils::visitors::{Descend, for_each_expr}; use hir::HirId; -use rustc_hir as hir; -use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; +use rustc_hir::{self as hir, AnonConst, Block, BlockCheckMode, ConstArg, ConstArgKind, ItemKind, Node, UnsafeSource}; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -243,7 +242,17 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { }, (ItemKind::Impl(_), _) => {}, // const and static items only need a safety comment if their body is an unsafe block, lint otherwise - (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => { + ( + &ItemKind::Const( + .., + &ConstArg { + kind: ConstArgKind::Anon(&AnonConst { body, .. }), + .. + }, + ) + | &ItemKind::Static(.., body), + HasSafetyComment::Yes(pos), + ) => { if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { let body = cx.tcx.hir_body(body); if !matches!( From bb32b29daad5fb774f4222cb761acb6bce528a7f Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 15 May 2025 15:51:45 +0200 Subject: [PATCH 04/19] wip on fixing const normalization ICEs --- compiler/rustc_hir_analysis/src/collect.rs | 23 +++++ compiler/rustc_middle/src/mir/consts.rs | 14 ++- compiler/rustc_middle/src/query/mod.rs | 7 ++ compiler/rustc_middle/src/ty/context.rs | 3 + .../src/solve/normalizes_to/free_alias.rs | 8 +- .../src/solve/normalizes_to/inherent.rs | 3 +- .../src/solve/normalizes_to/mod.rs | 14 +-- .../src/traits/normalize.rs | 85 ++++++++----------- .../src/traits/project.rs | 23 +---- compiler/rustc_type_ir/src/interner.rs | 1 + 10 files changed, 90 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f5206d9a01529..23c71de371808 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -89,6 +89,7 @@ pub(crate) fn provide(providers: &mut Providers) { rendered_precise_capturing_args, const_param_default, anon_const_kind, + const_of_item, ..*providers }; } @@ -1851,3 +1852,25 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin _ => ty::AnonConstKind::NonTypeSystem, } } + +fn const_of_item<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + let ct_arg = match tcx.hir_node_by_def_id(def_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(.., ct), .. }) => ct, + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(.., ct), .. + }) => ct.expect("no default value for trait assoc const"), + hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(.., ct), .. }) => ct, + _ => { + span_bug!(tcx.def_span(def_id), "`const_of_item` expected a const or assoc const item") + } + }; + let icx = ItemCtxt::new(tcx, def_id); + let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); + let ct = icx + .lowerer() + .lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args)); + ty::EarlyBinder::bind(ct) +} diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 2b2ffa7162880..32ed3a04aa94a 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -362,7 +362,19 @@ impl<'tcx> Const<'tcx> { } Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` - tcx.const_eval_resolve(typing_env, uneval, span) + let uneval_ty_ct = ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(uneval.def, uneval.args)); + let mir_ct = tcx.normalize_erasing_regions(typing_env, uneval_ty_ct); + // FIXME: duplicated with above match arm + match mir_ct.kind() { + ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)), + ConstKind::Expr(_) => { + bug!("Normalization of `ty::ConstKind::Expr` is unimplemented") + } + _ => Err(ReportedErrorInfo::non_const_eval_error( + tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body"), + ) + .into()), + } } Const::Val(val, _) => Ok(val), } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 30245bc82d427..b46e1d771f070 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -230,6 +230,13 @@ rustc_queries! { separate_provide_extern } + /// Returns the const of the RHS of a const item. + query const_of_item(def_id: DefId) -> ty::EarlyBinder<'tcx, ty::Const<'tcx>> { + desc { |tcx| "computing the value for `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } + /// Returns the *type* of the definition given by `DefId`. /// /// For type aliases (whether eager or lazy) and associated types, this returns diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8c915fea950a4..0d8f4e2feef8a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -213,6 +213,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of_opaque_hir_typeck(def_id) } + fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { + self.const_of_item(def_id) + } type AdtDef = ty::AdtDef<'tcx>; fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index 8aa6e4a3d7118..8777f84957a79 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -30,14 +30,12 @@ where ); let actual = if free_alias.kind(cx).is_type() { - cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args) + cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args).into() } else { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead return that. - panic!("normalizing free const aliases in the type system is unsupported"); + cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into() }; - self.instantiate_normalizes_to_term(goal, actual.into()); + self.instantiate_normalizes_to_term(goal, actual); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 2640238f5a904..dc69200839eab 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -51,8 +51,7 @@ where let normalized = if inherent.kind(cx).is_type() { cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() } else { - // FIXME(mgca): Properly handle IACs in the type system - panic!("normalizing inherent associated consts in the type system is unsupported"); + cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into() }; self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 2fddc0044cb9e..616a3295641d5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -367,19 +367,7 @@ where cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead return that. - if cx.features().associated_const_equality() { - panic!("associated const projection is not supported yet") - } else { - ty::EarlyBinder::bind( - Const::new_error_with_message( - cx, - "associated const projection is not supported yet", - ) - .into(), - ) - } + cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into()) } kind => panic!("expected projection, found {kind:?}"), }; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index eb6d5c8a60a25..d529aec2342e9 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -284,7 +284,6 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { } } - // FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(self), ret)] fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> { let recursion_limit = self.cx().recursion_limit(); @@ -333,10 +332,11 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { let res = if free.kind(infcx.tcx).is_type() { infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into() } else { - // FIXME(mgca): once const items are actual aliases defined as equal to type system consts - // this should instead use that rather than evaluating. - super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env) - .super_fold_with(self) + infcx + .tcx + .const_of_item(free.def_id) + .instantiate(infcx.tcx, free.args) + .fold_with(self) .into() }; self.depth -= 1; @@ -436,51 +436,38 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx return ct; } - // Doing "proper" normalization of const aliases is inherently cyclic until const items - // are real aliases instead of having bodies. We gate proper const alias handling behind - // mgca to avoid breaking stable code, though this should become the "main" codepath long - // before mgca is stabilized. - // - // FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items - // are represented. - if tcx.features().min_generic_const_args() { - let uv = match ct.kind() { - ty::ConstKind::Unevaluated(uv) => uv, - _ => return ct.super_fold_with(self), - }; - - let ct = match tcx.def_kind(uv.def) { - DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { - DefKind::Trait => self.normalize_trait_projection(uv.into()), - DefKind::Impl { of_trait: false } => { - self.normalize_inherent_projection(uv.into()) - } - kind => unreachable!( - "unexpected `DefKind` for const alias' resolution's parent def: {:?}", - kind - ), - }, - DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()), - kind => { - unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) - } - }; + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return ct.super_fold_with(self), + }; - // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be - // unnormalized after const evaluation returns. - ct.expect_const().super_fold_with(self) - } else { - let ct = ct.super_fold_with(self); - return super::with_replaced_escaping_bound_vars( - self.selcx.infcx, - &mut self.universes, - ct, - |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), - ) - .super_fold_with(self); - // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be - // unnormalized after const evaluation returns. - } + let ct = match tcx.def_kind(uv.def) { + DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { + DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(), + DefKind::Impl { of_trait: false } => self.normalize_inherent_projection(uv.into()).expect_const(), + kind => unreachable!( + "unexpected `DefKind` for const alias' resolution's parent def: {:?}", + kind + ), + }, + DefKind::Const => self.normalize_free_alias(uv.into()).expect_const(), + DefKind::AnonConst => { + let ct = ct.super_fold_with(self); + super::with_replaced_escaping_bound_vars( + self.selcx.infcx, + &mut self.universes, + ct, + |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), + ) + } + kind => { + unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + } + }; + + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. + ct.super_fold_with(self) } #[inline] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ed0f34b5aa915..ce310bffe0275 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -547,7 +547,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( let term: Term<'tcx> = if alias_term.kind(tcx).is_type() { tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() } else { - get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into() + tcx.const_of_item(alias_term.def_id).instantiate(tcx, args).into() }; let mut term = selcx.infcx.resolve_vars_if_possible(term); @@ -2030,14 +2030,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let term = if obligation.predicate.kind(tcx).is_type() { tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - ty::EarlyBinder::bind( - get_associated_const_value( - selcx, - obligation.predicate.to_term(tcx).expect_const(), - param_env, - ) - .into(), - ) + tcx.const_of_item(assoc_term.item.def_id).map_bound(|ct| ct.into()) }; let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) { @@ -2129,15 +2122,3 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { }) } } - -fn get_associated_const_value<'tcx>( - selcx: &mut SelectionContext<'_, 'tcx>, - alias_ct: ty::Const<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> ty::Const<'tcx> { - // FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type - // system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the - // constant is "close enough" to getting the actual rhs of the const item for now even if it might - // lead to some cycles - super::evaluate_const(selcx.infcx, alias_ct, param_env) -} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7e88114df460f..716644c978625 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -169,6 +169,7 @@ pub trait Interner: fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> ty::EarlyBinder; + fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; type AdtDef: AdtDef; fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef; From 17596bb5e07f5f6db1a6a82d21506e992d3c525e Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 16 May 2025 15:53:06 +0200 Subject: [PATCH 05/19] Extract helper function for normalizing free/assoc terms --- compiler/rustc_middle/src/mir/consts.rs | 5 +- .../src/traits/normalize.rs | 4 +- .../src/traits/query/normalize.rs | 144 +++++++++--------- 3 files changed, 81 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 32ed3a04aa94a..ceb81985f9a46 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -362,7 +362,10 @@ impl<'tcx> Const<'tcx> { } Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` - let uneval_ty_ct = ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(uneval.def, uneval.args)); + let uneval_ty_ct = ty::Const::new_unevaluated( + tcx, + ty::UnevaluatedConst::new(uneval.def, uneval.args), + ); let mir_ct = tcx.normalize_erasing_regions(typing_env, uneval_ty_ct); // FIXME: duplicated with above match arm match mir_ct.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d529aec2342e9..e3beb5e9b7605 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -444,7 +444,9 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx let ct = match tcx.def_kind(uv.def) { DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { DefKind::Trait => self.normalize_trait_projection(uv.into()).expect_const(), - DefKind::Impl { of_trait: false } => self.normalize_inherent_projection(uv.into()).expect_const(), + DefKind::Impl { of_trait: false } => { + self.normalize_inherent_projection(uv.into()).expect_const() + } kind => unreachable!( "unexpected `DefKind` for const alias' resolution's parent def: {:?}", kind diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index eb34cb10c68dd..6438f1951e2f5 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -253,76 +253,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } } - ty::Projection | ty::Inherent | ty::Free => { - // See note in `rustc_trait_selection::traits::project` - - let infcx = self.infcx; - let tcx = infcx.tcx; - // Just an optimization: When we don't have escaping bound vars, - // we don't need to replace them with placeholders. - let (data, maps) = if data.has_escaping_bound_vars() { - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - (data, Some((mapped_regions, mapped_types, mapped_consts))) - } else { - (data, None) - }; - let data = data.try_fold_with(self)?; - - let mut orig_values = OriginalQueryValues::default(); - let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values); - debug!("QueryNormalizer: c_data = {:#?}", c_data); - debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - let result = match kind { - ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data), - ty::Free => tcx.normalize_canonicalized_free_alias(c_data), - ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data), - kind => unreachable!("did not expect {kind:?} due to match arm above"), - }?; - // We don't expect ambiguity. - if !result.value.is_proven() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.dcx() - .delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}")); - } - return Err(NoSolution); - } - let InferOk { value: result, obligations } = infcx - .instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - result, - )?; - debug!("QueryNormalizer: result = {:#?}", result); - debug!("QueryNormalizer: obligations = {:#?}", obligations); - self.obligations.extend(obligations); - let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps { - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - result.normalized_ty, - ) - } else { - result.normalized_ty - }; - // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that - // still has unevaluated consts, so keep normalizing here if that's the case. - // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer - // of type and we need to continue folding it to reveal the TAIT behind it. - if res != ty - && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free) - { - res.try_fold_with(self)? - } else { - res - } - } + ty::Projection | ty::Inherent | ty::Free => self.try_fold_free_or_assoc(ty, kind, data)?, }; self.cache.insert(ty, res); @@ -359,3 +290,76 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } } } + +impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { + fn try_fold_free_or_assoc( + &mut self, + ty: Ty<'tcx>, + kind: ty::AliasTyKind, + data: ty::AliasTy<'tcx>, + ) -> Result, NoSolution> { + let infcx = self.infcx; + let tcx = infcx.tcx; + // Just an optimization: When we don't have escaping bound vars, + // we don't need to replace them with placeholders. + let (data, maps) = if data.has_escaping_bound_vars() { + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + (data, Some((mapped_regions, mapped_types, mapped_consts))) + } else { + (data, None) + }; + let data = data.try_fold_with(self)?; + + let mut orig_values = OriginalQueryValues::default(); + let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values); + debug!("QueryNormalizer: c_data = {:#?}", c_data); + debug!("QueryNormalizer: orig_values = {:#?}", orig_values); + let result = match kind { + ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data), + ty::Free => tcx.normalize_canonicalized_free_alias(c_data), + ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data), + kind => unreachable!("did not expect {kind:?} due to match arm above"), + }?; + // We don't expect ambiguity. + if !result.value.is_proven() { + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.dcx().delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}")); + } + return Err(NoSolution); + } + let InferOk { value: result, obligations } = infcx + .instantiate_query_response_and_region_obligations( + self.cause, + self.param_env, + &orig_values, + result, + )?; + debug!("QueryNormalizer: result = {:#?}", result); + debug!("QueryNormalizer: obligations = {:#?}", obligations); + self.obligations.extend(obligations); + let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps { + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + result.normalized_ty, + ) + } else { + result.normalized_ty + }; + // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that + // still has unevaluated consts, so keep normalizing here if that's the case. + // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer + // of type and we need to continue folding it to reveal the TAIT behind it. + if res != ty && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free) { + res.try_fold_with(self) + } else { + Ok(res) + } + } +} From b2437530e5a659519f9b985d0db150f2175d1907 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 17 May 2025 12:51:27 +0200 Subject: [PATCH 06/19] more wip on fixing ICEs --- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/traits/query.rs | 6 +- .../src/traits/project.rs | 1 - .../src/traits/query/normalize.rs | 82 ++++++++++++------- .../src/normalize_projection_ty.rs | 30 ++++--- 6 files changed, 75 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index a0f4597408939..693761eb5c918 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -46,7 +46,7 @@ macro_rules! arena_types { rustc_middle::traits::query::DropckOutlivesResult<'tcx> > >, - [] normalize_canonicalized_projection_ty: + [] normalize_canonicalized_projection: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::traits::query::NormalizationResult<'tcx> diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b46e1d771f070..4a3ad1a0ddf24 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2305,7 +2305,7 @@ rustc_queries! { /// Do not call this query directly: Invoke `normalize` instead. /// /// - query normalize_canonicalized_projection_ty( + query normalize_canonicalized_projection( goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, @@ -2333,7 +2333,7 @@ rustc_queries! { /// Do not call this query directly: Invoke `normalize` instead. /// /// - query normalize_canonicalized_inherent_projection_ty( + query normalize_canonicalized_inherent_projection( goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 3f6faa1a572d9..8bb6d4ea87f21 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -65,7 +65,7 @@ pub mod type_op { } pub type CanonicalAliasGoal<'tcx> = - CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; + CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTerm<'tcx>>>; pub type CanonicalTyGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; @@ -181,11 +181,11 @@ pub struct MethodAutoderefBadTy<'tcx> { pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, } -/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}_ty` queries. +/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}` queries. #[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct NormalizationResult<'tcx> { /// Result of the normalization. - pub normalized_ty: Ty<'tcx>, + pub normalized_term: ty::Term<'tcx>, } /// Outlives bounds are relationships between generic parameters, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ce310bffe0275..6a15559d6895a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -484,7 +484,6 @@ fn normalize_to_error<'a, 'tcx>( } /// Confirm and normalize the given inherent projection. -// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub fn normalize_inherent_projection<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 6438f1951e2f5..81777d4878300 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -1,9 +1,10 @@ //! Code for the 'normalization' query. This consists of a wrapper //! which folds deeply, invoking the underlying -//! `normalize_canonicalized_projection_ty` query when it encounters projections. +//! `normalize_canonicalized_projection` query when it encounters projections. use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::def::DefKind; use rustc_infer::traits::PredicateObligations; use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; @@ -253,7 +254,9 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } } - ty::Projection | ty::Inherent | ty::Free => self.try_fold_free_or_assoc(ty, kind, data)?, + ty::Projection | ty::Inherent | ty::Free => self + .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), data.def_id, data.args))? + .expect_type(), }; self.cache.insert(ty, res); @@ -268,12 +271,22 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { return Ok(constant); } - let constant = crate::traits::with_replaced_escaping_bound_vars( - self.infcx, - &mut self.universes, - constant, - |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env), - ); + let uv = match constant.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return constant.try_super_fold_with(self), + }; + + let constant = match self.cx().def_kind(uv.def) { + DefKind::AnonConst => crate::traits::with_replaced_escaping_bound_vars( + self.infcx, + &mut self.universes, + constant, + |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env), + ), + _ => self + .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), uv.def, uv.args))? + .expect_const(), + }; debug!(?constant, ?self.param_env); constant.try_super_fold_with(self) } @@ -294,39 +307,45 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { fn try_fold_free_or_assoc( &mut self, - ty: Ty<'tcx>, - kind: ty::AliasTyKind, - data: ty::AliasTy<'tcx>, - ) -> Result, NoSolution> { + term: ty::AliasTerm<'tcx>, + ) -> Result, NoSolution> { let infcx = self.infcx; let tcx = infcx.tcx; // Just an optimization: When we don't have escaping bound vars, // we don't need to replace them with placeholders. - let (data, maps) = if data.has_escaping_bound_vars() { - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - (data, Some((mapped_regions, mapped_types, mapped_consts))) + let (term, maps) = if term.has_escaping_bound_vars() { + let (term, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, term); + (term, Some((mapped_regions, mapped_types, mapped_consts))) } else { - (data, None) + (term, None) }; - let data = data.try_fold_with(self)?; + let term = term.try_fold_with(self)?; let mut orig_values = OriginalQueryValues::default(); - let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values); - debug!("QueryNormalizer: c_data = {:#?}", c_data); + let c_term = infcx.canonicalize_query(self.param_env.and(term), &mut orig_values); + debug!("QueryNormalizer: c_term = {:#?}", c_term); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - let result = match kind { - ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data), - ty::Free => tcx.normalize_canonicalized_free_alias(c_data), - ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data), - kind => unreachable!("did not expect {kind:?} due to match arm above"), + let result = match term.kind(tcx) { + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { + tcx.normalize_canonicalized_projection(c_term) + } + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => { + tcx.normalize_canonicalized_free_alias(c_term) + } + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { + tcx.normalize_canonicalized_inherent_projection(c_term) + } + kind @ (ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst) => { + unreachable!("did not expect {kind:?} due to match arm above") + } }?; // We don't expect ambiguity. if !result.value.is_proven() { // Rustdoc normalizes possibly not well-formed types, so only // treat this as a bug if we're not in rustdoc. if !tcx.sess.opts.actually_rustdoc { - tcx.dcx().delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}")); + tcx.dcx().delayed_bug(format!("unexpected ambiguity: {c_term:?} {result:?}")); } return Err(NoSolution); } @@ -347,16 +366,19 @@ impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { mapped_types, mapped_consts, &self.universes, - result.normalized_ty, + result.normalized_term, ) } else { - result.normalized_ty + result.normalized_term }; - // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that + // `tcx.normalize_canonicalized_projection` may normalize to a type that // still has unevaluated consts, so keep normalizing here if that's the case. // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer // of type and we need to continue folding it to reveal the TAIT behind it. - if res != ty && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free) { + if res != term.to_term(tcx) + && (res.as_type().map_or(false, |t| t.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION)) + || term.kind(tcx) == ty::AliasTermKind::FreeTy) + { res.try_fold_with(self) } else { Ok(res) diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index e52898cc6e242..16054733562ae 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -12,18 +12,18 @@ use tracing::debug; pub(crate) fn provide(p: &mut Providers) { *p = Providers { - normalize_canonicalized_projection_ty, + normalize_canonicalized_projection, normalize_canonicalized_free_alias, - normalize_canonicalized_inherent_projection_ty, + normalize_canonicalized_inherent_projection, ..*p }; } -fn normalize_canonicalized_projection_ty<'tcx>( +fn normalize_canonicalized_projection<'tcx>( tcx: TyCtxt<'tcx>, goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal); + debug!("normalize_canonicalized_projection(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, @@ -32,7 +32,7 @@ fn normalize_canonicalized_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = PredicateObligations::new(); - let answer = traits::normalize_projection_term( + let normalized_term = traits::normalize_projection_term( selcx, param_env, goal.into(), @@ -61,10 +61,10 @@ fn normalize_canonicalized_projection_ty<'tcx>( return Err(NoSolution); } - // FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty + // FIXME(associated_const_equality): All users of normalize_canonicalized_projection // expected a type, but there is the possibility it could've been a const now. // Maybe change it to a Term later? - Ok(NormalizationResult { normalized_ty: answer.expect_type() }) + Ok(NormalizationResult { normalized_term }) }, ) } @@ -89,17 +89,21 @@ fn normalize_canonicalized_free_alias<'tcx>( }, ); ocx.register_obligations(obligations); - let normalized_ty = tcx.type_of(goal.def_id).instantiate(tcx, goal.args); - Ok(NormalizationResult { normalized_ty }) + let normalized_term = if goal.kind(tcx).is_type() { + tcx.type_of(goal.def_id).instantiate(tcx, goal.args).into() + } else { + tcx.const_of_item(goal.def_id).instantiate(tcx, goal.args).into() + }; + Ok(NormalizationResult { normalized_term }) }, ) } -fn normalize_canonicalized_inherent_projection_ty<'tcx>( +fn normalize_canonicalized_inherent_projection<'tcx>( tcx: TyCtxt<'tcx>, goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal); + debug!("normalize_canonicalized_inherent_projection(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, @@ -107,7 +111,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = PredicateObligations::new(); - let answer = traits::normalize_inherent_projection( + let normalized_term = traits::normalize_inherent_projection( selcx, param_env, goal.into(), @@ -117,7 +121,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( ); ocx.register_obligations(obligations); - Ok(NormalizationResult { normalized_ty: answer.expect_type() }) + Ok(NormalizationResult { normalized_term }) }, ) } From 53aea5305a50ea8b5da51f641e90a8b71b44981a Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 17 May 2025 16:36:11 +0200 Subject: [PATCH 07/19] Recurse through const items in instance resolution --- compiler/rustc_middle/src/mir/consts.rs | 17 +------------ .../rustc_middle/src/mir/interpret/queries.rs | 24 ++++++++++++++++++ compiler/rustc_resolve/src/def_collector.rs | 4 +-- compiler/rustc_ty_utils/src/instance.rs | 25 ++++++++++++++++--- 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index ceb81985f9a46..2b2ffa7162880 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -362,22 +362,7 @@ impl<'tcx> Const<'tcx> { } Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` - let uneval_ty_ct = ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst::new(uneval.def, uneval.args), - ); - let mir_ct = tcx.normalize_erasing_regions(typing_env, uneval_ty_ct); - // FIXME: duplicated with above match arm - match mir_ct.kind() { - ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)), - ConstKind::Expr(_) => { - bug!("Normalization of `ty::ConstKind::Expr` is unimplemented") - } - _ => Err(ReportedErrorInfo::non_const_eval_error( - tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body"), - ) - .into()), - } + tcx.const_eval_resolve(typing_env, uneval, span) } Const::Val(val, _) => Ok(val), } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 4a5c42c721c12..1bc96723cb181 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -75,6 +75,30 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { + if let ty::InstanceKind::Item(def_id) = instance.def + && matches!(self.def_kind(def_id), DefKind::Const | DefKind::AssocConst) + { + let ct = self.const_of_item(def_id).instantiate(self, instance.args); + match ct.kind() { + ty::ConstKind::Unevaluated(_) => { + return Err(ErrorHandled::TooGeneric(DUMMY_SP)); + } + ty::ConstKind::Value(cv) => return Ok(self.valtree_to_const_val(cv)), + ty::ConstKind::Error(guar) => { + return Err(ErrorHandled::Reported( + ReportedErrorInfo::const_eval_error(guar), + DUMMY_SP, + )); + } + ty::ConstKind::Expr(_) => return Err(ErrorHandled::TooGeneric(DUMMY_SP)), + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => { + return Err(ErrorHandled::TooGeneric(DUMMY_SP)); + } + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => { + bug!("unexpected constant {ct:?}") + } + } + } let cid = GlobalId { instance, promoted: ct.promoted }; self.const_eval_global_id(typing_env, cid, span) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index c42ecdae6c8a4..d091fc7cbe8cc 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -176,7 +176,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } // HACK(mgca): see lower_const_item in ast_lowering ItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) => { - this.create_def(body_id, None, DefKind::InlineConst, i.span); + this.create_def(body_id, None, DefKind::AnonConst, i.span); } _ => {} } @@ -341,7 +341,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.with_parent(def, |this| { // HACK(mgca): see lower_const_item in ast_lowering if let AssocItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) = i.kind { - this.create_def(body_id, None, DefKind::InlineConst, i.span); + this.create_def(body_id, None, DefKind::AnonConst, i.span); } visit::walk_assoc_item(this, i, ctxt) }); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 166e8f1934299..0a31602e09704 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -1,5 +1,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::LangItem; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; @@ -10,11 +11,12 @@ use rustc_middle::ty::{ }; use rustc_span::sym; use rustc_trait_selection::traits; -use tracing::debug; +use tracing::{debug, instrument}; use traits::translate_args; use crate::errors::UnexpectedFnPtrAssociatedItem; +#[instrument(level = "debug", skip(tcx), ret)] fn resolve_instance_raw<'tcx>( tcx: TyCtxt<'tcx>, key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)>, @@ -90,13 +92,30 @@ fn resolve_instance_raw<'tcx>( let ty = args.type_at(0); ty::InstanceKind::AsyncDropGlue(def_id, ty) } else { - debug!(" => free item"); + debug!(" => free or inherent item"); ty::InstanceKind::Item(def_id) }; Ok(Some(Instance { def, args })) }; - debug!("resolve_instance: result={:?}", result); + if let Ok(Some(Instance { def: ty::InstanceKind::Item(def_id), args })) = result + && matches!(tcx.def_kind(def_id), DefKind::Const | DefKind::AssocConst) + { + debug!(" => resolved to const item"); + let ct = tcx.const_of_item(def_id).instantiate(tcx, args); + debug!("ct={ct:?}"); + if let ty::ConstKind::Unevaluated(uv) = ct.kind() { + if tcx.def_kind(uv.def) == DefKind::AnonConst { + return Ok(Some(ty::Instance { + def: ty::InstanceKind::Item(uv.def), + args: uv.args, + })); + } else { + let input = PseudoCanonicalInput { typing_env, value: (uv.def, uv.args) }; + return tcx.resolve_instance_raw(input); + } + } + } result } From 4546d7714975f5c12b623f592279ca28f8257308 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 17 May 2025 17:06:30 +0200 Subject: [PATCH 08/19] Fix more ICEs --- .../src/const_eval/eval_queries.rs | 23 +++++++++++++++ compiler/rustc_hir/src/hir.rs | 28 ++++--------------- compiler/rustc_hir_analysis/src/lib.rs | 6 ---- .../rustc_middle/src/mir/interpret/queries.rs | 24 ---------------- 4 files changed, 28 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index ce8eceebdf8d2..1afe1dcfcbfb0 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -294,6 +294,29 @@ pub fn eval_to_const_value_raw_provider<'tcx>( ) }, ); + } else if let ty::InstanceKind::Item(def_id) = key.value.instance.def + && matches!(tcx.def_kind(def_id), DefKind::Const | DefKind::AssocConst) + { + let ct = tcx.const_of_item(def_id).instantiate(tcx, key.value.instance.args); + match ct.kind() { + ty::ConstKind::Unevaluated(_) => { + return Err(ErrorHandled::TooGeneric(DUMMY_SP)); + } + ty::ConstKind::Value(cv) => return Ok(tcx.valtree_to_const_val(cv)), + ty::ConstKind::Error(guar) => { + return Err(ErrorHandled::Reported( + ReportedErrorInfo::const_eval_error(guar), + DUMMY_SP, + )); + } + ty::ConstKind::Expr(_) => return Err(ErrorHandled::TooGeneric(DUMMY_SP)), + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => { + return Err(ErrorHandled::TooGeneric(DUMMY_SP)); + } + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => { + bug!("unexpected constant {ct:?}") + } + } } tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1a7c0e68c66a0..c064e0de1c17f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4846,35 +4846,17 @@ impl<'hir> Node<'hir> { match self { Node::Item(Item { owner_id, - kind: - ItemKind::Const( - .., - ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }, - ) - | ItemKind::Static(.., body) - | ItemKind::Fn { body, .. }, + kind: ItemKind::Static(.., body) | ItemKind::Fn { body, .. }, .. }) | Node::TraitItem(TraitItem { owner_id, - kind: - TraitItemKind::Const( - _, - Some(ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }), - ) - | TraitItemKind::Fn(_, TraitFn::Provided(body)), + kind: TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) - | Node::ImplItem(ImplItem { - owner_id, - kind: - ImplItemKind::Const( - _, - ConstArg { kind: ConstArgKind::Anon(AnonConst { body, .. }), .. }, - ) - | ImplItemKind::Fn(_, body), - .. - }) => Some((owner_id.def_id, *body)), + | Node::ImplItem(ImplItem { owner_id, kind: ImplItemKind::Fn(_, body), .. }) => { + Some((owner_id.def_id, *body)) + } Node::Item(Item { owner_id, kind: ItemKind::GlobalAsm { asm: _, fake_body }, .. diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 010c6c376fe3d..8f948ebe0ed79 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -203,12 +203,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.ensure_ok().eval_static_initializer(item_def_id); check::maybe_check_static_with_link_section(tcx, item_def_id); } - DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { - let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty()); - let cid = GlobalId { instance, promoted: None }; - let typing_env = ty::TypingEnv::fully_monomorphized(); - tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid)); - } _ => (), } // Skip `AnonConst`s because we feed their `type_of`. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 1bc96723cb181..4a5c42c721c12 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -75,30 +75,6 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { - if let ty::InstanceKind::Item(def_id) = instance.def - && matches!(self.def_kind(def_id), DefKind::Const | DefKind::AssocConst) - { - let ct = self.const_of_item(def_id).instantiate(self, instance.args); - match ct.kind() { - ty::ConstKind::Unevaluated(_) => { - return Err(ErrorHandled::TooGeneric(DUMMY_SP)); - } - ty::ConstKind::Value(cv) => return Ok(self.valtree_to_const_val(cv)), - ty::ConstKind::Error(guar) => { - return Err(ErrorHandled::Reported( - ReportedErrorInfo::const_eval_error(guar), - DUMMY_SP, - )); - } - ty::ConstKind::Expr(_) => return Err(ErrorHandled::TooGeneric(DUMMY_SP)), - ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => { - return Err(ErrorHandled::TooGeneric(DUMMY_SP)); - } - ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => { - bug!("unexpected constant {ct:?}") - } - } - } let cid = GlobalId { instance, promoted: ct.promoted }; self.const_eval_global_id(typing_env, cid, span) } From a38bbded5f8a7c8a611630d888c0dec4aebee8bc Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 22 May 2025 15:26:16 +0100 Subject: [PATCH 09/19] Use AnonConst as RHS of const items instead of side channel hack --- compiler/rustc_ast/src/ast.rs | 7 +-- compiler/rustc_ast/src/mut_visit.rs | 5 +-- compiler/rustc_ast/src/visit.rs | 10 ++--- compiler/rustc_ast_lowering/src/item.rs | 45 +++++-------------- compiler/rustc_ast_lowering/src/lib.rs | 6 +-- .../rustc_ast_passes/src/ast_validation.rs | 6 +-- .../rustc_ast_pretty/src/pprust/state/item.rs | 10 ++--- .../src/alloc_error_handler.rs | 2 +- .../src/global_allocator.rs | 2 +- .../src/proc_macro_harness.rs | 2 +- compiler/rustc_builtin_macros/src/test.rs | 8 ++-- compiler/rustc_expand/src/build.rs | 9 ++-- compiler/rustc_hir_analysis/src/lib.rs | 3 +- compiler/rustc_lint/src/unused.rs | 29 ++++++------ compiler/rustc_parse/src/parser/item.rs | 31 ++++++------- compiler/rustc_resolve/src/def_collector.rs | 12 +---- compiler/rustc_resolve/src/late.rs | 21 +++++---- 17 files changed, 87 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 54f6b57391f79..d2c1e1e68ebc1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3617,12 +3617,7 @@ pub struct ConstItem { pub ident: Ident, pub generics: Generics, pub ty: P, - /// A [`NodeId`] that can be used for the body of the const, independently of the ID - /// of the body's root expression. - // HACK(mgca): this is potentially temporary, tbd, in order to create defs for const bodies. - // FIXME(mgca): maybe merge this with expr since their Options should be in sync - pub body_id: Option, - pub expr: Option>, + pub body: Option>, pub define_opaque: Option>, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 609437e6881a9..16964cec056be 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1307,13 +1307,12 @@ impl WalkItemKind for AssocItemKind { } fn walk_const_item(vis: &mut T, item: &mut ConstItem) { - let ConstItem { defaultness, ident, generics, ty, body_id, expr, define_opaque } = item; + let ConstItem { defaultness, ident, generics, ty, body, define_opaque } = item; visit_defaultness(vis, defaultness); vis.visit_ident(ident); vis.visit_generics(generics); vis.visit_ty(ty); - visit_opt(body_id, |body_id| vis.visit_id(body_id)); - visit_opt(expr, |expr| vis.visit_expr(expr)); + visit_opt(body, |body| vis.visit_anon_const(body)); walk_define_opaques(vis, define_opaque); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 43046aee93deb..ada7fa3710a83 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -448,14 +448,13 @@ impl WalkItemKind for ItemKind { ident, generics, ty, - body_id: _, - expr, + body, define_opaque, }) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); + visit_opt!(visitor, visit_anon_const, body); try_visit!(walk_define_opaques(visitor, define_opaque)); } ItemKind::Fn(func) => { @@ -1045,14 +1044,13 @@ impl WalkItemKind for AssocItemKind { ident, generics, ty, - body_id: _, - expr, + body, define_opaque, }) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_expr, expr); + visit_opt!(visitor, visit_anon_const, body); try_visit!(walk_define_opaques(visitor, define_opaque)); } AssocItemKind::Fn(func) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 485371726814d..a5f362f6ae132 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -187,8 +187,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, - body_id, - expr, + body, define_opaque, .. }) => { @@ -200,8 +199,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = - this.lower_const_item(span, body_id.unwrap(), expr.as_deref().unwrap()); + let body = this.lower_const_item(body.as_deref().unwrap()); (ty, body) }, ); @@ -486,25 +484,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_const_item( - &mut self, - span: Span, - body_id: NodeId, - body_expr: &Expr, - ) -> &'hir hir::ConstArg<'hir> { + fn lower_const_item(&mut self, body: &AnonConst) -> &'hir hir::ConstArg<'hir> { let mgca = self.tcx.features().min_generic_const_args(); - if mgca && let Some(ct_arg) = self.try_lower_as_const_path(body_expr) { + if mgca && let Some(ct_arg) = self.try_lower_as_const_path(body) { return ct_arg; } - let anon = self.arena.alloc(self.with_new_scopes(span, |this| { - let body = this.lower_const_body(span, Some(body_expr)); - hir::AnonConst { - hir_id: this.lower_node_id(body_id), - def_id: this.local_def_id(body_id), - body, - span, - } - })); + let anon = self.lower_anon_const_to_anon_const(body); self.arena .alloc(hir::ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(anon) }) } @@ -804,8 +789,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, - body_id, - expr, + body, define_opaque, .. }) => { @@ -816,15 +800,13 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = body_id - .zip(expr.as_deref()) - .map(|(b_id, b_ex)| this.lower_const_item(i.span, b_id, b_ex)); + let body = body.as_deref().map(|body| this.lower_const_item(body)); hir::TraitItemKind::Const(ty, body) }, ); if define_opaque.is_some() { - if expr.is_some() { + if body.is_some() { self.lower_define_opaque(hir_id, &define_opaque); } else { self.dcx().span_err( @@ -834,7 +816,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - (*ident, generics, kind, expr.is_some()) + (*ident, generics, kind, body.is_some()) } AssocItemKind::Fn(box Fn { sig, ident, generics, body: None, define_opaque, .. @@ -998,8 +980,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, - body_id, - expr, + body, define_opaque, .. }) => ( @@ -1012,11 +993,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); this.lower_define_opaque(hir_id, &define_opaque); - let body = this.lower_const_item( - i.span, - body_id.unwrap(), - expr.as_deref().unwrap(), - ); + let body = this.lower_const_item(body.as_deref().unwrap()); hir::ImplItemKind::Const(ty, body) }, ), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 72feb11cc79a1..508ab87f3d741 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2085,10 +2085,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Assumes mgca feature is enabled. - fn try_lower_as_const_path(&mut self, expr: &Expr) -> Option<&'hir hir::ConstArg<'hir>> { - let ExprKind::Path(qself, path) = &expr.kind else { return None }; + fn try_lower_as_const_path(&mut self, body: &AnonConst) -> Option<&'hir hir::ConstArg<'hir>> { + let ExprKind::Path(qself, path) = &body.value.kind else { return None }; let qpath = self.lower_qpath( - expr.id, + body.value.id, qself, path, ParamMode::Optional, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index cbf4f2f5eb2be..dc12a87a0ae63 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1084,9 +1084,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { _ => visit::walk_item(self, item), } } - ItemKind::Const(box ConstItem { defaultness, expr, .. }) => { + ItemKind::Const(box ConstItem { defaultness, body, .. }) => { self.check_defaultness(item.span, *defaultness); - if expr.is_none() { + if body.is_none() { self.dcx().emit_err(errors::ConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), @@ -1436,7 +1436,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let AssocCtxt::Impl { .. } = ctxt { match &item.kind { - AssocItemKind::Const(box ConstItem { expr: None, .. }) => { + AssocItemKind::Const(box ConstItem { body: None, .. }) => { self.dcx().emit_err(errors::AssocConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index eadf0e2c6b1f8..a537a8f44a0e4 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -214,8 +214,7 @@ impl<'a> State<'a> { ident, generics, ty, - body_id: _, - expr, + body, define_opaque, }) => { self.print_item_const( @@ -223,7 +222,7 @@ impl<'a> State<'a> { None, generics, ty, - expr.as_deref(), + body.as_deref().map(|ct| &*ct.value), &item.vis, ast::Safety::Default, *defaultness, @@ -564,8 +563,7 @@ impl<'a> State<'a> { ident, generics, ty, - body_id: _, - expr, + body, define_opaque, }) => { self.print_item_const( @@ -573,7 +571,7 @@ impl<'a> State<'a> { None, generics, ty, - expr.as_deref(), + body.as_deref().map(|ct| &*ct.value), vis, ast::Safety::Default, *defaultness, diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index ea406e706660d..78f350c5747ca 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -43,7 +43,7 @@ pub(crate) fn expand( // Generate anonymous constant serving as container for the allocator methods. let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new())); - let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_body = ecx.anon_const_block(ecx.block(span, stmts)); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 4b1958bce3223..55637813e0517 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -48,7 +48,7 @@ pub(crate) fn expand( // Generate anonymous constant serving as container for the allocator methods. let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new())); - let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_body = ecx.anon_const_block(ecx.block(span, stmts)); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index a91f2d38a93ae..9814a36417025 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -379,7 +379,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { i }); - let block = cx.expr_block( + let block = cx.anon_const_block( cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), ); diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 27b7dad21cad0..96482d1e868f2 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -293,10 +293,10 @@ pub(crate) fn expand_test_or_bench( generics: ast::Generics::default(), ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), define_opaque: None, - body_id: Some(ast::DUMMY_NODE_ID), // test::TestDescAndFn { - expr: Some( - cx.expr_struct( + body: Some(P(ast::AnonConst { + id: ast::DUMMY_NODE_ID, + value: cx.expr_struct( sp, test_path("TestDescAndFn"), thin_vec![ @@ -377,7 +377,7 @@ pub(crate) fn expand_test_or_bench( field("testfn", test_fn), // } ], ), // } - ), + })), } .into(), ), diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 8c630f1f4c7c2..c0e28cb154ce8 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -105,6 +105,10 @@ impl<'a> ExtCtxt<'a> { } } + pub fn anon_const_block(&self, b: P) -> P { + P(self.anon_const(b.span, ast::ExprKind::Block(b, None))) + } + pub fn const_ident(&self, span: Span, ident: Ident) -> ast::AnonConst { self.anon_const(span, ast::ExprKind::Path(None, self.path_ident(span, ident))) } @@ -711,7 +715,7 @@ impl<'a> ExtCtxt<'a> { span: Span, ident: Ident, ty: P, - expr: P, + body: P, ) -> P { let defaultness = ast::Defaultness::Final; self.item( @@ -724,8 +728,7 @@ impl<'a> ExtCtxt<'a> { // FIXME(generic_const_items): Pass the generics as a parameter. generics: ast::Generics::default(), ty, - body_id: Some(ast::DUMMY_NODE_ID), - expr: Some(expr), + body: Some(body), define_opaque: None, } .into(), diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 8f948ebe0ed79..fb2ae6973a642 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -95,9 +95,8 @@ use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::middle; -use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_middle::ty::{Const, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{ErrorGuaranteed, Span}; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 50a27d7e84f58..d0b385673f8b1 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -983,19 +983,22 @@ trait UnusedDelimLint { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { use ast::ItemKind::*; - if let Const(box ast::ConstItem { expr: Some(expr), .. }) - | Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind - { - self.check_unused_delims_expr( - cx, - expr, - UnusedDelimsCtx::AssignedValue, - false, - None, - None, - false, - ); - } + let expr = if let Const(box ast::ConstItem { body: Some(body), .. }) = &item.kind { + &body.value + } else if let Static(box ast::StaticItem { expr: Some(expr), .. }) = &item.kind { + expr + } else { + return; + }; + self.check_unused_delims_expr( + cx, + expr, + UnusedDelimsCtx::AssignedValue, + false, + None, + None, + false, + ); } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 54c8a8843a8d2..3678bd94bf708 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -252,14 +252,13 @@ impl<'a> Parser<'a> { } else { self.recover_const_mut(const_span); self.recover_missing_kw_before_item()?; - let (ident, generics, ty, expr) = self.parse_const_item()?; + let (ident, generics, ty, body) = self.parse_const_item()?; ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ident, generics, ty, - body_id: expr.is_some().then_some(DUMMY_NODE_ID), - expr, + body, define_opaque: None, })) } @@ -969,13 +968,13 @@ impl<'a> Parser<'a> { define_opaque, }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); + let body = expr.map(|e| P(AnonConst { id: DUMMY_NODE_ID, value: e })); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, ident, generics: Generics::default(), ty, - body_id: expr.is_some().then_some(DUMMY_NODE_ID), - expr, + body, define_opaque, })) } @@ -1229,7 +1228,7 @@ impl<'a> Parser<'a> { let kind = match ForeignItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Const(box ConstItem { ident, ty, expr, .. }) => { + ItemKind::Const(box ConstItem { ident, ty, body, .. }) => { let const_span = Some(span.with_hi(ident.span.lo())) .filter(|span| span.can_be_used_for_suggestions()); self.dcx().emit_err(errors::ExternItemCannotBeConst { @@ -1240,7 +1239,7 @@ impl<'a> Parser<'a> { ident, ty, mutability: Mutability::Not, - expr, + expr: body.map(|ct| ct.into_inner().value), safety: Safety::Default, define_opaque: None, })) @@ -1409,7 +1408,9 @@ impl<'a> Parser<'a> { /// ```ebnf /// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ; /// ``` - fn parse_const_item(&mut self) -> PResult<'a, (Ident, Generics, P, Option>)> { + fn parse_const_item( + &mut self, + ) -> PResult<'a, (Ident, Generics, P, Option>)> { let ident = self.parse_ident_or_underscore()?; let mut generics = self.parse_generics()?; @@ -1436,7 +1437,7 @@ impl<'a> Parser<'a> { let before_where_clause = if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() }; - let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None }; + let body = if self.eat(exp!(Eq)) { Some(P(self.parse_expr_anon_const()?)) } else { None }; let after_where_clause = self.parse_where_clause()?; @@ -1444,18 +1445,18 @@ impl<'a> Parser<'a> { // Users may be tempted to write such code if they are still used to the deprecated // where-clause location on type aliases and associated types. See also #89122. if before_where_clause.has_where_token - && let Some(expr) = &expr + && let Some(body) = &body { self.dcx().emit_err(errors::WhereClauseBeforeConstBody { span: before_where_clause.span, name: ident.span, - body: expr.span, + body: body.value.span, sugg: if !after_where_clause.has_where_token { - self.psess.source_map().span_to_snippet(expr.span).ok().map(|body| { + self.psess.source_map().span_to_snippet(body.value.span).ok().map(|body_s| { errors::WhereClauseBeforeConstBodySugg { left: before_where_clause.span.shrink_to_lo(), - snippet: body, - right: before_where_clause.span.shrink_to_hi().to(expr.span), + snippet: body_s, + right: before_where_clause.span.shrink_to_hi().to(body.value.span), } }) } else { @@ -1493,7 +1494,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, generics, ty, expr)) + Ok((ident, generics, ty, body)) } /// We were supposed to parse `":" $ty` but the `:` or the type was missing. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index d091fc7cbe8cc..13dfb59f27fc0 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -174,10 +174,6 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ); } } - // HACK(mgca): see lower_const_item in ast_lowering - ItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) => { - this.create_def(body_id, None, DefKind::AnonConst, i.span); - } _ => {} } visit::walk_item(this, i); @@ -338,13 +334,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { }; let def = self.create_def(i.id, Some(ident.name), def_kind, i.span); - self.with_parent(def, |this| { - // HACK(mgca): see lower_const_item in ast_lowering - if let AssocItemKind::Const(box ConstItem { body_id: Some(body_id), .. }) = i.kind { - this.create_def(body_id, None, DefKind::AnonConst, i.span); - } - visit::walk_assoc_item(this, i, ctxt) - }); + self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } fn visit_pat(&mut self, pat: &'a Pat) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fd977a8eb6c0b..f5499be447edb 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2806,7 +2806,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident, ref generics, ref ty, - ref expr, + ref body, ref define_opaque, .. }) => { @@ -2835,8 +2835,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| this.visit_ty(ty), ); - if let Some(expr) = expr { - this.resolve_const_body(expr, Some((ident, ConstantItemKind::Const))); + if let Some(body) = body { + this.resolve_const_body( + &*body.value, + Some((ident, ConstantItemKind::Const)), + ); } }, ); @@ -3143,7 +3146,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { AssocItemKind::Const(box ast::ConstItem { generics, ty, - expr, + body, define_opaque, .. }) => { @@ -3167,13 +3170,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. - if let Some(expr) = expr { + if let Some(body) = body { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); + this.resolve_const_body(&*body.value, None); } }, ) @@ -3354,7 +3357,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident, generics, ty, - expr, + body, define_opaque, .. }) => { @@ -3397,13 +3400,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.visit_generics(generics); this.visit_ty(ty); - if let Some(expr) = expr { + if let Some(body) = body { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); + this.resolve_const_body(&*body.value, None); } }, ) From d322846e544ec809c4899d5adbb76356c345729c Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 22 May 2025 16:55:21 +0100 Subject: [PATCH 10/19] Implement type_of for anon consts on RHS of const items --- compiler/rustc_hir_analysis/src/collect/type_of.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 1b92ac97c5516..4cd73ab050e78 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -103,6 +103,12 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S icx.lower_ty(ty) } + Node::Item(hir::Item { kind: hir::ItemKind::Const(_, ty, ..), .. }) + | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, ..), .. }) + | Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(ty, ..), .. }) => { + icx.lower_ty(ty) + } + // This is not a `bug!` as const arguments in path segments that did not resolve to anything // will result in `type_of` never being fed. _ => Ty::new_error_with_message( From 4122d4ad474680fa6aa7f7c439024f3c53eb31e4 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 22 May 2025 17:33:48 +0100 Subject: [PATCH 11/19] Fix yet more ICEs --- compiler/rustc_const_eval/src/check_consts/qualifs.rs | 9 +++++++-- compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_mir_transform/src/lib.rs | 8 +++----- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index dfcd1969a73d1..4354a863a01fb 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -7,6 +7,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::LangItem; +use rustc_hir::def::DefKind; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty::{self, AdtDef, Ty}; @@ -368,8 +369,12 @@ where // check performed after the promotion. Verify that with an assertion. assert!(promoted.is_none() || Q::ALLOW_PROMOTED); - // Don't peek inside trait associated constants. - if promoted.is_none() && cx.tcx.trait_of_item(def).is_none() { + // Const items don't themselves have bodies -- they will have either a path or an anon const instead. + // FIXME(mgca): is this really the right behavior? should we return the qualifs of the anon const body instead? + // (note also that original code ignored trait assoc items) + if promoted.is_none() + && !matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst) + { let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); if !Q::in_qualifs(&qualifs) { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c064e0de1c17f..474f196ce64d9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4280,6 +4280,7 @@ pub enum ItemKind<'hir> { /// A `static` item. Static(Ident, &'hir Ty<'hir>, Mutability, BodyId), /// A `const` item. + // TODO: make sure we only allow usage of path RHS in generic contexts under mgca, not stable! Const(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, &'hir ConstArg<'hir>), /// A function declaration. Fn { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3ab989d2d3ba7..7b2b45a53c123 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1310,6 +1310,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool { fn should_encode_const(def_kind: DefKind) -> bool { match def_kind { + // FIXME(mgca): should we remove Const and AssocConst here? DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst => true, DefKind::Struct diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 10dbb3437dcbf..1731e484fd3a7 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -418,11 +418,9 @@ fn mir_promoted( { tcx.mir_const_qualif(def) } - DefKind::AssocConst - | DefKind::Const - | DefKind::Static { .. } - | DefKind::InlineConst - | DefKind::AnonConst => tcx.mir_const_qualif(def), + DefKind::Static { .. } | DefKind::InlineConst | DefKind::AnonConst => { + tcx.mir_const_qualif(def) + } _ => ConstQualifs::default(), }; From 93a39eedf8dec15b6d5c1ad3d531c2c127818df0 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 22 May 2025 18:00:17 +0100 Subject: [PATCH 12/19] wip on fixing more ICEs (this might make it worse) --- .../rustc_hir_analysis/src/collect/predicates_of.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index ce0f83d0ec288..47ef1d272eae2 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -23,6 +23,16 @@ use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason}; /// inferred constraints concerning which regions outlive other regions. #[instrument(level = "debug", skip(tcx))] pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { + // Anon const as RHS of const item is the body, so should have the same predicates. + // FIXME(mgca): probably should have only the predicates of params that are explicitly referenced, + // as should generics_of (maybe only under mgca?) + if matches!(tcx.def_kind(def_id), DefKind::AnonConst) + && let parent = tcx.parent(def_id) + && matches!(tcx.def_kind(parent), DefKind::Const | DefKind::AssocConst) + { + return tcx.predicates_of(parent); + } + let mut result = tcx.explicit_predicates_of(def_id); debug!("predicates_of: explicit_predicates_of({:?}) = {:?}", def_id, result); From c5841ec8ebcea5c71e56f324a6ef06bbf3876baf Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 23 May 2025 21:24:36 -0700 Subject: [PATCH 13/19] Fix clippy and rustfmt --- .../clippy/clippy_utils/src/ast_utils/mod.rs | 16 ++--- src/tools/rustfmt/src/items.rs | 62 +++++++++---------- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 8dad0411f8b0c..a3a48bd8874fa 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -355,8 +355,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: li, generics: lg, ty: lt, - body_id: _, - expr: le, + body: lb, define_opaque: _, }), Const(box ConstItem { @@ -364,8 +363,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ident: ri, generics: rg, ty: rt, - body_id: _, - expr: re, + body: rb, define_opaque: _, }), ) => { @@ -373,7 +371,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()) + && both(lb.as_ref(), rb.as_ref(), |l, r| eq_anon_const(l, r)) }, ( Fn(box ast::Fn { @@ -597,8 +595,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ident: li, generics: lg, ty: lt, - body_id: _, - expr: le, + body: lb, define_opaque: _, }), Const(box ConstItem { @@ -606,8 +603,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { ident: ri, generics: rg, ty: rt, - body_id: _, - expr: re, + body: rb, define_opaque: _, }), ) => { @@ -615,7 +611,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()) + && both(lb.as_ref(), rb.as_ref(), |l, r| eq_anon_const(l, r)) }, ( Fn(box ast::Fn { diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index e79b7803c6072..8a67629674ae8 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -2029,30 +2029,30 @@ pub(crate) struct StaticParts<'a> { impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { - let (defaultness, prefix, safety, ident, ty, mutability, expr, generics) = match &item.kind - { - ast::ItemKind::Static(s) => ( - None, - "static", - s.safety, - s.ident, - &s.ty, - s.mutability, - &s.expr, - None, - ), - ast::ItemKind::Const(c) => ( - Some(c.defaultness), - "const", - ast::Safety::Default, - c.ident, - &c.ty, - ast::Mutability::Not, - &c.expr, - Some(&c.generics), - ), - _ => unreachable!(), - }; + let (defaultness, prefix, safety, ident, ty, mutability, expr_opt, generics) = + match &item.kind { + ast::ItemKind::Static(s) => ( + None, + "static", + s.safety, + s.ident, + &s.ty, + s.mutability, + s.expr.as_ref(), + None, + ), + ast::ItemKind::Const(c) => ( + Some(c.defaultness), + "const", + ast::Safety::Default, + c.ident, + &c.ty, + ast::Mutability::Not, + c.body.as_ref().map(|ct| &ct.value), + Some(&c.generics), + ), + _ => unreachable!(), + }; StaticParts { prefix, safety, @@ -2061,15 +2061,15 @@ impl<'a> StaticParts<'a> { generics, ty, mutability, - expr_opt: expr.as_ref(), + expr_opt, defaultness, span: item.span, } } pub(crate) fn from_trait_item(ti: &'a ast::AssocItem, ident: Ident) -> Self { - let (defaultness, ty, expr_opt, generics) = match &ti.kind { - ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)), + let (defaultness, ty, body_opt, generics) = match &ti.kind { + ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.body, Some(&c.generics)), _ => unreachable!(), }; StaticParts { @@ -2080,15 +2080,15 @@ impl<'a> StaticParts<'a> { generics, ty, mutability: ast::Mutability::Not, - expr_opt: expr_opt.as_ref(), + expr_opt: body_opt.as_ref().map(|ct| &ct.value), defaultness: Some(defaultness), span: ti.span, } } pub(crate) fn from_impl_item(ii: &'a ast::AssocItem, ident: Ident) -> Self { - let (defaultness, ty, expr, generics) = match &ii.kind { - ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)), + let (defaultness, ty, body, generics) = match &ii.kind { + ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.body, Some(&c.generics)), _ => unreachable!(), }; StaticParts { @@ -2099,7 +2099,7 @@ impl<'a> StaticParts<'a> { generics, ty, mutability: ast::Mutability::Not, - expr_opt: expr.as_ref(), + expr_opt: body.as_ref().map(|ct| &ct.value), defaultness: Some(defaultness), span: ii.span, } From 5ea917f65e74a477ead64a7154f42ec810a6692e Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 25 May 2025 14:26:46 -0700 Subject: [PATCH 14/19] Address some review comments --- .../rustc_hir_analysis/src/collect/predicates_of.rs | 10 ---------- compiler/rustc_hir_analysis/src/collect/type_of.rs | 10 +++++----- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 47ef1d272eae2..ce0f83d0ec288 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -23,16 +23,6 @@ use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason}; /// inferred constraints concerning which regions outlive other regions. #[instrument(level = "debug", skip(tcx))] pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - // Anon const as RHS of const item is the body, so should have the same predicates. - // FIXME(mgca): probably should have only the predicates of params that are explicitly referenced, - // as should generics_of (maybe only under mgca?) - if matches!(tcx.def_kind(def_id), DefKind::AnonConst) - && let parent = tcx.parent(def_id) - && matches!(tcx.def_kind(parent), DefKind::Const | DefKind::AssocConst) - { - return tcx.predicates_of(parent); - } - let mut result = tcx.explicit_predicates_of(def_id); debug!("predicates_of: explicit_predicates_of({:?}) = {:?}", def_id, result); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 4cd73ab050e78..135d8604bce69 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -103,11 +103,11 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S icx.lower_ty(ty) } - Node::Item(hir::Item { kind: hir::ItemKind::Const(_, ty, ..), .. }) - | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, ..), .. }) - | Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Const(ty, ..), .. }) => { - icx.lower_ty(ty) - } + Node::Item(hir::Item { kind: hir::ItemKind::Const(..), owner_id, .. }) + | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), owner_id, .. }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const(..), owner_id, .. + }) => tcx.type_of(owner_id.def_id).instantiate_identity(), // This is not a `bug!` as const arguments in path segments that did not resolve to anything // will result in `type_of` never being fed. From 2e0a6e599e08231258c6681277c3a8800fab8936 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 25 May 2025 15:16:59 -0700 Subject: [PATCH 15/19] Inherit generics correctly for anon const as const item RHS --- compiler/rustc_hir_analysis/src/collect/generics_of.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 7eb896f0bf149..e73661000b797 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -87,7 +87,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // would implicitly have a closure in its body that would be the parent of // the `{ 1 + 2 }` anon const. This closure's generics is simply a witness // instead of `['a]`. - let parent_did = if let DefKind::AnonConst = tcx.def_kind(parent_did) { + let parent_def_kind = tcx.def_kind(parent_did); + let parent_did = if let DefKind::AnonConst = parent_def_kind { parent_did } else { tcx.hir_get_parent_item(hir_id).to_def_id() @@ -105,6 +106,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } match tcx.anon_const_kind(def_id) { + // Stable: the RHS of a const item is desugared to be either a const path or an anon const. + // If it's an anon const, it should inherit the const item's generics. + ty::AnonConstKind::MCG + if matches!(parent_def_kind, DefKind::Const | DefKind::AssocConst) => + { + Some(parent_did) + } // Stable: anon consts are not able to use any generic parameters... ty::AnonConstKind::MCG => None, // we provide generics to repeat expr counts as a backwards compatibility hack. #76200 From eb5c4d67b1629a15a60e84d9c7e74959fcccd8c6 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 25 May 2025 15:39:14 -0700 Subject: [PATCH 16/19] Lower const item RHS to const path even on stable --- compiler/rustc_ast_lowering/src/item.rs | 17 ++++------------- compiler/rustc_ast_lowering/src/lib.rs | 16 ---------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a5f362f6ae132..744a7e4056f7c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -199,7 +199,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = this.lower_const_item(body.as_deref().unwrap()); + let body = this.lower_anon_const_to_const_arg(body.as_deref().unwrap()); (ty, body) }, ); @@ -484,16 +484,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_const_item(&mut self, body: &AnonConst) -> &'hir hir::ConstArg<'hir> { - let mgca = self.tcx.features().min_generic_const_args(); - if mgca && let Some(ct_arg) = self.try_lower_as_const_path(body) { - return ct_arg; - } - let anon = self.lower_anon_const_to_anon_const(body); - self.arena - .alloc(hir::ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(anon) }) - } - #[instrument(level = "debug", skip(self))] fn lower_use_tree( &mut self, @@ -800,7 +790,8 @@ impl<'hir> LoweringContext<'_, 'hir> { |this| { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); - let body = body.as_deref().map(|body| this.lower_const_item(body)); + let body = + body.as_deref().map(|body| this.lower_anon_const_to_const_arg(body)); hir::TraitItemKind::Const(ty, body) }, ); @@ -993,7 +984,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = this .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); this.lower_define_opaque(hir_id, &define_opaque); - let body = this.lower_const_item(body.as_deref().unwrap()); + let body = this.lower_anon_const_to_const_arg(body.as_deref().unwrap()); hir::ImplItemKind::Const(ty, body) }, ), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 508ab87f3d741..422e79ca82ffd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2084,22 +2084,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - /// Assumes mgca feature is enabled. - fn try_lower_as_const_path(&mut self, body: &AnonConst) -> Option<&'hir hir::ConstArg<'hir>> { - let ExprKind::Path(qself, path) = &body.value.kind else { return None }; - let qpath = self.lower_qpath( - body.value.id, - qself, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - let ct_kind = hir::ConstArgKind::Path(qpath); - Some(self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })) - } - /// Used when lowering a type argument that turned out to actually be a const argument. /// /// Only use for that purpose since otherwise it will create a duplicate def. From 67a30ab60cb8745b6772445456cf32b3ca59187e Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 25 May 2025 16:38:00 -0700 Subject: [PATCH 17/19] wip on moving const RHS special-casing --- .../src/const_eval/eval_queries.rs | 48 ++++++++++--------- .../rustc_const_eval/src/const_eval/mod.rs | 2 +- .../src/const_eval/valtrees.rs | 16 ++++++- compiler/rustc_const_eval/src/lib.rs | 2 + compiler/rustc_middle/src/query/mod.rs | 5 ++ 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 1afe1dcfcbfb0..12ee519219181 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -294,29 +294,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>( ) }, ); - } else if let ty::InstanceKind::Item(def_id) = key.value.instance.def - && matches!(tcx.def_kind(def_id), DefKind::Const | DefKind::AssocConst) - { - let ct = tcx.const_of_item(def_id).instantiate(tcx, key.value.instance.args); - match ct.kind() { - ty::ConstKind::Unevaluated(_) => { - return Err(ErrorHandled::TooGeneric(DUMMY_SP)); - } - ty::ConstKind::Value(cv) => return Ok(tcx.valtree_to_const_val(cv)), - ty::ConstKind::Error(guar) => { - return Err(ErrorHandled::Reported( - ReportedErrorInfo::const_eval_error(guar), - DUMMY_SP, - )); - } - ty::ConstKind::Expr(_) => return Err(ErrorHandled::TooGeneric(DUMMY_SP)), - ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => { - return Err(ErrorHandled::TooGeneric(DUMMY_SP)); - } - ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => { - bug!("unexpected constant {ct:?}") - } - } } tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) @@ -374,6 +351,31 @@ pub fn eval_to_allocation_raw_provider<'tcx>( trace!("const eval: {:?} ({})", key, instance); } + if let ty::InstanceKind::Item(def_id) = key.value.instance.def + && matches!(tcx.def_kind(def_id), DefKind::Const | DefKind::AssocConst) + { + let ct = tcx.const_of_item(def_id).instantiate(tcx, key.value.instance.args); + match ct.kind() { + ty::ConstKind::Unevaluated(_) => { + return Err(ErrorHandled::TooGeneric(DUMMY_SP)); + } + ty::ConstKind::Value(cv) => return Ok(tcx.valtree_to_const_alloc(cv)), + ty::ConstKind::Error(guar) => { + return Err(ErrorHandled::Reported( + ReportedErrorInfo::const_eval_error(guar), + DUMMY_SP, + )); + } + ty::ConstKind::Expr(_) => return Err(ErrorHandled::TooGeneric(DUMMY_SP)), + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => { + return Err(ErrorHandled::TooGeneric(DUMMY_SP)); + } + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => { + bug!("unexpected constant {ct:?}") + } + } + } + eval_in_interpreter(tcx, key.value, key.typing_env) } diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index c0438fb3ff81a..8406eee138b76 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -21,7 +21,7 @@ pub use self::error::*; pub use self::eval_queries::*; pub use self::fn_queries::*; pub use self::machine::*; -pub(crate) use self::valtrees::{eval_to_valtree, valtree_to_const_value}; +pub(crate) use self::valtrees::{eval_to_valtree, valtree_to_const_alloc, valtree_to_const_value}; // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. const VALTREE_MAX_NODES: usize = 100000; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 34239ae1d1527..c786cb066735f 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -9,7 +9,9 @@ use tracing::{debug, instrument, trace}; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; use super::machine::CompileTimeInterpCx; -use super::{VALTREE_MAX_NODES, ValTreeCreationError, ValTreeCreationResult}; +use super::{ + InterpretationResult as _, VALTREE_MAX_NODES, ValTreeCreationError, ValTreeCreationResult, +}; use crate::const_eval::CanAccessMutGlobal; use crate::errors::MaxNumNodesInConstErr; use crate::interpret::{ @@ -365,6 +367,18 @@ pub fn valtree_to_const_value<'tcx>( } } +#[instrument(skip(tcx), level = "debug", ret)] +pub(crate) fn valtree_to_const_alloc<'tcx>( + tcx: TyCtxt<'tcx>, + env: ty::TypingEnv<'tcx>, + val: ty::Value<'tcx>, +) -> mir::ConstAlloc<'tcx> { + let mut ecx = mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, env, CanAccessMutGlobal::No); + let layout = ecx.layout_of(val.ty).unwrap(); + let mplace = create_valtree_place(&mut ecx, layout, val.valtree); + mir::ConstAlloc::make_result(mplace, &mut ecx) +} + /// Put a valtree into memory and return a reference to that. fn valtree_to_ref<'tcx>( ecx: &mut CompileTimeInterpCx<'tcx>, diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index bf7a79dcb20f0..b8e9ac772a505 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -46,6 +46,8 @@ pub fn provide(providers: &mut Providers) { const_eval::try_destructure_mir_constant_for_user_output; providers.valtree_to_const_val = |tcx, cv| const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), cv); + providers.valtree_to_const_alloc = + |tcx, cv| const_eval::valtree_to_const_alloc(tcx, ty::TypingEnv::fully_monomorphized(), cv); providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) }; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4a3ad1a0ddf24..58dcf8a766061 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1329,6 +1329,11 @@ rustc_queries! { desc { "converting type-level constant value to MIR constant value"} } + /// Converts a type-level constant value into a MIR constant allocation. + query valtree_to_const_alloc(key: ty::Value<'tcx>) -> mir::ConstAlloc<'tcx> { + desc { "converting type-level constant value to MIR constant allocation"} + } + /// Destructures array, ADT or tuple constants into the constants /// of their fields. query destructure_const(key: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> { From e3f9fa3e74bc2f96f5bf91ad86dbf8773fc4280b Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 26 May 2025 00:54:07 +0100 Subject: [PATCH 18/19] intern + write to place --- compiler/rustc_const_eval/src/const_eval/valtrees.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index c786cb066735f..4595fe0a88fe4 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -376,6 +376,8 @@ pub(crate) fn valtree_to_const_alloc<'tcx>( let mut ecx = mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, env, CanAccessMutGlobal::No); let layout = ecx.layout_of(val.ty).unwrap(); let mplace = create_valtree_place(&mut ecx, layout, val.valtree); + valtree_into_mplace(&mut ecx, &mplace, val.valtree); + intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &mplace).unwrap(); mir::ConstAlloc::make_result(mplace, &mut ecx) } From fae3918d6bb45d453d6d938214ef74a89b2f2946 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 26 May 2025 00:54:29 +0100 Subject: [PATCH 19/19] allow anon consts with expected types with generics --- compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 6b21bbbfcd809..df1a5cd84ec9b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2223,7 +2223,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // We error when the type contains unsubstituted generics since we do not currently // give the anon const any of the generics from the parent. - if anon_const_type.has_non_region_param() { + if tcx.features().generic_const_parameter_types() + && anon_const_type.has_non_region_param() + { let e = self.dcx().span_err( const_arg.span(), "anonymous constants referencing generics are not yet supported",