Skip to content

Commit

Permalink
rustc: split Generics of a method from its parent Generics.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Aug 17, 2016
1 parent c1cfd58 commit 3e74e5b
Show file tree
Hide file tree
Showing 25 changed files with 290 additions and 264 deletions.
3 changes: 1 addition & 2 deletions src/librustc/infer/error_reporting.rs
Expand Up @@ -82,7 +82,6 @@ use hir::def::Def;
use hir::def_id::DefId;
use infer::{self, TypeOrigin};
use middle::region;
use ty::subst;
use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, ReFree};
use ty::error::TypeError;
Expand Down Expand Up @@ -1369,7 +1368,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
let generics = self.tcx.lookup_generics(did);

let expected =
generics.regions.len(subst::TypeSpace) as u32;
generics.regions.len() as u32;
let lifetimes =
path.segments.last().unwrap().parameters.lifetimes();
let mut insert = Vec::new();
Expand Down
12 changes: 4 additions & 8 deletions src/librustc/traits/error_reporting.rs
Expand Up @@ -271,14 +271,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let def = self.tcx.lookup_trait_def(trait_ref.def_id);
let trait_str = def.trait_ref.to_string();
if let Some(ref istring) = item.value_str() {
let mut generic_map = def.generics.types.iter_enumerated()
.map(|(param, i, gen)| {
(gen.name.as_str().to_string(),
trait_ref.substs.types.get(param, i)
.to_string())
}).collect::<FnvHashMap<String, String>>();
generic_map.insert("Self".to_string(),
trait_ref.self_ty().to_string());
let generic_map = def.generics.types.iter().map(|param| {
(param.name.as_str().to_string(),
trait_ref.substs.type_for_def(param).to_string())
}).collect::<FnvHashMap<String, String>>();
let parser = Parser::new(&istring);
let mut errored = false;
let err: String = parser.filter_map(|p| {
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/traits/object_safety.rs
Expand Up @@ -20,7 +20,6 @@
use super::elaborate_predicates;

use hir::def_id::DefId;
use ty::subst;
use traits;
use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use std::rc::Rc;
Expand Down Expand Up @@ -266,7 +265,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

// We can't monomorphize things like `fn foo<A>(...)`.
if !method.generics.types.is_empty_in(subst::FnSpace) {
if !method.generics.types.is_empty() {
return Some(MethodViolationCode::Generic);
}

Expand Down
29 changes: 5 additions & 24 deletions src/librustc/ty/mod.rs
Expand Up @@ -757,33 +757,14 @@ impl RegionParameterDef {
/// with an item or method. Analogous to hir::Generics.
#[derive(Clone, Debug)]
pub struct Generics<'tcx> {
pub types: VecPerParamSpace<TypeParameterDef<'tcx>>,
pub regions: VecPerParamSpace<RegionParameterDef>,
pub parent: Option<DefId>,
pub parent_regions: u32,
pub parent_types: u32,
pub regions: Vec<RegionParameterDef>,
pub types: Vec<TypeParameterDef<'tcx>>,
pub has_self: bool,
}

impl<'tcx> Generics<'tcx> {
pub fn empty() -> Generics<'tcx> {
Generics {
types: VecPerParamSpace::empty(),
regions: VecPerParamSpace::empty(),
has_self: false,
}
}

pub fn is_empty(&self) -> bool {
self.types.is_empty() && self.regions.is_empty()
}

pub fn has_type_params(&self, space: subst::ParamSpace) -> bool {
!self.types.is_empty_in(space)
}

pub fn has_region_params(&self, space: subst::ParamSpace) -> bool {
!self.regions.is_empty_in(space)
}
}

/// Bounds on generics.
#[derive(Clone)]
pub struct GenericPredicates<'tcx> {
Expand Down
14 changes: 0 additions & 14 deletions src/librustc/ty/structural_impls.rs
Expand Up @@ -832,20 +832,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::Generics {
types: self.types.fold_with(folder),
regions: self.regions.fold_with(folder),
has_self: self.has_self
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.types.visit_with(visitor) || self.regions.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::GenericPredicates {
Expand Down
71 changes: 41 additions & 30 deletions src/librustc/ty/subst.rs
Expand Up @@ -89,42 +89,55 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
let defs = tcx.lookup_generics(def_id);
let num_regions = defs.parent_regions as usize + defs.regions.len();
let num_types = defs.parent_types as usize + defs.types.len();
let mut substs = Substs {
types: VecPerParamSpace {
regions: VecPerParamSpace {
type_limit: 0,
content: Vec::with_capacity(defs.types.content.len())
content: Vec::with_capacity(num_regions)
},
regions: VecPerParamSpace {
types: VecPerParamSpace {
type_limit: 0,
content: Vec::with_capacity(defs.regions.content.len())
content: Vec::with_capacity(num_types)
}
};

for &space in &ParamSpace::all() {
for def in defs.regions.get_slice(space) {
assert_eq!(def.space, space);

let region = mk_region(def, &substs);
substs.regions.content.push(region);
substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type);

if space == TypeSpace {
substs.regions.type_limit += 1;
}
}
Substs::new(tcx, substs.types, substs.regions)
}

for def in defs.types.get_slice(space) {
assert_eq!(def.space, space);
fn fill_item<FR, FT>(&mut self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
defs: &ty::Generics<'tcx>,
mk_region: &mut FR,
mk_type: &mut FT)
where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
if let Some(def_id) = defs.parent {
let parent_defs = tcx.lookup_generics(def_id);
self.fill_item(tcx, parent_defs, mk_region, mk_type);
}

let ty = mk_type(def, &substs);
substs.types.content.push(ty);
for def in &defs.regions {
let region = mk_region(def, self);
self.regions.content.push(region);

if space == TypeSpace {
substs.types.type_limit += 1;
}
if def.space == TypeSpace {
self.regions.type_limit += 1;
assert_eq!(self.regions.content.len(), self.regions.type_limit);
}
}

Substs::new(tcx, substs.types, substs.regions)
for def in &defs.types {
let ty = mk_type(def, self);
self.types.content.push(ty);

if def.space == TypeSpace {
self.types.type_limit += 1;
assert_eq!(self.types.content.len(), self.types.type_limit);
}
}
}

pub fn is_noop(&self) -> bool {
Expand All @@ -149,16 +162,14 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
target_substs: &Substs<'tcx>)
-> &'tcx Substs<'tcx> {
let defs = tcx.lookup_generics(source_ancestor);
assert_eq!(self.types.len(TypeSpace), defs.types.len(TypeSpace));
assert_eq!(self.types.len(TypeSpace), defs.types.len());
assert_eq!(target_substs.types.len(FnSpace), 0);
assert_eq!(defs.types.len(FnSpace), 0);
assert_eq!(self.regions.len(TypeSpace), defs.regions.len(TypeSpace));
assert_eq!(self.regions.len(TypeSpace), defs.regions.len());
assert_eq!(target_substs.regions.len(FnSpace), 0);
assert_eq!(defs.regions.len(FnSpace), 0);

let Substs { mut types, mut regions } = target_substs.clone();
types.content.extend(&self.types.as_full_slice()[defs.types.content.len()..]);
regions.content.extend(&self.regions.as_full_slice()[defs.regions.content.len()..]);
types.content.extend(&self.types.as_full_slice()[defs.types.len()..]);
regions.content.extend(&self.regions.as_full_slice()[defs.regions.len()..]);
Substs::new(tcx, types, regions)
}
}
Expand Down Expand Up @@ -597,8 +608,8 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> {
-> ty::TraitRef<'tcx> {
let Substs { mut types, mut regions } = substs.clone();
let defs = tcx.lookup_generics(trait_id);
types.content.truncate(defs.types.type_limit);
regions.content.truncate(defs.regions.type_limit);
types.content.truncate(defs.types.len());
regions.content.truncate(defs.regions.len());

ty::TraitRef {
def_id: trait_id,
Expand Down
10 changes: 6 additions & 4 deletions src/librustc/util/ppaux.rs
Expand Up @@ -73,13 +73,15 @@ pub fn parameterized(f: &mut fmt::Formatter,
let mut has_self = false;
let (fn_trait_kind, item_name) = ty::tls::with(|tcx| {
verbose = tcx.sess.verbose();
let generics = tcx.lookup_generics(did);
let mut generics = tcx.lookup_generics(did);
if let Some(def_id) = generics.parent {
generics = tcx.lookup_generics(def_id);
}
if !verbose {
let ty_params = generics.types.get_slice(subst::TypeSpace);
if ty_params.last().map_or(false, |def| def.default.is_some()) {
if generics.types.last().map_or(false, |def| def.default.is_some()) {
if let Some(substs) = tcx.lift(&substs) {
let tps = substs.types.get_slice(subst::TypeSpace);
for (def, actual) in ty_params.iter().zip(tps).rev() {
for (def, actual) in generics.types.iter().zip(tps).rev() {
if def.default.subst(tcx, substs) != Some(actual) {
break;
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_metadata/encoder.rs
Expand Up @@ -620,9 +620,9 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
if let Some(impl_item) = impl_item_opt {
if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
encode_attributes(rbml_w, &impl_item.attrs);
let scheme = ecx.tcx.lookup_item_type(m.def_id);
let any_types = !scheme.generics.types.is_empty();
let needs_inline = any_types || is_default_impl ||
let generics = ecx.tcx.lookup_generics(m.def_id);
let types = generics.parent_types as usize + generics.types.len();
let needs_inline = types > 0 || is_default_impl ||
attr::requests_inline(&impl_item.attrs);
if needs_inline || sig.constness == hir::Constness::Const {
encode_inlined_item(ecx,
Expand Down
24 changes: 22 additions & 2 deletions src/librustc_metadata/tydecode.rs
Expand Up @@ -149,9 +149,29 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
}

pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> {
let regions = self.parse_vec_per_param_space(|this| this.parse_region_param_def());
let types = self.parse_vec_per_param_space(|this| this.parse_type_param_def());
let parent = self.parse_opt(|this| this.parse_def());
let parent_regions = self.parse_u32();
assert_eq!(self.next(), '|');
let parent_types = self.parse_u32();

let mut regions = vec![];
assert_eq!(self.next(), '[');
while self.peek() != ']' {
regions.push(self.parse_region_param_def());
}
assert_eq!(self.next(), ']');

let mut types = vec![];
assert_eq!(self.next(), '[');
while self.peek() != ']' {
types.push(self.parse_type_param_def());
}
assert_eq!(self.next(), ']');

self.tcx.alloc_generics(ty::Generics {
parent: parent,
parent_regions: parent_regions,
parent_types: parent_types,
regions: regions,
types: types,
has_self: self.next() == 'S'
Expand Down
19 changes: 15 additions & 4 deletions src/librustc_metadata/tyencode.rs
Expand Up @@ -274,10 +274,21 @@ pub fn enc_substs<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,

pub fn enc_generics<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
generics: &ty::Generics<'tcx>) {
enc_vec_per_param_space(w, cx, &generics.regions,
|w, cx, r| enc_region_param_def(w, cx, r));
enc_vec_per_param_space(w, cx, &generics.types,
|w, cx, ty| enc_type_param_def(w, cx, ty));
enc_opt(w, generics.parent, |w, def_id| {
write!(w, "{}|", (cx.ds)(cx.tcx, def_id));
});
write!(w, "{}|{}[",
generics.parent_regions,
generics.parent_types);

for r in &generics.regions {
enc_region_param_def(w, cx, r)
}
write!(w, "][");
for t in &generics.types {
enc_type_param_def(w, cx, t);
}
write!(w, "]");

if generics.has_self {
write!(w, "S");
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/base.rs
Expand Up @@ -2470,8 +2470,8 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet {
hir_map::NodeImplItem(&hir::ImplItem {
node: hir::ImplItemKind::Method(..), .. }) => {
let def_id = tcx.map.local_def_id(id);
let scheme = tcx.lookup_item_type(def_id);
scheme.generics.types.is_empty()
let generics = tcx.lookup_generics(def_id);
generics.parent_types == 0 && generics.types.is_empty()
}

_ => false
Expand Down
15 changes: 7 additions & 8 deletions src/librustc_trans/collector.rs
Expand Up @@ -195,7 +195,7 @@ use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::middle::lang_items::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem};
use rustc::traits;
use rustc::ty::subst::{self, Substs, Subst};
use rustc::ty::subst::{Substs, Subst};
use rustc::ty::{self, TypeFoldable, TyCtxt};
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::mir::repr as mir;
Expand Down Expand Up @@ -1219,17 +1219,16 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id_to_string(tcx, impl_def_id));

if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
let default_impls = tcx.provided_trait_methods(trait_ref.def_id);
let callee_substs = tcx.erase_regions(&trait_ref.substs);
let overridden_methods: FnvHashSet<_> = items.iter()
.map(|item| item.name)
.collect();
for default_impl in default_impls {
if overridden_methods.contains(&default_impl.name) {
for method in tcx.provided_trait_methods(trait_ref.def_id) {
if overridden_methods.contains(&method.name) {
continue;
}

if default_impl.generics.has_type_params(subst::FnSpace) {
if !method.generics.types.is_empty() {
continue;
}

Expand All @@ -1242,7 +1241,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
callee_substs,
impl_def_id,
impl_substs,
default_impl.name);
method.name);

assert!(mth.is_provided);

Expand All @@ -1251,10 +1250,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
continue;
}

if can_have_local_instance(tcx, default_impl.def_id) {
if can_have_local_instance(tcx, method.def_id) {
let empty_substs = tcx.erase_regions(&mth.substs);
let item = create_fn_trans_item(tcx,
default_impl.def_id,
method.def_id,
callee_substs,
empty_substs);
output.push(item);
Expand Down

0 comments on commit 3e74e5b

Please sign in to comment.