1
Fork 0

Rollup merge of #89561 - nbdd0121:const_typeck, r=nikomatsakis

Type inference for inline consts

Fixes #78132
Fixes #78174
Fixes #81857
Fixes #89964

Perform type checking/inference of inline consts in the same context as the outer def, similar to what is currently done to closure.

Doing so would require `closure_base_def_id` of the inline const to return the outer def, and since `closure_base_def_id` can be called on non-local crate (and thus have no HIR available), a new `DefKind` is created for inline consts.

The type of the generated anon const can capture lifetime of outer def, so we couldn't just use the typeck result as the type of the inline const's def. Closure has a similar issue, and it uses extra type params `CK, CS, U` to capture closure kind, input/output signature and upvars. I use a similar approach for inline consts, letting it have an extra type param `R`, and then `typeof(InlineConst<[paremt generics], R>)` would just be `R`. In borrowck region requirements are also propagated to the outer MIR body just like it's currently done for closure.

With this PR, inline consts in expression position are quitely usable now; however the usage in pattern position is still incomplete -- since those does not remain in the MIR borrowck couldn't verify the lifetime there. I have left an ignored test as a FIXME.

Some disucssions can be found on [this Zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/260443-project-const-generics/topic/inline.20consts.20typeck).
cc `````@spastorino````` `````@lcnr`````
r? `````@nikomatsakis`````

`````@rustbot````` label A-inference F-inline_const T-compiler
This commit is contained in:
Matthias Krüger 2021-11-09 19:00:40 +01:00 committed by GitHub
commit fd74c93403
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 656 additions and 119 deletions

View file

@ -408,7 +408,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let param = generics.type_param(&param_ty, tcx); let param = generics.type_param(&param_ty, tcx);
if let Some(generics) = tcx if let Some(generics) = tcx
.hir() .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( suggest_constraining_type_param(
tcx, tcx,

View file

@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
errors_buffer: &mut Vec<Diagnostic>, errors_buffer: &mut Vec<Diagnostic>,
) { ) {
let tcx = infcx.tcx; 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) { if !tcx.has_attr(base_def_id, sym::rustc_regions) {
return; return;
} }

View file

@ -569,7 +569,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// to store those. Otherwise, we'll pass in `None` to the // to store those. Otherwise, we'll pass in `None` to the
// functions below, which will trigger them to report errors // functions below, which will trigger them to report errors
// eagerly. // eagerly.
let mut outlives_requirements = infcx.tcx.is_closure(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); self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
@ -2229,7 +2229,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
tcx, tcx,
closure_substs, closure_substs,
self.num_external_vids, 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); debug!("apply_requirements: closure_mapping={:?}", closure_mapping);

View file

