mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Implement type inference for inline consts
In most cases it is handled in the same way as closures.
This commit is contained in:
parent
02c1774cd3
commit
468192a9c5
@ -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);
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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), .. })
|
||||
|
Loading…
Reference in New Issue
Block a user