diff options
| -rw-r--r-- | compiler/rustc_borrowck/src/region_infer/mod.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/type_check/mod.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/universal_regions.rs | 49 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/consts.rs | 79 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/sty.rs | 60 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/subst.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/util.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/region.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/expr.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/pat.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/regionck.rs | 28 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/writeback.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/collect.rs | 22 | ||||
| -rw-r--r-- | 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 f4a5da1fe36..053e5c33313 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 7e6a481ca69..9e068ef7165 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 147e2aead64..ab872583437 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 06041bbb02d..b0952d34676 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 869b2ab9dbc..080ef6cb82a 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 26bae1e15a3..40670f1fdca 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 874de3366d7..e57075ed338 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 2438d1a1602..73a8e18949d 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 2c884813d23..d5b78820411 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 17296a95bc1..b4005ccd1cc 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 cb74ae4df2e..ce80214c875 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 5fc8e230d72..40905c1f8af 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 2d0a4068fbb..c03ae17b172 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 5aa11cce25f..cbf33cf1b78 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 86d4e4d2b11..52faf5fbe9f 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 d951df94dcf..fdc8b6b5e64 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 18e8ed394e8..11666fcc2d8 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("<const_ty>"), + 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 a6ea8abdf3f..04a68250ced 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), .. }) |