@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::vec_map::VecMap; use rustc_data_structures::vec_map::VecMap;
use rustc_errors::struct_span_err; use rustc_errors::struct_span_err;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec}; use rustc_index::vec::{Idx, IndexVec};
@ -1343,13 +1344,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// though. // though.
let category = match place.as_local() { let category = match place.as_local() {
Some(RETURN_PLACE) => { Some(RETURN_PLACE) => {
if let BorrowCheckContext { let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
universal_regions: if defining_ty.is_const() {
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, if tcx.is_static(defining_ty.def_id()) {
..
} = self.borrowck_context
{
if tcx.is_static(*def_id) {
ConstraintCategory::UseAsStatic ConstraintCategory::UseAsStatic
} else { } else {
ConstraintCategory::UseAsConst ConstraintCategory::UseAsConst
@ -1527,6 +1524,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
} }
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => { TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
self.check_operand(discr, term_location);
let discr_ty = discr.ty(body, tcx); let discr_ty = discr.ty(body, tcx);
if let Err(terr) = self.sub_types( if let Err(terr) = self.sub_types(
discr_ty, discr_ty,
@ -1549,6 +1548,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// FIXME: check the values // FIXME: check the values
} }
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => { 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); let func_ty = func.ty(body, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty); debug!("check_terminator: call, func_ty={:?}", func_ty);
let sig = match func_ty.kind() { let sig = match func_ty.kind() {
@ -1593,6 +1597,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call); self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
} }
TerminatorKind::Assert { ref cond, ref msg, .. } => { TerminatorKind::Assert { ref cond, ref msg, .. } => {
self.check_operand(cond, term_location);
let cond_ty = cond.ty(body, tcx); let cond_ty = cond.ty(body, tcx);
if cond_ty != tcx.types.bool { if cond_ty != tcx.types.bool {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
@ -1608,6 +1614,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
} }
TerminatorKind::Yield { ref value, .. } => { TerminatorKind::Yield { ref value, .. } => {
self.check_operand(value, term_location);
let value_ty = value.ty(body, tcx); let value_ty = value.ty(body, tcx);
match body.yield_ty() { match body.yield_ty() {
None => span_mirbug!(self, term, "yield in non-generator"), None => span_mirbug!(self, term, "yield in non-generator"),
@ -1650,7 +1658,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Some(RETURN_PLACE) => { Some(RETURN_PLACE) => {
if let BorrowCheckContext { if let BorrowCheckContext {
universal_regions: universal_regions:
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. }, UniversalRegions {
defining_ty:
DefiningTy::Const(def_id, _)
| DefiningTy::InlineConst(def_id, _),
..
},
.. ..
} = self.borrowck_context } = self.borrowck_context
{ {
@ -1931,15 +1944,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) { fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
let tcx = self.tcx(); let tcx = self.tcx();
match rvalue { match rvalue {
Rvalue::Aggregate(ak, ops) => { Rvalue::Aggregate(ak, ops) => {
for op in ops {
self.check_operand(op, location);
}
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location) self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
} }
Rvalue::Repeat(operand, len) => { Rvalue::Repeat(operand, len) => {
self.check_operand(operand, location);
// If the length cannot be evaluated we must assume that the length can be larger // If the length cannot be evaluated we must assume that the length can be larger
// than 1. // than 1.
// If the length is larger than 1, the repeat expression will need to copy the // If the length is larger than 1, the repeat expression will need to copy the
@ -1990,7 +2039,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 { let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]), substs: tcx.mk_substs_trait(ty, &[]),
@ -2004,6 +2068,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
Rvalue::Cast(cast_kind, op, ty) => { Rvalue::Cast(cast_kind, op, ty) => {
self.check_operand(op, location);
match cast_kind { match cast_kind {
CastKind::Pointer(PointerCast::ReifyFnPointer) => { CastKind::Pointer(PointerCast::ReifyFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx); let fn_sig = op.ty(body, tcx).fn_sig(tcx);
@ -2250,6 +2316,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
box (left, right), box (left, right),
) => { ) => {
self.check_operand(left, location);
self.check_operand(right, location);
let ty_left = left.ty(body, tcx); let ty_left = left.ty(body, tcx);
match ty_left.kind() { match ty_left.kind() {
// Types with regions are comparable if they have a common super-type. // Types with regions are comparable if they have a common super-type.
@ -2300,13 +2369,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::AddressOf(..)
| Rvalue::ThreadLocalRef(..) | Rvalue::ThreadLocalRef(..)
| Rvalue::Use(..)
| Rvalue::Len(..) | Rvalue::Len(..)
| Rvalue::BinaryOp(..)
| Rvalue::CheckedBinaryOp(..)
| Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => {} | Rvalue::Discriminant(..) => {}
} }
} }

View file

@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; 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 std::iter;
use crate::nll::ToRegionVid; 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 /// is that it has no inputs and a single return value, which is
/// the value of the constant. /// the value of the constant.
Const(DefId, SubstsRef<'tcx>), 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> { impl<'tcx> DefiningTy<'tcx> {
@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> {
DefiningTy::Generator(_, substs, _) => { DefiningTy::Generator(_, substs, _) => {
Either::Right(Either::Left(substs.as_generator().upvar_tys())) 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())) Either::Right(Either::Right(iter::empty()))
} }
} }
@ -133,7 +137,7 @@ impl<'tcx> DefiningTy<'tcx> {
pub fn implicit_inputs(self) -> usize { pub fn implicit_inputs(self) -> usize {
match self { match self {
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1, 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 { pub fn is_const(&self) -> bool {
matches!(*self, DefiningTy::Const(..)) matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
} }
pub fn def_id(&self) -> DefId { pub fn def_id(&self) -> DefId {
@ -150,7 +154,8 @@ impl<'tcx> DefiningTy<'tcx> {
DefiningTy::Closure(def_id, ..) DefiningTy::Closure(def_id, ..)
| DefiningTy::Generator(def_id, ..) | DefiningTy::Generator(def_id, ..)
| DefiningTy::FnDef(def_id, ..) | DefiningTy::FnDef(def_id, ..)
| DefiningTy::Const(def_id, ..) => def_id, | DefiningTy::Const(def_id, ..)
| DefiningTy::InlineConst(def_id, ..) => def_id,
} }
} }
} }
@ -242,7 +247,7 @@ impl<'tcx> UniversalRegions<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
closure_substs: SubstsRef<'tcx>, closure_substs: SubstsRef<'tcx>,
expected_num_vars: usize, expected_num_vars: usize,
closure_base_def_id: DefId, typeck_root_def_id: DefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> { ) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars); let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.lifetimes.re_static); region_mapping.push(tcx.lifetimes.re_static);
@ -250,7 +255,7 @@ impl<'tcx> UniversalRegions<'tcx> {
region_mapping.push(fr); 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); region_mapping.push(r);
}); });
@ -344,8 +349,8 @@ impl<'tcx> UniversalRegions<'tcx> {
// tests, and the resulting print-outs include def-ids // tests, and the resulting print-outs include def-ids
// and other things that are not stable across tests! // and other things that are not stable across tests!
// So we just include the region-vid. Annoying. // So we just include the region-vid. Annoying.
let closure_base_def_id = tcx.closure_base_def_id(def_id); let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
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| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
}); });
} }
@ -359,8 +364,8 @@ impl<'tcx> UniversalRegions<'tcx> {
// FIXME: As above, we'd like to print out the region // FIXME: As above, we'd like to print out the region
// `r` but doing so is not stable across architectures // `r` but doing so is not stable across architectures
// and so forth. // and so forth.
let closure_base_def_id = tcx.closure_base_def_id(def_id); let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
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| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),)); err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
}); });
} }
@ -376,6 +381,12 @@ impl<'tcx> UniversalRegions<'tcx> {
tcx.def_path_str_with_substs(def_id, substs), 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),
));
}
} }
} }
} }
@ -411,7 +422,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let mut indices = self.compute_indices(fr_static, defining_ty); let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices); 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 // 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 // function are actually external regions to us. For example, here, 'a is not local
@ -419,7 +430,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// fn foo<'a>() { // fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; } // 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 self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices) .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
} }
@ -437,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 // Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn. // 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 self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices); .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
} }
@ -502,12 +513,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
/// see `DefiningTy` for details. /// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> { fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.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) { match tcx.hir().body_owner_kind(self.mir_hir_id) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => { BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id { let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
tcx.type_of(closure_base_def_id) tcx.type_of(typeck_root_def_id)
} else { } else {
let tables = tcx.typeck(self.mir_def.did); let tables = tcx.typeck(self.mir_def.did);
tables.node_type(self.mir_hir_id) tables.node_type(self.mir_hir_id)
@ -534,11 +545,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
} }
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { 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, typeck_root_def_id);
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); if self.mir_def.did.to_def_id() == typeck_root_def_id {
let substs = let substs =
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
DefiningTy::Const(self.mir_def.did.to_def_id(), 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)
}
} }
} }
} }
@ -553,17 +574,19 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
defining_ty: DefiningTy<'tcx>, defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> { ) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.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());
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id); let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
let fr_substs = match defining_ty { 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 // In the case of closures, we rely on the fact that
// the first N elements in the ClosureSubsts are // 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 // Therefore, when we zip together (below) with
// `identity_substs`, we will get only those regions // `identity_substs`, we will get only those regions
// that correspond to early-bound regions declared on // 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!(substs.len() >= identity_substs.len());
assert_eq!(substs.regions().count(), identity_substs.regions().count()); assert_eq!(substs.regions().count(), identity_substs.regions().count());
substs substs
@ -648,6 +671,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let ty = indices.fold_to_region_vids(tcx, ty); let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.intern_type_list(&[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]))
}
} }
} }
} }
@ -736,8 +765,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
indices: &mut UniversalRegionIndices<'tcx>, indices: &mut UniversalRegionIndices<'tcx>,
) { ) {
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); 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()); 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, closure_base_def_id, |r| { 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); debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) { if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR); let region_vid = self.next_nll_region_var(FR);

