From 4816e60667596718682ae70f6c34fed03288e07b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 22 Jul 2015 21:53:52 +0300 Subject: [PATCH] create VariantDef-s (but don't actually use them) --- src/librustc/metadata/csearch.rs | 4 +- src/librustc/metadata/decoder.rs | 109 +++++++++- src/librustc/metadata/encoder.rs | 92 ++++---- src/librustc/middle/check_match.rs | 2 +- src/librustc/middle/ty.rs | 151 +++++++++++-- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 327 +++++++++++++++++++---------- 7 files changed, 504 insertions(+), 183 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index b54e7707f63..f97ffebaebb 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -222,10 +222,10 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe decoder::get_trait_def(&*cdata, def.node, tcx) } -pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> &'tcx ty::ADTDef<'tcx> { +pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> &'tcx ty::ADTDef_<'tcx, 'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_adt_def(&*cdata, def.node, tcx) + decoder::get_adt_def(&cstore.intr, &*cdata, def.node, tcx) } pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 9e8c5505c89..7a899218512 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -108,7 +108,7 @@ fn lookup_item<'a>(item_id: ast::NodeId, data: &'a [u8]) -> rbml::Doc<'a> { find_item(item_id, items) } -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] enum Family { ImmStatic, // c MutStatic, // b @@ -390,12 +390,111 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, } } -pub fn get_adt_def<'tcx>(cdata: Cmd, +pub fn get_adt_def<'tcx>(intr: &IdentInterner, + cdata: Cmd, item_id: ast::NodeId, - tcx: &ty::ctxt<'tcx>) -> &'tcx ty::ADTDef<'tcx> + tcx: &ty::ctxt<'tcx>) -> &'tcx ty::ADTDef_<'tcx, 'tcx> { - tcx.intern_adt_def(ast::DefId { krate: cdata.cnum, node: item_id }, - ty::ADTKind::Enum) + fn get_enum_variants<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) -> Vec> { + let mut disr_val = 0; + reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { + let did = translated_def_id(cdata, p); + let item = lookup_item(did.node, cdata.data()); + + if let Some(disr) = variant_disr_val(item) { + disr_val = disr; + } + let disr = disr_val; + disr_val = disr_val.wrapping_add(1); + + ty::VariantDef_ { + did: did, + name: item_name(intr, item), + fields: get_variant_fields(intr, cdata, item, tcx), + disr_val: disr + } + }).collect() + } + fn get_variant_fields<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) -> Vec> { + reader::tagged_docs(doc, tag_item_field).map(|f| { + let ff = item_family(f); + match ff { + PublicField | InheritedField => {}, + _ => tcx.sess.bug(&format!("expected field, found {:?}", ff)) + }; + ty::FieldDef_::new(item_def_id(f, cdata), + item_name(intr, f), + struct_field_family_to_visibility(ff)) + }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| { + let ff = item_family(f); + ty::FieldDef_::new(item_def_id(f, cdata), + special_idents::unnamed_field.name, + struct_field_family_to_visibility(ff)) + })).collect() + } + fn get_struct_variant<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + did: ast::DefId, + tcx: &ty::ctxt<'tcx>) -> ty::VariantDef_<'tcx, 'tcx> { + ty::VariantDef_ { + did: did, + name: item_name(intr, doc), + fields: get_variant_fields(intr, cdata, doc, tcx), + disr_val: 0 + } + } + + let doc = lookup_item(item_id, cdata.data()); + let did = ast::DefId { krate: cdata.cnum, node: item_id }; + let (kind, variants) = match item_family(doc) { + Enum => (ty::ADTKind::Enum, + get_enum_variants(intr, cdata, doc, tcx)), + Struct => (ty::ADTKind::Struct, + vec![get_struct_variant(intr, cdata, doc, did, tcx)]), + _ => tcx.sess.bug("get_adt_def called on a non-ADT") + }; + + let adt = tcx.intern_adt_def(did, kind, variants); + + // this needs to be done *after* the variant is interned, + // to support recursive structures + for variant in &adt.variants { + if variant.kind() == ty::VariantKind::Tuple && + adt.adt_kind() == ty::ADTKind::Enum { + // tuple-like enum variant fields aren't real items - get the types + // from the ctor. + debug!("evaluating the ctor-type of {:?}", + variant.name); + let ctor_ty = get_type(cdata, variant.did.node, tcx).ty; + debug!("evaluating the ctor-type of {:?}.. {:?}", + variant.name, + ctor_ty); + let field_tys = match ctor_ty.sty { + ty::TyBareFn(_, ref f) => &f.sig.skip_binder().inputs, + _ => tcx.sess.bug("tuple-variant ctor is not an ADT") + }; + for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) { + field.fulfill_ty(ty); + } + } else { + for field in &variant.fields { + debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); + let ty = get_type(cdata, field.did.node, tcx).ty; + field.fulfill_ty(ty); + debug!("evaluating the type of {:?}::{:?}: {:?}", + variant.name, field.name, ty); + } + } + } + + adt } pub fn get_predicates<'tcx>(cdata: Cmd, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 5167014d4ab..4c4a1e07f44 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -41,7 +41,6 @@ use syntax::diagnostic::SpanHandler; use syntax::parse::token::special_idents; use syntax::print::pprust; -use syntax::ptr::P; use syntax::visit::Visitor; use syntax::visit; use syntax; @@ -266,7 +265,7 @@ fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { } fn encode_struct_fields(rbml_w: &mut Encoder, - fields: &[ty::FieldTy], + fields: &[ty::FieldDef], origin: DefId) { for f in fields { if f.name == special_idents::unnamed_field.name { @@ -276,7 +275,7 @@ fn encode_struct_fields(rbml_w: &mut Encoder, encode_name(rbml_w, f.name); } encode_struct_field_family(rbml_w, f.vis); - encode_def_id(rbml_w, f.id); + encode_def_id(rbml_w, f.did); rbml_w.wr_tagged_u64(tag_item_field_origin, def_to_u64(origin)); rbml_w.end_tag(); } @@ -285,57 +284,56 @@ fn encode_struct_fields(rbml_w: &mut Encoder, fn encode_enum_variant_info(ecx: &EncodeContext, rbml_w: &mut Encoder, id: NodeId, - variants: &[P], + vis: ast::Visibility, index: &mut Vec>) { debug!("encode_enum_variant_info(id={})", id); let mut disr_val = 0; - let mut i = 0; - let vi = ecx.tcx.enum_variants(local_def(id)); - for variant in variants { - let def_id = local_def(variant.node.id); + let def = ecx.tcx.lookup_adt_def(local_def(id)); + for variant in &def.variants { + let vid = variant.did; + assert!(is_local(vid)); index.push(entry { - val: variant.node.id as i64, + val: vid.node as i64, pos: rbml_w.mark_stable_position(), }); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); - match variant.node.kind { - ast::TupleVariantKind(_) => encode_family(rbml_w, 'v'), - ast::StructVariantKind(_) => encode_family(rbml_w, 'V') - } - encode_name(rbml_w, variant.node.name.name); + encode_def_id(rbml_w, vid); + encode_family(rbml_w, match variant.kind() { + ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v', + ty::VariantKind::Dict => 'V' + }); + encode_name(rbml_w, variant.name); encode_parent_item(rbml_w, local_def(id)); - encode_visibility(rbml_w, variant.node.vis); - encode_attributes(rbml_w, &variant.node.attrs); - encode_repr_attrs(rbml_w, ecx, &variant.node.attrs); + encode_visibility(rbml_w, vis); + + let attrs = ecx.tcx.get_attrs(vid); + encode_attributes(rbml_w, &attrs); + encode_repr_attrs(rbml_w, ecx, &attrs); - let stab = stability::lookup(ecx.tcx, ast_util::local_def(variant.node.id)); + let stab = stability::lookup(ecx.tcx, vid); encode_stability(rbml_w, stab); - match variant.node.kind { - ast::TupleVariantKind(_) => {}, - ast::StructVariantKind(_) => { - let fields = ecx.tcx.lookup_struct_fields(def_id); - let idx = encode_info_for_struct(ecx, - rbml_w, - &fields[..], - index); - encode_struct_fields(rbml_w, &fields[..], def_id); - encode_index(rbml_w, idx, write_i64); - } + if let ty::VariantKind::Dict = variant.kind() { + let idx = encode_info_for_struct(ecx, + rbml_w, + &variant.fields, + index); + encode_index(rbml_w, idx, write_i64); } - let specified_disr_val = vi[i].disr_val; + + encode_struct_fields(rbml_w, &variant.fields, vid); + + let specified_disr_val = variant.disr_val; if specified_disr_val != disr_val { encode_disr_val(ecx, rbml_w, specified_disr_val); disr_val = specified_disr_val; } - encode_bounds_and_type_for_item(rbml_w, ecx, def_id.local_id()); + encode_bounds_and_type_for_item(rbml_w, ecx, vid.node); - ecx.tcx.map.with_path(variant.node.id, |path| encode_path(rbml_w, path)); + ecx.tcx.map.with_path(vid.node, |path| encode_path(rbml_w, path)); rbml_w.end_tag(); disr_val = disr_val.wrapping_add(1); - i += 1; } } @@ -630,11 +628,11 @@ fn encode_provided_source(rbml_w: &mut Encoder, } /* Returns an index of items in this class */ -fn encode_info_for_struct(ecx: &EncodeContext, - rbml_w: &mut Encoder, - fields: &[ty::FieldTy], - global_index: &mut Vec>) - -> Vec> { +fn encode_info_for_struct<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + fields: &[ty::FieldDef<'tcx>], + global_index: &mut Vec>) + -> Vec> { /* Each class has its own index, since different classes may have fields with the same name */ let mut index = Vec::new(); @@ -642,7 +640,7 @@ fn encode_info_for_struct(ecx: &EncodeContext, private fields to get the offsets right */ for field in fields { let nm = field.name; - let id = field.id.node; + let id = field.did.node; let pos = rbml_w.mark_stable_position(); index.push(entry {val: id as i64, pos: pos}); @@ -658,7 +656,7 @@ fn encode_info_for_struct(ecx: &EncodeContext, encode_bounds_and_type_for_item(rbml_w, ecx, id); encode_def_id(rbml_w, local_def(id)); - let stab = stability::lookup(ecx.tcx, field.id); + let stab = stability::lookup(ecx.tcx, field.did); encode_stability(rbml_w, stab); rbml_w.end_tag(); @@ -1150,20 +1148,18 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder, encode_enum_variant_info(ecx, rbml_w, item.id, - &(*enum_definition).variants, + vis, index); } ast::ItemStruct(ref struct_def, _) => { - let fields = tcx.lookup_struct_fields(def_id); + let def = ecx.tcx.lookup_adt_def(def_id); + let fields = &def.struct_variant().fields; /* First, encode the fields These come first because we need to write them to make the index, and the index needs to be in the item for the class itself */ - let idx = encode_info_for_struct(ecx, - rbml_w, - &fields[..], - index); + let idx = encode_info_for_struct(ecx, rbml_w, &fields, index); /* Index the class*/ add_to_index(item, rbml_w, index); @@ -1185,7 +1181,7 @@ fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder, /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - encode_struct_fields(rbml_w, &fields[..], def_id); + encode_struct_fields(rbml_w, &fields, def_id); encode_inlined_item(ecx, rbml_w, IIItemRef(item)); diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index e7a349265ba..5cef50be770 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -513,7 +513,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, &Variant(vid) => (vid, cx.tcx.enum_variant_with_id(cid.did, vid).arg_names.is_some()), _ => - (cid.did, !cid.is_tuple_struct(cx.tcx)) + (cid.did, !cid.struct_variant().is_tuple_struct()) }; if is_structure { let fields = cx.tcx.lookup_struct_fields(vid); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a491d6e65b7..0354918acf8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -74,10 +74,12 @@ use std::cmp; use std::fmt; use std::hash::{Hash, SipHasher, Hasher}; +use std::iter; use std::marker::PhantomData; use std::mem; use std::ops; use std::rc::Rc; +use std::slice; use std::vec::IntoIter; use collections::enum_set::{self, EnumSet, CLike}; use core::nonzero::NonZero; @@ -90,7 +92,7 @@ use syntax::ast_util::{self, is_local, local_def}; use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; use syntax::codemap::Span; -use syntax::parse::token::{self, InternedString, special_idents}; +use syntax::parse::token::{InternedString, special_idents}; use syntax::print::pprust; use syntax::ptr::P; use syntax::ast; @@ -211,7 +213,7 @@ pub fn has_drop_flag(&self) -> bool { } } -trait IntTypeExt { +pub trait IntTypeExt { fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>; fn i64_to_disr(&self, val: i64) -> Option; fn u64_to_disr(&self, val: u64) -> Option; @@ -852,7 +854,7 @@ pub struct ctxt<'tcx> { pub impl_trait_refs: RefCell>>>, pub trait_defs: RefCell>>, - pub adt_defs: RefCell>>, + pub adt_defs: RefCell>>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its /// associated predicates. @@ -1023,8 +1025,12 @@ pub fn intern_trait_def(&self, def: TraitDef<'tcx>) -> &'tcx TraitDef<'tcx> { interned } - pub fn intern_adt_def(&self, did: DefId, kind: ADTKind) -> &'tcx ADTDef_<'tcx, 'tcx> { - let def = ADTDef_::new(self, did, kind); + pub fn intern_adt_def(&self, + did: DefId, + kind: ADTKind, + variants: Vec>) + -> &'tcx ADTDef_<'tcx, 'tcx> { + let def = ADTDef_::new(self, did, kind, variants); let interned = self.arenas.adt_defs.alloc(def); // this will need a transmute when reverse-variance is removed self.adt_defs.borrow_mut().insert(did, interned); @@ -2190,7 +2196,7 @@ pub struct ExistentialBounds<'tcx> { pub struct BuiltinBounds(EnumSet); impl BuiltinBounds { - pub fn empty() -> BuiltinBounds { + pub fn empty() -> BuiltinBounds { BuiltinBounds(EnumSet::new()) } @@ -3274,17 +3280,21 @@ pub fn for_each_relevant_impl(&self, } pub type ADTDef<'tcx> = ADTDef_<'tcx, 'static>; +pub type VariantDef<'tcx> = VariantDef_<'tcx, 'static>; +pub type FieldDef<'tcx> = FieldDef_<'tcx, 'static>; -pub struct VariantDef<'tcx, 'lt: 'tcx> { +pub struct VariantDef_<'tcx, 'lt: 'tcx> { pub did: DefId, pub name: Name, // struct's name if this is a struct pub disr_val: Disr, - pub fields: Vec> + pub fields: Vec> } -pub struct FieldDef<'tcx, 'lt: 'tcx> { +pub struct FieldDef_<'tcx, 'lt: 'tcx> { pub did: DefId, - pub name: Name, // XXX if tuple-like + // special_idents::unnamed_field.name + // if this is a tuple-like field + pub name: Name, pub vis: ast::Visibility, // TyIVar is used here to allow for ty: TyIVar<'tcx, 'lt> @@ -3294,7 +3304,7 @@ pub struct FieldDef<'tcx, 'lt: 'tcx> { /// is here so 'tcx can be variant. pub struct ADTDef_<'tcx, 'lt: 'tcx> { pub did: DefId, - pub variants: Vec>, + pub variants: Vec>, flags: Cell, } @@ -3313,11 +3323,18 @@ fn hash(&self, s: &mut H) { } } -#[derive(Copy, Clone, Debug)] + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ADTKind { Struct, Enum } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum VariantKind { Dict, Tuple, Unit } + impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { - fn new(tcx: &ctxt<'tcx>, did: DefId, kind: ADTKind) -> Self { + fn new(tcx: &ctxt<'tcx>, + did: DefId, + kind: ADTKind, + variants: Vec>) -> Self { let mut flags = ADTFlags::NO_ADT_FLAGS; if tcx.has_attr(did, "fundamental") { flags = flags | ADTFlags::IS_FUNDAMENTAL; @@ -3330,7 +3347,7 @@ fn new(tcx: &ctxt<'tcx>, did: DefId, kind: ADTKind) -> Self { } ADTDef { did: did, - variants: vec![], + variants: variants, flags: Cell::new(flags), } } @@ -3374,9 +3391,9 @@ pub fn has_dtor(&self, tcx: &ctxt<'tcx>) -> bool { tcx.destructor_for_type.borrow().contains_key(&self.did) } - pub fn is_tuple_struct(&self, tcx: &ctxt<'tcx>) -> bool { - let fields = tcx.lookup_struct_fields(self.did); - !fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field) + pub fn struct_variant(&self) -> &ty::VariantDef_<'tcx, 'lt> { + assert!(self.adt_kind() == ADTKind::Struct); + &self.variants[0] } #[inline] @@ -3388,6 +3405,104 @@ pub fn type_scheme(&self, tcx: &ctxt<'tcx>) -> TypeScheme<'tcx> { pub fn predicates(&self, tcx: &ctxt<'tcx>) -> GenericPredicates<'tcx> { tcx.lookup_predicates(self.did) } + + #[inline] + pub fn all_fields(&self) -> + iter::FlatMap< + slice::Iter>, + slice::Iter>, + for<'s> fn(&'s VariantDef_<'tcx, 'lt>) + -> slice::Iter<'s, FieldDef_<'tcx, 'lt>> + > { + self.variants.iter().flat_map(VariantDef_::fields_iter) + } + + #[inline] + pub fn is_empty(&self) -> bool { + // FIXME(#TODO(wxyz)): be smarter here + self.variants.is_empty() + } + + #[inline] + pub fn is_univariant(&self) -> bool { + self.variants.len() == 1 + } + + pub fn is_payloadfree(&self) -> bool { + !self.variants.is_empty() && + self.variants.iter().all(|v| v.fields.is_empty()) + } + + pub fn variant_with_id(&self, vid: DefId) -> &VariantDef_<'tcx, 'lt> { + self.variants + .iter() + .find(|v| v.did == vid) + .expect("variant_with_id: unknown variant") + } + + pub fn variant_of_def(&self, def: def::Def) -> &VariantDef_<'tcx, 'lt> { + match def { + def::DefVariant(_, vid, _) => self.variant_with_id(vid), + def::DefStruct(..) | def::DefTy(..) => self.struct_variant(), + _ => panic!("unexpected def {:?} in variant_of_def", def) + } + } +} + +impl<'tcx, 'lt> VariantDef_<'tcx, 'lt> { + #[inline] + fn fields_iter(&self) -> slice::Iter> { + self.fields.iter() + } + + pub fn kind(&self) -> VariantKind { + match self.fields.get(0) { + None => VariantKind::Unit, + Some(&FieldDef_ { name, .. }) if name == special_idents::unnamed_field.name => { + VariantKind::Tuple + } + Some(_) => VariantKind::Dict + } + } + + pub fn is_tuple_struct(&self) -> bool { + self.kind() == VariantKind::Tuple + } + + #[inline] + pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef_<'tcx, 'lt>> { + self.fields.iter().find(|f| f.name == name) + } + + #[inline] + pub fn field_named(&self, name: ast::Name) -> &FieldDef_<'tcx, 'lt> { + self.find_field_named(name).unwrap() + } +} + +impl<'tcx, 'lt> FieldDef_<'tcx, 'lt> { + pub fn new(did: DefId, + name: Name, + vis: ast::Visibility) -> Self { + FieldDef_ { + did: did, + name: name, + vis: vis, + ty: TyIVar::new() + } + } + + pub fn ty(&self, tcx: &ctxt<'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { + self.unsubst_ty().subst(tcx, subst) + } + + pub fn unsubst_ty(&self) -> Ty<'tcx> { + self.ty.unwrap() + } + + pub fn fulfill_ty(&self, ty: Ty<'lt>) { + self.ty.fulfill(ty); + } } /// Records the substitutions used to translate the polytype for an @@ -6132,7 +6247,7 @@ pub fn lookup_trait_def(&self, did: ast::DefId) -> &'tcx TraitDef<'tcx> { } /// Given the did of a trait, returns its canonical trait ref. - pub fn lookup_adt_def(&self, did: ast::DefId) -> &'tcx ADTDef<'tcx> { + pub fn lookup_adt_def(&self, did: ast::DefId) -> &'tcx ADTDef_<'tcx, 'tcx> { lookup_locally_or_in_crate_store( "adt_defs", did, &self.adt_defs, || csearch::get_adt_def(self, did) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e5886cd13c..2f63d7abe4a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2980,7 +2980,7 @@ fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, |base_t, _| { match base_t.sty { ty::TyStruct(base_def, substs) => { - tuple_like = base_def.is_tuple_struct(tcx); + tuple_like = base_def.struct_variant().is_tuple_struct(); if tuple_like { debug!("tuple struct named {:?}", base_t); let fields = tcx.lookup_struct_fields(base_def.did); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 708825fc95a..c9f6ccb8cb2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -71,9 +71,12 @@ use middle::free_region::FreeRegionMap; use middle::region; use middle::resolve_lifetime; +use middle::const_eval::{self, ConstVal}; +use middle::const_eval::EvalHint::UncheckedExprHint; use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme}; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme, IntTypeExt}; +use middle::ty::{VariantKind}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; @@ -89,8 +92,10 @@ use syntax::abi; use syntax::ast; use syntax::ast_util::local_def; +use syntax::attr; use syntax::codemap::Span; use syntax::parse::token::special_idents; +use syntax::print::pprust; use syntax::ptr::P; use syntax::visit; @@ -563,48 +568,6 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, } } -fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - enum_scheme: ty::TypeScheme<'tcx>, - enum_predicates: ty::GenericPredicates<'tcx>, - variants: &[P]) { - let tcx = ccx.tcx; - let icx = ccx.icx(&enum_predicates); - - // Create a set of parameter types shared among all the variants. - for variant in variants { - let variant_def_id = local_def(variant.node.id); - - // Nullary enum constructors get turned into constants; n-ary enum - // constructors get turned into functions. - let result_ty = match variant.node.kind { - ast::TupleVariantKind(ref args) if !args.is_empty() => { - let rs = ExplicitRscope; - let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); - tcx.mk_ctor_fn(variant_def_id, &input_tys, enum_scheme.ty) - } - - ast::TupleVariantKind(_) => { - enum_scheme.ty - } - - ast::StructVariantKind(ref struct_def) => { - convert_struct(ccx, &**struct_def, enum_scheme.clone(), - enum_predicates.clone(), variant.node.id); - enum_scheme.ty - } - }; - - let variant_scheme = TypeScheme { - generics: enum_scheme.generics.clone(), - ty: result_ty - }; - - tcx.register_item_type(variant_def_id, variant_scheme.clone()); - tcx.predicates.borrow_mut().insert(variant_def_id, enum_predicates.clone()); - write_ty_to_tcx(tcx, variant.node.id, result_ty); - } -} - fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, sig: &ast::MethodSig, @@ -657,10 +620,12 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_generics: &ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, v: &ast::StructField, + ty_f: &'tcx ty::FieldDef_<'tcx, 'tcx>, origin: ast::DefId) -> ty::FieldTy { let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &*v.node.ty); + ty_f.fulfill_ty(tt); write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ @@ -803,10 +768,11 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { ast::ItemEnum(ref enum_definition, _) => { let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); - get_enum_variant_types(ccx, - scheme, - predicates, - &enum_definition.variants); + convert_enum_variant_types(ccx, + tcx.lookup_adt_def(local_def(it.id)), + scheme, + predicates, + &enum_definition.variants); }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { let trait_ref = @@ -1048,10 +1014,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } }, ast::ItemStruct(ref struct_def, _) => { - // Write the class type. let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); - convert_struct(ccx, &**struct_def, scheme, predicates, it.id); + + let variant = tcx.lookup_adt_def(local_def(it.id)).struct_variant(); + convert_struct_variant_types(ccx, &struct_def, variant, &scheme, &predicates); + if let Some(ctor_id) = struct_def.ctor_id { + convert_variant_ctor(tcx, ctor_id, variant, scheme, predicates); + } }, ast::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); @@ -1068,74 +1038,216 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } } -fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - struct_def: &ast::StructDef, - scheme: ty::TypeScheme<'tcx>, - predicates: ty::GenericPredicates<'tcx>, - id: ast::NodeId) { +fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, + ctor_id: ast::NodeId, + variant: &'tcx ty::VariantDef<'tcx>, + scheme: ty::TypeScheme<'tcx>, + predicates: ty::GenericPredicates<'tcx>) { + let ctor_ty = match variant.kind() { + VariantKind::Unit | VariantKind::Dict => scheme.ty, + VariantKind::Tuple => { + let inputs: Vec<_> = + variant.fields + .iter() + .map(|field| field.unsubst_ty()) + .collect(); + tcx.mk_ctor_fn(local_def(ctor_id), + &inputs[..], + scheme.ty) + } + }; + write_ty_to_tcx(tcx, ctor_id, ctor_ty); + tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); + tcx.register_item_type(local_def(ctor_id), + TypeScheme { + generics: scheme.generics, + ty: ctor_ty + }); +} + +fn convert_struct_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + def: &ast::StructDef, + variant: &'tcx ty::VariantDef_<'tcx, 'tcx>, + scheme: &ty::TypeScheme<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) { + let field_tys = def.fields.iter().zip(variant.fields.iter()).map(|(f, ty_f)| { + convert_field(ccx, &scheme.generics, &predicates, f, ty_f, variant.did) + }).collect(); + ccx.tcx.struct_fields.borrow_mut().insert(variant.did, Rc::new(field_tys)); +} + +fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + def: &'tcx ty::ADTDef_<'tcx, 'tcx>, + scheme: ty::TypeScheme<'tcx>, + predicates: ty::GenericPredicates<'tcx>, + variants: &[P]) { let tcx = ccx.tcx; + let icx = ccx.icx(&predicates); - // Write the type of each of the members and check for duplicate fields. - let mut seen_fields: FnvHashMap = FnvHashMap(); - let field_tys = struct_def.fields.iter().map(|f| { - let result = convert_field(ccx, &scheme.generics, &predicates, f, local_def(id)); + // Create a set of parameter types shared among all the variants. + for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { + match variant.node.kind { + ast::TupleVariantKind(ref args) => { + let rs = ExplicitRscope; + let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); + for (field, &ty) in ty_variant.fields.iter().zip(input_tys.iter()) { + field.fulfill_ty(ty); + } + } + + ast::StructVariantKind(ref struct_def) => { + convert_struct_variant_types(ccx, &struct_def, ty_variant, &scheme, &predicates); + } + }; - if result.name != special_idents::unnamed_field.name { - let dup = match seen_fields.get(&result.name) { - Some(prev_span) => { + convert_variant_ctor( + tcx, + variant.node.id, + ty_variant, + scheme.clone(), + predicates.clone() + ); + } +} + +fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, + did: ast::DefId, + name: ast::Name, + disr_val: ty::Disr, + def: &ast::StructDef) -> ty::VariantDef_<'tcx, 'tcx> { + let mut seen_fields: FnvHashMap = FnvHashMap(); + let fields = def.fields.iter().map(|f| { + let fid = local_def(f.node.id); + match f.node.kind { + ast::NamedField(ident, vis) => { + let dup_span = seen_fields.get(&ident.name).cloned(); + if let Some(prev_span) = dup_span { span_err!(tcx.sess, f.span, E0124, "field `{}` is already declared", - result.name); - span_note!(tcx.sess, *prev_span, "previously declared here"); - true - }, - None => false, - }; - // FIXME(#6393) this whole dup thing is just to satisfy - // the borrow checker :-( - if !dup { - seen_fields.insert(result.name, f.span); + ident.name); + span_note!(tcx.sess, prev_span, "previously declared here"); + } else { + seen_fields.insert(ident.name, f.span); + } + + ty::FieldDef_::new(fid, ident.name, vis) + }, + ast::UnnamedField(vis) => { + ty::FieldDef_::new(fid, special_idents::unnamed_field.name, vis) } } - - result }).collect(); + ty::VariantDef_ { + did: did, + name: name, + disr_val: disr_val, + fields: fields + } +} - tcx.struct_fields.borrow_mut().insert(local_def(id), Rc::new(field_tys)); +fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>, + it: &ast::Item, + def: &ast::StructDef) + -> &'tcx ty::ADTDef_<'tcx, 'tcx> +{ + let did = local_def(it.id); + tcx.intern_adt_def( + did, + ty::ADTKind::Struct, + vec![convert_struct_variant(tcx, did, it.ident.name, 0, def)] + ) +} - // If this struct is enum-like or tuple-like, create the type of its - // constructor. - if let Some(ctor_id) = struct_def.ctor_id { - let substs = mk_item_substs(ccx, &scheme.generics); - let selfty = tcx.mk_struct(tcx.lookup_adt_def(local_def(id)), - tcx.mk_substs(substs)); - if struct_def.fields.is_empty() { - // Enum-like. - write_ty_to_tcx(tcx, ctor_id, selfty); +fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, + it: &ast::Item, + def: &ast::EnumDef) + -> &'tcx ty::ADTDef_<'tcx, 'tcx> +{ + fn evaluate_disr_expr<'tcx>(tcx: &ty::ctxt<'tcx>, + repr_ty: Ty<'tcx>, + e: &ast::Expr) -> Option { + debug!("disr expr, checking {}", pprust::expr_to_string(e)); + + let hint = UncheckedExprHint(repr_ty); + match const_eval::eval_const_expr_partial(tcx, e, hint) { + Ok(ConstVal::Int(val)) => Some(val as ty::Disr), + Ok(ConstVal::Uint(val)) => Some(val as ty::Disr), + Ok(_) => { +// let sign_desc = if repr_type.is_signed() { +// "signed" +// } else { +// "unsigned" +// }; +// span_err!(self.sess, e.span, E0079, +// "expected {} integer constant", +// sign_desc); + None + }, + Err(_) => { +// span_err!(self.sess, err.span, E0080, +// "constant evaluation error: {}", +// err.description()); + None + } + } + } - tcx.register_item_type(local_def(ctor_id), scheme); - tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); - } else if struct_def.fields[0].node.kind.is_unnamed() { - // Tuple-like. - let inputs: Vec<_> = - struct_def.fields - .iter() - .map(|field| tcx.lookup_item_type( - local_def(field.node.id)).ty) - .collect(); - let ctor_fn_ty = tcx.mk_ctor_fn(local_def(ctor_id), - &inputs[..], - selfty); - write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); - tcx.register_item_type(local_def(ctor_id), - TypeScheme { - generics: scheme.generics, - ty: ctor_fn_ty - }); - tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); + fn next_disr(repr_type: attr::IntType, + prev_disr_val: Option) -> Option { + if let Some(prev_disr_val) = prev_disr_val { + let result = repr_type.disr_incr(prev_disr_val); +// if let None = result { +// self.report_discrim_overflow(v.span, &v.node.name.name.as_str(), +// repr_type, prev_disr_val); +// } + result + } else { + Some(ty::INITIAL_DISCRIMINANT_VALUE) } } + fn convert_enum_variant<'tcx>(tcx: &ty::ctxt<'tcx>, + v: &ast::Variant, + disr: ty::Disr) + -> ty::VariantDef_<'tcx, 'tcx> + { + let did = local_def(v.node.id); + let name = v.node.name.name; + match v.node.kind { + ast::TupleVariantKind(ref va) => { + ty::VariantDef_ { + did: did, + name: name, + disr_val: disr, + fields: va.iter().map(|&ast::VariantArg { id, .. }| { + ty::FieldDef_::new( + local_def(id), + special_idents::unnamed_field.name, + ast::Visibility::Public + ) + }).collect() + } + } + ast::StructVariantKind(ref def) => { + convert_struct_variant(tcx, did, name, disr, &def) + } + } + } + let did = local_def(it.id); + let repr_hints = tcx.lookup_repr_hints(did); + let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0)); + let mut prev_disr = None; + let variants = def.variants.iter().map(|v| { + let disr = match v.node.disr_expr { + Some(ref e) => evaluate_disr_expr(tcx, repr_type_ty, e), + None => next_disr(repr_type, prev_disr) + }.unwrap_or(repr_type.disr_wrap_incr(prev_disr)); + + let v = convert_enum_variant(tcx, v, disr); + prev_disr = Some(disr); + v + }).collect(); + tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Enum, variants) } /// Ensures that the super-predicates of the trait with def-id @@ -1469,18 +1581,17 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let ty = ccx.icx(generics).to_ty(&ExplicitRscope, &**t); ty::TypeScheme { ty: ty, generics: ty_generics } } - ast::ItemEnum(_, ref generics) => { - // Create a new generic polytype. + ast::ItemEnum(ref ei, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let def = tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Enum); + let def = convert_enum_def(tcx, it, ei); let t = tcx.mk_enum(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } - ast::ItemStruct(_, ref generics) => { + ast::ItemStruct(ref si, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let def = tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Struct); + let def = convert_struct_def(tcx, it, si); let t = tcx.mk_struct(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } -- GitLab