Skip to content

Commit 468192a

Browse files
committed
Implement type inference for inline consts
In most cases it is handled in the same way as closures.
1 parent 02c1774 commit 468192a

File tree

18 files changed

+299
-43
lines changed

18 files changed

+299
-43
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
569569
// to store those. Otherwise, we'll pass in `None` to the
570570
// functions below, which will trigger them to report errors
571571
// eagerly.
572-
let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
572+
let mut outlives_requirements =
573+
infcx.tcx.is_closure_or_inline_const(mir_def_id).then(Vec::new);
573574

574575
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
575576

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,7 +1345,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13451345
Some(RETURN_PLACE) => {
13461346
if let BorrowCheckContext {
13471347
universal_regions:
1348-
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
1348+
UniversalRegions {
1349+
defining_ty:
1350+
DefiningTy::Const(def_id, _)
1351+
| DefiningTy::InlineConst(def_id, _),
1352+
..
1353+
},
13491354
..
13501355
} = self.borrowck_context
13511356
{
@@ -1650,7 +1655,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16501655
Some(RETURN_PLACE) => {
16511656
if let BorrowCheckContext {
16521657
universal_regions:
1653-
UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
1658+
UniversalRegions {
1659+
defining_ty:
1660+
DefiningTy::Const(def_id, _)
1661+
| DefiningTy::InlineConst(def_id, _),
1662+
..
1663+
},
16541664
..
16551665
} = self.borrowck_context
16561666
{

compiler/rustc_borrowck/src/universal_regions.rs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec};
2323
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
2424
use rustc_middle::ty::fold::TypeFoldable;
2525
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
26-
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
26+
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
2727
use std::iter;
2828

2929
use crate::nll::ToRegionVid;
@@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> {
108108
/// is that it has no inputs and a single return value, which is
109109
/// the value of the constant.
110110
Const(DefId, SubstsRef<'tcx>),
111+
112+
/// The MIR represents an inline const. The signature has no inputs and a
113+
/// single return value found via `InlineConstSubsts::ty`.
114+
InlineConst(DefId, SubstsRef<'tcx>),
111115
}
112116

113117
impl<'tcx> DefiningTy<'tcx> {
@@ -121,7 +125,7 @@ impl<'tcx> DefiningTy<'tcx> {
121125
DefiningTy::Generator(_, substs, _) => {
122126
Either::Right(Either::Left(substs.as_generator().upvar_tys()))
123127
}
124-
DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
128+
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
125129
Either::Right(Either::Right(iter::empty()))
126130
}
127131
}
@@ -133,7 +137,7 @@ impl<'tcx> DefiningTy<'tcx> {
133137
pub fn implicit_inputs(self) -> usize {
134138
match self {
135139
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
136-
DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
140+
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
137141
}
138142
}
139143

@@ -142,15 +146,16 @@ impl<'tcx> DefiningTy<'tcx> {
142146
}
143147

144148
pub fn is_const(&self) -> bool {
145-
matches!(*self, DefiningTy::Const(..))
149+
matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
146150
}
147151

148152
pub fn def_id(&self) -> DefId {
149153
match *self {
150154
DefiningTy::Closure(def_id, ..)
151155
| DefiningTy::Generator(def_id, ..)
152156
| DefiningTy::FnDef(def_id, ..)
153-
| DefiningTy::Const(def_id, ..) => def_id,
157+
| DefiningTy::Const(def_id, ..)
158+
| DefiningTy::InlineConst(def_id, ..) => def_id,
154159
}
155160
}
156161
}
@@ -376,6 +381,12 @@ impl<'tcx> UniversalRegions<'tcx> {
376381
tcx.def_path_str_with_substs(def_id, substs),
377382
));
378383
}
384+
DefiningTy::InlineConst(def_id, substs) => {
385+
err.note(&format!(
386+
"defining inline constant type: {}",
387+
tcx.def_path_str_with_substs(def_id, substs),
388+
));
389+
}
379390
}
380391
}
381392
}
@@ -534,11 +545,21 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
534545
}
535546