View file

@ -322,7 +322,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
type_names::push_item_name(self.tcx(), def_id, false, &mut name); type_names::push_item_name(self.tcx(), def_id, false, &mut name);
// Find the enclosing function, in case this is a closure. // 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 // Get_template_parameters() will append a `<...>` clause to the function
// name if necessary. // name if necessary.

View file

@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
| DefKind::Static | DefKind::Static
| DefKind::ConstParam | DefKind::ConstParam
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::AssocConst | DefKind::AssocConst
), ),
"Unexpected DefKind: {:?}", "Unexpected DefKind: {:?}",

View file

@ -104,8 +104,10 @@ pub enum DefKind {
Use, Use,
/// An `extern` block. /// An `extern` block.
ForeignMod, 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, AnonConst,
/// An inline constant, e.g. `const { 1 + 2 }`
InlineConst,
/// Opaque type, aka `impl Trait`. /// Opaque type, aka `impl Trait`.
OpaqueTy, OpaqueTy,
Field, Field,
@ -155,6 +157,7 @@ impl DefKind {
DefKind::Use => "import", DefKind::Use => "import",
DefKind::ForeignMod => "foreign module", DefKind::ForeignMod => "foreign module",
DefKind::AnonConst => "constant expression", DefKind::AnonConst => "constant expression",
DefKind::InlineConst => "inline constant",
DefKind::Field => "field", DefKind::Field => "field",
DefKind::Impl => "implementation", DefKind::Impl => "implementation",
DefKind::Closure => "closure", DefKind::Closure => "closure",
@ -174,6 +177,7 @@ impl DefKind {
| DefKind::OpaqueTy | DefKind::OpaqueTy
| DefKind::Impl | DefKind::Impl
| DefKind::Use | DefKind::Use
| DefKind::InlineConst
| DefKind::ExternCrate => "an", | DefKind::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(), DefKind::Macro(macro_kind) => macro_kind.article(),
_ => "a", _ => "a",
@ -207,6 +211,7 @@ impl DefKind {
// Not namespaced. // Not namespaced.
DefKind::AnonConst DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Field | DefKind::Field
| DefKind::LifetimeParam | DefKind::LifetimeParam
| DefKind::ExternCrate | DefKind::ExternCrate

View file

@ -99,7 +99,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
/// function. We can then add implied bounds and the like from the /// function. We can then add implied bounds and the like from the
/// closure arguments into the environment -- these should only /// closure arguments into the environment -- these should only
/// apply in the closure body, so once we exit, we invoke /// 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: /// Example:
/// ///
@ -129,12 +129,12 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
/// seems like it'd be readily fixed if we wanted. There are /// seems like it'd be readily fixed if we wanted. There are
/// similar leaks around givens that seem equally suspicious, to /// similar leaks around givens that seem equally suspicious, to
/// be honest. --nmatsakis /// 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() self.region_bound_pairs_accum.len()
} }
/// See `push_snapshot_pre_closure`. /// See `push_snapshot_pre_typeck_child`.
pub fn pop_snapshot_post_closure(&mut self, len: usize) { pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
self.region_bound_pairs_accum.truncate(len); self.region_bound_pairs_accum.truncate(len);
} }

View file

@ -797,6 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
| DefKind::ConstParam | DefKind::ConstParam
| DefKind::LifetimeParam | DefKind::LifetimeParam
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::GlobalAsm | DefKind::GlobalAsm
| DefKind::Closure | DefKind::Closure
| DefKind::Generator | DefKind::Generator
@ -832,6 +833,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
DefKind::Use DefKind::Use
| DefKind::LifetimeParam | DefKind::LifetimeParam
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::GlobalAsm | DefKind::GlobalAsm
| DefKind::Closure | DefKind::Closure
| DefKind::Generator | DefKind::Generator
@ -856,9 +858,11 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
(true, mir_opt_base) (true, mir_opt_base)
} }
// Constants // Constants
DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => { DefKind::AnonConst
(true, false) | DefKind::InlineConst
} | DefKind::AssocConst
| DefKind::Static
| DefKind::Const => (true, false),
// Full-fledged functions // Full-fledged functions
DefKind::AssocFn | DefKind::Fn => { DefKind::AssocFn | DefKind::Fn => {
let generics = tcx.generics_of(def_id); let generics = tcx.generics_of(def_id);
@ -914,6 +918,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
| DefKind::Use | DefKind::Use
| DefKind::LifetimeParam | DefKind::LifetimeParam
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::GlobalAsm | DefKind::GlobalAsm
| DefKind::Closure | DefKind::Closure
| DefKind::Generator | DefKind::Generator
@ -939,6 +944,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
| DefKind::AssocFn | DefKind::AssocFn
| DefKind::AssocConst | DefKind::AssocConst
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::OpaqueTy | DefKind::OpaqueTy
| DefKind::Impl | DefKind::Impl
| DefKind::Field | DefKind::Field

View file

@ -266,7 +266,15 @@ impl<'hir> Map<'hir> {
}; };
DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data)) 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::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind { Node::Expr(expr) => match expr.kind {
ExprKind::Closure(.., None) => DefKind::Closure, ExprKind::Closure(.., None) => DefKind::Closure,

View file

@ -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 { "" })? write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
} }
(_, _) if is_function => write!(w, "fn ")?, (_, _) 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), _ => bug!("Unexpected def kind {:?}", kind),
} }

