Implement type inference for inline consts

In most cases it is handled in the same way as closures.
This commit is contained in:
Gary Guo 2021-10-02 13:12:33 +01:00
parent 02c1774cd3
commit 468192a9c5
18 changed files with 299 additions and 43 deletions

View File

@ -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);

View File

@ -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
{

View File

@ -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]))
}
}
}
}

View File

@ -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 {

View File

@ -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.

View File

@ -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;

View File

@ -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> {

View File

@ -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))

View File

@ -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);
});

View File

@ -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 }
}

View File

@ -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));

View File

@ -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);
}

View File

@ -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>,

View File

@ -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,
},

View File

@ -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),
}
}

View File

@ -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);
}
_ => {}
}

View File

@ -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 {

View File

@ -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), .. })