536547
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
537-
assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
538548
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
539-
let substs =
540-
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
541-
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
549+
if self.mir_def.did.to_def_id() == closure_base_def_id {
550+
let substs =
551+
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
552+
DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
553+
} else {
554+
let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
555+
let substs = InlineConstSubsts::new(
556+
tcx,
557+
InlineConstSubstsParts { parent_substs: identity_substs, ty },
558+
)
559+
.substs;
560+
let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
561+
DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
562+
}
542563
}
543564
}
544565
}
@@ -556,7 +577,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
556577
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
557578
let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
558579
let fr_substs = match defining_ty {
559-
DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
580+
DefiningTy::Closure(_, ref substs)
581+
| DefiningTy::Generator(_, ref substs, _)
582+
| DefiningTy::InlineConst(_, ref substs) => {
560583
// In the case of closures, we rely on the fact that
561584
// the first N elements in the ClosureSubsts are
562585
// inherited from the `closure_base_def_id`.
@@ -648,6 +671,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
648671
let ty = indices.fold_to_region_vids(tcx, ty);
649672
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
650673
}
674+
675+
DefiningTy::InlineConst(def_id, substs) => {
676+
assert_eq!(self.mir_def.did.to_def_id(), def_id);
677+
let ty = substs.as_inline_const().ty();
678+
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
679+
}
651680
}
652681
}
653682
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ rustc_queries! {
797797
/// additional requirements that the closure's creator must verify.
798798
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
799799
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
800-
cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
800+
cache_on_disk_if(tcx) { tcx.is_closure_or_inline_const(key.to_def_id()) }
801801
}
802802
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
803803
desc {

compiler/rustc_middle/src/ty/consts.rs

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::mir::interpret::ConstValue;
22
use crate::mir::interpret::{LitToConstInput, Scalar};
3-
use crate::ty::{self, Ty, TyCtxt};
4-
use crate::ty::{ParamEnv, ParamEnvAnd};
3+
use crate::ty::{
4+
self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
5+
TyCtxt, TypeFoldable,
6+
};
57
use rustc_errors::ErrorReported;
68
use rustc_hir as hir;
79
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -54,6 +56,24 @@ impl<'tcx> Const<'tcx> {
5456

5557
let ty = tcx.type_of(def.def_id_for_type_of());
5658

59+
match Self::try_eval_body_expr(tcx, ty, expr) {
60+
Some(v) => v,
61+
None => tcx.mk_const(ty::Const {
62+
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
63+
def: def.to_global(),
64+
substs_: None,
65+
promoted: None,
66+
}),
67+
ty,
68+
}),
69+
}
70+
}
71+
72+
fn try_eval_body_expr(
73+
tcx: TyCtxt<'tcx>,
74+
ty: Ty<'tcx>,
75+
expr: &'tcx hir::Expr<'tcx>,
76+
) -> Option<&'tcx Self> {
5777
let lit_input = match expr.kind {
5878
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
5979
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
@@ -69,7 +89,7 @@ impl<'tcx> Const<'tcx> {
6989
// If an error occurred, ignore that it's a literal and leave reporting the error up to
7090
// mir.
7191
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
72-
return c;
92+
return Some(c);
7393
} else {
7494
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
7595
}
@@ -85,7 +105,7 @@ impl<'tcx> Const<'tcx> {
85105
};
86106

87107
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
88-
let val = match expr.kind {
108+
match expr.kind {
89109
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
90110
// Find the name and index of the const parameter by indexing the generics of
91111
// the parent item and construct a `ParamConst`.
@@ -95,16 +115,53 @@ impl<'tcx> Const<'tcx> {
95115
let generics = tcx.generics_of(item_def_id.to_def_id());
96116
let index = generics.param_def_id_to_index[&def_id];
97117
let name = tcx.hir().name(hir_id);
98-
ty::ConstKind::Param(ty::ParamConst::new(index, name))
118+
Some(tcx.mk_const(ty::Const {
119+
val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
120+
ty,
121+
}))
99122
}
100-
_ => ty::ConstKind::Unevaluated(ty::Unevaluated {
101-
def: def.to_global(),
102-
substs_: None,
103-
promoted: None,
104-
}),
123+
_ => None,
124+
}
125+
}
126+
127+
pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
128+
debug!("Const::from_inline_const(def_id={:?})", def_id);
129+
130+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
131+
132+
let body_id = match tcx.hir().get(hir_id) {
133+
hir::Node::AnonConst(ac) => ac.body,
134+
_ => span_bug!(
135+
tcx.def_span(def_id.to_def_id()),
136+
"from_inline_const can only process anonymous constants"
137+
),
105138
};
106139

107-
tcx.mk_const(ty::Const { val, ty })
140+
let expr = &tcx.hir().body(body_id).value;
141+
142+
let ty = tcx.typeck(def_id).node_type(hir_id);
143+
144+
let ret = match Self::try_eval_body_expr(tcx, ty, expr) {
145+
Some(v) => v,
146+
None => {
147+
let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id());
148+
let parent_substs =
149+
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, outer_def_id));
150+
let substs =
151+
InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
152+
.substs;
153+
tcx.mk_const(ty::Const {
154+
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
155+
def: ty::WithOptConstParam::unknown(def_id).to_global(),
156+
substs_: Some(substs),
157+
promoted: None,
158+
}),
159+
ty,
160+
})
161+
}
162+
};
163+
debug_assert!(!ret.has_free_regions(tcx));
164+
ret
108165
}
109166