View file

@ -797,7 +797,7 @@ rustc_queries! {
/// additional requirements that the closure's creator must verify. /// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> { query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) } 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_typeck_child(key.to_def_id()) }
} }
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> { query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { desc {

View file

@ -1,7 +1,9 @@
use crate::mir::interpret::ConstValue; use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::mir::interpret::{LitToConstInput, Scalar};
use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{
use crate::ty::{ParamEnv, ParamEnvAnd}; self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
TyCtxt, TypeFoldable,
};
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; 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()); let ty = tcx.type_of(def.def_id_for_type_of());
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 {
def: def.to_global(),
substs_: None,
promoted: None,
}),
ty,
}),
}
}
fn try_eval_lit_or_param(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Option<&'tcx Self> {
let lit_input = match expr.kind { let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { 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 // If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir. // mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
return c; return Some(c);
} else { } else {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const"); 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}; 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), .. })) => { 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 // Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`. // 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 generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id]; let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_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 { _ => None,
def: def.to_global(), }
substs_: None, }
promoted: 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_lit_or_param(tcx, ty, expr) {
Some(v) => v,
None => {
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, typeck_root_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. /// Interns the given value as a constant.

View file

@ -74,9 +74,10 @@ pub use self::sty::{
Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
}; };
pub use self::trait_def::TraitDef; pub use self::trait_def::TraitDef;
@ -1927,7 +1928,8 @@ impl<'tcx> TyCtxt<'tcx> {
| DefKind::Static | DefKind::Static
| DefKind::AssocConst | DefKind::AssocConst
| DefKind::Ctor(..) | 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 // 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. // `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => { _ => {

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(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)] #[derive(HashStable, TypeFoldable)]
pub enum ExistentialPredicate<'tcx> { pub enum ExistentialPredicate<'tcx> {

View file

@ -3,7 +3,7 @@
use crate::mir; use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; 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 crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -204,6 +204,14 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
GeneratorSubsts { substs: self } 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. /// Creates an `InternalSubsts` that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { 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)) Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))

View file

@ -423,6 +423,15 @@ impl<'tcx> TyCtxt<'tcx> {
matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator) matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
} }
/// 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
)
}
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
pub fn is_trait(self, def_id: DefId) -> bool { pub fn is_trait(self, def_id: DefId) -> bool {
self.def_kind(def_id) == DefKind::Trait self.def_kind(def_id) == DefKind::Trait
@ -440,16 +449,19 @@ impl<'tcx> TyCtxt<'tcx> {
matches!(self.def_kind(def_id), DefKind::Ctor(..)) matches!(self.def_kind(def_id), DefKind::Ctor(..))
} }
/// Given the def-ID of a fn or closure, returns the def-ID of /// Given the `DefId`, returns the `DefId` of the innermost item that
/// the innermost fn item that the closure is contained within. /// has its own type-checking context or "inference enviornment".
/// This is a significant `DefId` because, when we do ///
/// type-checking, we type-check this fn item and all of its /// For example, a closure has its own `DefId`, but it is type-checked
/// (transitive) closures together. Therefore, when we fetch the /// 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 /// `typeck` the closure, for example, we really wind up
/// fetching the `typeck` the enclosing fn item. /// 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; let mut def_id = def_id;
while self.is_closure(def_id) { while self.is_typeck_child(def_id) {
def_id = self.parent(def_id).unwrap_or_else(|| { def_id = self.parent(def_id).unwrap_or_else(|| {
bug!("closure {:?} has no parent", def_id); bug!("closure {:?} has no parent", def_id);
}); });

View file

@ -578,7 +578,7 @@ impl<'tcx> Cx<'tcx> {
hir::ExprKind::ConstBlock(ref anon_const) => { hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); 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 } ExprKind::ConstBlock { value }
} }

View file

@ -544,7 +544,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let (lit, neg) = match expr.kind { let (lit, neg) = match expr.kind {
hir::ExprKind::ConstBlock(ref anon_const) => { hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); 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(_)) { if matches!(value.val, ConstKind::Param(_)) {
let span = self.tcx.hir().span(anon_const.hir_id); let span = self.tcx.hir().span(anon_const.hir_id);
self.errors.push(PatternError::ConstParamInPattern(span)); self.errors.push(PatternError::ConstParamInPattern(span));

View file

@ -167,6 +167,7 @@ fn mark_used_by_default_parameters<'tcx>(
| DefKind::Use | DefKind::Use
| DefKind::ForeignMod | DefKind::ForeignMod
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::OpaqueTy | DefKind::OpaqueTy
| DefKind::Field | DefKind::Field
| DefKind::LifetimeParam | DefKind::LifetimeParam
@ -195,7 +196,7 @@ fn emit_unused_generic_params_error<'tcx>(
generics: &'tcx ty::Generics, generics: &'tcx ty::Generics,
unused_parameters: &FiniteBitSet<u32>, unused_parameters: &FiniteBitSet<u32>,
) { ) {
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)) { if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
return; return;
} }
@ -303,7 +304,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
ty::ConstKind::Unevaluated(uv) 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)); self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE ControlFlow::CONTINUE

