From 02c1774cd3e4239c26b67ae78a21a87f4e460fad Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 2 Oct 2021 12:59:26 +0100 Subject: [PATCH 1/8] Give inline const separate DefKind --- .../rustc_const_eval/src/const_eval/eval_queries.rs | 1 + compiler/rustc_hir/src/def.rs | 7 ++++++- compiler/rustc_metadata/src/rmeta/encoder.rs | 12 +++++++++--- compiler/rustc_middle/src/hir/map/mod.rs | 10 +++++++++- compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 3 ++- compiler/rustc_monomorphize/src/polymorphize.rs | 3 ++- compiler/rustc_privacy/src/lib.rs | 1 + compiler/rustc_resolve/src/build_reduced_graph.rs | 1 + compiler/rustc_resolve/src/late/lifetimes.rs | 2 +- compiler/rustc_save_analysis/src/lib.rs | 1 + .../src/traits/const_evaluatable.rs | 4 ++-- src/librustdoc/clean/utils.rs | 5 +++-- src/librustdoc/formats/item_type.rs | 1 + src/librustdoc/passes/collect_intra_doc_links.rs | 3 ++- src/tools/clippy/clippy_lints/src/matches.rs | 5 ++++- 16 files changed, 46 insertions(+), 15 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 57af0ff071433..6d3a89c0a8a5b 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( | DefKind::Static | DefKind::ConstParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::AssocConst ), "Unexpected DefKind: {:?}", diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index cb668eb35e093..60761a05de827 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -104,8 +104,10 @@ pub enum DefKind { Use, /// An `extern` block. ForeignMod, - /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}` + /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]` AnonConst, + /// An inline constant, e.g. `const { 1 + 2 }` + InlineConst, /// Opaque type, aka `impl Trait`. OpaqueTy, Field, @@ -155,6 +157,7 @@ impl DefKind { DefKind::Use => "import", DefKind::ForeignMod => "foreign module", DefKind::AnonConst => "constant expression", + DefKind::InlineConst => "inline constant", DefKind::Field => "field", DefKind::Impl => "implementation", DefKind::Closure => "closure", @@ -174,6 +177,7 @@ impl DefKind { | DefKind::OpaqueTy | DefKind::Impl | DefKind::Use + | DefKind::InlineConst | DefKind::ExternCrate => "an", DefKind::Macro(macro_kind) => macro_kind.article(), _ => "a", @@ -207,6 +211,7 @@ impl DefKind { // Not namespaced. DefKind::AnonConst + | DefKind::InlineConst | DefKind::Field | DefKind::LifetimeParam | DefKind::ExternCrate diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0dbef66ac37d7..aff5e02d0c655 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -797,6 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::ConstParam | DefKind::LifetimeParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure | DefKind::Generator @@ -832,6 +833,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool { DefKind::Use | DefKind::LifetimeParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure | DefKind::Generator @@ -856,9 +858,11 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { (true, mir_opt_base) } // Constants - DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => { - (true, false) - } + DefKind::AnonConst + | DefKind::InlineConst + | DefKind::AssocConst + | DefKind::Static + | DefKind::Const => (true, false), // Full-fledged functions DefKind::AssocFn | DefKind::Fn => { let generics = tcx.generics_of(def_id); @@ -914,6 +918,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Use | DefKind::LifetimeParam | DefKind::AnonConst + | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure | DefKind::Generator @@ -939,6 +944,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::AssocFn | DefKind::AssocConst | DefKind::AnonConst + | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::Impl | DefKind::Field diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8f52e16c2ebe4..d9d0781b37aac 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -266,7 +266,15 @@ impl<'hir> Map<'hir> { }; DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data)) } - Node::AnonConst(_) => DefKind::AnonConst, + Node::AnonConst(_) => { + let inline = match self.find(self.get_parent_node(hir_id)) { + Some(Node::Expr(&Expr { + kind: ExprKind::ConstBlock(ref anon_const), .. + })) if anon_const.hir_id == hir_id => true, + _ => false, + }; + if inline { DefKind::InlineConst } else { DefKind::AnonConst } + } Node::Field(_) => DefKind::Field, Node::Expr(expr) => match expr.kind { ExprKind::Closure(.., None) => DefKind::Closure, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 8e363cfbff562..8e1b887f87da7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -958,7 +958,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })? } (_, _) if is_function => write!(w, "fn ")?, - (DefKind::AnonConst, _) => {} // things like anon const, not an item + (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item _ => bug!("Unexpected def kind {:?}", kind), } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cf47da157d19f..26bae1e15a372 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1927,7 +1927,8 @@ impl<'tcx> TyCtxt<'tcx> { | DefKind::Static | DefKind::AssocConst | DefKind::Ctor(..) - | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def), + | DefKind::AnonConst + | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def), // If the caller wants `mir_for_ctfe` of a function they should not be using // `instance_mir`, so we'll assume const fn also wants the optimized version. _ => { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index e6e4438b6d41a..ba62a6eea10ea 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -167,6 +167,7 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst + | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::Field | DefKind::LifetimeParam @@ -303,7 +304,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { ControlFlow::CONTINUE } ty::ConstKind::Unevaluated(uv) - if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst => + if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) => { self.visit_child_body(uv.def.did, uv.substs(self.tcx)); ControlFlow::CONTINUE diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index fa34b9abc1e6c..a01efc5d85c6e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -618,6 +618,7 @@ impl EmbargoVisitor<'tcx> { | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst + | DefKind::InlineConst | DefKind::Field | DefKind::GlobalAsm | DefKind::Impl diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 33af9884cbb66..44268877cb0a5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -967,6 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst + | DefKind::InlineConst | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 94563400a8b53..ed9100024def8 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -540,7 +540,7 @@ fn is_late_bound_map<'tcx>( def_id: LocalDefId, ) -> Option<(LocalDefId, &'tcx FxHashSet)> { match tcx.def_kind(def_id) { - DefKind::AnonConst => { + DefKind::AnonConst | DefKind::InlineConst => { let mut def_id = tcx .parent(def_id.to_def_id()) .unwrap_or_else(|| bug!("anon const or closure without a parent")); diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 543cd0247a53d..c7f8fe3a88a64 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -739,6 +739,7 @@ impl<'tcx> SaveContext<'tcx> { | HirDefKind::ForeignMod | HirDefKind::LifetimeParam | HirDefKind::AnonConst + | HirDefKind::InlineConst | HirDefKind::Use | HirDefKind::Field | HirDefKind::GlobalAsm diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8edb7069fc45f..6b5d37c0f4308 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -151,7 +151,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) { match infcx.tcx.def_kind(uv.def.did) { - DefKind::AnonConst => { + DefKind::AnonConst | DefKind::InlineConst => { let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); if mir_body.is_polymorphic { @@ -495,7 +495,7 @@ pub(super) fn thir_abstract_const<'tcx>( // we want to look into them or treat them as opaque projections. // // Right now we do neither of that and simply always fail to unify them. - DefKind::AnonConst => (), + DefKind::AnonConst | DefKind::InlineConst => (), _ => return Ok(None), } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 2fae3163a1a1a..2fa7efcc6509b 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -430,8 +430,9 @@ crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { | Res::NonMacroAttr(_) | Res::Err => return res.def_id(), Res::Def( - TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy - | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator, + TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst + | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure + | Generator, id, ) => return id, }; diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 793db16faf385..3979d29b673fd 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -134,6 +134,7 @@ impl From for ItemType { | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst + | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::Field | DefKind::LifetimeParam diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 8541e6e18816f..4e5812d7f8429 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1937,7 +1937,8 @@ fn resolution_failure( | Use | LifetimeParam | Ctor(_, _) - | AnonConst => { + | AnonConst + | InlineConst => { let note = assoc_item_not_allowed(res); if let Some(span) = sp { diag.span_label(span, ¬e); diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index eb311983b2927..7142df98c3f10 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1065,7 +1065,10 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) PatKind::Path(path) => { #[allow(clippy::match_same_arms)] let id = match cx.qpath_res(path, pat.hir_id) { - Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return, + Res::Def( + DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst, + _, + ) => return, Res::Def(_, id) => id, _ => return, }; From 468192a9c52e613f56af5b2a967d33c326cbf373 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 2 Oct 2021 13:12:33 +0100 Subject: [PATCH 2/8] Implement type inference for inline consts In most cases it is handled in the same way as closures. --- .../rustc_borrowck/src/region_infer/mod.rs | 3 +- compiler/rustc_borrowck/src/type_check/mod.rs | 14 +++- .../rustc_borrowck/src/universal_regions.rs | 49 +++++++++--- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 79 ++++++++++++++++--- compiler/rustc_middle/src/ty/mod.rs | 7 +- compiler/rustc_middle/src/ty/sty.rs | 60 ++++++++++++++ compiler/rustc_middle/src/ty/subst.rs | 10 ++- compiler/rustc_middle/src/ty/util.rs | 23 ++++-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 2 +- compiler/rustc_passes/src/region.rs | 5 +- compiler/rustc_typeck/src/check/expr.rs | 23 +++++- compiler/rustc_typeck/src/check/pat.rs | 4 +- compiler/rustc_typeck/src/check/regionck.rs | 28 +++++++ compiler/rustc_typeck/src/check/writeback.rs | 6 ++ compiler/rustc_typeck/src/collect.rs | 22 +++++- compiler/rustc_typeck/src/collect/type_of.rs | 3 +- 18 files changed, 299 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f4a5da1fe36fa..053e5c33313cc 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -569,7 +569,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to store those. Otherwise, we'll pass in `None` to the // functions below, which will trigger them to report errors // eagerly. - let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new); + let mut outlives_requirements = + infcx.tcx.is_closure_or_inline_const(mir_def_id).then(Vec::new); self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7e6a481ca69a1..9e068ef716504 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1345,7 +1345,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(RETURN_PLACE) => { if let BorrowCheckContext { universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, + UniversalRegions { + defining_ty: + DefiningTy::Const(def_id, _) + | DefiningTy::InlineConst(def_id, _), + .. + }, .. } = self.borrowck_context { @@ -1650,7 +1655,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(RETURN_PLACE) => { if let BorrowCheckContext { universal_regions: - UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, + UniversalRegions { + defining_ty: + DefiningTy::Const(def_id, _) + | DefiningTy::InlineConst(def_id, _), + .. + }, .. } = self.borrowck_context { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 147e2aead648d..ab8725834376c 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt}; use std::iter; use crate::nll::ToRegionVid; @@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> { /// is that it has no inputs and a single return value, which is /// the value of the constant. Const(DefId, SubstsRef<'tcx>), + + /// The MIR represents an inline const. The signature has no inputs and a + /// single return value found via `InlineConstSubsts::ty`. + InlineConst(DefId, SubstsRef<'tcx>), } impl<'tcx> DefiningTy<'tcx> { @@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Generator(_, substs, _) => { Either::Right(Either::Left(substs.as_generator().upvar_tys())) } - DefiningTy::FnDef(..) | DefiningTy::Const(..) => { + DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { Either::Right(Either::Right(iter::empty())) } } @@ -133,7 +137,7 @@ impl<'tcx> DefiningTy<'tcx> { pub fn implicit_inputs(self) -> usize { match self { DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1, - DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0, + DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, } } @@ -142,7 +146,7 @@ impl<'tcx> DefiningTy<'tcx> { } pub fn is_const(&self) -> bool { - matches!(*self, DefiningTy::Const(..)) + matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..)) } pub fn def_id(&self) -> DefId { @@ -150,7 +154,8 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(def_id, ..) | DefiningTy::Generator(def_id, ..) | DefiningTy::FnDef(def_id, ..) - | DefiningTy::Const(def_id, ..) => def_id, + | DefiningTy::Const(def_id, ..) + | DefiningTy::InlineConst(def_id, ..) => def_id, } } } @@ -376,6 +381,12 @@ impl<'tcx> UniversalRegions<'tcx> { tcx.def_path_str_with_substs(def_id, substs), )); } + DefiningTy::InlineConst(def_id, substs) => { + err.note(&format!( + "defining inline constant type: {}", + tcx.def_path_str_with_substs(def_id, substs), + )); + } } } } @@ -534,11 +545,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { - assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id); let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); - let substs = - self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); - DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + if self.mir_def.did.to_def_id() == closure_base_def_id { + let substs = + self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); + DefiningTy::Const(self.mir_def.did.to_def_id(), substs) + } else { + let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id); + let substs = InlineConstSubsts::new( + tcx, + InlineConstSubstsParts { parent_substs: identity_substs, ty }, + ) + .substs; + let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs); + DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs) + } } } } @@ -556,7 +577,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); let fr_substs = match defining_ty { - DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => { + DefiningTy::Closure(_, ref substs) + | DefiningTy::Generator(_, ref substs, _) + | DefiningTy::InlineConst(_, ref substs) => { // In the case of closures, we rely on the fact that // the first N elements in the ClosureSubsts are // inherited from the `closure_base_def_id`. @@ -648,6 +671,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = indices.fold_to_region_vids(tcx, ty); ty::Binder::dummy(tcx.intern_type_list(&[ty])) } + + DefiningTy::InlineConst(def_id, substs) => { + assert_eq!(self.mir_def.did.to_def_id(), def_id); + let ty = substs.as_inline_const().ty(); + ty::Binder::dummy(tcx.intern_type_list(&[ty])) + } } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 06041bbb02d35..b0952d346766c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -797,7 +797,7 @@ rustc_queries! { /// additional requirements that the closure's creator must verify. query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) } + cache_on_disk_if(tcx) { tcx.is_closure_or_inline_const(key.to_def_id()) } } query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 869b2ab9dbcbc..080ef6cb82a0f 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,7 +1,9 @@ use crate::mir::interpret::ConstValue; use crate::mir::interpret::{LitToConstInput, Scalar}; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::{ParamEnv, ParamEnvAnd}; +use crate::ty::{ + self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, + TyCtxt, TypeFoldable, +}; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -54,6 +56,24 @@ impl<'tcx> Const<'tcx> { let ty = tcx.type_of(def.def_id_for_type_of()); + match Self::try_eval_body_expr(tcx, ty, expr) { + Some(v) => v, + None => tcx.mk_const(ty::Const { + val: ty::ConstKind::Unevaluated(ty::Unevaluated { + def: def.to_global(), + substs_: None, + promoted: None, + }), + ty, + }), + } + } + + fn try_eval_body_expr( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ) -> Option<&'tcx Self> { let lit_input = match expr.kind { hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { @@ -69,7 +89,7 @@ impl<'tcx> Const<'tcx> { // If an error occurred, ignore that it's a literal and leave reporting the error up to // mir. if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { - return c; + return Some(c); } else { tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const"); } @@ -85,7 +105,7 @@ impl<'tcx> Const<'tcx> { }; use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; - let val = match expr.kind { + match expr.kind { ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. @@ -95,16 +115,53 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id.to_def_id()); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.hir().name(hir_id); - ty::ConstKind::Param(ty::ParamConst::new(index, name)) + Some(tcx.mk_const(ty::Const { + val: ty::ConstKind::Param(ty::ParamConst::new(index, name)), + ty, + })) } - _ => ty::ConstKind::Unevaluated(ty::Unevaluated { - def: def.to_global(), - substs_: None, - promoted: None, - }), + _ => None, + } + } + + pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self { + debug!("Const::from_inline_const(def_id={:?})", def_id); + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + let body_id = match tcx.hir().get(hir_id) { + hir::Node::AnonConst(ac) => ac.body, + _ => span_bug!( + tcx.def_span(def_id.to_def_id()), + "from_inline_const can only process anonymous constants" + ), }; - tcx.mk_const(ty::Const { val, ty }) + let expr = &tcx.hir().body(body_id).value; + + let ty = tcx.typeck(def_id).node_type(hir_id); + + let ret = match Self::try_eval_body_expr(tcx, ty, expr) { + Some(v) => v, + None => { + let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()); + let parent_substs = + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, outer_def_id)); + let substs = + InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty }) + .substs; + tcx.mk_const(ty::Const { + val: ty::ConstKind::Unevaluated(ty::Unevaluated { + def: ty::WithOptConstParam::unknown(def_id).to_global(), + substs_: Some(substs), + promoted: None, + }), + ty, + }) + } + }; + debug_assert!(!ret.has_free_regions(tcx)); + ret } /// Interns the given value as a constant. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 26bae1e15a372..40670f1fdcaef 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -74,9 +74,10 @@ pub use self::sty::{ Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, - GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, - PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, - RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, + GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, + ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, + PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, + UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, }; pub use self::trait_def::TraitDef; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 874de3366d792..e57075ed33811 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -704,6 +704,66 @@ impl<'tcx> UpvarSubsts<'tcx> { } } +/// An inline const is modeled like +/// +/// const InlineConst<'l0...'li, T0...Tj, R>: R; +/// +/// where: +/// +/// - 'l0...'li and T0...Tj are the generic parameters +/// inherited from the item that defined the inline const, +/// - R represents the type of the constant. +/// +/// When the inline const is instantiated, `R` is substituted as the actual inferred +/// type of the constant. The reason that `R` is represented as an extra type parameter +/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters: +/// inline const can reference lifetimes that are internal to the creating function. +#[derive(Copy, Clone, Debug, TypeFoldable)] +pub struct InlineConstSubsts<'tcx> { + /// Generic parameters from the enclosing item, + /// concatenated with the inferred type of the constant. + pub substs: SubstsRef<'tcx>, +} + +/// Struct returned by `split()`. +pub struct InlineConstSubstsParts<'tcx, T> { + pub parent_substs: &'tcx [GenericArg<'tcx>], + pub ty: T, +} + +impl<'tcx> InlineConstSubsts<'tcx> { + /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`. + pub fn new( + tcx: TyCtxt<'tcx>, + parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>, + ) -> InlineConstSubsts<'tcx> { + InlineConstSubsts { + substs: tcx.mk_substs( + parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())), + ), + } + } + + /// Divides the inline const substs into their respective components. + /// The ordering assumed here must match that used by `InlineConstSubsts::new` above. + fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> { + match self.substs[..] { + [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty }, + _ => bug!("inline const substs missing synthetics"), + } + } + + /// Returns the substitutions of the inline const's parent. + pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] { + self.split().parent_substs + } + + /// Returns the type of this inline const. + pub fn ty(self) -> Ty<'tcx> { + self.split().ty.expect_ty() + } +} + #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub enum ExistentialPredicate<'tcx> { diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 2438d1a16021b..73a8e18949de0 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -3,7 +3,7 @@ use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; +use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_hir::def_id::DefId; @@ -204,6 +204,14 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { GeneratorSubsts { substs: self } } + /// Interpret these substitutions as the substitutions of an inline const. + /// Inline const substitutions have a particular structure controlled by the + /// compiler that encodes information like the inferred type; + /// see `ty::InlineConstSubsts` struct for more comments. + pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> { + InlineConstSubsts { substs: self } + } + /// Creates an `InternalSubsts` that maps each generic parameter to itself. pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param)) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2c884813d2318..d5b78820411be 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -423,6 +423,14 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator) } + /// Returns `true` if `def_id` refers to a closure, generator or inline const. + pub fn is_closure_or_inline_const(self, def_id: DefId) -> bool { + matches!( + self.def_kind(def_id), + DefKind::Closure | DefKind::Generator | DefKind::InlineConst + ) + } + /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). pub fn is_trait(self, def_id: DefId) -> bool { self.def_kind(def_id) == DefKind::Trait @@ -440,16 +448,19 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.def_kind(def_id), DefKind::Ctor(..)) } - /// Given the def-ID of a fn or closure, returns the def-ID of - /// the innermost fn item that the closure is contained within. - /// This is a significant `DefId` because, when we do - /// type-checking, we type-check this fn item and all of its - /// (transitive) closures together. Therefore, when we fetch the + /// Given the `DefId`, returns the `DefId` of the innermost item that + /// has its own type-checking context or "inference enviornment". + /// + /// For example, a closure has its own `DefId`, but it is type-checked + /// with the containing item. Similarly, an inline const block has its + /// own `DefId` but it is type-checked together with the containing item. + /// + /// Therefore, when we fetch the /// `typeck` the closure, for example, we really wind up /// fetching the `typeck` the enclosing fn item. pub fn closure_base_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; - while self.is_closure(def_id) { + while self.is_closure_or_inline_const(def_id) { def_id = self.parent(def_id).unwrap_or_else(|| { bug!("closure {:?} has no parent", def_id); }); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 17296a95bc17e..b4005ccd1cc42 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -578,7 +578,7 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::ConstBlock(ref anon_const) => { let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); ExprKind::ConstBlock { value } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index cb74ae4df2ef8..ce80214c875fc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -544,7 +544,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let (lit, neg) = match expr.kind { hir::ExprKind::ConstBlock(ref anon_const) => { let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); if matches!(value.val, ConstKind::Param(_)) { let span = self.tcx.hir().span(anon_const.hir_id); self.errors.push(PatternError::ConstParamInPattern(span)); diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index 5fc8e230d72a3..40905c1f8affc 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -334,9 +334,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h // properly, we can't miss any types. match expr.kind { - // Manually recurse over closures, because they are the only + // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. - hir::ExprKind::Closure(.., body, _, _) => { + hir::ExprKind::Closure(.., body, _, _) + | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 2d0a4068fbbe3..c03ae17b17236 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -30,6 +30,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -323,7 +324,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), - ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty, + ExprKind::ConstBlock(ref anon_const) => { + self.check_expr_const_block(anon_const, expected, expr) + } ExprKind::Repeat(element, ref count) => { self.check_expr_repeat(element, count, expected, expr) } @@ -1166,6 +1169,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.mk_array(element_ty, args.len() as u64) } + fn check_expr_const_block( + &self, + anon_const: &'tcx hir::AnonConst, + expected: Expectation<'tcx>, + _expr: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + let body = self.tcx.hir().body(anon_const.body); + + // Create a new function context. + let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id); + crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body); + + let ty = fcx.check_expr_with_expectation(&body.value, expected); + fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized); + fcx.write_ty(anon_const.hir_id, ty); + ty + } + fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 5aa11cce25fb6..cbf33cf1b78a1 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -292,7 +292,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. - PatKind::Lit(lt) => match self.check_expr(lt).kind() { + // + // Call `resolve_vars_if_possible` here for inline const blocks. + PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { ty::Ref(..) => AdjustMode::Pass, _ => AdjustMode::Peel, }, diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 86d4e4d2b115b..52faf5fbe9fb3 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -341,6 +341,29 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.visit_region_obligations(body_id.hir_id); } + fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) { + debug!("visit_inline_const(id={:?})", id); + + // Save state of current function. We will restore afterwards. + let old_body_id = self.body_id; + let old_body_owner = self.body_owner; + let env_snapshot = self.outlives_environment.push_snapshot_pre_closure(); + + let body_id = body.id(); + self.body_id = body_id.hir_id; + self.body_owner = self.tcx.hir().body_owner_def_id(body_id); + + self.outlives_environment.save_implied_bounds(body_id.hir_id); + + self.visit_body(body); + self.visit_region_obligations(body_id.hir_id); + + // Restore state from previous function. + self.outlives_environment.pop_snapshot_post_closure(env_snapshot); + self.body_id = old_body_id; + self.body_owner = old_body_owner; + } + fn visit_region_obligations(&mut self, hir_id: hir::HirId) { debug!("visit_region_obligations: hir_id={:?}", hir_id); @@ -460,6 +483,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { intravisit::walk_expr(self, expr); } + hir::ExprKind::ConstBlock(anon_const) => { + let body = self.tcx.hir().body(anon_const.body); + self.visit_inline_const(anon_const.hir_id, body); + } + _ => intravisit::walk_expr(self, expr), } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index d951df94dcf50..fdc8b6b5e6451 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -282,6 +282,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::ExprKind::Field(..) => { self.visit_field_id(e.hir_id); } + hir::ExprKind::ConstBlock(anon_const) => { + self.visit_node_id(e.span, anon_const.hir_id); + + let body = self.tcx().hir().body(anon_const.body); + self.visit_body(body); + } _ => {} } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 18e8ed394e814..11666fcc2d84f 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1494,7 +1494,9 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { { Some(parent_def_id.to_def_id()) } - + Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { + Some(tcx.closure_base_def_id(def_id)) + } _ => None, } } @@ -1692,6 +1694,24 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { })); } + // provide junk type parameter defs for const blocks. + if let Node::AnonConst(_) = node { + let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); + if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node { + params.push(ty::GenericParamDef { + index: type_start, + name: Symbol::intern(""), + def_id, + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Type { + has_default: false, + object_lifetime_default: rl::Set1::Empty, + synthetic: None, + }, + }); + } + } + let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index a6ea8abdf3fa6..04a68250ced0c 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -494,7 +494,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. }) if anon_const.hir_id == hir_id => { - tcx.typeck(def_id).node_type(anon_const.hir_id) + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + substs.as_inline_const().ty() } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) From 4acef9ac19133e7cd3a0648ab6395c7c4eb3031f Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 3 Oct 2021 16:03:34 +0100 Subject: [PATCH 3/8] Add unit test for issue 78132 --- src/test/ui/inline-const/const-expr-inference.rs | 12 ++++++++++++ .../ui/inline-const/const-match-pat-inference.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/ui/inline-const/const-expr-inference.rs create mode 100644 src/test/ui/inline-const/const-match-pat-inference.rs diff --git a/src/test/ui/inline-const/const-expr-inference.rs b/src/test/ui/inline-const/const-expr-inference.rs new file mode 100644 index 0000000000000..6aa2a2f3367fc --- /dev/null +++ b/src/test/ui/inline-const/const-expr-inference.rs @@ -0,0 +1,12 @@ +// check-pass + +#![feature(inline_const)] +#![allow(incomplete_features)] + +pub fn todo() -> T { + const { todo!() } +} + +fn main() { + let _: usize = const { 0 }; +} diff --git a/src/test/ui/inline-const/const-match-pat-inference.rs b/src/test/ui/inline-const/const-match-pat-inference.rs new file mode 100644 index 0000000000000..61188ed5d47bd --- /dev/null +++ b/src/test/ui/inline-const/const-match-pat-inference.rs @@ -0,0 +1,12 @@ +// check-pass + +#![feature(inline_const)] +#![allow(incomplete_features)] + +fn main() { + match 1u64 { + 0 => (), + const { 0 + 1 } => (), + const { 2 - 1 } ..= const { u64::MAX } => (), + } +} From 1d32b201707ce6327c0ab322c4e06d8e0367f563 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 3 Oct 2021 16:04:30 +0100 Subject: [PATCH 4/8] Add unit test for issue 78174 --- .../ui/inline-const/const-expr-lifetime.rs | 36 +++++++++++++++++++ .../inline-const/const-match-pat-lifetime.rs | 36 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/test/ui/inline-const/const-expr-lifetime.rs create mode 100644 src/test/ui/inline-const/const-match-pat-lifetime.rs diff --git a/src/test/ui/inline-const/const-expr-lifetime.rs b/src/test/ui/inline-const/const-expr-lifetime.rs new file mode 100644 index 0000000000000..f622f2cbddf48 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-lifetime.rs @@ -0,0 +1,36 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(const_mut_refs)] +#![feature(inline_const)] + +use std::marker::PhantomData; + +// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid" +fn issue_78174() { + let foo = const { "foo" }; + assert_eq!(foo, "foo"); +} + +pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); + +impl<'a, T: ?Sized> InvariantRef<'a, T> { + pub const fn new(r: &'a T) -> Self { + InvariantRef(r, PhantomData) + } +} + +fn get_invariant_ref<'a>() -> InvariantRef<'a, ()> { + const { InvariantRef::<'a, ()>::new(&()) } +} + +fn get_invariant_ref2<'a>() -> InvariantRef<'a, ()> { + // Try some type inference + const { InvariantRef::new(&()) } +} + +fn main() { + issue_78174(); + get_invariant_ref(); + get_invariant_ref2(); +} diff --git a/src/test/ui/inline-const/const-match-pat-lifetime.rs b/src/test/ui/inline-const/const-match-pat-lifetime.rs new file mode 100644 index 0000000000000..3d986f0d9ee08 --- /dev/null +++ b/src/test/ui/inline-const/const-match-pat-lifetime.rs @@ -0,0 +1,36 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(const_mut_refs)] +#![feature(inline_const)] + +use std::marker::PhantomData; + +// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid" +fn issue_78174() { + match "foo" { + const { concat!("fo", "o") } => (), + _ => unreachable!(), + } +} + +#[derive(PartialEq, Eq)] +pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); + +impl<'a, T: ?Sized> InvariantRef<'a, T> { + pub const fn new(r: &'a T) -> Self { + InvariantRef(r, PhantomData) + } +} + +fn match_invariant_ref<'a>() { + match const { InvariantRef::<'a, _>::new(&()) } { + const { InvariantRef::<'a, ()>::new(&()) } => { + } + } +} + +fn main() { + issue_78174(); + match_invariant_ref(); +} From ff055e2135574a0b795c0bc03144a89b54351af7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 3 Oct 2021 23:14:33 +0100 Subject: [PATCH 5/8] Ensure closure requirements are proven for inline const --- compiler/rustc_borrowck/src/type_check/mod.rs | 84 +++++++++++++++++-- .../inline-const/const-expr-lifetime-err.rs | 30 +++++++ .../const-expr-lifetime-err.stderr | 18 ++++ 3 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/inline-const/const-expr-lifetime-err.rs create mode 100644 src/test/ui/inline-const/const-expr-lifetime-err.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9e068ef716504..890f1235a9d43 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::vec_map::VecMap; use rustc_errors::struct_span_err; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; @@ -1532,6 +1533,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { + self.check_operand(discr, term_location); + let discr_ty = discr.ty(body, tcx); if let Err(terr) = self.sub_types( discr_ty, @@ -1554,6 +1557,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // FIXME: check the values } TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { + self.check_operand(func, term_location); + for arg in args { + self.check_operand(arg, term_location); + } + let func_ty = func.ty(body, tcx); debug!("check_terminator: call, func_ty={:?}", func_ty); let sig = match func_ty.kind() { @@ -1598,6 +1606,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); } TerminatorKind::Assert { ref cond, ref msg, .. } => { + self.check_operand(cond, term_location); + let cond_ty = cond.ty(body, tcx); if cond_ty != tcx.types.bool { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); @@ -1613,6 +1623,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } TerminatorKind::Yield { ref value, .. } => { + self.check_operand(value, term_location); + let value_ty = value.ty(body, tcx); match body.yield_ty() { None => span_mirbug!(self, term, "yield in non-generator"), @@ -1941,15 +1953,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { + if let Operand::Constant(constant) = op { + let maybe_uneval = match constant.literal { + ConstantKind::Ty(ct) => match ct.val { + ty::ConstKind::Unevaluated(uv) => Some(uv), + _ => None, + }, + _ => None, + }; + if let Some(uv) = maybe_uneval { + if uv.promoted.is_none() { + let tcx = self.tcx(); + let def_id = uv.def.def_id_for_type_of(); + if tcx.def_kind(def_id) == DefKind::InlineConst { + let predicates = self.prove_closure_bounds( + tcx, + def_id.expect_local(), + uv.substs(tcx), + location, + ); + self.normalize_and_prove_instantiated_predicates( + def_id, + predicates, + location.to_locations(), + ); + } + } + } + } + } + fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { let tcx = self.tcx(); match rvalue { Rvalue::Aggregate(ak, ops) => { + for op in ops { + self.check_operand(op, location); + } self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) } Rvalue::Repeat(operand, len) => { + self.check_operand(operand, location); + // If the length cannot be evaluated we must assume that the length can be larger // than 1. // If the length is larger than 1, the repeat expression will need to copy the @@ -2000,7 +2048,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => { + Rvalue::NullaryOp(_, ty) => { + let trait_ref = ty::TraitRef { + def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + substs: tcx.mk_substs_trait(ty, &[]), + }; + + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); + } + + Rvalue::ShallowInitBox(operand, ty) => { + self.check_operand(operand, location); + let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2014,6 +2077,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Rvalue::Cast(cast_kind, op, ty) => { + self.check_operand(op, location); + match cast_kind { CastKind::Pointer(PointerCast::ReifyFnPointer) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); @@ -2260,6 +2325,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, box (left, right), ) => { + self.check_operand(left, location); + self.check_operand(right, location); + let ty_left = left.ty(body, tcx); match ty_left.kind() { // Types with regions are comparable if they have a common super-type. @@ -2310,13 +2378,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => { + self.check_operand(operand, location); + } + + Rvalue::BinaryOp(_, box (left, right)) + | Rvalue::CheckedBinaryOp(_, box (left, right)) => { + self.check_operand(left, location); + self.check_operand(right, location); + } + Rvalue::AddressOf(..) | Rvalue::ThreadLocalRef(..) - | Rvalue::Use(..) | Rvalue::Len(..) - | Rvalue::BinaryOp(..) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) => {} } } diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.rs b/src/test/ui/inline-const/const-expr-lifetime-err.rs new file mode 100644 index 0000000000000..e56cbc94038a0 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-lifetime-err.rs @@ -0,0 +1,30 @@ +#![allow(incomplete_features)] +#![feature(const_mut_refs)] +#![feature(inline_const)] + +use std::marker::PhantomData; + +#[derive(PartialEq, Eq)] +pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); + +impl<'a, T: ?Sized> InvariantRef<'a, T> { + pub const fn new(r: &'a T) -> Self { + InvariantRef(r, PhantomData) + } +} + +impl<'a> InvariantRef<'a, ()> { + pub const NEW: Self = InvariantRef::new(&()); +} + +fn equate(x: T, y: T){} + +fn foo<'a>() { + let y = (); + equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW }); + //~^ ERROR `y` does not live long enough [E0597] +} + +fn main() { + foo(); +} diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.stderr b/src/test/ui/inline-const/const-expr-lifetime-err.stderr new file mode 100644 index 0000000000000..30ecd338a856d --- /dev/null +++ b/src/test/ui/inline-const/const-expr-lifetime-err.stderr @@ -0,0 +1,18 @@ +error[E0597]: `y` does not live long enough + --> $DIR/const-expr-lifetime-err.rs:24:30 + | +LL | fn foo<'a>() { + | -- lifetime `'a` defined here +LL | let y = (); +LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW }); + | ------------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `y` is borrowed for `'a` +LL | +LL | } + | - `y` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 4060ed7eff2dfb38ee8f9e3d2806f9d82c2cfc65 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 3 Oct 2021 16:05:55 +0100 Subject: [PATCH 6/8] Add a FIXME note about what's missing --- .../const-match-pat-lifetime-err.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/ui/inline-const/const-match-pat-lifetime-err.rs diff --git a/src/test/ui/inline-const/const-match-pat-lifetime-err.rs b/src/test/ui/inline-const/const-match-pat-lifetime-err.rs new file mode 100644 index 0000000000000..bc5aa24894427 --- /dev/null +++ b/src/test/ui/inline-const/const-match-pat-lifetime-err.rs @@ -0,0 +1,34 @@ +// ignore-test + +#![allow(incomplete_features)] +#![feature(const_mut_refs)] +#![feature(inline_const)] + +use std::marker::PhantomData; + +#[derive(PartialEq, Eq)] +pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); + +impl<'a, T: ?Sized> InvariantRef<'a, T> { + pub const fn new(r: &'a T) -> Self { + InvariantRef(r, PhantomData) + } +} + +impl<'a> InvariantRef<'a, ()> { + pub const NEW: Self = InvariantRef::new(&()); +} + +fn match_invariant_ref<'a>() { + let y = (); + match InvariantRef::new(&y) { + //~^ ERROR `y` does not live long enough [E0597] + // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without + // const block) + const { InvariantRef::<'a>::NEW } => (), + } +} + +fn main() { + match_invariant_ref(); +} From d0f59f6d6575e04d3e4d08e919ce01e29bc9e41e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 24 Oct 2021 00:26:40 +0100 Subject: [PATCH 7/8] Fix closures within inline const --- compiler/rustc_typeck/src/check/upvar.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 774d8078e52ca..5f5d308a3329b 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -148,10 +148,17 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind { - let body = self.fcx.tcx.hir().body(body_id); - self.visit_body(body); - self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc); + match expr.kind { + hir::ExprKind::Closure(cc, _, body_id, _, _) => { + let body = self.fcx.tcx.hir().body(body_id); + self.visit_body(body); + self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc); + } + hir::ExprKind::ConstBlock(anon_const) => { + let body = self.fcx.tcx.hir().body(anon_const.body); + self.visit_body(body); + } + _ => {} } intravisit::walk_expr(self, expr); From c4103d438fa922edbe5c40085f40b96656c6b18a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 6 Nov 2021 20:01:35 +0000 Subject: [PATCH 8/8] Rename functions reflect that inline const is also "typeck_child" --- .../src/diagnostics/conflict_errors.rs | 2 +- compiler/rustc_borrowck/src/nll.rs | 2 +- .../rustc_borrowck/src/region_infer/mod.rs | 5 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 15 ++----- .../rustc_borrowck/src/universal_regions.rs | 40 +++++++++---------- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 2 +- .../rustc_infer/src/infer/outlives/env.rs | 8 ++-- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 10 ++--- compiler/rustc_middle/src/ty/util.rs | 9 +++-- .../rustc_monomorphize/src/polymorphize.rs | 2 +- compiler/rustc_passes/src/region.rs | 6 +-- .../src/traits/error_reporting/suggestions.rs | 2 +- compiler/rustc_typeck/src/check/closure.rs | 2 +- compiler/rustc_typeck/src/check/mod.rs | 12 +++--- compiler/rustc_typeck/src/check/regionck.rs | 8 ++-- compiler/rustc_typeck/src/collect.rs | 4 +- src/librustdoc/core.rs | 6 +-- 18 files changed, 64 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 439c728798d3a..46a3c0fa10152 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -408,7 +408,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let param = generics.type_param(¶m_ty, tcx); if let Some(generics) = tcx .hir() - .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id())) + .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id())) { suggest_constraining_type_param( tcx, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index e5924f9d08478..6ffab16577908 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( errors_buffer: &mut Vec, ) { let tcx = infcx.tcx; - let base_def_id = tcx.closure_base_def_id(body.source.def_id()); + let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); if !tcx.has_attr(base_def_id, sym::rustc_regions) { return; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 053e5c33313cc..b39a28f79aadd 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -569,8 +569,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // to store those. Otherwise, we'll pass in `None` to the // functions below, which will trigger them to report errors // eagerly. - let mut outlives_requirements = - infcx.tcx.is_closure_or_inline_const(mir_def_id).then(Vec::new); + let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new); self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer); @@ -2230,7 +2229,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx tcx, closure_substs, self.num_external_vids, - tcx.closure_base_def_id(closure_def_id), + tcx.typeck_root_def_id(closure_def_id), ); debug!("apply_requirements: closure_mapping={:?}", closure_mapping); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 890f1235a9d43..82f68605b281f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1344,18 +1344,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // though. let category = match place.as_local() { Some(RETURN_PLACE) => { - if let BorrowCheckContext { - universal_regions: - UniversalRegions { - defining_ty: - DefiningTy::Const(def_id, _) - | DefiningTy::InlineConst(def_id, _), - .. - }, - .. - } = self.borrowck_context - { - if tcx.is_static(*def_id) { + let defining_ty = &self.borrowck_context.universal_regions.defining_ty; + if defining_ty.is_const() { + if tcx.is_static(defining_ty.def_id()) { ConstraintCategory::UseAsStatic } else { ConstraintCategory::UseAsConst diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index ab8725834376c..b986df403f9f3 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -247,7 +247,7 @@ impl<'tcx> UniversalRegions<'tcx> { tcx: TyCtxt<'tcx>, closure_substs: SubstsRef<'tcx>, expected_num_vars: usize, - closure_base_def_id: DefId, + typeck_root_def_id: DefId, ) -> IndexVec> { let mut region_mapping = IndexVec::with_capacity(expected_num_vars); region_mapping.push(tcx.lifetimes.re_static); @@ -255,7 +255,7 @@ impl<'tcx> UniversalRegions<'tcx> { region_mapping.push(fr); }); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { region_mapping.push(r); }); @@ -349,8 +349,8 @@ impl<'tcx> UniversalRegions<'tcx> { // tests, and the resulting print-outs include def-ids // and other things that are not stable across tests! // So we just include the region-vid. Annoying. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); }); } @@ -364,8 +364,8 @@ impl<'tcx> UniversalRegions<'tcx> { // FIXME: As above, we'd like to print out the region // `r` but doing so is not stable across architectures // and so forth. - let closure_base_def_id = tcx.closure_base_def_id(def_id); - for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| { + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| { err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); }); } @@ -422,7 +422,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let mut indices = self.compute_indices(fr_static, defining_ty); debug!("build: indices={:?}", indices); - let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); // If this is a closure or generator, then the late-bound regions from the enclosing // function are actually external regions to us. For example, here, 'a is not local @@ -430,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // fn foo<'a>() { // let c = || { let x: &'a u32 = ...; } // } - if self.mir_def.did.to_def_id() != closure_base_def_id { + if self.mir_def.did.to_def_id() != typeck_root_def_id { self.infcx .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices) } @@ -448,7 +448,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ); // Converse of above, if this is a function then the late-bound regions declared on its // signature are local to the fn. - if self.mir_def.did.to_def_id() == closure_base_def_id { + if self.mir_def.did.to_def_id() == typeck_root_def_id { self.infcx .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); } @@ -513,12 +513,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { /// see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); match tcx.hir().body_owner_kind(self.mir_hir_id) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id { - tcx.type_of(closure_base_def_id) + let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id { + tcx.type_of(typeck_root_def_id) } else { let tables = tcx.typeck(self.mir_def.did); tables.node_type(self.mir_hir_id) @@ -545,8 +545,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); - if self.mir_def.did.to_def_id() == closure_base_def_id { + let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); + if self.mir_def.did.to_def_id() == typeck_root_def_id { let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); DefiningTy::Const(self.mir_def.did.to_def_id(), substs) @@ -574,19 +574,19 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> UniversalRegionIndices<'tcx> { let tcx = self.infcx.tcx; - let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id()); - let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); + let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id); let fr_substs = match defining_ty { DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) | DefiningTy::InlineConst(_, ref substs) => { // In the case of closures, we rely on the fact that // the first N elements in the ClosureSubsts are - // inherited from the `closure_base_def_id`. + // inherited from the `typeck_root_def_id`. // Therefore, when we zip together (below) with // `identity_substs`, we will get only those regions // that correspond to early-bound regions declared on - // the `closure_base_def_id`. + // the `typeck_root_def_id`. assert!(substs.len() >= identity_substs.len()); assert_eq!(substs.regions().count(), identity_substs.regions().count()); substs @@ -765,8 +765,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { indices: &mut UniversalRegionIndices<'tcx>, ) { debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); - let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id()); - for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| { + let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id()); + for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| { debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); if !indices.indices.contains_key(&r) { let region_vid = self.next_nll_region_var(FR); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 1f1bd73c7d035..2a6bf7d9b1a4d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -322,7 +322,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { type_names::push_item_name(self.tcx(), def_id, false, &mut name); // Find the enclosing function, in case this is a closure. - let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id); + let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 9e04773c5fa20..3947282aa6217 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { /// function. We can then add implied bounds and the like from the /// closure arguments into the environment -- these should only /// apply in the closure body, so once we exit, we invoke - /// `pop_snapshot_post_closure` to remove them. + /// `pop_snapshot_post_typeck_child` to remove them. /// /// Example: /// @@ -129,12 +129,12 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { /// seems like it'd be readily fixed if we wanted. There are /// similar leaks around givens that seem equally suspicious, to /// be honest. --nmatsakis - pub fn push_snapshot_pre_closure(&self) -> usize { + pub fn push_snapshot_pre_typeck_child(&self) -> usize { self.region_bound_pairs_accum.len() } - /// See `push_snapshot_pre_closure`. - pub fn pop_snapshot_post_closure(&mut self, len: usize) { + /// See `push_snapshot_pre_typeck_child`. + pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) { self.region_bound_pairs_accum.truncate(len); } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b0952d346766c..a9f94b74c5efb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -797,7 +797,7 @@ rustc_queries! { /// additional requirements that the closure's creator must verify. query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } - cache_on_disk_if(tcx) { tcx.is_closure_or_inline_const(key.to_def_id()) } + cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) } } query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { desc { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 080ef6cb82a0f..27e22ccac02a7 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -56,7 +56,7 @@ impl<'tcx> Const<'tcx> { let ty = tcx.type_of(def.def_id_for_type_of()); - match Self::try_eval_body_expr(tcx, ty, expr) { + match Self::try_eval_lit_or_param(tcx, ty, expr) { Some(v) => v, None => tcx.mk_const(ty::Const { val: ty::ConstKind::Unevaluated(ty::Unevaluated { @@ -69,7 +69,7 @@ impl<'tcx> Const<'tcx> { } } - fn try_eval_body_expr( + fn try_eval_lit_or_param( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>, @@ -141,12 +141,12 @@ impl<'tcx> Const<'tcx> { let ty = tcx.typeck(def_id).node_type(hir_id); - let ret = match Self::try_eval_body_expr(tcx, ty, expr) { + let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) { Some(v) => v, None => { - let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); let parent_substs = - tcx.erase_regions(InternalSubsts::identity_for_item(tcx, outer_def_id)); + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); let substs = InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty }) .substs; diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index d5b78820411be..6b287445ff032 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -423,8 +423,9 @@ impl<'tcx> TyCtxt<'tcx> { matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator) } - /// Returns `true` if `def_id` refers to a closure, generator or inline const. - pub fn is_closure_or_inline_const(self, def_id: DefId) -> bool { + /// Returns `true` if `def_id` refers to a definition that does not have its own + /// type-checking context, i.e. closure, generator or inline const. + pub fn is_typeck_child(self, def_id: DefId) -> bool { matches!( self.def_kind(def_id), DefKind::Closure | DefKind::Generator | DefKind::InlineConst @@ -458,9 +459,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Therefore, when we fetch the /// `typeck` the closure, for example, we really wind up /// fetching the `typeck` the enclosing fn item. - pub fn closure_base_def_id(self, def_id: DefId) -> DefId { + pub fn typeck_root_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; - while self.is_closure_or_inline_const(def_id) { + while self.is_typeck_child(def_id) { def_id = self.parent(def_id).unwrap_or_else(|| { bug!("closure {:?} has no parent", def_id); }); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index ba62a6eea10ea..595080619da6f 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -196,7 +196,7 @@ fn emit_unused_generic_params_error<'tcx>( generics: &'tcx ty::Generics, unused_parameters: &FiniteBitSet, ) { - let base_def_id = tcx.closure_base_def_id(def_id); + let base_def_id = tcx.typeck_root_def_id(def_id); if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) { return; } diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index 40905c1f8affc..6a8feb041da19 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -818,9 +818,9 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { } fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { - let closure_base_def_id = tcx.closure_base_def_id(def_id); - if closure_base_def_id != def_id { - return tcx.region_scope_tree(closure_base_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + if typeck_root_def_id != def_id { + return tcx.region_scope_tree(typeck_root_def_id); } let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 2689e2134fc6b..b21936a00b04f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1474,7 +1474,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = self.tcx.def_span(generator_did); let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()); - let generator_did_root = self.tcx.closure_base_def_id(generator_did); + let generator_did_root = self.tcx.typeck_root_def_id(generator_did); debug!( "maybe_note_obligation_cause_for_async_await: generator_did={:?} \ generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}", diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 410ac24b1f19c..f7accbb430caa 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -92,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_substs = InternalSubsts::identity_for_item( self.tcx, - self.tcx.closure_base_def_id(expr_def_id.to_def_id()), + self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), ); let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 7450b4a4ef1c3..d19e99606bcd8 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -297,9 +297,9 @@ fn primary_body_of( fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id); - if outer_def_id != def_id { - return tcx.has_typeck_results(outer_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id); + if typeck_root_def_id != def_id { + return tcx.has_typeck_results(typeck_root_def_id); } if let Some(def_id) = def_id.as_local() { @@ -348,9 +348,9 @@ fn typeck_with_fallback<'tcx>( ) -> &'tcx ty::TypeckResults<'tcx> { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); - if outer_def_id != def_id { - return tcx.typeck(outer_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); + if typeck_root_def_id != def_id { + return tcx.typeck(typeck_root_def_id); } let id = tcx.hir().local_def_id_to_hir_id(def_id); diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 52faf5fbe9fb3..d2d8b14dd9695 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -347,7 +347,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { // Save state of current function. We will restore afterwards. let old_body_id = self.body_id; let old_body_owner = self.body_owner; - let env_snapshot = self.outlives_environment.push_snapshot_pre_closure(); + let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); let body_id = body.id(); self.body_id = body_id.hir_id; @@ -359,7 +359,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.visit_region_obligations(body_id.hir_id); // Restore state from previous function. - self.outlives_environment.pop_snapshot_post_closure(env_snapshot); + self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); self.body_id = old_body_id; self.body_owner = old_body_owner; } @@ -429,13 +429,13 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { // `visit_fn_body`. We will restore afterwards. let old_body_id = self.body_id; let old_body_owner = self.body_owner; - let env_snapshot = self.outlives_environment.push_snapshot_pre_closure(); + let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child(); let body = self.tcx.hir().body(body_id); self.visit_fn_body(hir_id, body, span); // Restore state from previous function. - self.outlives_environment.pop_snapshot_post_closure(env_snapshot); + self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot); self.body_id = old_body_id; self.body_owner = old_body_owner; } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 11666fcc2d84f..2274db76c05fb 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1495,14 +1495,14 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { Some(parent_def_id.to_def_id()) } Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => { - Some(tcx.closure_base_def_id(def_id)) + Some(tcx.typeck_root_def_id(def_id)) } _ => None, } } } Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { - Some(tcx.closure_base_def_id(def_id)) + Some(tcx.typeck_root_def_id(def_id)) } Node::Item(item) => match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b7251e8f57151..3ed711c43e16d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -281,9 +281,9 @@ crate fn create_config( // Closures' tables come from their outermost function, // as they are part of the same "inference environment". // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`) - let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); - if outer_def_id != def_id { - return tcx.typeck(outer_def_id); + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); + if typeck_root_def_id != def_id { + return tcx.typeck(typeck_root_def_id); } let hir = tcx.hir();