Skip to content

Commit d6d0590

Browse files
authored
Auto merge of #35605 - eddyb:substs, r=nikomatsakis
Remove the ParamSpace separation from formal and actual generics in rustc. This is the first step towards enabling the typesystem implemented by `rustc` to be extended (with generic modules, HKT associated types, generics over constants, etc.). The current implementation splits all formal (`ty::Generics`) and actual (`Substs`) lifetime and type parameters (and even `where` clauses) into 3 "parameter spaces": * `TypeSpace` for `enum`, `struct`, `trait` and `impl` * `SelfSpace` for `Self` in a `trait` * `FnSpace` for functions and methods For example, in `<X as Trait<A, B>>::method::<T, U>`, the `Substs` are `[[A, B], [X], [T, U]]`. The representation uses a single `Vec` with 2 indices where it's split into the 3 "parameter spaces". Such a simplistic approach doesn't scale beyond the Rust 1.0 typesystem, and its existence was mainly motivated by keeping code manipulating generic parameters correct, across all possible situations. Summary of changes: * `ty::Generics` are uniformly stored and can be queried with `tcx.lookup_generics(def_id)` * the `typeck::collect` changes for this resulted in a function to lazily compute the `ty::Generics` for a local node, given only its `DefId` - this can be further generalized to other kinds of type information * `ty::Generics` and `ty::GenericPredicates` now contain only their own parameters (or `where` clauses, respectively), and refer to their "parent", forming a linked list * right now most items have one level of nesting, only associated items and variants having two * in the future, if `<X as mod1<A>::mod2<B>::mod3::Trait<C>>::Assoc<Y>` is supported, it would be represented by item with the path `mod1::mod2::mod3::Trait::Assoc`, and 4 levels of generics: `mod1` with `[A]`, `mod2` with `[B]`, `Trait` with `[X, C]` and `Assoc` with `[Y]` * `Substs` gets two new APIs for working with arbitrary items: * `Substs::for_item(def_id, mk_region, mk_type)` will construct `Substs` expected by the definition `def_id`, calling `mk_region` for lifetime parameters and `mk_type` for type parameters, and it's guaranteed to *always* return `Substs` compatible with `def_id` * `substs.rebase_onto(from_base_def_id, to_base_substs)` can be used if `substs` is for an item nested within `from_base_def_id` (e.g. an associated item), to replace the "outer parameters" with `to_base_substs` - for example, you can translate a method's `Substs` between a `trait` and an `impl` (in both directions) if you have the `DefId` of one and `Substs` for the other * trait objects, without a `Self` in their `Substs`, use *solely* `ExistentialTraitRef` now, letting `TraitRef` assume it *always* has a `Self` present * both `TraitRef` and `ExistentialTraitRef` get methods which do operations on their `Substs` which are valid only for traits (or trait objects, respectively) * `Substs` loses its "parameter spaces" distinction, with effectively no code creating `Substs` in an ad-hoc manner, or inspecting them, without knowing what shape they have already Future plans: * combine both lifetimes and types in a single `Vec<Kind<'tcx>>` where `Kind` would be a tagged pointer that can be `Ty<'tcx>`, `&'tcx ty::Region` or, in the future, potentially-polymorphic constants * this would require some performance investigation, if it implies a lot of dynamic checks * introduce an abstraction for `(T, Substs)`, where the `Substs` are even more hidden away from code manipulating it; a precedent for this is `Instance` in trans, which has `T = DefId`; @nikomatsakis also referred to this, as "lazy substitution", when `T = Ty` * rewrite type pretty-printing to fully take advantage of this to inject actual in the exact places of formal generic parameters in any paths * extend the set of type-level information (e.g. beyond `ty::Generics`) that can be lazily queried during `typeck` and introduce a way to do those queries from code that can't refer to `typeck` directly * this is almost unrelated but is necessary for DAG-shaped recursion between constant evaluation and type-level information, i.e. for implementing generics over constants r? @nikomatsakis cc @rust-lang/compiler cc @nrc Could get any perf numbers ahead of merging this?
2 parents 9376da6 + 9453d9b commit d6d0590