View file

@ -334,9 +334,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// properly, we can't miss any types. // properly, we can't miss any types.
match expr.kind { 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. // 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); let body = visitor.tcx.hir().body(body);
visitor.visit_body(body); visitor.visit_body(body);
} }
@ -817,9 +818,9 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
} }
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree { fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
let closure_base_def_id = tcx.closure_base_def_id(def_id); let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
if closure_base_def_id != def_id { if typeck_root_def_id != def_id {
return tcx.region_scope_tree(closure_base_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()); let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());

View file

@ -618,6 +618,7 @@ impl EmbargoVisitor<'tcx> {
| DefKind::Use | DefKind::Use
| DefKind::ForeignMod | DefKind::ForeignMod
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Field | DefKind::Field
| DefKind::GlobalAsm | DefKind::GlobalAsm
| DefKind::Impl | DefKind::Impl

View file

@ -967,6 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
| DefKind::Use | DefKind::Use
| DefKind::ForeignMod | DefKind::ForeignMod
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Field | DefKind::Field
| DefKind::LifetimeParam | DefKind::LifetimeParam
| DefKind::GlobalAsm | DefKind::GlobalAsm

View file

@ -540,7 +540,7 @@ fn is_late_bound_map<'tcx>(
def_id: LocalDefId, def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> { ) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
match tcx.def_kind(def_id) { match tcx.def_kind(def_id) {
DefKind::AnonConst => { DefKind::AnonConst | DefKind::InlineConst => {
let mut def_id = tcx let mut def_id = tcx
.parent(def_id.to_def_id()) .parent(def_id.to_def_id())
.unwrap_or_else(|| bug!("anon const or closure without a parent")); .unwrap_or_else(|| bug!("anon const or closure without a parent"));

View file

@ -739,6 +739,7 @@ impl<'tcx> SaveContext<'tcx> {
| HirDefKind::ForeignMod | HirDefKind::ForeignMod
| HirDefKind::LifetimeParam | HirDefKind::LifetimeParam
| HirDefKind::AnonConst | HirDefKind::AnonConst
| HirDefKind::InlineConst
| HirDefKind::Use | HirDefKind::Use
| HirDefKind::Field | HirDefKind::Field
| HirDefKind::GlobalAsm | HirDefKind::GlobalAsm

View file

@ -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) { if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
match infcx.tcx.def_kind(uv.def.did) { 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); let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic { 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. // 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. // Right now we do neither of that and simply always fail to unify them.
DefKind::AnonConst => (), DefKind::AnonConst | DefKind::InlineConst => (),
_ => return Ok(None), _ => return Ok(None),
} }

View file

@ -1474,7 +1474,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let span = self.tcx.def_span(generator_did); let span = self.tcx.def_span(generator_did);
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()); 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!( debug!(
"maybe_note_obligation_cause_for_async_await: generator_did={:?} \ "maybe_note_obligation_cause_for_async_await: generator_did={:?} \
generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}", generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",

View file

@ -92,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let parent_substs = InternalSubsts::identity_for_item( let parent_substs = InternalSubsts::identity_for_item(
self.tcx, 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 { let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {

View file

@ -30,6 +30,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder,
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, QPath}; use rustc_hir::{ExprKind, QPath};
use rustc_infer::infer; use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; 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::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr), 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) => { ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr) 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) 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( fn check_expr_repeat(
&self, &self,
element: &'tcx hir::Expr<'tcx>, element: &'tcx hir::Expr<'tcx>,

View file

@ -297,9 +297,9 @@ fn primary_body_of(
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function, // Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment". // as they are part of the same "inference environment".
let outer_def_id = tcx.closure_base_def_id(def_id); let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
if outer_def_id != def_id { if typeck_root_def_id != def_id {
return tcx.has_typeck_results(outer_def_id); return tcx.has_typeck_results(typeck_root_def_id);
} }
if let Some(def_id) = def_id.as_local() { if let Some(def_id) = def_id.as_local() {
@ -348,9 +348,9 @@ fn typeck_with_fallback<'tcx>(
) -> &'tcx ty::TypeckResults<'tcx> { ) -> &'tcx ty::TypeckResults<'tcx> {
// Closures' typeck results come from their outermost function, // Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment". // 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(); let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
if outer_def_id != def_id { if typeck_root_def_id != def_id {
return tcx.typeck(outer_def_id); return tcx.typeck(typeck_root_def_id);
} }
let id = tcx.hir().local_def_id_to_hir_id(def_id); let id = tcx.hir().local_def_id_to_hir_id(def_id);

View file

@ -292,7 +292,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// String and byte-string literals result in types `&str` and `&[u8]` respectively. // String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types. // All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. // 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, ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel, _ => AdjustMode::Peel,
}, },

View file

@ -341,6 +341,29 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
self.visit_region_obligations(body_id.hir_id); 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_typeck_child();
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_typeck_child(env_snapshot);
self.body_id = old_body_id;
self.body_owner = old_body_owner;
}
fn visit_region_obligations(&mut self, hir_id: hir::HirId) { fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
debug!("visit_region_obligations: hir_id={:?}", hir_id); debug!("visit_region_obligations: hir_id={:?}", hir_id);
@ -406,13 +429,13 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
// `visit_fn_body`. We will restore afterwards. // `visit_fn_body`. We will restore afterwards.
let old_body_id = self.body_id; let old_body_id = self.body_id;
let old_body_owner = self.body_owner; 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); let body = self.tcx.hir().body(body_id);
self.visit_fn_body(hir_id, body, span); self.visit_fn_body(hir_id, body, span);
// Restore state from previous function. // 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_id = old_body_id;
self.body_owner = old_body_owner; self.body_owner = old_body_owner;
} }
@ -460,6 +483,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
intravisit::walk_expr(self, expr); 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), _ => intravisit::walk_expr(self, expr),
} }
} }

View file

@ -148,11 +148,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
} }
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind { match expr.kind {
hir::ExprKind::Closure(cc, _, body_id, _, _) => {
let body = self.fcx.tcx.hir().body(body_id); let body = self.fcx.tcx.hir().body(body_id);
self.visit_body(body); self.visit_body(body);
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc); 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); intravisit::walk_expr(self, expr);
} }

