diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4ace80a73444b..9e3340fd47a9b 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 e49886721e364..2e99b92851f54 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1331,11 +1331,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 69a186c8cf1b7..f24f35cdc656f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -388,6 +388,7 @@ impl WalkItemKind for ItemKind { ident, generics, ty, + body_id: _, expr, define_opaque, }) => { @@ -990,6 +991,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 f48a571b86a7d..de9dc8cab0681 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -182,15 +182,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) } @@ -198,21 +199,26 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, + body_id, expr, define_opaque, .. }) => { 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| { - this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + 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 }, @@ -494,13 +500,25 @@ 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)) + 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))] @@ -798,6 +816,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, + body_id, expr, define_opaque, .. @@ -809,8 +828,9 @@ 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 = 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) }, ); @@ -990,6 +1010,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, generics, ty, + body_id, expr, define_opaque, .. @@ -1002,8 +1023,12 @@ 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, + body_id.unwrap(), + expr.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 19095f2e01e54..58dca4988890c 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_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_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_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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 107aea4e5a401..cc46f1a952028 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3094,7 +3094,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>), @@ -3119,7 +3119,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 @@ -3169,9 +3169,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; } } @@ -3180,7 +3180,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. @@ -4107,8 +4107,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); @@ -4278,7 +4278,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, @@ -4576,17 +4576,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, @@ -4832,23 +4844,17 @@ impl<'hir> Node<'hir> { match self { Node::Item(Item { owner_id, - kind: - ItemKind::Const(_, _, _, body) - | ItemKind::Static(.., body) - | ItemKind::Fn { body, .. }, + kind: ItemKind::Static(.., body) | ItemKind::Fn { body, .. }, .. }) | Node::TraitItem(TraitItem { owner_id, - kind: - TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), + kind: TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) - | Node::ImplItem(ImplItem { - owner_id, - kind: ImplItemKind::Const(_, 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/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.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4520fbe352cea..395be2cf34146 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) { opaque_ty_origin, rendered_precise_capturing_args, const_param_default, + const_of_item, ..*providers }; } @@ -1828,3 +1829,25 @@ fn const_param_default<'tcx>( .lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args)); ty::EarlyBinder::bind(ct) } + +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_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_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 4937eb73a8be5..ee82c7c1a77d1 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -214,12 +214,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_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_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 b2133fea08cc3..45bbf39427630 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 @@ -2292,7 +2299,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>>>, @@ -2320,7 +2327,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_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0759fa3da428a..42ac36baf06b1 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -210,6 +210,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 b90e34e78101c..d99a0a0846d62 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 @@ -335,19 +335,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_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_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index f0e8fa986feae..e87ab6993c383 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 13dfb59f27fc0..d091fc7cbe8cc 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -174,6 +174,10 @@ 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); @@ -334,7 +338,13 @@ 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_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) + }); } fn visit_pat(&mut self, pat: &'a Pat) { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 88a0c402702e1..2814f898c9bb0 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(); @@ -324,10 +323,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; @@ -427,51 +427,40 @@ 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), + }; + + 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.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. - } + // 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 ca58da5ca6d55..7e20d9bc6ef3f 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -482,7 +482,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>, @@ -545,7 +544,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); @@ -2009,14 +2008,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) { @@ -2108,15 +2100,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_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index eb34cb10c68dd..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,76 +254,9 @@ 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::AliasTerm::new(self.cx(), data.def_id, data.args))? + .expect_type(), }; self.cache.insert(ty, res); @@ -337,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) } @@ -359,3 +303,85 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } } } + +impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { + fn try_fold_free_or_assoc( + &mut self, + 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 (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 { + (term, None) + }; + let term = term.try_fold_with(self)?; + + let mut orig_values = OriginalQueryValues::default(); + 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 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_term:?} {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_term, + ) + } else { + result.normalized_term + }; + // `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 != 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 }) }, ) } 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 } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 0fd2d9f3ad38b..2a5d4bc3bd362 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -166,6 +166,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; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 622a410837b54..0d8e49ead7a93 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/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 6d3e77b6b6e97..fe3cafddd373f 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -9,7 +9,7 @@ use rustc_abi::VariantIdx; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ - BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, + Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo}; @@ -260,8 +260,7 @@ impl<'tcx> NonCopyConst<'tcx> { ) } - fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { - let def_id = body_id.hir_id.owner.to_def_id(); + fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, def_id: DefId, ty: Ty<'tcx>) -> bool { let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { @@ -310,11 +309,11 @@ impl<'tcx> NonCopyConst<'tcx> { impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(.., body_id) = it.kind { + if let ItemKind::Const(..) = it.kind { let ty = cx.tcx.type_of(it.owner_id).instantiate_identity(); if !ignored_macro(cx, it) && self.interior_mut.is_interior_mut_ty(cx, ty) - && Self::is_value_unfrozen_poly(cx, body_id, ty) + && Self::is_value_unfrozen_poly(cx, it.owner_id.def_id.into(), ty) { lint(cx, Source::Item { item: it.span, ty }); } @@ -341,7 +340,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { // i.e. having an enum doesn't necessary mean a type has a frozen variant. // And, implementing it isn't a trivial task; it'll probably end up // re-implementing the trait predicate evaluation specific to `Freeze`. - && body_id_opt.is_none_or(|body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized)) + && body_id_opt.is_none_or(|_| Self::is_value_unfrozen_poly(cx, trait_item.owner_id.def_id.into(), normalized)) { lint(cx, Source::Assoc { item: trait_item.span }); } @@ -349,7 +348,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Const(_, body_id) = &impl_item.kind { + if let ImplItemKind::Const(..) = &impl_item.kind { let item_def_id = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; let item = cx.tcx.hir_expect_item(item_def_id); @@ -384,7 +383,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity() && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty) && self.interior_mut.is_interior_mut_ty(cx, normalized) - && Self::is_value_unfrozen_poly(cx, *body_id, normalized) + && Self::is_value_unfrozen_poly(cx, impl_item.owner_id.def_id.into(), normalized) { lint(cx, Source::Assoc { item: impl_item.span }); } @@ -395,7 +394,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty); if self.interior_mut.is_interior_mut_ty(cx, normalized) - && Self::is_value_unfrozen_poly(cx, *body_id, normalized) + && Self::is_value_unfrozen_poly(cx, impl_item.owner_id.def_id.into(), normalized) { lint(cx, Source::Assoc { item: impl_item.span }); } 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!( 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: _, }),