File tree

115 files changed

+2903
-4131
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+2903
-4131
lines changed

src/librustc/hir/def.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010

1111
use hir::def_id::DefId;
12-
use ty::subst::ParamSpace;
1312
use util::nodemap::NodeMap;
1413
use syntax::ast;
1514
use hir;
@@ -31,7 +30,7 @@ pub enum Def {
3130
AssociatedTy(DefId /* trait */, DefId),
3231
Trait(DefId),
3332
PrimTy(hir::PrimTy),
34-
TyParam(ParamSpace, u32, DefId, ast::Name),
33+
TyParam(DefId),
3534
Upvar(DefId, // def id of closed over local
3635
ast::NodeId, // node id of closed over local
3736
usize, // index in the freevars list of the closure
@@ -122,7 +121,7 @@ impl Def {
122121
match *self {
123122
Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
124123
Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
125-
Def::TyParam(_, _, id, _) | Def::Struct(id) | Def::Trait(id) |
124+
Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) |
126125
Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
127126
Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
128127
id

src/librustc/infer/error_reporting.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ use hir::def::Def;
8282
use hir::def_id::DefId;
8383
use infer::{self, TypeOrigin};
8484
use middle::region;
85-
use ty::subst;
8685
use ty::{self, TyCtxt, TypeFoldable};
8786
use ty::{Region, ReFree};
8887
use ty::error::TypeError;
@@ -1366,10 +1365,10 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
13661365
hir::TyPath(ref maybe_qself, ref path) => {
13671366
match self.tcx.expect_def(cur_ty.id) {
13681367
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
1369-
let generics = self.tcx.lookup_item_type(did).generics;
1368+
let generics = self.tcx.lookup_generics(did);
13701369

13711370
let expected =
1372-
generics.regions.len(subst::TypeSpace) as u32;
1371+
generics.regions.len() as u32;
13731372
let lifetimes =
13741373
path.segments.last().unwrap().parameters.lifetimes();
13751374
let mut insert = Vec::new();

src/librustc/infer/mod.rs

+44-89
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ use middle::mem_categorization as mc;
2525
use middle::mem_categorization::McResult;
2626
use middle::region::CodeExtent;
2727
use mir::tcx::LvalueTy;
28-
use ty::subst;
29-
use ty::subst::Substs;
30-
use ty::subst::Subst;
28+
use ty::subst::{Subst, Substs};
3129
use ty::adjustment;
3230
use ty::{TyVid, IntVid, FloatVid};
3331
use ty::{self, Ty, TyCtxt};
@@ -1172,15 +1170,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11721170
self.tcx.mk_var(self.next_ty_var_id(false))
11731171
}
11741172

1175-
pub fn next_ty_var_with_default(&self,
1176-
default: Option<type_variable::Default<'tcx>>) -> Ty<'tcx> {
1177-
let ty_var_id = self.type_variables
1178-
.borrow_mut()
1179-
.new_var(false, default);
1180-
1181-
self.tcx.mk_var(ty_var_id)
1182-
}
1183-
11841173
pub fn next_diverging_ty_var(&self) -> Ty<'tcx> {
11851174
self.tcx.mk_var(self.next_ty_var_id(true))
11861175
}
@@ -1205,89 +1194,55 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
12051194
ty::ReVar(self.region_vars.new_region_var(origin))
12061195
}
12071196

1208-
pub fn region_vars_for_defs(&self,
1209-
span: Span,
1210-
defs: &[ty::RegionParameterDef])
1211-
-> Vec<ty::Region> {
1212-
defs.iter()
1213-
.map(|d| self.next_region_var(EarlyBoundRegion(span, d.name)))
1214-
.collect()
1215-
}
1216-
1217-
// We have to take `&mut Substs` in order to provide the correct substitutions for defaults
1218-
// along the way, for this reason we don't return them.
1219-
pub fn type_vars_for_defs(&self,
1197+
/// Create a region inference variable for the given
1198+
/// region parameter definition.
1199+
pub fn region_var_for_def(&self,
12201200
span: Span,
1221-
space: subst::ParamSpace,
1222-
substs: &mut Substs<'tcx>,
1223-
defs: &[ty::TypeParameterDef<'tcx>]) {
1224-
1225-
for def in defs.iter() {
1226-
let default = def.default.map(|default| {
1227-
type_variable::Default {
1228-
ty: default.subst_spanned(self.tcx, substs, Some(span)),
1229-
origin_span: span,
1230-
def_id: def.default_def_id
1231-
}
1232-
});
1233-
1234-
let ty_var = self.next_ty_var_with_default(default);
1235-
substs.types.push(space, ty_var);
1236-
}
1237-
}
1238-
1239-
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
1240-
/// type/region parameter to a fresh inference variable.
1241-
pub fn fresh_substs_for_generics(&self,
1242-
span: Span,
1243-
generics: &ty::Generics<'tcx>)
1244-
-> &'tcx subst::Substs<'tcx>
1245-
{
1246-
let type_params = subst::VecPerParamSpace::empty();
1247-
1248-
let region_params =
1249-
generics.regions.map(
1250-
|d| self.next_region_var(EarlyBoundRegion(span, d.name)));
1201+
def: &ty::RegionParameterDef)
1202+
-> ty::Region {
1203+
self.next_region_var(EarlyBoundRegion(span, def.name))
1204+
}
1205+
1206+
/// Create a type inference variable for the given
1207+
/// type parameter definition. The substitutions are
1208+
/// for actual parameters that may be referred to by
1209+
/// the default of this type parameter, if it exists.
1210+
/// E.g. `struct Foo<A, B, C = (A, B)>(...);` when
1211+
/// used in a path such as `Foo::<T, U>::new()` will
1212+
/// use an inference variable for `C` with `[T, U]`
1213+
/// as the substitutions for the default, `(T, U)`.
1214+
pub fn type_var_for_def(&self,
1215+
span: Span,
1216+
def: &ty::TypeParameterDef<'tcx>,
1217+
substs: &Substs<'tcx>)
1218+
-> Ty<'tcx> {
1219+
let default = def.default.map(|default| {
1220+
type_variable::Default {
1221+
ty: default.subst_spanned(self.tcx, substs, Some(span)),
1222+
origin_span: span,
1223+
def_id: def.default_def_id
1224+
}
1225+
});
12511226

1252-
let mut substs = subst::Substs::new(type_params, region_params);
12531227

1254-
for space in subst::ParamSpace::all().iter() {
1255-
self.type_vars_for_defs(
1256-
span,
1257-
*space,
1258-
&mut substs,
1259-
generics.types.get_slice(*space));
1260-
}
1228+
let ty_var_id = self.type_variables
1229+
.borrow_mut()
1230+
.new_var(false, default);
12611231

1262-
self.tcx.mk_substs(substs)
1232+
self.tcx.mk_var(ty_var_id)
12631233
}
12641234

1265-
/// Given a set of generics defined on a trait, returns a substitution mapping each output
1266-
/// type/region parameter to a fresh inference variable, and mapping the self type to
1267-
/// `self_ty`.
1268-
pub fn fresh_substs_for_trait(&self,
1269-
span: Span,
1270-
generics: &ty::Generics<'tcx>,
1271-
self_ty: Ty<'tcx>)
1272-
-> subst::Substs<'tcx>
1273-
{
1274-
1275-
assert!(generics.types.len(subst::SelfSpace) == 1);
1276-
assert!(generics.types.len(subst::FnSpace) == 0);
1277-
assert!(generics.regions.len(subst::SelfSpace) == 0);
1278-
assert!(generics.regions.len(subst::FnSpace) == 0);
1279-
1280-
let type_params = Vec::new();
1281-
1282-
let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
1283-
let regions = self.region_vars_for_defs(span, region_param_defs);
1284-
1285-
let mut substs = subst::Substs::new_trait(type_params, regions, self_ty);
1286-
1287-
let type_parameter_defs = generics.types.get_slice(subst::TypeSpace);
1288-
self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs);
1289-
1290-
return substs;
1235+
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
1236+
/// type/region parameter to a fresh inference variable.
1237+
pub fn fresh_substs_for_item(&self,
1238+
span: Span,
1239+
def_id: DefId)
1240+
-> &'tcx Substs<'tcx> {
1241+
Substs::for_item(self.tcx, def_id, |def, _| {
1242+
self.region_var_for_def(span, def)
1243+
}, |def, substs| {
1244+
self.type_var_for_def(span, def, substs)
1245+
})
12911246
}
12921247

12931248
pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {

src/librustc/middle/cstore.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,16 @@ pub trait CrateStore<'tcx> {
154154
fn item_variances(&self, def: DefId) -> ty::ItemVariances;
155155
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
156156
fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
157-
-> ty::TypeScheme<'tcx>;
157+
-> Ty<'tcx>;
158158
fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
159159
fn item_name(&self, def: DefId) -> ast::Name;
160160
fn opt_item_name(&self, def: DefId) -> Option<ast::Name>;
161161
fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
162162
-> ty::GenericPredicates<'tcx>;
163163
fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
164164
-> ty::GenericPredicates<'tcx>;
165+
fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
166+
-> &'tcx ty::Generics<'tcx>;
165167
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
166168
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>;
167169
fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>;
@@ -187,8 +189,7 @@ pub trait CrateStore<'tcx> {
187189
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
188190

189191
// trait/impl-item info
190-
fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
191-
-> Option<DefId>;
192+
fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
192193
fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
193194
-> Option<ty::ImplOrTraitItem<'tcx>>;
194195

@@ -334,7 +335,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
334335
fn item_variances(&self, def: DefId) -> ty::ItemVariances { bug!("item_variances") }
335336
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { bug!("repr_attrs") }
336337
fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
337-
-> ty::TypeScheme<'tcx> { bug!("item_type") }
338+
-> Ty<'tcx> { bug!("item_type") }
338339
fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
339340
bug!("visible_parent_map")
340341
}
@@ -344,6 +345,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
344345
-> ty::GenericPredicates<'tcx> { bug!("item_predicates") }
345346
fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
346347
-> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
348+
fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
349+
-> &'tcx ty::Generics<'tcx> { bug!("item_generics") }
347350
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
348351
fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>
349352
{ bug!("trait_def") }
@@ -379,8 +382,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
379382
fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
380383

381384
// trait/impl-item info
382-
fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
383-
-> Option<DefId> { bug!("trait_of_item") }
385+
fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
384386
fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
385387
-> Option<ty::ImplOrTraitItem<'tcx>> { bug!("impl_or_trait_item") }
386388

@@ -583,7 +585,7 @@ pub mod tls {
583585
pub trait DecodingContext<'tcx> {
584586
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
585587
fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx>;
586-
fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> Substs<'tcx>;
588+
fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx>;
587589
fn translate_def_id(&self, def_id: DefId) -> DefId;
588590
}
589591

src/librustc/middle/dead.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,24 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
8888
fn lookup_and_handle_definition(&mut self, id: ast::NodeId) {
8989
use ty::TypeVariants::{TyEnum, TyStruct};
9090

91+
let def = self.tcx.expect_def(id);
92+
9193
// If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar`
92-
self.tcx.tables.borrow().item_substs.get(&id)
93-
.and_then(|substs| substs.substs.self_ty())
94-
.map(|ty| match ty.sty {
95-
TyEnum(tyid, _) | TyStruct(tyid, _) => self.check_def_id(tyid.did),
96-
_ => (),
97-
});
94+
match def {
95+
Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_)
96+
if self.tcx.trait_of_item(def.def_id()).is_some() => {
97+
if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) {
98+
match substs.substs.types[0].sty {
99+
TyEnum(tyid, _) | TyStruct(tyid, _) => {
100+
self.check_def_id(tyid.did)
101+
}
102+
_ => {}
103+
}
104+
}
105+
}
106+
_ => {}
107+
}
98108

99-
let def = self.tcx.expect_def(id);
100109
match def {
101110
Def::Const(_) | Def::AssociatedConst(..) => {
102111
self.check_def_id(def.def_id());

0 commit comments

Comments
 (0)