View file

@ -282,6 +282,12 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
hir::ExprKind::Field(..) => { hir::ExprKind::Field(..) => {
self.visit_field_id(e.hir_id); 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,13 +1494,15 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
{ {
Some(parent_def_id.to_def_id()) Some(parent_def_id.to_def_id())
} }
Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
Some(tcx.typeck_root_def_id(def_id))
}
_ => None, _ => None,
} }
} }
} }
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { 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 { Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
@ -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(); let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
ty::Generics { 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), .. }) Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
if anon_const.hir_id == hir_id => 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), .. }) Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })

View file

@ -430,8 +430,9 @@ crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
| Res::NonMacroAttr(_) | Res::NonMacroAttr(_)
| Res::Err => return res.def_id(), | Res::Err => return res.def_id(),
Res::Def( Res::Def(
TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
| Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator, | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
| Generator,
id, id,
) => return id, ) => return id,
}; };

View file

@ -265,9 +265,9 @@ crate fn create_config(
// Closures' tables come from their outermost function, // Closures' tables come from their outermost function,
// as they are part of the same "inference environment". // as they are part of the same "inference environment".
// This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`) // 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(); let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
if outer_def_id != def_id { if typeck_root_def_id != def_id {
return tcx.typeck(outer_def_id); return tcx.typeck(typeck_root_def_id);
} }
let hir = tcx.hir(); let hir = tcx.hir();

View file

@ -134,6 +134,7 @@ impl From<DefKind> for ItemType {
| DefKind::Use | DefKind::Use
| DefKind::ForeignMod | DefKind::ForeignMod
| DefKind::AnonConst | DefKind::AnonConst
| DefKind::InlineConst
| DefKind::OpaqueTy | DefKind::OpaqueTy
| DefKind::Field | DefKind::Field
| DefKind::LifetimeParam | DefKind::LifetimeParam

View file

@ -1937,7 +1937,8 @@ fn resolution_failure(
| Use | Use
| LifetimeParam | LifetimeParam
| Ctor(_, _) | Ctor(_, _)
| AnonConst => { | AnonConst
| InlineConst => {
let note = assoc_item_not_allowed(res); let note = assoc_item_not_allowed(res);
if let Some(span) = sp { if let Some(span) = sp {
diag.span_label(span, &note); diag.span_label(span, &note);

View file

@ -0,0 +1,12 @@
// check-pass
#![feature(inline_const)]
#![allow(incomplete_features)]
pub fn todo<T>() -> T {
const { todo!() }
}
fn main() {
let _: usize = const { 0 };
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1065,7 +1065,10 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
PatKind::Path(path) => { PatKind::Path(path) => {
#[allow(clippy::match_same_arms)] #[allow(clippy::match_same_arms)]
let id = match cx.qpath_res(path, pat.hir_id) { 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, Res::Def(_, id) => id,
_ => return, _ => return,
}; };