110167
/// Interns the given value as a constant.

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@ pub use self::sty::{
7474
Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
7575
CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
7676
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
77-
GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
78-
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
79-
RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
77+
GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
78+
ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
79+
PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
80+
UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
8081
};
8182
pub use self::trait_def::TraitDef;
8283

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,66 @@ impl<'tcx> UpvarSubsts<'tcx> {
704704
}
705705
}
706706

707+
/// An inline const is modeled like
708+
///
709+
/// const InlineConst<'l0...'li, T0...Tj, R>: R;
710+
///
711+
/// where:
712+
///
713+
/// - 'l0...'li and T0...Tj are the generic parameters
714+
/// inherited from the item that defined the inline const,
715+
/// - R represents the type of the constant.
716+
///
717+
/// When the inline const is instantiated, `R` is substituted as the actual inferred
718+
/// type of the constant. The reason that `R` is represented as an extra type parameter
719+
/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
720+
/// inline const can reference lifetimes that are internal to the creating function.
721+
#[derive(Copy, Clone, Debug, TypeFoldable)]
722+
pub struct InlineConstSubsts<'tcx> {
723+
/// Generic parameters from the enclosing item,
724+
/// concatenated with the inferred type of the constant.
725+
pub substs: SubstsRef<'tcx>,
726+
}
727+
728+
/// Struct returned by `split()`.
729+
pub struct InlineConstSubstsParts<'tcx, T> {
730+
pub parent_substs: &'tcx [GenericArg<'tcx>],
731+
pub ty: T,
732+
}
733+
734+
impl<'tcx> InlineConstSubsts<'tcx> {
735+
/// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
736+
pub fn new(
737+
tcx: TyCtxt<'tcx>,
738+
parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
739+
) -> InlineConstSubsts<'tcx> {
740+
InlineConstSubsts {
741+
substs: tcx.mk_substs(
742+
parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
743+
),
744+
}
745+
}
746+
747+
/// Divides the inline const substs into their respective components.
748+
/// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
749+
fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
750+
match self.substs[..] {
751+
[ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
752+
_ => bug!("inline const substs missing synthetics"),
753+
}
754+
}
755+
756+
/// Returns the substitutions of the inline const's parent.
757+
pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
758+
self.split().parent_substs
759+
}
760+
761+
/// Returns the type of this inline const.
762+
pub fn ty(self) -> Ty<'tcx> {
763+
self.split().ty.expect_ty()
764+
}
765+
}
766+
707767
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
708768
#[derive(HashStable, TypeFoldable)]
709769
pub enum ExistentialPredicate<'tcx> {

compiler/rustc_middle/src/ty/subst.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::mir;
44
use crate::ty::codec::{TyDecoder, TyEncoder};
55
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
6-
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
6+
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
77
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
88

99
use rustc_hir::def_id::DefId;
@@ -204,6 +204,14 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
204204
GeneratorSubsts { substs: self }
205205
}
206206

207+
/// Interpret these substitutions as the substitutions of an inline const.
208+
/// Inline const substitutions have a particular structure controlled by the
209+
/// compiler that encodes information like the inferred type;
210+
/// see `ty::InlineConstSubsts` struct for more comments.
211+
pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
212+
InlineConstSubsts { substs: self }
213+
}
214+
207215
/// Creates an `InternalSubsts` that maps each generic parameter to itself.
208216
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
209217
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))

0 commit comments

Comments
 (0)