diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 26cb4f917c566..d1f45b12febb9 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -138,6 +138,7 @@ pub mod util { pub mod nodemap; pub mod snapshot_vec; pub mod lev_distance; + pub mod ivar; } pub mod lib { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a4f69e651df60..d26beccc9cacf 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -601,8 +601,8 @@ impl LintPass for RawPointerDerive { } match ty::node_id_to_type(cx.tcx, item.id).sty { - ty::ty_enum(did, _) => did, - ty::ty_struct(did, _) => did, + ty::ty_enum(def, _) | + ty::ty_struct(def, _) => def.def_id, _ => return, } } @@ -727,15 +727,15 @@ impl LintPass for UnusedResults { match t.sty { ty::ty_tup(ref tys) if tys.is_empty() => return, ty::ty_bool => return, - ty::ty_struct(did, _) | - ty::ty_enum(did, _) => { - if ast_util::is_local(did) { - if let ast_map::NodeItem(it) = cx.tcx.map.get(did.node) { + ty::ty_struct(def, _) | + ty::ty_enum(def, _) => { + if ast_util::is_local(def.def_id) { + if let ast_map::NodeItem(it) = cx.tcx.map.get(def.def_id.node) { warned |= check_must_use(cx, &it.attrs, s.span); } } else { - let attrs = csearch::get_item_attrs(&cx.sess().cstore, did); - warned |= check_must_use(cx, &attrs[..], s.span); + let attrs = csearch::get_item_attrs(&cx.sess().cstore, def.def_id); + warned |= check_must_use(cx, &attrs, s.span); } } _ => {} @@ -1626,16 +1626,18 @@ impl LintPass for MissingCopyImplementations { if ast_generics.is_parameterized() { return } + let def = ty::lookup_datatype_def(cx.tcx, ast_util::local_def(item.id)); ty::mk_struct(cx.tcx, - ast_util::local_def(item.id), + def, cx.tcx.mk_substs(Substs::empty())) } ast::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return } + let def = ty::lookup_datatype_def(cx.tcx, ast_util::local_def(item.id)); ty::mk_enum(cx.tcx, - ast_util::local_def(item.id), + def, cx.tcx.mk_substs(Substs::empty())) } _ => return, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index f5c4cce065955..926af746a604b 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -13,7 +13,6 @@ use metadata::common::*; use metadata::cstore; use metadata::decoder; -use middle::def; use middle::lang_items; use middle::ty; @@ -36,6 +35,14 @@ pub struct MethodInfo { pub vis: ast::Visibility, } +#[derive(Copy)] +pub struct FieldInfo { + pub name: ast::Name, + pub def_id: ast::DefId, + pub vis: ast::Visibility, + pub origin: ast::DefId, +} + pub fn get_symbol(cstore: &cstore::CStore, def: ast::DefId) -> String { let cdata = cstore.get_crate_data(def.krate); decoder::get_symbol(cdata.data(), def.node) @@ -114,19 +121,6 @@ pub fn maybe_get_item_ast<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId, decoder::maybe_get_item_ast(&*cdata, tcx, def.node, decode_inlined_item) } -pub fn get_enum_variant_defs(cstore: &cstore::CStore, enum_id: ast::DefId) - -> Vec<(def::Def, ast::Name, ast::Visibility)> { - let cdata = cstore.get_crate_data(enum_id.krate); - decoder::get_enum_variant_defs(&*cstore.intr, &*cdata, enum_id.node) -} - -pub fn get_enum_variants<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) - -> Vec>> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_enum_variants(cstore.intr.clone(), &*cdata, def.node, tcx) -} - /// Returns information about the given implementation. pub fn get_impl_items(cstore: &cstore::CStore, impl_def_id: ast::DefId) -> Vec { @@ -203,9 +197,16 @@ pub fn get_item_attrs(cstore: &cstore::CStore, decoder::get_item_attrs(&*cdata, def_id.node) } -pub fn get_struct_fields(cstore: &cstore::CStore, - def: ast::DefId) - -> Vec { +pub fn get_datatype_def<'tcx>(tcx: &ty::ctxt<'tcx>, + def: ast::DefId) -> &'tcx ty::DatatypeDef<'tcx> { + let cstore = &tcx.sess.cstore; + let cdata = cstore.get_crate_data(def.krate); + decoder::get_datatype_def(tcx, cstore.intr.clone(), &*cdata, def.node) +} + +/// Get the fields for the struct. Use this when you don't have a type context to +/// pass to `ty::lookup_struct_def`. +pub fn get_struct_fields(cstore: &cstore::CStore, def: ast::DefId) -> Vec { let cdata = cstore.get_crate_data(def.krate); decoder::get_struct_fields(cstore.intr.clone(), &*cdata, def.node) } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 0503045ac6e2d..7b5908fa2b177 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -18,7 +18,7 @@ use self::Family::*; use back::svh::Svh; use metadata::cstore::crate_metadata; use metadata::common::*; -use metadata::csearch::MethodInfo; +use metadata::csearch::{FieldInfo, MethodInfo}; use metadata::csearch; use metadata::cstore; use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, @@ -727,72 +727,6 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeI } } -pub fn get_enum_variant_defs(intr: &IdentInterner, - cdata: Cmd, - id: ast::NodeId) - -> Vec<(def::Def, ast::Name, ast::Visibility)> { - let data = cdata.data(); - let items = reader::get_doc(rbml::Doc::new(data), tag_items); - let item = find_item(id, items); - enum_variant_ids(item, cdata).iter().map(|did| { - let item = find_item(did.node, items); - let name = item_name(intr, item); - let visibility = item_visibility(item); - match item_to_def_like(item, *did, cdata.cnum) { - DlDef(def @ def::DefVariant(..)) => (def, name, visibility), - _ => unreachable!() - } - }).collect() -} - -pub fn get_enum_variants<'tcx>(intr: Rc, cdata: Cmd, id: ast::NodeId, - tcx: &ty::ctxt<'tcx>) -> Vec>> { - let data = cdata.data(); - let items = reader::get_doc(rbml::Doc::new(data), tag_items); - let item = find_item(id, items); - let mut disr_val = 0; - enum_variant_ids(item, cdata).iter().map(|did| { - let item = find_item(did.node, items); - let ctor_ty = item_type(ast::DefId { krate: cdata.cnum, node: id}, - item, tcx, cdata); - let name = item_name(&*intr, item); - let (ctor_ty, arg_tys, arg_names) = match ctor_ty.sty { - ty::ty_bare_fn(_, ref f) => - (Some(ctor_ty), f.sig.0.inputs.clone(), None), - _ => { // Nullary or struct enum variant. - let mut arg_names = Vec::new(); - let arg_tys = get_struct_fields(intr.clone(), cdata, did.node) - .iter() - .map(|field_ty| { - arg_names.push(ast::Ident::new(field_ty.name)); - get_type(cdata, field_ty.id.node, tcx).ty - }) - .collect(); - let arg_names = if arg_names.len() == 0 { None } else { Some(arg_names) }; - - (None, arg_tys, arg_names) - } - }; - match variant_disr_val(item) { - Some(val) => { disr_val = val; } - _ => { /* empty */ } - } - let old_disr_val = disr_val; - disr_val += 1; - Rc::new(ty::VariantInfo { - args: arg_tys, - arg_names: arg_names, - ctor_ty: ctor_ty, - name: name, - // I'm not even sure if we encode visibility - // for variants -- TEST -- tjc - id: *did, - disr_val: old_disr_val, - vis: ast::Inherited - }) - }).collect() -} - fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { fn get_mutability(ch: u8) -> ast::Mutability { match ch as char { @@ -1089,40 +1023,164 @@ fn struct_field_family_to_visibility(family: Family) -> ast::Visibility { } } -pub fn get_struct_fields(intr: Rc, cdata: Cmd, id: ast::NodeId) - -> Vec { +pub fn get_datatype_def<'tcx>(tcx: &ty::ctxt<'tcx>, intr: Rc, + cdata: Cmd, id: ast::NodeId) -> &'tcx ty::DatatypeDef<'tcx> { let data = cdata.data(); let item = lookup_item(id, data); - let mut result = Vec::new(); + + let family = item_family(item); + match family { + Enum => get_enum_datatype_def(tcx, &*intr, cdata, id), + Struct => get_struct_datatype_def(tcx, &*intr, cdata, id), + _ => tcx.sess.bug("Non data-type item family in get_datatype_def") + } +} + +fn get_struct_datatype_def<'tcx>(tcx: &ty::ctxt<'tcx>, intr: &IdentInterner, + cdata: Cmd, id: ast::NodeId) -> &'tcx ty::DatatypeDef<'tcx> { + let data = cdata.data(); + let item = lookup_item(id, data); + + let name = item_name(intr, item); + let def_id = item_def_id(item, cdata); + + let fields = get_variant_fields(intr, cdata, item); + let def = tcx.mk_datatype_def(ty::DatatypeDef { + def_id: def_id, + variants: vec![ty::VariantDef { + id: def_id, + name: name, + disr_val: 0, + fields: fields, + }] + }); + + tcx.datatype_defs.borrow_mut().insert(def_id, def); + + for fld in def.variants.iter().flat_map(|v| v.fields.iter()) { + // FIXME(aatch) I shouldn't have to use get_type here, but using item_type seems + // to break things (Like cause infinite recursion in trans) + let ty = get_type(cdata, fld.id.node, tcx).ty; + fld.set_ty(ty); + } + + def +} + +fn get_enum_datatype_def<'tcx>(tcx: &ty::ctxt<'tcx>, intr: &IdentInterner, + cdata: Cmd, id: ast::NodeId) -> &'tcx ty::DatatypeDef<'tcx> { + let data = cdata.data(); + let item = lookup_item(id, data); + + let def_id = item_def_id(item, cdata); + + let variants_doc = reader::get_doc(rbml::Doc::new(data), tag_items); + + let mut disr_val = 0; + let variants = enum_variant_ids(item, cdata).iter().map(|did| { + let item = find_item(did.node, variants_doc); + let vname = item_name(intr, item); + match variant_disr_val(item) { + Some(val) => { disr_val = val; } + _ => {} + } + + let fields = get_variant_fields(intr, cdata, item); + + ty::VariantDef { + id: *did, + name: vname, + disr_val: disr_val, + fields: fields, + } + }).collect(); + + let def = tcx.mk_datatype_def(ty::DatatypeDef { + def_id: def_id, + variants: variants, + }); + + tcx.datatype_defs.borrow_mut().insert(def_id, def); + for fld in def.variants.iter().flat_map(|v| v.fields.iter()) { + // FIXME(aatch) I shouldn't have to use get_type here, but using item_type seems + // to break things (Like cause infinite recursion in trans) + let ty = get_type(cdata, fld.id.node, tcx).ty; + fld.set_ty(ty); + } + + def +} + +fn get_variant_fields<'tcx>(intr: &IdentInterner, cdata: Cmd, + item: rbml::Doc) -> Vec> { + + let mut fields = Vec::new(); reader::tagged_docs(item, tag_item_field, |an_item| { let f = item_family(an_item); - if f == PublicField || f == InheritedField { - let name = item_name(&*intr, an_item); - let did = item_def_id(an_item, cdata); - let tagdoc = reader::get_doc(an_item, tag_item_field_origin); - let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); - result.push(ty::field_ty { - name: name, - id: did, - vis: struct_field_family_to_visibility(f), - origin: origin_id, - }); - } + let name = item_name(intr, an_item); + let did = item_def_id(an_item, cdata); + + let tagdoc = reader::get_doc(an_item, tag_item_field_origin); + let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + let fld = ty::FieldTy::new(did, name, + struct_field_family_to_visibility(f), + origin_id); + fields.push(fld); true }); + reader::tagged_docs(item, tag_item_unnamed_field, |an_item| { let did = item_def_id(an_item, cdata); let tagdoc = reader::get_doc(an_item, tag_item_field_origin); let f = item_family(an_item); let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); - result.push(ty::field_ty { + let fld = ty::FieldTy::new(did, special_idents::unnamed_field.name, + struct_field_family_to_visibility(f), + origin_id); + fields.push(fld); + true + }); + + return fields; +} + +pub fn get_struct_fields(intr: Rc, + cdata: Cmd, id: ast::NodeId) -> Vec { + let data = cdata.data(); + let item = lookup_item(id, data); + let mut result = Vec::new(); + reader::tagged_docs(item, tag_item_field, |an_item| { + let f = item_family(an_item); + let name = item_name(&*intr, an_item); + let did = item_def_id(an_item, cdata); + + let tagdoc = reader::get_doc(an_item, tag_item_field_origin); + let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + + result.push(FieldInfo { + name: name, + def_id: did, + vis: struct_field_family_to_visibility(f), + origin: origin_id, + }); + true + }); + reader::tagged_docs(item, tag_item_unnamed_field, |an_item| { + let did = item_def_id(an_item, cdata); + let f = item_family(an_item); + + let tagdoc = reader::get_doc(an_item, tag_item_field_origin); + let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + + result.push(FieldInfo { name: special_idents::unnamed_field.name, - id: did, + def_id: did, vis: struct_field_family_to_visibility(f), origin: origin_id, }); true }); + result } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index ee2745ca66bc5..715b3ea5139ec 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -295,9 +295,9 @@ fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { rbml_w.end_tag(); } -fn encode_struct_fields(rbml_w: &mut Encoder, - fields: &[ty::field_ty], - origin: DefId) { +fn encode_struct_fields<'tcx>(rbml_w: &mut Encoder, + fields: &[ty::FieldTy<'tcx>], + origin: DefId) { for f in fields { if f.name == special_idents::unnamed_field.name { rbml_w.start_tag(tag_item_unnamed_field); @@ -322,10 +322,10 @@ fn encode_enum_variant_info(ecx: &EncodeContext, index: &mut Vec>) { debug!("encode_enum_variant_info(id={})", id); - let mut disr_val = 0; let mut i = 0; - let vi = ty::enum_variants(ecx.tcx, - DefId { krate: ast::LOCAL_CRATE, node: id }); + let def = ty::lookup_datatype_def(ecx.tcx, + DefId { krate: ast::LOCAL_CRATE, node: id }); + let vi = &def.variants[]; for variant in variants { let def_id = local_def(variant.node.id); index.push(entry { @@ -347,27 +347,19 @@ fn encode_enum_variant_info(ecx: &EncodeContext, let stab = stability::lookup(ecx.tcx, ast_util::local_def(variant.node.id)); encode_stability(rbml_w, stab); - match variant.node.kind { - ast::TupleVariantKind(_) => {}, - ast::StructVariantKind(_) => { - let fields = ty::lookup_struct_fields(ecx.tcx, 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 (*vi)[i].disr_val != disr_val { - encode_disr_val(ecx, rbml_w, (*vi)[i].disr_val); - disr_val = (*vi)[i].disr_val; - } - encode_bounds_and_type_for_item(rbml_w, ecx, def_id.local_id()); + let fields = &vi[i].fields[]; + 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); + + encode_disr_val(ecx, rbml_w, (*vi)[i].disr_val); + encode_bounds_and_type_for_item(rbml_w, ecx, variant.node.id); ecx.tcx.map.with_path(variant.node.id, |path| encode_path(rbml_w, path)); rbml_w.end_tag(); - disr_val += 1; i += 1; } } @@ -683,11 +675,10 @@ 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::field_ty], - global_index: &mut Vec>) - -> Vec> { +fn encode_info_for_struct<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + fields: &[ty::FieldTy<'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(); @@ -1142,56 +1133,57 @@ fn encode_info_for_item(ecx: &EncodeContext, index); } ast::ItemStruct(ref struct_def, _) => { - let fields = ty::lookup_struct_fields(tcx, def_id); - - /* 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 def = ty::lookup_datatype_def(tcx, def_id); + let fields = &def.variants[0].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); - /* Index the class*/ - add_to_index(item, rbml_w, index); + // Index the class + add_to_index(item, rbml_w, index); - /* Now, make an item for the class itself */ - rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); - encode_family(rbml_w, 'S'); - encode_bounds_and_type_for_item(rbml_w, ecx, item.id); + // Now, make an item for the class itself + rbml_w.start_tag(tag_items_data_item); + encode_def_id(rbml_w, def_id); + encode_family(rbml_w, 'S'); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); - encode_item_variances(rbml_w, ecx, item.id); - encode_name(rbml_w, item.ident.name); - encode_attributes(rbml_w, &item.attrs); - encode_path(rbml_w, path.clone()); - encode_stability(rbml_w, stab); - encode_visibility(rbml_w, vis); - encode_repr_attrs(rbml_w, ecx, &item.attrs); + encode_item_variances(rbml_w, ecx, item.id); + encode_name(rbml_w, item.ident.name); + encode_attributes(rbml_w, &item.attrs[]); + encode_path(rbml_w, path.clone()); + encode_stability(rbml_w, stab); + encode_visibility(rbml_w, vis); + encode_repr_attrs(rbml_w, ecx, &item.attrs[]); - /* 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 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_inlined_item(ecx, rbml_w, IIItemRef(item)); + encode_inlined_item(ecx, rbml_w, IIItemRef(item)); - // Encode inherent implementations for this structure. - encode_inherent_implementations(ecx, rbml_w, def_id); + // Encode inherent implementations for this structure. + encode_inherent_implementations(ecx, rbml_w, def_id); - /* Each class has its own index -- encode it */ - encode_index(rbml_w, idx, write_i64); - rbml_w.end_tag(); + // Each class has its own index -- encode it + encode_index(rbml_w, idx, write_i64); + rbml_w.end_tag(); - // If this is a tuple-like struct, encode the type of the constructor. - match struct_def.ctor_id { - Some(ctor_id) => { - encode_info_for_struct_ctor(ecx, rbml_w, item.ident, - ctor_id, index, def_id.node); - } - None => {} - } + // If this is a tuple-like struct, encode the type of the constructor. + match struct_def.ctor_id { + Some(ctor_id) => { + encode_info_for_struct_ctor(ecx, rbml_w, item.ident, + ctor_id, index, def_id.node); + } + None => {} + } } ast::ItemDefaultImpl(unsafety, _) => { add_to_index(item, rbml_w, index); diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index baecfb7eb22c5..2903a879396dd 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -129,21 +129,6 @@ pub fn parse_state_from_data<'a, 'tcx>(data: &'a [u8], crate_num: ast::CrateNum, } } -fn data_log_string(data: &[u8], pos: uint) -> String { - let mut buf = String::new(); - buf.push_str("<<"); - for i in pos..data.len() { - let c = data[i]; - if c > 0x20 && c <= 0x7F { - buf.push(c as char); - } else { - buf.push('.'); - } - } - buf.push_str(">>"); - buf -} - pub fn parse_ty_closure_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint, @@ -160,7 +145,7 @@ pub fn parse_ty_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt<'tcx>, conv: F) -> Ty<'tcx> where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { - debug!("parse_ty_data {}", data_log_string(data, pos)); + debug!("parse_ty_data(data=#{} bytes, pos={}", data.len(), pos); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_ty(&mut st, conv) } @@ -169,7 +154,7 @@ pub fn parse_region_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tc conv: F) -> ty::Region where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { - debug!("parse_region_data {}", data_log_string(data, pos)); + debug!("parse_region_data(data=#{} bytes, pos={}", data.len(), pos); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_region(&mut st, conv) } @@ -179,7 +164,7 @@ pub fn parse_bare_fn_ty_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos -> ty::BareFnTy<'tcx> where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { - debug!("parse_bare_fn_ty_data {}", data_log_string(data, pos)); + debug!("parse_bare_fn_ty_data(data=#{} bytes, pos={}", data.len(), pos); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_bare_fn_ty(&mut st, conv) } @@ -189,7 +174,7 @@ pub fn parse_trait_ref_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: -> Rc> where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { - debug!("parse_trait_ref_data {}", data_log_string(data, pos)); + debug!("parse_trait_ref_data(data=#{} bytes, pos={}", data.len(), pos); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_trait_ref(&mut st, conv) } @@ -198,7 +183,7 @@ pub fn parse_substs_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum, pos: ui tcx: &ty::ctxt<'tcx>, conv: F) -> subst::Substs<'tcx> where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, { - debug!("parse_substs_data {}", data_log_string(data, pos)); + debug!("parse_substs_data(data=#{} bytes, pos={}", data.len(), pos); let mut st = parse_state_from_data(data, crate_num, pos, tcx); parse_substs(&mut st, conv) } @@ -465,13 +450,14 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w } } 'c' => return tcx.types.char, - 't' => { - assert_eq!(next(st), '['); - let def = parse_def_(st, NominalType, conv); - let substs = parse_substs_(st, conv); - assert_eq!(next(st), ']'); - return ty::mk_enum(tcx, def, st.tcx.mk_substs(substs)); - } + 't' => { + assert_eq!(next(st), '['); + let def_id = parse_def_(st, NominalType, conv); + let substs = parse_substs_(st, conv); + assert_eq!(next(st), ']'); + let def = ty::lookup_datatype_def(st.tcx, def_id); + return ty::mk_enum(tcx, def, st.tcx.mk_substs(substs)); + } 'x' => { assert_eq!(next(st), '['); let trait_ref = ty::Binder(parse_trait_ref_(st, conv)); @@ -542,15 +528,16 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w } '\"' => { let _ = parse_def_(st, TypeWithId, conv); - let inner = parse_ty_(st, conv); - inner + return parse_ty_(st, conv); } 'a' => { assert_eq!(next(st), '['); let did = parse_def_(st, NominalType, conv); let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); - return ty::mk_struct(st.tcx, did, st.tcx.mk_substs(substs)); + + let def = ty::lookup_datatype_def(st.tcx, did); + return ty::mk_struct(st.tcx, def, st.tcx.mk_substs(substs)); } 'k' => { assert_eq!(next(st), '['); @@ -572,6 +559,7 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w } c => { panic!("unexpected char in type string: {}", c);} } + } fn parse_mutability(st: &mut PState) -> ast::Mutability { diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 76a365259aa57..8804b1fac9b0b 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -84,7 +84,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t } } ty::ty_enum(def, substs) => { - mywrite!(w, "t[{}|", (cx.ds)(def)); + mywrite!(w, "t[{}|", (cx.ds)(def.def_id)); enc_substs(w, cx, substs); mywrite!(w, "]"); } @@ -135,7 +135,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), token::get_name(name)) } ty::ty_struct(def, substs) => { - mywrite!(w, "a[{}|", (cx.ds)(def)); + mywrite!(w, "a[{}|", (cx.ds)(def.def_id)); enc_substs(w, cx, substs); mywrite!(w, "]"); } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 8401d25024d35..584b125964dfa 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -376,8 +376,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &ast::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { - ty::ty_struct(did, _) | - ty::ty_enum(did, _) if ty::has_dtor(v.tcx, did) => { + ty::ty_struct(def, _) | + ty::ty_enum(def, _) if ty::has_dtor(v.tcx, def.def_id) => { v.add_qualif(NEEDS_DROP); if v.mode != Mode::Var { v.tcx.sess.span_err(e.span, diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index c409c8fb13f14..88b5a38b8bea3 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -206,7 +206,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) { // Check for empty enum, because is_useful only works on inhabited types. let pat_ty = node_id_to_type(cx.tcx, scrut.id); if inlined_arms.is_empty() { - if !type_is_empty(cx.tcx, pat_ty) { + if !type_is_empty(pat_ty) { // We know the type is inhabited, so this must be wrong span_err!(cx.tcx.sess, ex.span, E0002, "non-exhaustive patterns: type {} is non-empty", @@ -241,12 +241,12 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) match p.node { ast::PatIdent(ast::BindByValue(ast::MutImmutable), ident, None) => { let pat_ty = ty::pat_ty(cx.tcx, p); - if let ty::ty_enum(def_id, _) = pat_ty.sty { + if let ty::ty_enum(enum_def, _) = pat_ty.sty { let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); if let Some(DefLocal(_)) = def { - if ty::enum_variants(cx.tcx, def_id).iter().any(|variant| + if enum_def.variants.iter().any(|variant| token::get_name(variant.name) == token::get_name(ident.node.name) - && variant.args.len() == 0 + && variant.fields.len() == 0 ) { span_warn!(cx.tcx.sess, p.span, E0170, "pattern binding `{}` is named the same as one \ @@ -501,16 +501,16 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, let pat = match left_ty.sty { ty::ty_tup(_) => ast::PatTup(pats.collect()), - ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => { - let (vid, is_structure) = match ctor { - &Variant(vid) => - (vid, ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()), - _ => - (cid, !ty::is_tuple_struct(cx.tcx, cid)) + ty::ty_enum(def, _) | ty::ty_struct(def, _) => { + let variant = if let &Variant(vid) = ctor { + def.get_variant(vid).expect("Variant is not in this type") + } else { + &def.variants[0] }; - if is_structure { - let fields = ty::lookup_struct_fields(cx.tcx, vid); - let field_pats: Vec<_> = fields.into_iter() + + if variant.fields.len() > 0 && !variant.is_tuple_variant() { + let fields = &variant.fields[]; + let field_pats: Vec<_> = fields.iter() .zip(pats) .filter(|&(_, ref pat)| pat.node != ast::PatWild(ast::PatWildSingle)) .map(|(field, pat)| Spanned { @@ -522,9 +522,9 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, } }).collect(); let has_more_fields = field_pats.len() < pats_len; - ast::PatStruct(def_to_path(cx.tcx, vid), field_pats, has_more_fields) + ast::PatStruct(def_to_path(cx.tcx, variant.id), field_pats, has_more_fields) } else { - ast::PatEnum(def_to_path(cx.tcx, vid), Some(pats.collect())) + ast::PatEnum(def_to_path(cx.tcx, variant.id), Some(pats.collect())) } } @@ -578,7 +578,7 @@ fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix, let used_constructors: Vec = rows.iter() .flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length).into_iter()) .collect(); - all_constructors(cx, left_ty, max_slice_length) + all_constructors(left_ty, max_slice_length) .into_iter() .find(|c| !used_constructors.contains(c)) } @@ -587,8 +587,7 @@ fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix, /// values of type `left_ty`. For vectors, this would normally be an infinite set /// but is instead bounded by the maximum fixed length of slice patterns in /// the column of patterns being analyzed. -fn all_constructors(cx: &MatchCheckCtxt, left_ty: Ty, - max_slice_length: uint) -> Vec { +fn all_constructors(left_ty: Ty, max_slice_length: uint) -> Vec { match left_ty.sty { ty::ty_bool => [true, false].iter().map(|b| ConstantValue(const_bool(*b))).collect(), @@ -599,9 +598,8 @@ fn all_constructors(cx: &MatchCheckCtxt, left_ty: Ty, _ => vec!(Single) }, - ty::ty_enum(eid, _) => - ty::enum_variants(cx.tcx, eid) - .iter() + ty::ty_enum(def, _) => + def.variants.iter() .map(|va| Variant(va.id)) .collect(), @@ -659,10 +657,10 @@ fn is_useful(cx: &MatchCheckCtxt, if constructors.is_empty() { match missing_constructor(cx, matrix, left_ty, max_slice_length) { None => { - all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| { + all_constructors(left_ty, max_slice_length).into_iter().map(|c| { match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) { UsefulWithWitness(pats) => UsefulWithWitness({ - let arity = constructor_arity(cx, &c, left_ty); + let arity = constructor_arity(&c, left_ty); let mut result = { let pat_slice = &pats[..]; let subpats: Vec<_> = (0..arity).map(|i| { @@ -688,7 +686,7 @@ fn is_useful(cx: &MatchCheckCtxt, }).collect(); match is_useful(cx, &matrix, v.tail(), witness) { UsefulWithWitness(pats) => { - let arity = constructor_arity(cx, &constructor, left_ty); + let arity = constructor_arity(&constructor, left_ty); let wild_pats: Vec<_> = repeat(DUMMY_WILD_PAT).take(arity).collect(); let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty); let mut new_pats = vec![enum_pat]; @@ -709,7 +707,7 @@ fn is_useful(cx: &MatchCheckCtxt, fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix, v: &[&Pat], ctor: Constructor, lty: Ty, witness: WitnessPreference) -> Usefulness { - let arity = constructor_arity(cx, &ctor, lty); + let arity = constructor_arity(&ctor, lty); let matrix = Matrix(m.iter().filter_map(|r| { specialize(cx, &r[..], &ctor, 0, arity) }).collect()); @@ -786,7 +784,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, /// /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. -pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> uint { +pub fn constructor_arity(ctor: &Constructor, ty: Ty) -> uint { match ty.sty { ty::ty_tup(ref fs) => fs.len(), ty::ty_uniq(_) => 1, @@ -799,13 +797,16 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> uin ty::ty_str => 0, _ => 1 }, - ty::ty_enum(eid, _) => { + ty::ty_enum(def, _) => { match *ctor { - Variant(id) => enum_variant_with_id(cx.tcx, eid, id).args.len(), + Variant(id) => { + let variant = def.get_variant(id).unwrap(); + variant.fields.len() + } _ => unreachable!() } } - ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(), + ty::ty_struct(def, _) => def.variants[0].fields.len(), ty::ty_vec(_, Some(n)) => n, _ => 0 } @@ -881,30 +882,35 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], ast::PatStruct(_, ref pattern_fields, _) => { // Is this a struct or an enum variant? let def = cx.tcx.def_map.borrow()[pat_id].full_def(); - let class_id = match def { + let variant = match def { DefConst(..) => cx.tcx.sess.span_bug(pat_span, "const pattern should've \ been rewritten"), - DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) { - Some(variant_id) + DefVariant(def_id, variant_id, _) => if *constructor == Variant(variant_id) { + let def = ty::lookup_datatype_def(cx.tcx, def_id); + def.get_variant(variant_id) } else { None }, _ => { // Assume this is a struct. - match ty::ty_to_def_id(node_id_to_type(cx.tcx, pat_id)) { - None => { - cx.tcx.sess.span_bug(pat_span, - "struct pattern wasn't of a \ - type with a def ID?!") - } - Some(def_id) => Some(def_id), + let def = match node_id_to_type(cx.tcx, pat_id).sty { + ty::ty_struct(def, _) => def, + ty::ty_enum(def, _) => def, + _ => cx.tcx.sess.span_bug(pat_span, "struct pattern isn't a data type") + }; + + if let &Variant(variant_id) = constructor { + def.get_variant(variant_id) + } else { + Some(&def.variants[0]) } } }; - class_id.map(|variant_id| { - let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id); - let args = struct_fields.iter().map(|sf| { + variant.map(|variant| { + let fields = &variant.fields[]; + + let args = fields.iter().map(|sf| { match pattern_fields.iter().find(|f| f.node.ident.name == sf.name) { Some(ref f) => &*f.node.pat, _ => DUMMY_WILD_PAT diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2d837ce52b56a..74895091eb554 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -135,8 +135,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_access(&mut self, lhs: &ast::Expr, name: &ast::Ident) { match ty::expr_ty_adjusted(self.tcx, lhs).sty { - ty::ty_struct(id, _) => { - let fields = ty::lookup_struct_fields(self.tcx, id); + ty::ty_struct(def, _) => { + let fields = &def.variants[0].fields[]; let field_id = fields.iter() .find(|field| field.name == name.name).unwrap().id; self.live_symbols.insert(field_id.node); @@ -147,8 +147,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: uint) { match ty::expr_ty_adjusted(self.tcx, lhs).sty { - ty::ty_struct(id, _) => { - let fields = ty::lookup_struct_fields(self.tcx, id); + ty::ty_struct(def, _) => { + let fields = &def.variants[0].fields[]; let field_id = fields[idx].id; self.live_symbols.insert(field_id.node); }, @@ -158,21 +158,26 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[codemap::Spanned]) { - let id = match self.tcx.def_map.borrow()[lhs.id].full_def() { - def::DefVariant(_, id, _) => id, + let variant = match self.tcx.def_map.borrow()[lhs.id].full_def() { + def::DefVariant(eid, vid, _) => { + let def = ty::lookup_datatype_def(self.tcx, eid); + def.get_variant(vid).expect("variant not in enum") + } _ => { - match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, - lhs.id)) { - None => { - self.tcx.sess.span_bug(lhs.span, - "struct pattern wasn't of a \ - type with a def ID?!") + // Should be a struct type + match ty::node_id_to_type(self.tcx, lhs.id).sty { + ty::ty_struct(def, _) | + // This case shouldn't happen, but handle it anyway + ty::ty_enum(def, _) => { + assert!(def.is_univariant()); + &def.variants[0] } - Some(def_id) => def_id, + _ => self.tcx.sess.span_bug(lhs.span, "pattern is not a data type") } } }; - let fields = ty::lookup_struct_fields(self.tcx, id); + + let fields = &variant.fields[]; for pat in pats { let field_id = fields.iter() .find(|field| field.name == pat.node.ident.name).unwrap().id; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a1e38a1c8bda7..b364ab3bda926 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -736,11 +736,20 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { let with_cmt = return_if_err!(self.mc.cat_expr(&*with_expr)); - // Select just those fields of the `with` - // expression that will actually be used - let with_fields = match with_cmt.ty.sty { - ty::ty_struct(did, substs) => { - ty::struct_fields(self.tcx(), did, substs) + match with_cmt.ty.sty { + ty::ty_struct(def, substs) => { + // Consume those fields of the with expression that are needed. + + for with_field in &def.variants[0].fields { + if !contains_field_named(with_field.name, &fields[]) { + let field_ty = with_field.subst_ty(self.tcx(), substs); + let cmt_field = self.mc.cat_field(&*with_expr, + with_cmt.clone(), + with_field.name, + field_ty); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + } + } } _ => { // the base expression should always evaluate to a @@ -753,31 +762,19 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { "with expression doesn't evaluate to a struct"); } assert!(self.tcx().sess.has_errors()); - vec!() - } - }; - - // Consume those fields of the with expression that are needed. - for with_field in &with_fields { - if !contains_field_named(with_field, fields) { - let cmt_field = self.mc.cat_field(&*with_expr, - with_cmt.clone(), - with_field.name, - with_field.mt.ty); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); } } + // walk the with expression so that complex expressions // are properly handled. self.walk_expr(with_expr); - fn contains_field_named(field: &ty::field, - fields: &Vec) - -> bool + fn contains_field_named(name: ast::Name, + fields: &[ast::Field]) -> bool { fields.iter().any( - |f| f.ident.node.name == field.name) + |f| f.ident.node.name == name) } } @@ -1104,13 +1101,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } Some(def::DefVariant(enum_did, variant_did, _is_struct)) => { - let downcast_cmt = - if ty::enum_is_univariant(tcx, enum_did) { - cmt_pat - } else { - let cmt_pat_ty = cmt_pat.ty; - mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did) - }; + let enum_def = ty::lookup_datatype_def(tcx, enum_did); + let downcast_cmt = if enum_def.is_univariant() { + cmt_pat + } else { + let cmt_pat_ty = cmt_pat.ty; + mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did) + }; debug!("variant downcast_cmt={} pat={}", downcast_cmt.repr(tcx), diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 7584a2e44cc7c..af4162b914961 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -53,15 +53,15 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_int(int_type) => Some(IntSimplifiedType(int_type)), ty::ty_uint(uint_type) => Some(UintSimplifiedType(uint_type)), ty::ty_float(float_type) => Some(FloatSimplifiedType(float_type)), - ty::ty_enum(def_id, _) => Some(EnumSimplifiedType(def_id)), + ty::ty_enum(def, _) => Some(EnumSimplifiedType(def.def_id)), ty::ty_str => Some(StrSimplifiedType), ty::ty_vec(..) => Some(VecSimplifiedType), ty::ty_ptr(_) => Some(PtrSimplifiedType), ty::ty_trait(ref trait_info) => { Some(TraitSimplifiedType(trait_info.principal_def_id())) } - ty::ty_struct(def_id, _) => { - Some(StructSimplifiedType(def_id)) + ty::ty_struct(def, _) => { + Some(StructSimplifiedType(def.def_id)) } ty::ty_rptr(_, mt) => { // since we introduce auto-refs during method lookup, we @@ -96,4 +96,3 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_infer(_) | ty::ty_err => None, } } - diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index b782a655d89ff..35194fe51734e 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -484,10 +484,12 @@ pub fn super_tys<'tcx, C>(this: &C, (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if a_p.idx == b_p.idx && a_p.space == b_p.space => Ok(a), - (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs)) - if a_id == b_id => { - let substs = try!(this.substs(a_id, a_substs, b_substs)); - Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs))) + (&ty::ty_enum(def_a, a_substs), &ty::ty_enum(def_b, b_substs)) + if def_a.def_id == def_b.def_id => { + let substs = try!(this.substs(def_a.def_id, + a_substs, + b_substs)); + Ok(ty::mk_enum(tcx, def_a, tcx.mk_substs(substs))) } (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => { @@ -497,10 +499,10 @@ pub fn super_tys<'tcx, C>(this: &C, Ok(ty::mk_trait(tcx, principal, bounds)) } - (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs)) - if a_id == b_id => { - let substs = try!(this.substs(a_id, a_substs, b_substs)); - Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) + (&ty::ty_struct(def_a, a_substs), &ty::ty_struct(def_b, b_substs)) + if def_a.def_id == def_b.def_id => { + let substs = try!(this.substs(def_a.def_id, a_substs, b_substs)); + Ok(ty::mk_struct(tcx, def_a, tcx.mk_substs(substs))) } (&ty::ty_closure(a_id, a_region, a_substs), diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c4446b87855ca..dc2f256482961 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1204,13 +1204,16 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // Note: This goes up here (rather than within the PatEnum arm // alone) because struct patterns can refer to struct types or // to struct variants within enums. - let cmt = match opt_def { - Some(def::DefVariant(enum_did, variant_did, _)) - // univariant enums do not need downcasts - if !ty::enum_is_univariant(self.tcx(), enum_did) => { - self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) - } - _ => cmt + let cmt = if let Some(def::DefVariant(enum_did, variant_did, _)) = opt_def { + let enum_def = ty::lookup_datatype_def(self.tcx(), enum_did); + // Univariant enums don't need a downcast + if !enum_def.is_univariant() { + self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) + } else { + cmt + } + } else { + cmt }; match pat.node { @@ -1635,4 +1638,3 @@ impl<'tcx> UserString<'tcx> for Upvar { format!("captured outer variable in an `{}` closure", kind) } } - diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 62b81f0ebe7db..c27f63ed69539 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -195,9 +195,9 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { false } - ty::ty_enum(def_id, _) | - ty::ty_struct(def_id, _) => { - def_id.krate == ast::LOCAL_CRATE + ty::ty_enum(def, _) | + ty::ty_struct(def, _) => { + def.def_id.krate == ast::LOCAL_CRATE } ty::ty_uniq(_) => { // treat ~T like Box diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 9ec89f55b8f32..4c111a1bcf7ab 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1567,21 +1567,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } - - ty::ty_struct(def_id, substs) => { - let types: Vec = - ty::struct_fields(self.tcx(), def_id, substs).iter() - .map(|f| f.mt.ty) - .collect(); - nominal(bound, types) - } - - ty::ty_enum(def_id, substs) => { - let types: Vec = - ty::substd_enum_variants(self.tcx(), def_id, substs) - .iter() - .flat_map(|variant| variant.args.iter()) - .cloned() + ty::ty_enum(def, substs) | + ty::ty_struct(def, substs) => { + let types: Vec = def.variants.iter() + .flat_map(|v| v.subst_fields(self.tcx(), substs)) .collect(); nominal(bound, types) } @@ -1700,18 +1689,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::ty_struct(def_id, substs) => { - Some(ty::struct_fields(self.tcx(), def_id, substs).iter() - .map(|f| f.mt.ty) - .collect()) - } - - ty::ty_enum(def_id, substs) => { - Some(ty::substd_enum_variants(self.tcx(), def_id, substs) - .iter() - .flat_map(|variant| variant.args.iter()) - .map(|&ty| ty) - .collect()) + ty::ty_enum(def, substs) | + ty::ty_struct(def, substs) => { + Some(def.variants.iter() + .flat_map(|v| v.subst_fields(self.tcx(), substs)).collect()) } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 78b8d4f7b1e28..7044e323dfa93 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -66,6 +66,7 @@ use util::ppaux::{Repr, UserString}; use util::common::{memoized, ErrorReported}; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{FnvHashMap}; +use util::ivar::Ivar; use arena::TypedArena; use std::borrow::{Borrow, Cow}; @@ -76,13 +77,14 @@ use std::hash::{Hash, SipHasher, Hasher}; use std::mem; use std::ops; use std::rc::Rc; +use std::slice; use std::vec::{CowVec, IntoIter}; use collections::enum_set::{EnumSet, CLike}; use std::collections::{HashMap, HashSet}; use syntax::abi; -use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE}; -use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; -use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility}; +use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE}; +use syntax::ast::{MutImmutable, MutMutable, Name, NodeId}; +use syntax::ast::{StmtExpr, StmtSemi, Visibility}; use syntax::ast_util::{self, is_local, lit_is_str, local_def, PostExpansionMethod}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::Span; @@ -107,12 +109,6 @@ pub struct CrateAnalysis<'tcx> { pub glob_map: Option, } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct field<'tcx> { - pub name: ast::Name, - pub mt: mt<'tcx> -} - #[derive(Clone, Copy, Debug)] pub enum ImplOrTraitItemContainer { TraitContainer(ast::DefId), @@ -249,14 +245,6 @@ pub struct mt<'tcx> { pub mutbl: ast::Mutability, } -#[derive(Clone, Copy, Debug)] -pub struct field_ty { - pub name: Name, - pub id: DefId, - pub vis: ast::Visibility, - pub origin: ast::DefId, // The DefId of the struct in which the field is declared. -} - // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. #[derive(Copy, PartialEq, Eq, Hash)] @@ -628,6 +616,7 @@ pub struct CtxtArenas<'tcx> { substs: TypedArena>, bare_fn: TypedArena>, region: TypedArena, + datatype_def: TypedArena>, } impl<'tcx> CtxtArenas<'tcx> { @@ -637,6 +626,7 @@ impl<'tcx> CtxtArenas<'tcx> { substs: TypedArena::new(), bare_fn: TypedArena::new(), region: TypedArena::new(), + datatype_def: TypedArena::new(), } } } @@ -723,19 +713,18 @@ pub struct ctxt<'tcx> { pub map: ast_map::Map<'tcx>, pub intrinsic_defs: RefCell>>, pub freevars: RefCell, + pub datatype_defs: RefCell>>, pub tcache: RefCell>>, pub rcache: RefCell>>, pub short_names_cache: RefCell, String>>, pub tc_cache: RefCell, TypeContents>>, pub ast_ty_to_ty_cache: RefCell>>, - pub enum_var_cache: RefCell>>>>>, pub ty_param_defs: RefCell>>, pub adjustments: RefCell>>, pub normalized_cache: RefCell, Ty<'tcx>>>, pub lang_items: middle::lang_items::LanguageItems, /// A mapping of fake provided method def_ids to the default implementation pub provided_method_sources: RefCell>, - pub struct_fields: RefCell>>>, /// Maps from def-id of a type or region parameter to its /// (inferred) variance. @@ -1353,7 +1342,7 @@ pub enum sty<'tcx> { /// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in /// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as /// well.` - ty_enum(DefId, &'tcx Substs<'tcx>), + ty_enum(&'tcx DatatypeDef<'tcx>, &'tcx Substs<'tcx>), ty_uniq(Ty<'tcx>), ty_str, ty_vec(Ty<'tcx>, Option), // Second field is length. @@ -1365,7 +1354,7 @@ pub enum sty<'tcx> { ty_bare_fn(Option, &'tcx BareFnTy<'tcx>), ty_trait(Box>), - ty_struct(DefId, &'tcx Substs<'tcx>), + ty_struct(&'tcx DatatypeDef<'tcx>, &'tcx Substs<'tcx>), ty_closure(DefId, &'tcx Region, &'tcx Substs<'tcx>), @@ -2282,6 +2271,162 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } } +pub struct DatatypeDef<'tcx> { + pub def_id: DefId, + pub variants: Vec>, +} + +pub struct VariantDef<'tcx> { + pub id: DefId, + pub name: Name, + pub disr_val: Disr, + pub fields: Vec>, +} + + +pub struct FieldTy<'tcx> { + // The DefId of the field itself. + pub id: DefId, + pub name: Name, + pub vis: ast::Visibility, + // The "parent" of the field, the DefId of the struct or enum this field comes from + pub origin: DefId, + // Ivar is used here to to allow the construction of a DatatypeDef that contains types + // that reference this type. For example: + // + // struct Foo(Bar); + // struct Bar(Option>); + // + // Making the `ty_struct` for `Foo` requires the type of `Bar`, but making the `type` + // of `Bar` requires the type of `Foo`. + ty: Ivar> +} + +impl<'tcx> DatatypeDef<'tcx> { + + pub fn is_tuple_variant(&self, variant_idx: usize) -> bool { + if self.variants.len() <= variant_idx { return false; } + + self.variants[variant_idx].is_tuple_variant() + } + + pub fn get_variant(&'tcx self, def: DefId) -> Option<&'tcx VariantDef<'tcx>> { + self.variants.iter().find(|v| v.id == def) + } + + pub fn is_univariant(&self) -> bool { + self.variants.len() == 1 + } + + pub fn is_struct_def(&self) -> bool { + self.is_univariant() && self.def_id == self.variants[0].id + } + + pub fn is_c_like(&self) -> bool { + if self.variants.len() == 0 { + return false; + } + + self.variants.iter().all(|v| v.fields.len() == 0) + } +} + +impl<'tcx> VariantDef<'tcx> { + pub fn subst_fields<'a>(&'a self, cx: &'a ctxt<'tcx>, + substs: &'tcx Substs<'tcx>) -> FieldTyIter<'a, 'tcx> { + FieldTyIter { + cx: cx, + substs: substs, + iter: self.fields.iter() + } + } + + pub fn is_tuple_variant(&self) -> bool { + !self.fields.is_empty() && + self.fields.iter().all(|f| f.is_unnamed()) + } +} + +impl<'tcx> FieldTy<'tcx> { + pub fn new(id: DefId, name: Name, vis: ast::Visibility, origin: DefId) -> FieldTy<'tcx> { + FieldTy { + id: id, + name: name, + vis: vis, + origin: origin, + ty: Ivar::new(), + } + } + + pub fn is_unnamed(&self) -> bool { + self.name == token::special_names::unnamed_field + } + + pub fn set_ty(&self, ty: Ty<'tcx>) { + self.ty.fulfill(ty); + } + + pub fn ty(&self) -> Ty<'tcx> { + self.ty.unwrap() + } + + pub fn subst_ty(&self, tcx: &ctxt<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { + self.ty().subst(tcx, substs) + } + + pub fn subst_ty_spanned(&self, tcx: &ctxt<'tcx>, substs: &Substs<'tcx>, + span: Span) -> Ty<'tcx> { + self.ty().subst_spanned(tcx, substs, Some(span)) + } +} + +pub struct FieldTyIter<'a, 'tcx:'a> { + cx: &'a ctxt<'tcx>, + substs: &'tcx Substs<'tcx>, + iter: slice::Iter<'a, FieldTy<'tcx>> +} + +impl<'a, 'tcx> Iterator for FieldTyIter<'a, 'tcx> { + type Item = Ty<'tcx>; + + fn next(&mut self) -> Option> { + self.iter.next().map(|f| f.subst_ty(self.cx, self.substs)) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + + +impl<'tcx> PartialEq for DatatypeDef<'tcx> { + fn eq(&self, other: &DatatypeDef) -> bool { + self.def_id == other.def_id + } +} + +impl<'tcx> Eq for DatatypeDef<'tcx> { } + +impl<'tcx> Hash for DatatypeDef<'tcx> { + fn hash(&self, s: &mut H) { + self.def_id.hash(s); + } +} + +impl<'tcx> fmt::Debug for DatatypeDef<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "DatatypeDef {{ def_id: {:?}, variants: [\n", + self.def_id)); + for v in self.variants.iter() { + try!(write!(f, " VariantDef {{ id: {:?}, disr_val: {:?}, <{} fields> }}\n", + v.id, v.disr_val, v.fields.len())); + } + + f.write_str(" ]\n}") + } +} + + /// A "type scheme", in ML terminology, is a type combined with some /// set of generic types that the type is, well, generic over. In Rust /// terms, it is the "type" of a fn item or struct -- this type will @@ -2455,12 +2600,12 @@ pub fn mk_ctxt<'tcx>(s: Session, map: map, intrinsic_defs: RefCell::new(DefIdMap()), freevars: freevars, + datatype_defs: RefCell::new(DefIdMap()), tcache: RefCell::new(DefIdMap()), rcache: RefCell::new(FnvHashMap()), short_names_cache: RefCell::new(FnvHashMap()), tc_cache: RefCell::new(FnvHashMap()), ast_ty_to_ty_cache: RefCell::new(NodeMap()), - enum_var_cache: RefCell::new(DefIdMap()), impl_or_trait_items: RefCell::new(DefIdMap()), trait_item_def_ids: RefCell::new(DefIdMap()), trait_items_cache: RefCell::new(DefIdMap()), @@ -2470,7 +2615,6 @@ pub fn mk_ctxt<'tcx>(s: Session, normalized_cache: RefCell::new(FnvHashMap()), lang_items: lang_items, provided_method_sources: RefCell::new(DefIdMap()), - struct_fields: RefCell::new(DefIdMap()), destructor_for_type: RefCell::new(DefIdMap()), destructors: RefCell::new(DefIdSet()), trait_impls: RefCell::new(DefIdMap()), @@ -2534,6 +2678,10 @@ impl<'tcx> ctxt<'tcx> { region } + pub fn mk_datatype_def(&self, def: DatatypeDef<'tcx>) -> &'tcx DatatypeDef<'tcx> { + self.arenas.datatype_def.alloc(def) + } + pub fn closure_kind(&self, def_id: ast::DefId) -> ty::ClosureKind { self.closure_kinds.borrow()[def_id] } @@ -2812,9 +2960,10 @@ pub fn mk_str_slice<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, m: ast::Mutability) }) } -pub fn mk_enum<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { +pub fn mk_enum<'tcx>(cx: &ctxt<'tcx>, + def: &'tcx DatatypeDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside - mk_t(cx, ty_enum(did, substs)) + mk_t(cx, ty_enum(def, substs)) } pub fn mk_uniq<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { mk_t(cx, ty_uniq(ty)) } @@ -2921,10 +3070,10 @@ pub fn mk_projection<'tcx>(cx: &ctxt<'tcx>, mk_t(cx, ty_projection(inner)) } -pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId, +pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, datatype_def: &'tcx DatatypeDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside - mk_t(cx, ty_struct(struct_id, substs)) + mk_t(cx, ty_struct(datatype_def, substs)) } pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, @@ -3160,7 +3309,7 @@ pub fn type_is_structural(ty: Ty) -> bool { pub fn type_is_simd(cx: &ctxt, ty: Ty) -> bool { match ty.sty { - ty_struct(did, _) => lookup_simd(cx, did), + ty_struct(def, _) => lookup_simd(cx, def.def_id), _ => false } } @@ -3174,21 +3323,20 @@ pub fn sequence_element_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { } } -pub fn simd_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { +pub fn simd_type<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> { match ty.sty { - ty_struct(did, substs) => { - let fields = lookup_struct_fields(cx, did); - lookup_field_type(cx, did, fields[0].id, substs) + ty_struct(def, _) => { + let fields = &def.variants[0].fields[]; + fields[0].ty() } _ => panic!("simd_type called on invalid type") } } -pub fn simd_size(cx: &ctxt, ty: Ty) -> uint { +pub fn simd_size(ty: Ty) -> uint { match ty.sty { - ty_struct(did, _) => { - let fields = lookup_struct_fields(cx, did); - fields.len() + ty_struct(def, _) => { + def.variants[0].fields.len() } _ => panic!("simd_size called on invalid type") } @@ -3366,10 +3514,11 @@ impl TypeContents { *self & TC::ReachesAll } - pub fn union(v: &[T], mut f: F) -> TypeContents where - F: FnMut(&T) -> TypeContents, + pub fn union(i: I, mut f: F) -> TypeContents where + I: Iterator, + F: FnMut(T) -> TypeContents, { - v.iter().fold(TC::None, |tc, ty| tc | f(ty)) + i.fold(TC::None, |tc, ty| tc | f(ty)) } pub fn has_dtor(&self) -> bool { @@ -3497,51 +3646,47 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } ty_str => TC::Nonsized, - ty_struct(did, substs) => { - let flds = struct_fields(cx, did, substs); - let mut res = - TypeContents::union(&flds[..], - |f| tc_mt(cx, f.mt, cache)); + ty_struct(def, substs) => { + let field_tys = def.variants.iter().flat_map(|v| { + v.subst_fields(cx, substs) + }); + let mut res = TypeContents::union(field_tys, |ty| tc_ty(cx, ty, cache)); - if !lookup_repr_hints(cx, did).contains(&attr::ReprExtern) { + if !lookup_repr_hints(cx, def.def_id).contains(&attr::ReprExtern) { res = res | TC::ReachesFfiUnsafe; } - if ty::has_dtor(cx, did) { + if ty::has_dtor(cx, def.def_id) { res = res | TC::OwnsDtor; } - apply_lang_items(cx, did, res) + apply_lang_items(cx, def.def_id, res) } ty_closure(did, r, substs) => { // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure. let param_env = ty::empty_parameter_environment(cx); let upvars = closure_upvars(¶m_env, did, substs).unwrap(); - TypeContents::union(&upvars, - |f| tc_ty(cx, &f.ty, cache)) + TypeContents::union(upvars.as_slice().iter(), + |f| tc_ty(cx, f.ty, cache)) | borrowed_contents(*r, MutMutable) } ty_tup(ref tys) => { - TypeContents::union(&tys[..], + TypeContents::union(tys.iter(), |ty| tc_ty(cx, *ty, cache)) } - ty_enum(did, substs) => { - let variants = substd_enum_variants(cx, did, substs); - let mut res = - TypeContents::union(&variants[..], |variant| { - TypeContents::union(&variant.args, - |arg_ty| { - tc_ty(cx, *arg_ty, cache) - }) - }); + ty_enum(def, substs) => { + let did = def.def_id; + let tys = def.variants.iter().flat_map(|v| v.subst_fields(cx, substs)); + let mut res = TypeContents::union(tys, |ty| tc_ty(cx, ty, cache)); if ty::has_dtor(cx, did) { res = res | TC::OwnsDtor; } - if variants.len() != 0 { + if def.variants.len() != 0 { + let variants = &def.variants[]; let repr_hints = lookup_repr_hints(cx, did); if repr_hints.len() > 1 { // this is an error later on, but this type isn't safe @@ -3563,12 +3708,13 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { if variants.len() == 2 { let mut data_idx = 0; - if variants[0].args.len() == 0 { + if variants[0].fields.len() == 0 { data_idx = 1; } - if variants[data_idx].args.len() == 1 { - match variants[data_idx].args[0].sty { + if variants[data_idx].fields.len() == 1 { + let ty = variants[data_idx].fields[0].subst_ty(cx, substs); + match ty.sty { ty_bare_fn(..) => { res = res - TC::ReachesFfiUnsafe; } _ => { } } @@ -3597,14 +3743,6 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { result } - fn tc_mt<'tcx>(cx: &ctxt<'tcx>, - mt: mt<'tcx>, - cache: &mut FnvHashMap, TypeContents>) -> TypeContents - { - let mc = TC::ReachesMutable.when(mt.mutbl == MutMutable); - mc | tc_ty(cx, mt.ty, cache) - } - fn apply_lang_items(cx: &ctxt, did: ast::DefId, tc: TypeContents) -> TypeContents { if Some(did) == cx.lang_items.managed_bound() { @@ -3760,14 +3898,33 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool { false } - ty_struct(ref did, _) if seen.contains(did) => { + ty_enum(&DatatypeDef { def_id: ref did, ..}, _) | + ty_struct(&DatatypeDef { def_id: ref did, ..}, _) if seen.contains(did) => { false } - ty_struct(did, substs) => { - seen.push(did); - let fields = struct_fields(cx, did, substs); - let r = fields.iter().any(|f| type_requires(cx, seen, r_ty, f.mt.ty)); + ty_struct(def, substs) => { + seen.push(def.def_id); + let r = def.variants[0].subst_fields(cx, substs).any(|ty| { + type_requires(cx, seen, r_ty, ty) + }); + seen.pop().unwrap(); + r + } + + ty_enum(def, substs) => { + seen.push(def.def_id); + let r = if !def.variants.is_empty() { + def.variants.iter() + .all(|v| { + v.subst_fields(cx, substs).any(|ty| { + type_requires(cx, seen, r_ty, ty) + }) + }) + } else { + false + }; + seen.pop().unwrap(); r } @@ -3784,22 +3941,6 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool { ts.iter().any(|ty| type_requires(cx, seen, r_ty, *ty)) } - ty_enum(ref did, _) if seen.contains(did) => { - false - } - - ty_enum(did, substs) => { - seen.push(did); - let vs = enum_variants(cx, did); - let r = !vs.is_empty() && vs.iter().all(|variant| { - variant.args.iter().any(|aty| { - let sty = aty.subst(cx, substs); - type_requires(cx, seen, r_ty, sty) - }) - }); - seen.pop().unwrap(); - r - } }; debug!("subtypes_require({:?}, {:?})? {:?}", @@ -3855,17 +3996,12 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) ty_vec(ty, Some(_)) => { is_type_structurally_recursive(cx, sp, seen, ty) } - ty_struct(did, substs) => { - let fields = struct_fields(cx, did, substs); - find_nonrepresentable(cx, sp, seen, fields.iter().map(|f| f.mt.ty)) - } - ty_enum(did, substs) => { - let vs = enum_variants(cx, did); - let iter = vs.iter() - .flat_map(|variant| { variant.args.iter() }) - .map(|aty| { aty.subst_spanned(cx, substs, Some(sp)) }); - - find_nonrepresentable(cx, sp, seen, iter) + ty_enum(def, substs) | + ty_struct(def, substs) => { + let fields = def.variants.iter().flat_map(|v| { + v.subst_fields(cx, substs) + }); + find_nonrepresentable(cx, sp, seen, fields) } ty_closure(..) => { // this check is run on type definitions, so we don't expect @@ -3878,8 +4014,8 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) fn same_struct_or_enum_def_id(ty: Ty, did: DefId) -> bool { match ty.sty { - ty_struct(ty_did, _) | ty_enum(ty_did, _) => { - ty_did == did + ty_struct(def, _) | ty_enum(def, _) => { + def.def_id == did } _ => false } @@ -3887,9 +4023,9 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.sty, &b.sty) { - (&ty_struct(did_a, ref substs_a), &ty_struct(did_b, ref substs_b)) | - (&ty_enum(did_a, ref substs_a), &ty_enum(did_b, ref substs_b)) => { - if did_a != did_b { + (&ty_struct(def_a, ref substs_a), &ty_struct(def_b, ref substs_b)) | + (&ty_enum(def_a, ref substs_a), &ty_enum(def_b, ref substs_b)) => { + if def_a != def_b { return false; } @@ -3915,7 +4051,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) ::util::ppaux::ty_to_string(cx, ty)); match ty.sty { - ty_struct(did, _) | ty_enum(did, _) => { + ty_struct(def, _) | ty_enum(def, _) => { { // Iterate through stack of previously seen types. let mut iter = seen.iter(); @@ -3930,7 +4066,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) match iter.next() { Some(&seen_type) => { - if same_struct_or_enum_def_id(seen_type, did) { + if same_struct_or_enum_def_id(seen_type, def.def_id) { debug!("SelfRecursive: {:?} contains {:?}", ::util::ppaux::ty_to_string(cx, seen_type), ::util::ppaux::ty_to_string(cx, ty)); @@ -4072,15 +4208,10 @@ pub fn type_is_machine(ty: Ty) -> bool { // Whether a type is enum like, that is an enum type with only nullary // constructors -pub fn type_is_c_like_enum(cx: &ctxt, ty: Ty) -> bool { +pub fn type_is_c_like_enum(ty: Ty) -> bool { match ty.sty { - ty_enum(did, _) => { - let variants = enum_variants(cx, did); - if variants.len() == 0 { - false - } else { - variants.iter().all(|v| v.args.len() == 0) - } + ty_enum(def, _) => { + def.is_c_like() } _ => false } @@ -4142,20 +4273,24 @@ pub fn positional_element_ty<'tcx>(cx: &ctxt<'tcx>, (&ty_tup(ref v), None) => v.get(i).cloned(), - (&ty_struct(def_id, substs), None) => lookup_struct_fields(cx, def_id) - .get(i) - .map(|&t|lookup_item_type(cx, t.id).ty.subst(cx, substs)), + (&ty_struct(def, substs), None) => { + def.variants.get(0).and_then(|v| { + v.fields.get(i).map(|f| f.subst_ty(cx, substs)) + }) + } - (&ty_enum(def_id, substs), Some(variant_def_id)) => { - let variant_info = enum_variant_with_id(cx, def_id, variant_def_id); - variant_info.args.get(i).map(|t|t.subst(cx, substs)) + (&ty_enum(def, substs), Some(variant_def_id)) => { + let variant = def.get_variant(variant_def_id); + variant.and_then(|v| { + v.fields.get(i).map(|f| f.subst_ty(cx, substs)) + }) } - (&ty_enum(def_id, substs), None) => { - assert!(enum_is_univariant(cx, def_id)); - let enum_variants = enum_variants(cx, def_id); - let variant_info = &(*enum_variants)[0]; - variant_info.args.get(i).map(|t|t.subst(cx, substs)) + (&ty_enum(def, substs), None) => { + assert!(def.variants.len() == 1); + def.variants.get(0).and_then(|v| { + v.fields.get(i).map(|f| f.subst_ty(cx, substs)) + }) } _ => None @@ -4170,18 +4305,15 @@ pub fn named_element_ty<'tcx>(cx: &ctxt<'tcx>, variant: Option) -> Option> { match (&ty.sty, variant) { - (&ty_struct(def_id, substs), None) => { - let r = lookup_struct_fields(cx, def_id); + (&ty_struct(def, substs), None) => { + let r = &def.variants[0].fields[]; r.iter().find(|f| f.name == n) - .map(|&f| lookup_field_type(cx, def_id, f.id, substs)) + .map(|f| f.subst_ty(cx, substs)) } - (&ty_enum(def_id, substs), Some(variant_def_id)) => { - let variant_info = enum_variant_with_id(cx, def_id, variant_def_id); - variant_info.arg_names.as_ref() - .expect("must have struct enum variant if accessing a named fields") - .iter().zip(variant_info.args.iter()) - .find(|&(ident, _)| ident.name == n) - .map(|(_ident, arg_t)| arg_t.subst(cx, substs)) + (&ty_enum(def, substs), Some(variant_def_id)) => { + let variant = def.get_variant(variant_def_id).unwrap(); + variant.fields.iter().find(|f| f.name == n) + .map(|f| f.subst_ty(cx, substs)) } _ => None } @@ -4311,7 +4443,11 @@ pub fn pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> { // ask for the type of "id" in "id(3)", it will return "fn(&int) -> int" // instead of "fn(ty) -> T with T = int". pub fn expr_ty<'tcx>(cx: &ctxt<'tcx>, expr: &ast::Expr) -> Ty<'tcx> { - return node_id_to_type(cx, expr.id); + if let Some(ty) = expr_ty_opt(cx, expr) { + ty + } else { + cx.sess.span_bug(expr.span, "No type for expression") + } } pub fn expr_ty_opt<'tcx>(cx: &ctxt<'tcx>, expr: &ast::Expr) -> Option> { @@ -4496,12 +4632,12 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>, ty_to_string(cx, ty))) }, &UnsizeStruct(box ref k, tp_index) => match ty.sty { - ty_struct(did, substs) => { + ty_struct(def, substs) => { let ty_substs = substs.types.get_slice(subst::TypeSpace); let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span); let mut unsized_substs = substs.clone(); unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty; - mk_struct(cx, did, cx.mk_substs(unsized_substs)) + mk_struct(cx, def, cx.mk_substs(unsized_substs)) } _ => cx.sess.span_bug(span, &format!("UnsizeStruct with bad sty: {:?}", @@ -4566,8 +4702,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprPath(..) => { match resolve_expr(tcx, expr) { def::DefVariant(tid, vid, _) => { - let variant_info = enum_variant_with_id(tcx, tid, vid); - if variant_info.args.len() > 0 { + let enum_def = ty::lookup_datatype_def(tcx, tid); + let variant = enum_def.get_variant(vid).expect("variant not in enum"); + if variant.fields.len() > 0 { // N-ary variant. RvalueDatumExpr } else { @@ -4728,18 +4865,6 @@ pub fn stmt_node_id(s: &ast::Stmt) -> ast::NodeId { } } -pub fn field_idx_strict(tcx: &ctxt, name: ast::Name, fields: &[field]) - -> uint { - let mut i = 0; - for f in fields { if f.name == name { return i; } i += 1; } - tcx.sess.bug(&format!( - "no field named `{}` found in the list of fields `{:?}`", - token::get_name(name), - fields.iter() - .map(|f| token::get_name(f.name).to_string()) - .collect::>())); -} - pub fn impl_or_trait_item_idx(id: ast::Name, trait_items: &[ImplOrTraitItem]) -> Option { trait_items.iter().position(|m| m.name() == id) @@ -4753,7 +4878,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { } ty_tup(ref tys) if tys.is_empty() => ::util::ppaux::ty_to_string(cx, ty), - ty_enum(id, _) => format!("enum `{}`", item_path_str(cx, id)), + ty_enum(def, _) => format!("enum `{}`", item_path_str(cx, def.def_id)), ty_uniq(_) => "box".to_string(), ty_vec(_, Some(n)) => format!("array of {} elements", n), ty_vec(_, None) => "slice".to_string(), @@ -4764,8 +4889,8 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_trait(ref inner) => { format!("trait {}", item_path_str(cx, inner.principal_def_id())) } - ty_struct(id, _) => { - format!("struct `{}`", item_path_str(cx, id)) + ty_struct(def, _) => { + format!("struct `{}`", item_path_str(cx, def.def_id)) } ty_closure(..) => "closure".to_string(), ty_tup(_) => "tuple".to_string(), @@ -5170,8 +5295,8 @@ pub fn ty_to_def_id(ty: Ty) -> Option { match ty.sty { ty_trait(ref tt) => Some(tt.principal_def_id()), - ty_struct(id, _) | - ty_enum(id, _) | + ty_enum(def, _) | + ty_struct(def, _) => Some(def.def_id), ty_closure(id, _, _) => Some(id), _ => @@ -5179,95 +5304,6 @@ pub fn ty_to_def_id(ty: Ty) -> Option { } } -// Enum information -#[derive(Clone)] -pub struct VariantInfo<'tcx> { - pub args: Vec>, - pub arg_names: Option>, - pub ctor_ty: Option>, - pub name: ast::Name, - pub id: ast::DefId, - pub disr_val: Disr, - pub vis: Visibility -} - -impl<'tcx> VariantInfo<'tcx> { - - /// Creates a new VariantInfo from the corresponding ast representation. - /// - /// Does not do any caching of the value in the type context. - pub fn from_ast_variant(cx: &ctxt<'tcx>, - ast_variant: &ast::Variant, - discriminant: Disr) -> VariantInfo<'tcx> { - let ctor_ty = node_id_to_type(cx, ast_variant.node.id); - - match ast_variant.node.kind { - ast::TupleVariantKind(ref args) => { - let arg_tys = if args.len() > 0 { - // the regions in the argument types come from the - // enum def'n, and hence will all be early bound - ty::no_late_bound_regions(cx, &ty_fn_args(ctor_ty)).unwrap() - } else { - Vec::new() - }; - - return VariantInfo { - args: arg_tys, - arg_names: None, - ctor_ty: Some(ctor_ty), - name: ast_variant.node.name.name, - id: ast_util::local_def(ast_variant.node.id), - disr_val: discriminant, - vis: ast_variant.node.vis - }; - }, - ast::StructVariantKind(ref struct_def) => { - let fields: &[StructField] = &struct_def.fields; - - assert!(fields.len() > 0); - - let arg_tys = struct_def.fields.iter() - .map(|field| node_id_to_type(cx, field.node.id)).collect(); - let arg_names = fields.iter().map(|field| { - match field.node.kind { - NamedField(ident, _) => ident, - UnnamedField(..) => cx.sess.bug( - "enum_variants: all fields in struct must have a name") - } - }).collect(); - - return VariantInfo { - args: arg_tys, - arg_names: Some(arg_names), - ctor_ty: None, - name: ast_variant.node.name.name, - id: ast_util::local_def(ast_variant.node.id), - disr_val: discriminant, - vis: ast_variant.node.vis - }; - } - } - } -} - -pub fn substd_enum_variants<'tcx>(cx: &ctxt<'tcx>, - id: ast::DefId, - substs: &Substs<'tcx>) - -> Vec>> { - enum_variants(cx, id).iter().map(|variant_info| { - let substd_args = variant_info.args.iter() - .map(|aty| aty.subst(cx, substs)).collect::>(); - - let substd_ctor_ty = variant_info.ctor_ty.subst(cx, substs); - - Rc::new(VariantInfo { - args: substd_args, - ctor_ty: substd_ctor_ty, - ..(**variant_info).clone() - }) - }).collect() -} - pub fn item_path_str(cx: &ctxt, id: ast::DefId) -> String { with_path(cx, id, |path| ast_map::path_to_string(path)).to_string() } @@ -5321,89 +5357,13 @@ pub fn with_path(cx: &ctxt, id: ast::DefId, f: F) -> T where } } -pub fn enum_is_univariant(cx: &ctxt, id: ast::DefId) -> bool { - enum_variants(cx, id).len() == 1 -} - -pub fn type_is_empty(cx: &ctxt, ty: Ty) -> bool { +pub fn type_is_empty(ty: Ty) -> bool { match ty.sty { - ty_enum(did, _) => (*enum_variants(cx, did)).is_empty(), + ty_enum(def, _) => def.variants.is_empty(), _ => false } } -pub fn enum_variants<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) - -> Rc>>> { - memoized(&cx.enum_var_cache, id, |id: ast::DefId| { - if ast::LOCAL_CRATE != id.krate { - Rc::new(csearch::get_enum_variants(cx, id)) - } else { - /* - Although both this code and check_enum_variants in typeck/check - call eval_const_expr, it should never get called twice for the same - expr, since check_enum_variants also updates the enum_var_cache - */ - match cx.map.get(id.node) { - ast_map::NodeItem(ref item) => { - match item.node { - ast::ItemEnum(ref enum_definition, _) => { - let mut last_discriminant: Option = None; - Rc::new(enum_definition.variants.iter().map(|variant| { - - let mut discriminant = match last_discriminant { - Some(val) => val + 1, - None => INITIAL_DISCRIMINANT_VALUE - }; - - if let Some(ref e) = variant.node.disr_expr { - // Preserve all values, and prefer signed. - let ty = Some(cx.types.i64); - match const_eval::eval_const_expr_partial(cx, &**e, ty) { - Ok(const_eval::const_int(val)) => { - discriminant = val as Disr; - } - Ok(const_eval::const_uint(val)) => { - discriminant = val as Disr; - } - Ok(_) => { - span_err!(cx.sess, e.span, E0304, - "expected signed integer constant"); - } - Err(err) => { - span_err!(cx.sess, e.span, E0305, - "expected constant: {}", err); - } - } - }; - - last_discriminant = Some(discriminant); - Rc::new(VariantInfo::from_ast_variant(cx, &**variant, - discriminant)) - }).collect()) - } - _ => { - cx.sess.bug("enum_variants: id not bound to an enum") - } - } - } - _ => cx.sess.bug("enum_variants: id not bound to an enum") - } - } - }) -} - -// Returns information about the enum variant with the given ID: -pub fn enum_variant_with_id<'tcx>(cx: &ctxt<'tcx>, - enum_id: ast::DefId, - variant_id: ast::DefId) - -> Rc> { - enum_variants(cx, enum_id).iter() - .find(|variant| variant.id == variant_id) - .expect("enum_variant_with_id(): no variant exists with that ID") - .clone() -} - - // If the given item is in an external crate, looks up its type and adds it to // the type cache. Returns the type parameters and type. pub fn lookup_item_type<'tcx>(cx: &ctxt<'tcx>, @@ -5433,6 +5393,15 @@ pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) }) } +pub fn lookup_datatype_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) -> &'tcx DatatypeDef<'tcx> { + if let Some(&def) = cx.datatype_defs.borrow().get(&did) { + return def; + } + + assert!(did.krate != ast::LOCAL_CRATE); + csearch::get_datatype_def(cx, did) +} + /// Given a reference to a trait, returns the "superbounds" declared /// on the trait, with appropriate substitutions applied. Basically, /// this applies a filter to the where clauses on the trait, returning @@ -5618,76 +5587,6 @@ pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc> { }) } -// Look up a field ID, whether or not it's local -// Takes a list of type substs in case the struct is generic -pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, - struct_id: DefId, - id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - let ty = if id.krate == ast::LOCAL_CRATE { - node_id_to_type(tcx, id.node) - } else { - let mut tcache = tcx.tcache.borrow_mut(); - let pty = tcache.entry(id).get().unwrap_or_else( - |vacant_entry| vacant_entry.insert(csearch::get_field_type(tcx, struct_id, id))); - pty.ty - }; - ty.subst(tcx, substs) -} - -// Look up the list of field names and IDs for a given struct. -// Panics if the id is not bound to a struct. -pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec { - if did.krate == ast::LOCAL_CRATE { - let struct_fields = cx.struct_fields.borrow(); - match struct_fields.get(&did) { - Some(fields) => (**fields).clone(), - _ => { - cx.sess.bug( - &format!("ID not mapped to struct fields: {}", - cx.map.node_to_string(did.node))); - } - } - } else { - csearch::get_struct_fields(&cx.sess.cstore, did) - } -} - -pub fn is_tuple_struct(cx: &ctxt, did: ast::DefId) -> bool { - let fields = lookup_struct_fields(cx, did); - !fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field) -} - -// Returns a list of fields corresponding to the struct's items. trans uses -// this. Takes a list of substs with which to instantiate field types. -pub fn struct_fields<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId, substs: &Substs<'tcx>) - -> Vec> { - lookup_struct_fields(cx, did).iter().map(|f| { - field { - name: f.name, - mt: mt { - ty: lookup_field_type(cx, did, f.id, substs), - mutbl: MutImmutable - } - } - }).collect() -} - -// Returns a list of fields corresponding to the tuple's items. trans uses -// this. -pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec> { - v.iter().enumerate().map(|(i, &f)| { - field { - name: token::intern(&i.to_string()), - mt: mt { - ty: f, - mutbl: MutImmutable - } - } - }).collect() -} - #[derive(Copy, Clone)] pub struct ClosureUpvar<'tcx> { pub def: def::Def, @@ -5796,7 +5695,7 @@ pub fn is_binopable<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, op: ast::BinOp) -> bool fn tycat<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> int { if type_is_simd(cx, ty) { - return tycat(cx, simd_type(cx, ty)) + return tycat(cx, simd_type(ty)) } match ty.sty { ty_char => tycat_char, @@ -6239,9 +6138,9 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - ty_str => { byte!(7); } - ty_enum(d, _) => { + ty_enum(def, _) => { byte!(8); - did(state, d); + did(state, def.def_id); } ty_uniq(_) => { byte!(9); @@ -6282,9 +6181,9 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - return false; } - ty_struct(d, _) => { + ty_struct(def, _) => { byte!(18); - did(state, d); + did(state, def.def_id); } ty_tup(ref inner) => { byte!(19); @@ -6962,27 +6861,26 @@ pub fn can_type_implement_copy<'a,'tcx>(param_env: &ParameterEnvironment<'a, 'tc let tcx = param_env.tcx; let did = match self_type.sty { - ty::ty_struct(struct_did, substs) => { - let fields = ty::struct_fields(tcx, struct_did, substs); - for field in &fields { - if type_moves_by_default(param_env, span, field.mt.ty) { + ty::ty_struct(struct_def, substs) => { + let fields = struct_def.variants.iter().flat_map(|v| v.fields.iter()); + for field in fields { + let fty = field.subst_ty_spanned(tcx, substs, span); + if type_moves_by_default(param_env, span, fty) { return Err(FieldDoesNotImplementCopy(field.name)) } } - struct_did - } - ty::ty_enum(enum_did, substs) => { - let enum_variants = ty::enum_variants(tcx, enum_did); - for variant in &*enum_variants { - for variant_arg_type in &variant.args { - let substd_arg_type = - variant_arg_type.subst(tcx, substs); - if type_moves_by_default(param_env, span, substd_arg_type) { + struct_def.def_id + } + ty::ty_enum(def, substs) => { + for variant in &def.variants { + for field in &variant.fields { + let fty = field.subst_ty_spanned(tcx, substs, span); + if type_moves_by_default(param_env, span, fty) { return Err(VariantDoesNotImplementCopy(variant.name)) } } } - enum_did + def.def_id } _ => return Err(TypeIsStructural), }; @@ -7273,15 +7171,15 @@ impl<'tcx> HasProjectionTypes for FnSig<'tcx> { } } -impl<'tcx> HasProjectionTypes for field<'tcx> { +impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> { fn has_projection_types(&self) -> bool { - self.mt.ty.has_projection_types() + self.sig.has_projection_types() } } -impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> { +impl<'tcx> HasProjectionTypes for FieldTy<'tcx> { fn has_projection_types(&self) -> bool { - self.sig.has_projection_types() + self.ty().has_projection_types() } } @@ -7325,6 +7223,12 @@ impl<'tcx> ReferencesError for Ty<'tcx> { } } +impl<'tcx> ReferencesError for FieldTy<'tcx> { + fn references_error(&self) -> bool { + self.ty().references_error() + } +} + impl<'tcx> ReferencesError for Predicate<'tcx> { fn references_error(&self) -> bool { match *self { @@ -7376,11 +7280,11 @@ impl<'tcx> Repr<'tcx> for ClosureUpvar<'tcx> { } } -impl<'tcx> Repr<'tcx> for field<'tcx> { +impl<'tcx> Repr<'tcx> for FieldTy<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("field({},{})", self.name.repr(tcx), - self.mt.repr(tcx)) + self.ty().repr(tcx)) } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4bf47c3a75f80..573e48403ab4c 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -263,12 +263,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::field<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::field<'tcx> { - ty::field { - name: self.name, - mt: self.mt.fold_with(folder), - } +impl<'tcx> TypeFoldable<'tcx> for ty::FieldTy<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::FieldTy<'tcx> { + let ty = ty::FieldTy::new(self.id, self.name, self.vis, self.origin); + ty.set_ty(self.ty().fold_with(folder)); + ty } } diff --git a/src/librustc/util/ivar.rs b/src/librustc/util/ivar.rs new file mode 100644 index 0000000000000..71707d4b33302 --- /dev/null +++ b/src/librustc/util/ivar.rs @@ -0,0 +1,70 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::cell::Cell; + +/// A write-once variable. When constructed, it is empty, and +/// can only be set once. +/// +/// Ivars ensure that data that can only be initialised once. A full +/// implementation is used for concurrency and blocks on a read of an +/// unfulfilled value. This implementation is more minimal and panics +/// if you attempt to read the value before it has been set. It is also +/// not `Sync`, but may be extended in the future to be usable as a true +/// concurrency type. +#[derive(PartialEq)] +pub struct Ivar { + data: Cell> +} + +impl Ivar { + pub fn new() -> Ivar { + Ivar { + data: Cell::new(None) + } + } + + pub fn get(&self) -> Option { + self.data.get() + } + + pub fn fulfill(&self, value: T) { + assert!(self.data.get().is_none(), + "Value already set!"); + self.data.set(Some(value)); + } + + pub fn fulfilled(&self) -> bool { + self.data.get().is_some() + } + + pub fn unwrap(&self) -> T { + self.get().unwrap() + } +} + +impl fmt::Debug for Ivar { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.get() { + Some(val) => write!(f, "Ivar {{ {:?} }}", val), + None => f.write_str("Ivar { }") + } + } +} + +impl Clone for Ivar { + fn clone(&self) -> Ivar { + match self.get() { + Some(val) => Ivar { data: Cell::new(Some(val)) }, + None => Ivar::new() + } + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 15b3c6d9d0602..faade470d0a32 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -391,10 +391,10 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { param_ty.user_string(cx) } } - ty_enum(did, substs) | ty_struct(did, substs) => { - let base = ty::item_path_str(cx, did); - parameterized(cx, &base, substs, did, &[], - || ty::lookup_item_type(cx, did).generics) + ty_enum(def, substs) | ty_struct(def, substs) => { + let base = ty::item_path_str(cx, def.def_id); + parameterized(cx, &base, substs, def.def_id, &[], + || ty::lookup_item_type(cx, def.def_id).generics) } ty_trait(ref data) => { data.user_string(cx) diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 23ca5b636815b..2be16a8843d33 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -751,8 +751,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => { match lp_base.to_type().sty { - ty::ty_struct(def_id, _) | ty::ty_enum(def_id, _) => { - if ty::has_dtor(self.tcx(), def_id) { + ty::ty_struct(def, _) | ty::ty_enum(def, _) => { + if ty::has_dtor(self.tcx(), def.def_id) { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 8cb4090bf3929..d5eff9d23f741 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -370,11 +370,11 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } } - (&ty::ty_struct(def_id, ref _substs), None) => { - let fields = ty::lookup_struct_fields(tcx, def_id); + (&ty::ty_struct(def, ref _substs), None) => { + let fields = &def.variants[0].fields[]; match *origin_field_name { mc::NamedField(ast_name) => { - for f in &fields { + for f in fields { if f.name == ast_name { continue; } @@ -394,35 +394,31 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } } - (&ty::ty_enum(enum_def_id, substs), ref enum_variant_info) => { - let variant_info = { - let mut variants = ty::substd_enum_variants(tcx, enum_def_id, substs); + (&ty::ty_enum(def, _), ref enum_variant_info) => { + let variant = { match *enum_variant_info { - Some((variant_def_id, ref _lp2)) => - variants.iter() - .find(|variant| variant.id == variant_def_id) - .expect("enum_variant_with_id(): no variant exists with that ID") - .clone(), + Some((variant_def_id, _)) => { + def.get_variant(variant_def_id) + .expect("no variant exists with that ID") + } None => { - assert_eq!(variants.len(), 1); - variants.pop().unwrap() + assert_eq!(def.variants.len(), 1); + &def.variants[0] } } }; match *origin_field_name { mc::NamedField(ast_name) => { - let variant_arg_names = variant_info.arg_names.as_ref().unwrap(); - for variant_arg_ident in variant_arg_names { - if variant_arg_ident.name == ast_name { + for field in &variant.fields { + if field.name == ast_name { continue; } - let field_name = mc::NamedField(variant_arg_ident.name); - add_fragment_sibling_local(field_name, Some(variant_info.id)); + let field_name = mc::NamedField(field.name); + add_fragment_sibling_local(field_name, Some(variant.id)); } } mc::PositionalField(tuple_idx) => { - let variant_arg_types = &variant_info.args; - for (i, _variant_arg_ty) in variant_arg_types.iter().enumerate() { + for (i, _) in variant.fields.iter().enumerate() { if tuple_idx == i { continue; } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index d0f5aa8cf003b..8d7da0f802a57 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -179,8 +179,8 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, mc::cat_interior(ref b, mc::InteriorField(_)) | mc::cat_interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { - ty::ty_struct(did, _) | ty::ty_enum(did, _) => { - if ty::has_dtor(bccx.tcx, did) { + ty::ty_struct(def, _) | ty::ty_enum(def, _) => { + if ty::has_dtor(bccx.tcx, def.def_id) { Some(cmt.clone()) } else { check_and_get_illegal_move_origin(bccx, b) diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 53761eb14713d..9b503431387c6 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -137,8 +137,8 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, mc::cat_downcast(ref b, _) | mc::cat_interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { - ty::ty_struct(did, _) | - ty::ty_enum(did, _) if ty::has_dtor(bccx.tcx, did) => { + ty::ty_struct(def, _) | + ty::ty_enum(def, _) if ty::has_dtor(bccx.tcx, def.def_id) => { bccx.span_err( move_from.span, &format!("cannot move out of type `{}`, \ diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 436a826687e13..8fa8e6d2eebd9 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -658,12 +658,15 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a field is in scope. fn check_field(&mut self, span: Span, - id: ast::DefId, + def: &'tcx ty::DatatypeDef<'tcx>, + variant_id: ast::DefId, name: FieldName) { - let fields = ty::lookup_struct_fields(self.tcx, id); + let variant = def.get_variant(variant_id).expect("variant not in enum"); + let fields = &variant.fields[]; let field = match name { NamedField(f_name) => { - debug!("privacy - check named field {} in struct {:?}", f_name, id); + debug!("privacy - check named field {} in struct {:?}", + f_name, variant_id); fields.iter().find(|f| f.name == f_name).unwrap() } UnnamedField(idx) => &fields[idx] @@ -673,14 +676,12 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { return } - let struct_type = ty::lookup_item_type(self.tcx, id).ty; - let struct_desc = match struct_type.sty { - ty::ty_struct(_, _) => - format!("struct `{}`", ty::item_path_str(self.tcx, id)), - // struct variant fields have inherited visibility - ty::ty_enum(..) => return, - _ => self.tcx.sess.span_bug(span, "can't find struct for field") - }; + // Enum variant fields are always public + if def.def_id != variant_id { + return + } + + let struct_desc = format!("struct `{}`", ty::item_path_str(self.tcx, variant_id)); let msg = match name { NamedField(name) => format!("field `{}` of {} is private", token::get_name(name), struct_desc), @@ -852,13 +853,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &ast::Expr) { match expr.node { ast::ExprField(ref base, ident) => { - if let ty::ty_struct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty { - self.check_field(expr.span, id, NamedField(ident.node.name)); + if let ty::ty_struct(def, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty { + self.check_field(expr.span, def, def.def_id, NamedField(ident.node.name)); } } ast::ExprTupField(ref base, idx) => { - if let ty::ty_struct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty { - self.check_field(expr.span, id, UnnamedField(idx.node)); + if let ty::ty_struct(def, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty { + self.check_field(expr.span, def, def.def_id, UnnamedField(idx.node)); } } ast::ExprMethodCall(ident, _, _) => { @@ -877,21 +878,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } ast::ExprStruct(_, ref fields, _) => { match ty::expr_ty(self.tcx, expr).sty { - ty::ty_struct(ctor_id, _) => { + ty::ty_struct(def, _) => { // RFC 736: ensure all unmentioned fields are visible. // Rather than computing the set of unmentioned fields - // (i.e. `all_fields - fields`), just check them all. - let all_fields = ty::lookup_struct_fields(self.tcx, ctor_id); - for field in all_fields { - self.check_field(expr.span, ctor_id, + // (i.e. `all_fields - fields`, just check them all. + for field in &def.variants[0].fields { + self.check_field(expr.span, def, def.def_id, NamedField(field.name)); } } - ty::ty_enum(_, _) => { + ty::ty_enum(def, _) => { match self.tcx.def_map.borrow()[expr.id].full_def() { def::DefVariant(_, variant_id, _) => { for field in fields { - self.check_field(expr.span, variant_id, + self.check_field(expr.span, def, variant_id, NamedField(field.ident.node.name)); } } @@ -909,7 +909,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } ast::ExprPath(..) => { let guard = |did: ast::DefId| { - let fields = ty::lookup_struct_fields(self.tcx, did); + let struct_def = ty::lookup_datatype_def(self.tcx, did); + let fields = &struct_def.variants[0].fields[]; let any_priv = fields.iter().any(|f| { f.vis != ast::Public && ( !is_local(f.id) || @@ -954,17 +955,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match pattern.node { ast::PatStruct(_, ref fields, _) => { match ty::pat_ty(self.tcx, pattern).sty { - ty::ty_struct(id, _) => { + ty::ty_struct(def, _) => { for field in fields { - self.check_field(pattern.span, id, + self.check_field(pattern.span, def, def.def_id, NamedField(field.node.ident.name)); } } - ty::ty_enum(_, _) => { + ty::ty_enum(def, _) => { match self.tcx.def_map.borrow().get(&pattern.id).map(|d| d.full_def()) { Some(def::DefVariant(_, variant_id, _)) => { for field in fields { - self.check_field(pattern.span, variant_id, + self.check_field(pattern.span, def, variant_id, NamedField(field.node.ident.name)); } } @@ -985,12 +986,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { // elsewhere). ast::PatEnum(_, Some(ref fields)) => { match ty::pat_ty(self.tcx, pattern).sty { - ty::ty_struct(id, _) => { + ty::ty_struct(def, _) => { for (i, field) in fields.iter().enumerate() { if let ast::PatWild(..) = field.node { continue } - self.check_field(field.span, id, UnnamedField(i)); + self.check_field(field.span, def, def.def_id, UnnamedField(i)); } } ty::ty_enum(..) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 67e2b409c8e22..8c43054d8649c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -781,20 +781,19 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { child_name_bindings.define_type(def, DUMMY_SP, modifiers); } DefStruct(def_id) => { - debug!("(building reduced graph for external \ - crate) building type and value for {}", - final_ident); - child_name_bindings.define_type(def, DUMMY_SP, modifiers); - let fields = csearch::get_struct_fields(&self.session.cstore, def_id).iter().map(|f| { - f.name - }).collect::>(); - - if fields.len() == 0 { - child_name_bindings.define_value(def, DUMMY_SP, modifiers); - } + debug!("(building reduced graph for external \ + crate) building type and value for {}", + final_ident); + child_name_bindings.define_type(def, DUMMY_SP, modifiers); + let fields : Vec<_> = csearch::get_struct_fields(&self.session.cstore, def_id) + .into_iter().map(|f| f.name ).collect(); + + if fields.len() == 0 { + child_name_bindings.define_value(def, DUMMY_SP, modifiers); + } - // Record the def ID and fields of this struct. - self.structs.insert(def_id, fields); + // Record the def ID and fields of this struct. + self.structs.insert(def_id, fields); } DefLocal(..) | DefPrimTy(..) | DefTyParam(..) | DefUse(..) | DefUpvar(..) | DefRegion(..) | diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 371b9268fba0d..143d5835279d8 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -901,14 +901,14 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, ex).sty; let struct_def = match *ty { - ty::ty_struct(def_id, _) => { + ty::ty_struct(def, _) => { let sub_span = self.span.span_for_last_ident(path.span); self.fmt.ref_str(recorder::StructRef, path.span, sub_span, - def_id, + def.def_id, self.cur_scope); - Some(def_id) + Some(def) } _ => None }; @@ -916,8 +916,8 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { for field in fields { match struct_def { Some(struct_def) => { - let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def); - for f in &fields { + let fields = &struct_def.variants[0].fields[]; + for f in fields { if generated_code(field.ident.span) { continue; } @@ -1021,10 +1021,11 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { }; if let Some(struct_def) = struct_def { - let struct_fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def); + let struct_def = ty::lookup_datatype_def(&self.analysis.ty_cx, struct_def); for &Spanned { node: ref field, span } in fields { let sub_span = self.span.span_for_first_ident(span); - for f in &struct_fields { + let fields = &struct_def.variants[0].fields[]; + for f in fields { if f.name == field.ident.name { self.fmt.ref_str(recorder::VarRef, span, @@ -1033,8 +1034,8 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { self.cur_scope); break; } + self.visit_pat(&*field.pat); } - self.visit_pat(&*field.pat); } } } @@ -1351,11 +1352,12 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { } self.visit_expr(&**sub_ex); + let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty; match *ty { - ty::ty_struct(def_id, _) => { - let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id); - for f in &fields { + ty::ty_struct(def, _) => { + let fields = &def.variants[0].fields[]; + for f in fields { if f.name == ident.node.name { let sub_span = self.span.span_for_last_ident(ex.span); self.fmt.ref_str(recorder::VarRef, @@ -1380,8 +1382,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty; match *ty { - ty::ty_struct(def_id, _) => { - let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id); + ty::ty_struct(def, _) => { + let fields = &def.variants[0].fields[]; for (i, f) in fields.iter().enumerate() { if i == idx.node { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 9a121a8830b2b..2f0166dc0265e 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -601,7 +601,8 @@ fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def()); match opt_def { Some(def::DefVariant(enum_id, var_id, _)) => { - let variant = ty::enum_variant_with_id(tcx, enum_id, var_id); + let enum_def = ty::lookup_datatype_def(tcx, enum_id); + let variant = enum_def.get_variant(var_id).expect("variant not in enum"); Variant(variant.disr_val, adt::represent_node(bcx, cur.id), var_id, @@ -1412,7 +1413,6 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, let _icx = push_ctxt("match::trans_match_inner"); let fcx = scope_cx.fcx; let mut bcx = scope_cx; - let tcx = bcx.tcx(); let discr_datum = unpack_datum!(bcx, expr::trans_to_lvalue(bcx, discr_expr, "match")); @@ -1421,7 +1421,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, } let t = node_id_type(bcx, discr_expr.id); - let chk = if ty::type_is_empty(tcx, t) { + let chk = if ty::type_is_empty(t) { Unreachable } else { Infallible @@ -1656,7 +1656,6 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("match::bind_irrefutable_pat"); let mut bcx = bcx; let tcx = bcx.tcx(); - let ccx = bcx.ccx(); match pat.node { ast::PatIdent(pat_binding_mode, ref path1, ref inner) => { if pat_is_binding(&tcx.def_map, &*pat) { @@ -1693,12 +1692,11 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match opt_def { Some(def::DefVariant(enum_id, var_id, _)) => { let repr = adt::represent_node(bcx, pat.id); - let vinfo = ty::enum_variant_with_id(ccx.tcx(), - enum_id, - var_id); + let enum_def = ty::lookup_datatype_def(bcx.tcx(), enum_id); + let variant = enum_def.get_variant(var_id).expect("variant not in enum"); let args = extract_variant_args(bcx, &*repr, - vinfo.disr_val, + variant.disr_val, val); if let Some(ref sub_pat) = *sub_pats { for (i, &argval) in args.vals.iter().enumerate() { @@ -1735,7 +1733,9 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let pat_repr = adt::represent_type(bcx.ccx(), pat_ty); expr::with_field_tys(tcx, pat_ty, Some(pat.id), |discr, field_tys| { for f in fields { - let ix = ty::field_idx_strict(tcx, f.node.ident.name, field_tys); + let ix = field_tys.iter().position(|fld| { + fld.name == f.node.ident.name + }).unwrap(); let fldptr = adt::trans_field_ptr(bcx, &*pat_repr, val, discr, ix); bcx = bind_irrefutable_pat(bcx, &*f.node.pat, fldptr, cleanup_scope); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 3ea14d3c58929..34ad386ab68cf 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -157,14 +157,14 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_tup(ref elems) => { Univariant(mk_struct(cx, &elems[..], false, t), false) } - ty::ty_struct(def_id, substs) => { - let fields = ty::lookup_struct_fields(cx.tcx(), def_id); + ty::ty_struct(def, substs) => { + let fields = &def.variants[0].fields[]; let mut ftys = fields.iter().map(|field| { - let fty = ty::lookup_field_type(cx.tcx(), def_id, field.id, substs); + let fty = field.subst_ty(cx.tcx(), substs); monomorphize::normalize_associated_type(cx.tcx(), &fty) }).collect::>(); - let packed = ty::lookup_packed(cx.tcx(), def_id); - let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); + let packed = ty::lookup_packed(cx.tcx(), def.def_id); + let dtor = ty::ty_dtor(cx.tcx(), def.def_id).has_drop_flag(); if dtor { ftys.push(cx.tcx().types.bool); } Univariant(mk_struct(cx, &ftys[..], packed, t), dtor) @@ -175,12 +175,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); Univariant(mk_struct(cx, &upvar_types[..], false, t), false) } - ty::ty_enum(def_id, substs) => { - let cases = get_cases(cx.tcx(), def_id, substs); - let hint = *ty::lookup_repr_hints(cx.tcx(), def_id).get(0) + ty::ty_enum(def, substs) => { + let cases = get_cases(cx.tcx(), def, substs); + let hint = *ty::lookup_repr_hints(cx.tcx(), def.def_id).get(0) .unwrap_or(&attr::ReprAny); - let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); + let dtor = ty::ty_dtor(cx.tcx(), def.def_id).has_drop_flag(); if cases.len() == 0 { // Uninhabitable; represent as unit @@ -206,11 +206,14 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Since there's at least one // non-empty body, explicit discriminants should have // been rejected by a checker before this point. - if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as Disr)) { - cx.sess().bug(&format!("non-C-like enum {} with specified \ - discriminants", + for (i, c) in cases.iter().enumerate() { + if c.discr != (i as Disr) { + cx.sess().bug(&format!("non-C-like enum {} with specified \ + discriminants (Enum {} has disr {})", ty::item_path_str(cx.tcx(), - def_id))); + def.def_id), + i, c.discr)[]); + } } if cases.len() == 1 { @@ -358,10 +361,10 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty::ty_bare_fn(..) => Some(path), // Is this the NonZero lang item wrapping a pointer or integer type? - ty::ty_struct(did, substs) if Some(did) == tcx.lang_items.non_zero() => { - let nonzero_fields = ty::lookup_struct_fields(tcx, did); + ty::ty_struct(def, substs) if Some(def.def_id) == tcx.lang_items.non_zero() => { + let nonzero_fields = &def.variants[0].fields[]; assert_eq!(nonzero_fields.len(), 1); - let nonzero_field = ty::lookup_field_type(tcx, did, nonzero_fields[0].id, substs); + let nonzero_field = nonzero_fields[0].subst_ty(tcx, substs); match nonzero_field.sty { ty::ty_ptr(..) | ty::ty_int(..) | ty::ty_uint(..) => { path.push(0); @@ -373,10 +376,10 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Perhaps one of the fields of this struct is non-zero // let's recurse and find out - ty::ty_struct(def_id, substs) => { - let fields = ty::lookup_struct_fields(tcx, def_id); + ty::ty_struct(def, substs) => { + let fields = &def.variants[0].fields[]; for (j, field) in fields.iter().enumerate() { - let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs); + let field_ty = field.subst_ty(tcx, substs); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { fpath.push(j); return Some(fpath); @@ -429,14 +432,13 @@ impl<'tcx> Case<'tcx> { } fn get_cases<'tcx>(tcx: &ty::ctxt<'tcx>, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> Vec> { - ty::enum_variants(tcx, def_id).iter().map(|vi| { - let arg_tys = vi.args.iter().map(|&raw_ty| { - monomorphize::apply_param_substs(tcx, substs, &raw_ty) + def: &'tcx ty::DatatypeDef<'tcx>, + substs: &subst::Substs<'tcx>) -> Vec> { + def.variants.iter().map(|v| { + let arg_tys = v.fields.iter().map(|f| { + monomorphize::apply_param_substs(tcx, substs, &f.ty()) }).collect(); - Case { discr: vi.disr_val, tys: arg_tys } + Case { discr: v.disr_val, tys: arg_tys } }).collect() } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index b18b7b75d32fc..ae10e1b9839d7 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -639,8 +639,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, repr: &adt::Repr<'tcx>, av: ValueRef, - variant: &ty::VariantInfo<'tcx>, - substs: &Substs<'tcx>, + variant: &ty::VariantDef<'tcx>, + substs: &'tcx Substs<'tcx>, f: &mut F) -> Block<'blk, 'tcx> where F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, @@ -649,8 +649,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, let tcx = cx.tcx(); let mut cx = cx; - for (i, &arg) in variant.args.iter().enumerate() { - let arg = monomorphize::apply_param_substs(tcx, substs, &arg); + for (i, fld) in variant.fields.iter().enumerate() { + let arg = monomorphize::apply_param_substs(tcx, substs, &fld.ty()); cx = f(cx, adt::trans_field_ptr(cx, repr, av, variant.disr_val, i), arg); } return cx; @@ -670,7 +670,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, let repr = adt::represent_type(cx.ccx(), t); expr::with_field_tys(cx.tcx(), t, None, |discr, field_tys| { for (i, field_ty) in field_tys.iter().enumerate() { - let field_ty = field_ty.mt.ty; + let field_ty = field_ty.ty; let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i); let val = if common::type_is_sized(cx.tcx(), field_ty) { @@ -706,20 +706,20 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, cx = f(cx, llfld_a, *arg); } } - ty::ty_enum(tid, substs) => { + ty::ty_enum(def, substs) => { let fcx = cx.fcx; let ccx = fcx.ccx; let repr = adt::represent_type(ccx, t); - let variants = ty::enum_variants(ccx.tcx(), tid); - let n_variants = (*variants).len(); + let variants = &def.variants[]; + let n_variants = variants.len(); // NB: we must hit the discriminant first so that structural // comparison know not to proceed when the discriminants differ. match adt::trans_switch(cx, &*repr, av) { (_match::Single, None) => { - cx = iter_variant(cx, &*repr, av, &*(*variants)[0], + cx = iter_variant(cx, &*repr, av, &variants[0], substs, &mut f); } (_match::Switch, Some(lldiscrim_a)) => { @@ -730,12 +730,10 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, n_variants); let next_cx = fcx.new_temp_block("enum-iter-next"); - for variant in &(*variants) { - let variant_cx = - fcx.new_temp_block( - &format!("enum-iter-variant-{}", - &variant.disr_val.to_string()) - ); + for variant in variants { + let block_name = format!("enum-iter-variant-{}", + &variant.disr_val.to_string()); + let variant_cx = fcx.new_temp_block(&block_name[]); match adt::trans_case(cx, &*repr, variant.disr_val) { _match::SingleResult(r) => { AddCase(llswitch, r.val, variant_cx.llbb) @@ -747,7 +745,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, iter_variant(variant_cx, &*repr, data_ptr, - &**variant, + variant, substs, &mut f); Br(variant_cx, next_cx.llbb, DebugLoc::None); @@ -1468,7 +1466,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, // This shouldn't need to recompute the return type, // as new_fn_ctxt did it already. let substd_output_type = fcx.monomorphize(&output_type); - if !return_type_is_void(fcx.ccx, substd_output_type) { + if !return_type_is_void(substd_output_type) { // If the function returns nil/bot, there is no real return // value, so do not set `llretslotptr`. if !skip_retptr || fcx.caller_expects_out_pointer { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 59fcd5492ebde..341674976f023 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -177,17 +177,17 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) bcx.fcx.param_substs).val) } def::DefVariant(tid, vid, _) => { - let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid); - let substs = common::node_id_substs(bcx.ccx(), - ExprId(ref_expr.id), - bcx.fcx.param_substs); + let enum_def = ty::lookup_datatype_def(bcx.tcx(), tid); + let variant = enum_def.get_variant(vid).expect("variant not in enum"); + let substs = common::node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); // Nullary variants are not callable - assert!(vinfo.args.len() > 0); + assert!(variant.fields.len() > 0u); Callee { bcx: bcx, - data: NamedTupleConstructor(substs, vinfo.disr_val) + data: NamedTupleConstructor(substs, variant.disr_val) } } def::DefStruct(_) => { diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d8fc6df2685dd..81d41f4a0b21c 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -24,7 +24,7 @@ use middle::infer; use middle::lang_items::LangItem; use middle::mem_categorization as mc; use middle::region; -use middle::subst::{self, Subst, Substs}; +use middle::subst::{self, Substs}; use trans::base; use trans::build; use trans::cleanup; @@ -151,11 +151,9 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { match ty.sty { ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty, - ty::ty_struct(def_id, substs) => { - let unsized_fields: Vec<_> = - ty::struct_fields(cx, def_id, substs) - .iter() - .map(|f| f.mt.ty) + ty::ty_struct(def, substs) => { + let unsized_fields: Vec<_> = def.variants[0].fields.iter() + .map(|f| f.subst_ty(cx, substs)) .filter(|ty| !type_is_sized(cx, *ty)) .collect(); @@ -197,14 +195,11 @@ pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty< ty::ty_bool | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | ty::ty_tup(_) | ty::ty_ptr(_) => false, - ty::ty_enum(did, substs) => - ty::enum_variants(tcx, did).iter().any(|v| - v.args.iter().any(|&aty| { - let t = aty.subst(tcx, substs); - type_needs_unwind_cleanup_(tcx, t, tycache) - }) - ), - + ty::ty_enum(def, substs) => { + def.variants.iter() + .flat_map(|v| v.subst_fields(tcx, substs)) + .any(|t| type_needs_unwind_cleanup_(tcx, t, tycache)) + } _ => true }; !needs_unwind_cleanup @@ -219,10 +214,10 @@ pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::ty_struct(def_id, substs) => { - let fields = ty::lookup_struct_fields(ccx.tcx(), def_id); + ty::ty_struct(def, substs) => { + let fields = &def.variants[0].fields[]; fields.len() == 1 && { - let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs); + let ty = fields[0].subst_ty(ccx.tcx(), substs); let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty); type_is_immediate(ccx, ty) } @@ -268,8 +263,8 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - /// return types. These are `()`, bot, and uninhabited enums. Note that all such types are also /// zero-size, but not all zero-size types use a `void` return type (in order to aid with C ABI /// compatibility). -pub fn return_type_is_void(ccx: &CrateContext, ty: Ty) -> bool { - ty::type_is_nil(ty) || ty::type_is_empty(ccx.tcx(), ty) +pub fn return_type_is_void(ty: Ty) -> bool { + ty::type_is_nil(ty) || ty::type_is_empty(ty) } /// Generates a unique symbol based off the name given. This is used to create diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index c1d22cc973c24..9fe75340e1397 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -369,7 +369,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let (te1, ty) = const_expr(cx, &**e1, param_substs); let is_simd = ty::type_is_simd(cx.tcx(), ty); let intype = if is_simd { - ty::simd_type(cx.tcx(), ty) + ty::simd_type(ty) } else { ty }; @@ -448,7 +448,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let (bv, bt) = const_expr(cx, &**base, param_substs); let brepr = adt::represent_type(cx, bt); expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { - let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys); + let ix = field_tys.iter().position(|f| f.name == field.node.name).unwrap(); adt::const_get_field(cx, &*brepr, bv, discr, ix) }) } @@ -611,7 +611,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, expr::with_field_tys(cx.tcx(), ety, Some(e.id), |discr, field_tys| { let cs = field_tys.iter().enumerate() - .map(|(ix, &field_ty)| { + .map(|(ix, field_ty)| { match fs.iter().find(|f| field_ty.name == f.ident.node.name) { Some(ref f) => const_expr(cx, &*f.expr, param_substs).0, None => { @@ -673,16 +673,16 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, const_deref_ptr(cx, get_const_val(cx, def_id, e)) } def::DefVariant(enum_did, variant_did, _) => { - let vinfo = ty::enum_variant_with_id(cx.tcx(), - enum_did, - variant_did); - if vinfo.args.len() > 0 { + let enum_def = ty::lookup_datatype_def(cx.tcx(), enum_did); + let variant = enum_def.get_variant(variant_did).expect("variant not in enum"); + + if variant.fields.len() > 0 { // N-ary variant. expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } else { // Nullary variant. let repr = adt::represent_type(cx, ety); - adt::trans_const(cx, &*repr, vinfo.disr_val, &[]) + adt::trans_const(cx, &*repr, variant.disr_val, &[]) } } def::DefStruct(_) => { @@ -714,12 +714,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } Some(def::DefVariant(enum_did, variant_did, _)) => { let repr = adt::represent_type(cx, ety); - let vinfo = ty::enum_variant_with_id(cx.tcx(), - enum_did, - variant_did); + + let enum_def = ty::lookup_datatype_def(cx.tcx(), enum_did); + let variant = enum_def.get_variant(variant_did) + .expect("variant not in enum"); + adt::trans_const(cx, &*repr, - vinfo.disr_val, + variant.disr_val, &arg_vals[..]) } _ => cx.sess().span_bug(e.span, "expected a struct or variant def") diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index d70a904b81189..a87e02856bee9 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -194,7 +194,6 @@ use llvm; use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::*; use metadata::csearch; -use middle::subst::{self, Substs}; use trans::{self, adt, machine, type_of}; use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, C_bytes, NormalizingClosureTyper}; @@ -202,6 +201,7 @@ use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; use trans::monomorphize; use trans::type_::Type; use middle::ty::{self, Ty, ClosureTyper}; +use middle::subst::{self, Substs}; use middle::pat_util; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; @@ -362,13 +362,13 @@ impl<'tcx> TypeMap<'tcx> { ty::ty_float(_) => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, - ty::ty_enum(def_id, substs) => { + ty::ty_enum(def, substs) => { unique_type_id.push_str("enum "); - from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id); + from_def_id_and_substs(self, cx, def.def_id, substs, &mut unique_type_id); }, - ty::ty_struct(def_id, substs) => { + ty::ty_struct(def, substs) => { unique_type_id.push_str("struct "); - from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id); + from_def_id_and_substs(self, cx, def.def_id, substs, &mut unique_type_id); }, ty::ty_tup(ref component_types) if component_types.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); @@ -1973,7 +1973,7 @@ impl<'tcx> RecursiveTypeDescription<'tcx> { // Creates MemberDescriptions for the fields of a struct struct StructMemberDescriptionFactory<'tcx> { - fields: Vec>, + fields: Vec>, is_simd: bool, span: Span, } @@ -1986,7 +1986,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { } let field_size = if self.is_simd { - machine::llsize_of_alloc(cx, type_of::type_of(cx, self.fields[0].mt.ty)) as uint + machine::llsize_of_alloc(cx, type_of::type_of(cx, self.fields[0].ty)) as uint } else { 0xdeadbeef }; @@ -2007,8 +2007,8 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { MemberDescription { name: name, - llvm_type: type_of::type_of(cx, field.mt.ty), - type_metadata: type_metadata(cx, field.mt.ty, self.span), + llvm_type: type_of::type_of(cx, field.ty), + type_metadata: type_metadata(cx, field.ty, self.span), offset: offset, flags: FLAGS_NONE, } @@ -2022,8 +2022,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, def_id: ast::DefId, substs: &subst::Substs<'tcx>, unique_type_id: UniqueTypeId, - span: Span) - -> RecursiveTypeDescription<'tcx> { + span: Span) -> RecursiveTypeDescription<'tcx> { let struct_name = compute_debuginfo_type_name(cx, struct_type, false); let struct_llvm_type = type_of::type_of(cx, struct_type); @@ -2035,13 +2034,14 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, containing_scope); - let mut fields = ty::struct_fields(cx.tcx(), def_id, substs); - - // The `Ty` values returned by `ty::struct_fields` can still contain - // `ty_projection` variants, so normalize those away. - for field in &mut fields { - field.mt.ty = monomorphize::normalize_associated_type(cx.tcx(), &field.mt.ty); - } + let struct_def = ty::lookup_datatype_def(cx.tcx(), def_id); + let fields = struct_def.variants[0].fields.iter().map(|f| { + let ty = f.subst_ty(cx.tcx(), substs); + trans::expr::FieldInfo { + name: f.name, + ty: monomorphize::normalize_associated_type(cx.tcx(), &ty) + } + }).collect(); create_and_register_recursive_type_forward_declaration( cx, @@ -2122,7 +2122,7 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, struct EnumMemberDescriptionFactory<'tcx> { enum_type: Ty<'tcx>, type_rep: Rc>, - variants: Rc>>>, + variants: &'tcx [ty::VariantDef<'tcx>], discriminant_type_metadata: Option, containing_scope: DIScope, file_metadata: DIFile, @@ -2147,7 +2147,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { describe_enum_variant(cx, self.enum_type, struct_def, - &*(*self.variants)[i], + &self.variants[i], discriminant_info, self.containing_scope, self.span); @@ -2180,7 +2180,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { describe_enum_variant(cx, self.enum_type, struct_def, - &*(*self.variants)[0], + &self.variants[0], NoDiscriminant, self.containing_scope, self.span); @@ -2224,10 +2224,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // For the metadata of the wrapper struct, we need to create a // MemberDescription of the struct's single field. let sole_struct_member_description = MemberDescription { - name: match non_null_variant.arg_names { - Some(ref names) => token::get_ident(names[0]).to_string(), - None => "".to_string() - }, + name: token::get_name(non_null_variant.fields[0].name).to_string(), llvm_type: non_null_llvm_type, type_metadata: non_null_type_metadata, offset: FixedMemberOffset { bytes: 0 }, @@ -2280,7 +2277,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { describe_enum_variant(cx, self.enum_type, struct_def, - &*(*self.variants)[nndiscr as uint], + &self.variants[nndiscr as uint], OptimizedDiscriminant, self.containing_scope, self.span); @@ -2357,14 +2354,14 @@ enum EnumDiscriminantInfo { // of the variant, and (3) a MemberDescriptionFactory for producing the // descriptions of the fields of the variant. This is a rudimentary version of a // full RecursiveTypeDescription. -fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - enum_type: Ty<'tcx>, - struct_def: &adt::Struct<'tcx>, - variant_info: &ty::VariantInfo<'tcx>, - discriminant_info: EnumDiscriminantInfo, - containing_scope: DIScope, - span: Span) - -> (DICompositeType, Type, MemberDescriptionFactory<'tcx>) { +fn describe_enum_variant<'a, 'tcx>( + cx: &CrateContext<'a, 'tcx>, + enum_type: Ty<'tcx>, + struct_def: &adt::Struct<'tcx>, + variant_info: &ty::VariantDef<'tcx>, + discriminant_info: EnumDiscriminantInfo, + containing_scope: DIScope, + span: Span) -> (DICompositeType, Type, MemberDescriptionFactory<'tcx>) { let variant_llvm_type = Type::struct_(cx, &struct_def.fields .iter() @@ -2390,15 +2387,9 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, containing_scope); // Get the argument names from the enum variant info - let mut arg_names: Vec<_> = match variant_info.arg_names { - Some(ref names) => { - names.iter() - .map(|ident| { - token::get_ident(*ident).to_string() - }).collect() - } - None => variant_info.args.iter().map(|_| "".to_string()).collect() - }; + let mut arg_names: Vec<_> = variant_info.fields.iter().map(|f| { + token::get_name(f.name).to_string() + }).collect(); // If this is not a univariant enum, there is also the discriminant field. match discriminant_info { @@ -2431,17 +2422,16 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, enum_type: Ty<'tcx>, enum_def_id: ast::DefId, unique_type_id: UniqueTypeId, - span: Span) - -> RecursiveTypeDescription<'tcx> { + span: Span) -> RecursiveTypeDescription<'tcx> { let enum_name = compute_debuginfo_type_name(cx, enum_type, false); let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, enum_def_id); let loc = span_start(cx, definition_span); let file_metadata = file_metadata(cx, &loc.file.name); - let variants = ty::enum_variants(cx.tcx(), enum_def_id); + let enum_def = ty::lookup_datatype_def(cx.tcx(), enum_def_id); - let enumerators_metadata: Vec = variants + let enumerators_metadata: Vec = enum_def.variants .iter() .map(|v| { let token = token::get_name(v.name); @@ -2452,8 +2442,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, name.as_ptr(), v.disr_val as u64) } - }) - .collect(); + }).collect(); let discriminant_type_metadata = |inttype| { // We can reuse the type of the discriminant for all monomorphized @@ -2544,7 +2533,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, EnumMDF(EnumMemberDescriptionFactory { enum_type: enum_type, type_rep: type_rep.clone(), - variants: variants, + variants: &enum_def.variants[], discriminant_type_metadata: discriminant_type_metadata, containing_scope: containing_scope, file_metadata: file_metadata, @@ -2938,8 +2927,8 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_tup(ref elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::ty_enum(def_id, _) => { - prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx) + ty::ty_enum(def, _) => { + prepare_enum_metadata(cx, t, def.def_id, unique_type_id, usage_site_span).finalize(cx) } ty::ty_vec(typ, len) => { fixed_vec_metadata(cx, unique_type_id, typ, len.map(|x| x as u64), usage_site_span) @@ -2988,10 +2977,10 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let sig = typer.closure_type(def_id, substs).sig; subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) } - ty::ty_struct(def_id, substs) => { + ty::ty_struct(def, substs) => { prepare_struct_metadata(cx, t, - def_id, + def.def_id, substs, unique_type_id, usage_site_span).finalize(cx) @@ -3721,9 +3710,9 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_uint(ast::TyU64) => output.push_str("u64"), ty::ty_float(ast::TyF32) => output.push_str("f32"), ty::ty_float(ast::TyF64) => output.push_str("f64"), - ty::ty_struct(def_id, substs) | - ty::ty_enum(def_id, substs) => { - push_item_name(cx, def_id, qualified, output); + ty::ty_struct(def, substs) | + ty::ty_enum(def, substs) => { + push_item_name(cx, def.def_id, qualified, output); push_type_params(cx, substs, output); }, ty::ty_tup(ref component_types) => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 5cc1baf66c621..0da66fa528b6f 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -71,7 +71,6 @@ use trans::meth; use trans::monomorphize; use trans::tvec; use trans::type_of; -use middle::ty::{struct_fields, tup_fields}; use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AutoUnsafe}; use middle::ty::{AutoPtr}; use middle::ty::{self, Ty}; @@ -699,7 +698,7 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, base: &ast::Expr, get_idx: F) -> DatumBlock<'blk, 'tcx, Expr> where - F: FnOnce(&'blk ty::ctxt<'tcx>, &[ty::field<'tcx>]) -> uint, + F: FnOnce(&'blk ty::ctxt<'tcx>, &[FieldInfo<'tcx>]) -> uint, { let mut bcx = bcx; let _icx = push_ctxt("trans_rec_field"); @@ -708,10 +707,10 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let bare_ty = base_datum.ty; let repr = adt::represent_type(bcx.ccx(), bare_ty); with_field_tys(bcx.tcx(), bare_ty, None, move |discr, field_tys| { - let ix = get_idx(bcx.tcx(), field_tys); + let ix = get_idx(bcx.tcx(), &field_tys[]); let d = base_datum.get_element( bcx, - field_tys[ix].mt.ty, + field_tys[ix].ty, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix)); if type_is_sized(bcx.tcx(), d.ty) { @@ -732,9 +731,10 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, /// Translates `base.field`. fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, base: &ast::Expr, - field: ast::Ident) - -> DatumBlock<'blk, 'tcx, Expr> { - trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field.name, field_tys)) + field: ast::Ident) -> DatumBlock<'blk, 'tcx, Expr> { + trans_field(bcx, base, |_, field_tys| { + field_tys.iter().position(|f| f.name == field.name).unwrap() + }) } /// Translates `base.`. @@ -1093,13 +1093,14 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; if let Some(did) = did { + let def = ty::lookup_datatype_def(tcx, did); let substs = Substs::new_type(ty_params, vec![]); trans_struct(bcx, &fields, None, expr.span, expr.id, - ty::mk_struct(tcx, did, tcx.mk_substs(substs)), + ty::mk_struct(tcx, def, tcx.mk_substs(substs)), dest) } else { tcx.sess.span_bug(expr.span, @@ -1229,8 +1230,9 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match def { def::DefVariant(tid, vid, _) => { - let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid); - if variant_info.args.len() > 0 { + let enum_def = ty::lookup_datatype_def(bcx.tcx(), tid); + let variant = enum_def.get_variant(vid).expect("variant not in enum"); + if variant.fields.len() > 0u { // N-ary variant. let llfn = callee::trans_fn_ref(bcx.ccx(), vid, ExprId(ref_expr.id), @@ -1242,14 +1244,14 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ty = expr_ty(bcx, ref_expr); let repr = adt::represent_type(bcx.ccx(), ty); adt::trans_set_discr(bcx, &*repr, lldest, - variant_info.disr_val); + variant.disr_val); return bcx; } } def::DefStruct(_) => { let ty = expr_ty(bcx, ref_expr); match ty.sty { - ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => { + ty::ty_struct(def, _) if ty::has_dtor(bcx.tcx(), def.def_id) => { let repr = adt::represent_type(bcx.ccx(), ty); adt::trans_set_discr(bcx, &*repr, lldest, 0); } @@ -1332,6 +1334,11 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } +pub struct FieldInfo<'tcx> { + pub name: ast::Name, + pub ty: ty::Ty<'tcx> +} + /// Helper for enumerating the field types of structs, enums, or records. The optional node ID here /// is the node ID of the path identifying the enum variant in use. If none, this cannot possibly /// an enum variant (so, if it is and `node_id_opt` is none, this function panics). @@ -1340,20 +1347,31 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, node_id_opt: Option, op: F) -> R where - F: FnOnce(ty::Disr, &[ty::field<'tcx>]) -> R, + F: FnOnce(ty::Disr, Vec>) -> R, { match ty.sty { - ty::ty_struct(did, substs) => { - let fields = struct_fields(tcx, did, substs); - let fields = monomorphize::normalize_associated_type(tcx, &fields); - op(0, &fields[..]) + ty::ty_struct(def, substs) => { + let fi = def.variants[0].fields.iter().map(|f| { + let ty = f.subst_ty(tcx, substs); + FieldInfo { + name: f.name, + ty: monomorphize::normalize_associated_type(tcx, &ty) + } + }).collect(); + op(0, fi) } ty::ty_tup(ref v) => { - op(0, &tup_fields(&v[..])) + let fi = v.iter().enumerate().map(|(i, &ty)| { + FieldInfo { + name: token::intern(&i.to_string()[]), + ty: ty + } + }).collect(); + op(0, fi) } - ty::ty_enum(_, substs) => { + ty::ty_enum(enum_def, substs) => { // We want the *variant* ID here, not the enum ID. match node_id_opt { None => { @@ -1366,11 +1384,17 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, let def = tcx.def_map.borrow()[node_id].full_def(); match def { def::DefVariant(enum_id, variant_id, _) => { - let variant_info = ty::enum_variant_with_id( - tcx, enum_id, variant_id); - let fields = struct_fields(tcx, variant_id, substs); - let fields = monomorphize::normalize_associated_type(tcx, &fields); - op(variant_info.disr_val, &fields[..]) + assert_eq!(enum_def.def_id, enum_id); + let variant = enum_def.get_variant(variant_id) + .expect("variant isn't in enum"); + let fi = variant.fields.iter().map(|f| { + let ty = f.subst_ty(tcx, substs); + FieldInfo { + name: f.name, + ty: monomorphize::normalize_associated_type(tcx, &ty) + } + }).collect(); + op(variant.disr_val, fi) } _ => { tcx.sess.bug("resolve didn't map this expr to a \ @@ -1423,7 +1447,7 @@ fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let mut leftovers = Vec::new(); for (i, b) in need_base.iter().enumerate() { if *b { - leftovers.push((i, field_tys[i].mt.ty)); + leftovers.push((i, field_tys[i].ty)); } } Some(StructBaseInfo {expr: base_expr, @@ -1703,7 +1727,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let tcx = bcx.tcx(); let is_simd = ty::type_is_simd(tcx, lhs_t); let intype = if is_simd { - ty::simd_type(tcx, lhs_t) + ty::simd_type(lhs_t) } else { lhs_t }; diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index efae76c5ef41c..cf5723aa2928b 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -888,7 +888,7 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let llarg_tys = arg_tys.iter().map(|&arg| foreign_arg_type_of(ccx, arg)).collect(); let (llret_ty, ret_def) = match fn_sig.output { ty::FnConverging(ret_ty) => - (type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)), + (type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ret_ty)), ty::FnDiverging => (Type::nil(ccx), false) }; diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index c14683aeade05..66895923de2b8 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -319,7 +319,7 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: return (size, align); } match t.sty { - ty::ty_struct(id, substs) => { + ty::ty_struct(def, substs) => { let ccx = bcx.ccx(); // First get the size of all statically known fields. // Don't use type_of::sizing_type_of because that expects t to be sized. @@ -331,9 +331,8 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: // Recurse to get the size of the dynamically sized field (must be // the last field). - let fields = ty::struct_fields(bcx.tcx(), id, substs); - let last_field = fields[fields.len()-1]; - let field_ty = last_field.mt.ty; + let last_field = &def.variants[0].fields[def.variants[0].fields.len()-1]; + let field_ty = last_field.subst_ty(bcx.tcx(), substs); let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info); // Return the sum of sizes and max of aligns. @@ -424,7 +423,8 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>) } } } - ty::ty_struct(did, substs) | ty::ty_enum(did, substs) => { + ty::ty_struct(def, substs) | ty::ty_enum(def, substs) => { + let did = def.def_id; let tcx = bcx.tcx(); match ty::ty_dtor(tcx, did) { ty::TraitDtor(dtor, true) => { diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 56fda20e0e8dc..8975448e886ae 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -37,6 +37,9 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) } } + debug!("maybe_instantiate_inline: inlining {}", + ty::item_path_str(ccx.tcx(), fn_id)); + let csearch_result = csearch::maybe_get_item_ast( ccx.tcx(), fn_id, @@ -101,14 +104,14 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) let mut my_id = 0; match item.node { - ast::ItemEnum(_, _) => { - let vs_here = ty::enum_variants(ccx.tcx(), local_def(item.id)); - let vs_there = ty::enum_variants(ccx.tcx(), parent_id); - for (here, there) in vs_here.iter().zip(vs_there.iter()) { - if there.id == fn_id { my_id = here.id.node; } - ccx.external().borrow_mut().insert(there.id, Some(here.id.node)); + ast::ItemEnum(ref def_here, _) => { + let def_there = ty::lookup_datatype_def(ccx.tcx(), parent_id); + + for (here, there) in def_here.variants.iter().zip(def_there.variants.iter()) { + if there.id == fn_id { my_id = here.node.id; } + ccx.external().borrow_mut().insert(there.id, Some(here.node.id)); + } } - } ast::ItemStruct(ref struct_def, _) => { match struct_def.ctor_id { None => {} diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 993c9eae45bf6..10102282e0fee 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -364,7 +364,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } (_, "init") => { let tp_ty = *substs.types.get(FnSpace, 0); - if !return_type_is_void(ccx, tp_ty) { + if !return_type_is_void(tp_ty) { // Just zero out the stack slot. (See comment on base::memzero for explanation) zero_mem(bcx, llresult, tp_ty); } diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 5ab1ec2a69eda..7b14494e7db33 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -197,8 +197,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ast_map::NodeVariant(v) => { let parent = ccx.tcx().map.get_parent(fn_id.node); - let tvs = ty::enum_variants(ccx.tcx(), local_def(parent)); - let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); + let disr_val = get_enum_disr(ccx.tcx(), local_def(parent), fn_id.node); + let d = mk_lldecl(abi::Rust); set_inline_hint(d); match v.node.kind { @@ -207,7 +207,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, parent, &*v, &args[..], - this_tv.disr_val, + disr_val, psubsts, d); } @@ -286,6 +286,35 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, (lldecl, mono_ty, true) } +// Get the discriminant value for the given enum. Inlined items have different def_ids to what +// ty::lookup_datatype_def expects, but we don't need the full datatype, just the discriminant +// value. +// This assumes that it has been passed a proper ADT enum, and not a C-Like enum, as C-Like enum +// variants cannot be monomorphised. This means we don't have to actually calculate the +// discriminant properly, we can just use the index of the variant. +fn get_enum_disr<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId, variant: ast::NodeId) -> ty::Disr { + // Use the existing datatype def if there is one. + if let Some(def) = tcx.datatype_defs.borrow().get(&def_id) { + return def.variants.iter().find(|v| v.id.node == variant).unwrap().disr_val; + } + + // Otherwise, get the item out of the ast_map + match tcx.map.get(def_id.node) { + ast_map::NodeItem(item) => { + match item.node { + ast::ItemEnum(ref enum_def, _) => { + for (i, v) in enum_def.variants.iter().enumerate() { + if v.node.id == variant { return i as ty::Disr } + } + panic!("variant not in enum") + } + _ => panic!("Not an enum") + } + } + _ => panic!("Not an item") + } +} + #[derive(PartialEq, Eq, Hash, Debug)] pub struct MonoId<'tcx> { pub def: ast::DefId, diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 97278eb0512e2..f3f2cdc11e4e8 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -123,7 +123,7 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if use_out_pointer { atys.push(lloutputtype.ptr_to()); Type::void(cx) - } else if return_type_is_void(cx, output) { + } else if return_type_is_void(output) { Type::void(cx) } else { lloutputtype @@ -219,8 +219,8 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ ty::ty_struct(..) => { if ty::type_is_simd(cx.tcx(), t) { - let llet = type_of(cx, ty::simd_type(cx.tcx(), t)); - let n = ty::simd_size(cx.tcx(), t) as u64; + let llet = type_of(cx, ty::simd_type(t)); + let n = ty::simd_size(t) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) } else { @@ -329,14 +329,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::ty_int(t) => Type::int_from_ty(cx, t), ty::ty_uint(t) => Type::uint_from_ty(cx, t), ty::ty_float(t) => Type::float_from_ty(cx, t), - ty::ty_enum(did, ref substs) => { + ty::ty_enum(def, ref substs) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. This // avoids creating more than one copy of the enum when one // of the enum's variants refers to the enum itself. let repr = adt::represent_type(cx, t); let tps = substs.types.get_slice(subst::TypeSpace); - let name = llvm_type_name(cx, did, tps); + let name = llvm_type_name(cx, def.def_id, tps); adt::incomplete_type_of(cx, &*repr, &name[..]) } ty::ty_closure(..) => { @@ -397,10 +397,10 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let repr = adt::represent_type(cx, t); adt::type_of(cx, &*repr) } - ty::ty_struct(did, ref substs) => { + ty::ty_struct(def, ref substs) => { if ty::type_is_simd(cx.tcx(), t) { - let llet = in_memory_type_of(cx, ty::simd_type(cx.tcx(), t)); - let n = ty::simd_size(cx.tcx(), t) as u64; + let llet = in_memory_type_of(cx, ty::simd_type(t)); + let n = ty::simd_size(t) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) } else { @@ -409,7 +409,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // infinite recursion with recursive struct types. let repr = adt::represent_type(cx, t); let tps = substs.types.get_slice(subst::TypeSpace); - let name = llvm_type_name(cx, did, tps); + let name = llvm_type_name(cx, def.def_id, tps); adt::incomplete_type_of(cx, &*repr, &name[..]) } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index dd2ab6c6b13ca..1f3bfc8a744b8 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -12,7 +12,7 @@ use middle::const_eval; use middle::def; use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; -use middle::subst::{Substs}; +use middle::subst::Substs; use middle::ty::{self, Ty}; use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; @@ -449,11 +449,11 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, _ => { let def_type = ty::lookup_item_type(tcx, def.def_id()); match def_type.ty.sty { - ty::ty_struct(struct_def_id, _) => - (struct_def_id, struct_def_id), - ty::ty_enum(enum_def_id, _) - if def == def::DefVariant(enum_def_id, def.def_id(), true) => - (enum_def_id, def.def_id()), + ty::ty_struct(def, _) => + (def.def_id, def.def_id), + ty::ty_enum(enum_def, _) + if def == def::DefVariant(enum_def.def_id, def.def_id(), true) => + (enum_def.def_id, def.def_id()), _ => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0163, @@ -487,7 +487,11 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, .map(|substs| substs.substs.clone()) .unwrap_or_else(|| Substs::empty()); - let struct_fields = ty::struct_fields(tcx, variant_def_id, &item_substs); + let def = ty::lookup_datatype_def(tcx, enum_def_id); + let variant = def.get_variant(variant_def_id).expect("variant not in enum"); + let struct_fields : Vec<_> = variant.fields.iter().map(|f| { + (f.name, f.subst_ty(tcx, &item_substs)) + }).collect(); check_struct_pat_fields(pcx, pat.span, fields, &struct_fields, variant_def_id, etc); } @@ -526,22 +530,21 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let real_path_ty = fcx.node_ty(pat.id); let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty { - ty::ty_enum(enum_def_id, expected_substs) - if def == def::DefVariant(enum_def_id, def.def_id(), false) => + ty::ty_enum(enum_def, expected_substs) + if def == def::DefVariant(enum_def.def_id, def.def_id(), false) => { - let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id()); - (variant.args.iter() - .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t)) - .collect(), + let variant = enum_def.get_variant(def.def_id()) + .expect("variant not in enum"); + (variant.fields.iter().map(|field| { + fcx.instantiate_type_scheme(pat.span, expected_substs, &field.ty()) + }).collect(), "variant") } - ty::ty_struct(struct_def_id, expected_substs) => { - let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs); - (struct_fields.iter() - .map(|field| fcx.instantiate_type_scheme(pat.span, - expected_substs, - &field.mt.ty)) - .collect(), + ty::ty_struct(def, expected_substs) => { + (def.variants[0].fields.iter().map(|field| { + fcx.instantiate_type_scheme(pat.span, + expected_substs, &field.ty()) + }).collect(), "struct") } _ => { @@ -594,16 +597,13 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, span: Span, fields: &'tcx [Spanned], - struct_fields: &[ty::field<'tcx>], + struct_fields: &[(ast::Name, Ty<'tcx>)], struct_id: ast::DefId, etc: bool) { let tcx = pcx.fcx.ccx.tcx; // Index the struct fields' types. - let field_type_map = struct_fields - .iter() - .map(|field| (field.name, field.mt.ty)) - .collect::>(); + let field_type_map = struct_fields.iter().map(|&f| f).collect::>(); // Keep track of which fields have already appeared in the pattern. let mut used_fields = FnvHashMap(); @@ -640,12 +640,12 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Report an error if not all the fields were specified. if !etc { - for field in struct_fields + for &(name, _) in struct_fields .iter() - .filter(|field| !used_fields.contains_key(&field.name)) { + .filter(|&&(ref name, _)| !used_fields.contains_key(name)) { span_err!(tcx.sess, span, E0027, "pattern does not mention field `{}`", - token::get_name(field.name)); + token::get_name(name)); } } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index ce67369ca9dda..c8f42de71a218 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -61,9 +61,9 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( // If we encounter `PhantomData`, then we should replace it // with `T`, the type it represents as owned by the // surrounding context, before doing further analysis. - let typ = if let ty::ty_struct(struct_did, substs) = typ.sty { - if opt_phantom_data_def_id == Some(struct_did) { - let item_type = ty::lookup_item_type(rcx.tcx(), struct_did); + let typ = if let ty::ty_struct(def, substs) = typ.sty { + if opt_phantom_data_def_id == Some(def.def_id) { + let item_type = ty::lookup_item_type(rcx.tcx(), def.def_id); let tp_def = item_type.generics.types .opt_get(subst::TypeSpace, 0).unwrap(); let new_typ = substs.type_for_def(tp_def); @@ -77,14 +77,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( typ }; - let opt_type_did = match typ.sty { - ty::ty_struct(struct_did, _) => Some(struct_did), - ty::ty_enum(enum_did, _) => Some(enum_did), + let opt_type_def = match typ.sty { + ty::ty_struct(def, _) => Some(def), + ty::ty_enum(def, _) => Some(def), _ => None, }; let opt_dtor = - opt_type_did.and_then(|did| destructor_for_type.get(&did)); + opt_type_def.and_then(|def| destructor_for_type.get(&def.def_id)); debug!("iterate_over_potentially_unsafe_regions_in_type \ {}typ: {} scope: {:?} opt_dtor: {:?}", @@ -227,19 +227,15 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( // destructor. match typ.sty { - ty::ty_struct(struct_did, substs) => { + ty::ty_enum(def, substs) | + ty::ty_struct(def, substs) => { // Don't recurse; we extract type's substructure, // so do not process subparts of type expression. walker.skip_current_subtree(); - let fields = - ty::lookup_struct_fields(rcx.tcx(), struct_did); - for field in fields.iter() { - let field_type = - ty::lookup_field_type(rcx.tcx(), - struct_did, - field.id, - substs); + let tcx = rcx.tcx(); + for field_type in def.variants.iter() + .flat_map(|v| v.subst_fields(tcx, substs)) { iterate_over_potentially_unsafe_regions_in_type( rcx, breadcrumbs, @@ -250,28 +246,6 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( } } - ty::ty_enum(enum_did, substs) => { - // Don't recurse; we extract type's substructure, - // so do not process subparts of type expression. - walker.skip_current_subtree(); - - let all_variant_info = - ty::substd_enum_variants(rcx.tcx(), - enum_did, - substs); - for variant_info in all_variant_info.iter() { - for argument_type in variant_info.args.iter() { - iterate_over_potentially_unsafe_regions_in_type( - rcx, - breadcrumbs, - *argument_type, - span, - scope, - depth+1) - } - } - } - ty::ty_rptr(..) | ty::ty_ptr(_) | ty::ty_bare_fn(..) => { // Don't recurse, since references, pointers, // boxes, and bare functions don't own instances diff --git a/src/librustc_typeck/check/implicator.rs b/src/librustc_typeck/check/implicator.rs index f65e585d23edd..8fca298593b69 100644 --- a/src/librustc_typeck/check/implicator.rs +++ b/src/librustc_typeck/check/implicator.rs @@ -122,10 +122,10 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds) } - ty::ty_enum(def_id, substs) | - ty::ty_struct(def_id, substs) => { - let item_scheme = ty::lookup_item_type(self.tcx(), def_id); - self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs) + ty::ty_enum(def, substs) | + ty::ty_struct(def, substs) => { + let item_scheme = ty::lookup_item_type(self.tcx(), def.def_id); + self.accumulate_from_adt(ty, def.def_id, &item_scheme.generics, substs) } ty::ty_vec(t, _) | diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f24da78bc7d39..c695940fad675 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -276,8 +276,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.assemble_inherent_candidates_from_object(self_ty, data); self.assemble_inherent_impl_candidates_for_type(data.principal_def_id()); } - ty::ty_enum(did, _) | - ty::ty_struct(did, _) | + ty::ty_enum(def, _) | + ty::ty_struct(def, _) => { + self.assemble_inherent_impl_candidates_for_type(def.def_id); + } ty::ty_closure(did, _, _) => { self.assemble_inherent_impl_candidates_for_type(did); } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 9832fe1cb6eac..10127f0ce6c68 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -58,8 +58,8 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None); // If the method has the name of a field, give a help note - if let (&ty::ty_struct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { - let fields = ty::lookup_struct_fields(cx, did); + if let (&ty::ty_struct(def, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) { + let fields = &def.variants[0].fields[..]; if fields.iter().any(|f| f.name == method_name) { cx.sess.span_note(span, &format!("use `(s.{0})(...)` if you meant to call the \ @@ -235,7 +235,7 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, rcvr_expr: Option<&ast::Expr>) -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { - ty::ty_enum(did, _) | ty::ty_struct(did, _) => ast_util::is_local(did), + ty::ty_enum(def, _) | ty::ty_struct(def, _) => ast_util::is_local(def.def_id), ty::ty_trait(ref tr) => ast_util::is_local(tr.principal_def_id()), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fd6ba79ec21bb..cdc5a01ca21e0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -86,7 +86,7 @@ use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; -use middle::{const_eval, def}; +use middle::{def}; use middle::infer; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; @@ -95,7 +95,7 @@ use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; use middle::traits; -use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme}; +use middle::ty::{FnSig, GenericPredicates, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::liberate_late_bound_regions; @@ -1072,7 +1072,7 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let t_e_is_scalar = ty::type_is_scalar(t_e); let t_e_is_integral = ty::type_is_integral(t_e); let t_e_is_float = ty::type_is_floating_point(t_e); - let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); + let t_e_is_c_enum = ty::type_is_c_like_enum(t_e); let t_1_is_scalar = ty::type_is_scalar(t_1); let t_1_is_char = ty::type_is_char(t_1); @@ -1463,7 +1463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { -> T where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> { - let value = value.subst(self.tcx(), substs); + let value = value.subst_spanned(self.tcx(), substs, Some(span)); let result = self.normalize_associated_types_in(span, &value); debug!("instantiate_type_scheme(value={}, substs={}) = {}", value.repr(self.tcx()), @@ -1883,27 +1883,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Indifferent to privacy flags pub fn lookup_field_ty(&self, span: Span, - class_id: ast::DefId, - items: &[ty::field_ty], + items: &[ty::FieldTy<'tcx>], fieldname: ast::Name, substs: &subst::Substs<'tcx>) -> Option> { let o_field = items.iter().find(|f| f.name == fieldname); - o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs)) + o_field.map(|f| f.subst_ty_spanned(self.tcx(), substs, span)) .map(|t| self.normalize_associated_types_in(span, &t)) } pub fn lookup_tup_field_ty(&self, span: Span, - class_id: ast::DefId, - items: &[ty::field_ty], + items: &[ty::FieldTy<'tcx>], idx: uint, substs: &subst::Substs<'tcx>) -> Option> { let o_field = if idx < items.len() { Some(&items[idx]) } else { None }; - o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs)) + o_field.map(|f| f.subst_ty_spanned(self.tcx(), substs, span)) .map(|t| self.normalize_associated_types_in(span, &t)) } } @@ -2926,7 +2924,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast::BiEq | ast::BiNe | ast::BiLt | ast::BiLe | ast::BiGe | ast::BiGt => { if ty::type_is_simd(tcx, lhs_t) { - if ty::type_is_fp(ty::simd_type(tcx, lhs_t)) { + if ty::type_is_fp(ty::simd_type(lhs_t)) { fcx.type_error_message(expr.span, |actual| { format!("binary comparison \ @@ -3071,10 +3069,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref, |base_t, _| { match base_t.sty { - ty::ty_struct(base_id, substs) => { + ty::ty_struct(def, substs) => { debug!("struct named {}", ppaux::ty_to_string(tcx, base_t)); - let fields = ty::lookup_struct_fields(tcx, base_id); - fcx.lookup_field_ty(expr.span, base_id, &fields[..], + let fields = &def.variants[0].fields[..]; + fcx.lookup_field_ty(expr.span, fields, field.node.name, &(*substs)) } _ => None @@ -3112,8 +3110,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, actual) }, expr_t, None); - if let Some(t) = ty::ty_to_def_id(expr_t) { - suggest_field_names(t, field, tcx, vec![]); + if let ty::ty_struct(def, _) = expr_t.sty { + suggest_field_names(def, field, tcx, vec![]); } } @@ -3121,7 +3119,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } // displays hints about the closest matches in field names - fn suggest_field_names<'tcx>(id : DefId, + fn suggest_field_names<'tcx>(struct_def : &'tcx ty::DatatypeDef<'tcx>, field : &ast::SpannedIdent, tcx : &ty::ctxt<'tcx>, skip : Vec<&str>) { @@ -3129,16 +3127,16 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let name = &ident; // only find fits with at least one matching letter let mut best_dist = name.len(); - let fields = ty::lookup_struct_fields(tcx, id); + let fields = &struct_def.variants[0].fields[]; let mut best = None; - for elem in &fields { + for elem in fields { let n = elem.name.as_str(); // ignore already set fields if skip.iter().any(|&x| x == n) { continue; } // ignore private fields from non-local crates - if id.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public { + if !ast_util::is_local(elem.id) && elem.vis != Visibility::Public { continue; } let dist = lev_distance(n, name); @@ -3173,13 +3171,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref, |base_t, _| { match base_t.sty { - ty::ty_struct(base_id, substs) => { - tuple_like = ty::is_tuple_struct(tcx, base_id); + ty::ty_struct(def, substs) => { + tuple_like = def.is_tuple_variant(0); if tuple_like { debug!("tuple struct named {}", ppaux::ty_to_string(tcx, base_t)); - let fields = ty::lookup_struct_fields(tcx, base_id); - fcx.lookup_tup_field_ty(expr.span, base_id, &fields[..], - idx.node, &(*substs)) + let fields = &def.variants[0].fields[..]; + fcx.lookup_tup_field_ty(expr.span, fields, idx.node, &(*substs)) } else { None } @@ -3222,19 +3219,22 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, struct_ty: Ty<'tcx>, span: Span, - class_id: ast::DefId, node_id: ast::NodeId, substitutions: &'tcx subst::Substs<'tcx>, - field_types: &[ty::field_ty], + data_def: &'tcx ty::DatatypeDef<'tcx>, + variant_id: ast::DefId, ast_fields: &'tcx [ast::Field], - check_completeness: bool, - enum_id_opt: Option) { + check_completeness: bool) { let tcx = fcx.ccx.tcx; + let variant = data_def.get_variant(variant_id).expect("variant not in enum"); + let field_types = &variant.fields[]; + let mut class_field_map = FnvHashMap(); let mut fields_found = 0; for field in field_types { - class_field_map.insert(field.name, (field.id, false)); + class_field_map.insert(field.name, + (field.subst_ty(tcx, substitutions), false)); } let mut error_happened = false; @@ -3248,30 +3248,32 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, None => { fcx.type_error_message( field.ident.span, - |actual| match enum_id_opt { - Some(enum_id) => { - let variant_type = ty::enum_variant_with_id(tcx, - enum_id, - class_id); - format!("struct variant `{}::{}` has no field named `{}`", - actual, variant_type.name.as_str(), - token::get_ident(field.ident.node)) - } - None => { + |actual| { + if variant.id == data_def.def_id { format!("structure `{}` has no field named `{}`", actual, token::get_ident(field.ident.node)) + } else { + format!("struct variant `{}::{}` has no field named `{}`", + actual, variant.name.as_str(), + token::get_ident(field.ident.node)) } }, struct_ty, None); // prevent all specified fields from being suggested let skip_fields = ast_fields.iter().map(|ref x| x.ident.node.name.as_str()); - let actual_id = match enum_id_opt { - Some(_) => class_id, - None => ty::ty_to_def_id(struct_ty).unwrap() + let actual_def = if variant.id == data_def.def_id { + if let ty::ty_struct(def, _) = struct_ty.sty { + def + } else { + tcx.sess.span_bug(field.ident.span, "`struct_ty` is not a struct type?") + } + } else { + data_def }; - suggest_field_names(actual_id, &field.ident, tcx, skip_fields.collect()); + + suggest_field_names(actual_def, &field.ident, tcx, skip_fields.collect()); error_happened = true; } Some((_, true)) => { @@ -3280,15 +3282,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, token::get_ident(field.ident.node)); error_happened = true; } - Some((field_id, false)) => { - expected_field_type = - ty::lookup_field_type( - tcx, class_id, field_id, substitutions); + Some((field_ty, false)) => { expected_field_type = fcx.normalize_associated_types_in( - field.span, &expected_field_type); + field.span, &field_ty); class_field_map.insert( - field.ident.node.name, (field_id, true)); + field.ident.node.name, (expected_field_type, true)); fields_found += 1; } } @@ -3324,8 +3323,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } if !error_happened { - fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx, - class_id, substitutions)); + fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx, data_def, substitutions)); } } @@ -3344,17 +3342,16 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } = fcx.instantiate_type(span, class_id); // Look up and check the fields. - let class_fields = ty::lookup_struct_fields(tcx, class_id); + let struct_def= ty::lookup_datatype_def(tcx, class_id); check_struct_or_variant_fields(fcx, struct_type, span, - class_id, id, fcx.ccx.tcx.mk_substs(struct_substs), - &class_fields[..], + struct_def, + class_id, fields, - base_expr.is_none(), - None); + base_expr.is_none()); if ty::type_is_error(fcx.node_ty(id)) { struct_type = tcx.types.err; } @@ -3387,17 +3384,17 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } = fcx.instantiate_type(span, enum_id); // Look up and check the enum variant fields. - let variant_fields = ty::lookup_struct_fields(tcx, variant_id); + + let struct_def = ty::lookup_datatype_def(tcx, enum_id); check_struct_or_variant_fields(fcx, enum_type, span, - variant_id, id, fcx.ccx.tcx.mk_substs(substitutions), - &variant_fields[..], + struct_def, + variant_id, fields, - true, - Some(enum_id)); + true); fcx.write_ty(id, enum_type); } @@ -3526,8 +3523,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, Some(mt) => mt.ty, None => { let is_newtype = match oprnd_t.sty { - ty::ty_struct(did, substs) => { - let fields = ty::struct_fields(fcx.tcx(), did, substs); + ty::ty_struct(def, _) => { + let fields = &def.variants[0].fields[]; fields.len() == 1 && fields[0].name == token::special_idents::unnamed_field.name @@ -3935,11 +3932,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Verify that this was actually a struct. let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id()); match typ.ty.sty { - ty::ty_struct(struct_did, _) => { + ty::ty_struct(def, _) => { check_struct_constructor(fcx, id, expr.span, - struct_did, + def.def_id, &fields[..], base_expr.as_ref().map(|e| &**e)); } @@ -4100,7 +4097,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, traits::ItemObligation(did)), &bounds); - ty::mk_struct(tcx, did, tcx.mk_substs(substs)) + let def = ty::lookup_datatype_def(tcx, did); + + ty::mk_struct(tcx, def, tcx.mk_substs(substs)) } else { span_err!(tcx.sess, expr.span, E0236, "no lang item for range syntax"); fcx.tcx().types.err @@ -4110,7 +4109,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Neither start nor end => RangeFull if let Some(did) = tcx.lang_items.range_full_struct() { let substs = Substs::new_type(vec![], vec![]); - ty::mk_struct(tcx, did, tcx.mk_substs(substs)) + let def = ty::lookup_datatype_def(tcx, did); + ty::mk_struct(tcx, def, tcx.mk_substs(substs)) } else { span_err!(tcx.sess, expr.span, E0237, "no lang item for range syntax"); fcx.tcx().types.err @@ -4495,15 +4495,15 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { return; } match t.sty { - ty::ty_struct(did, substs) => { - let fields = ty::lookup_struct_fields(tcx, did); + ty::ty_struct(def, substs) => { + let fields = &def.variants[0].fields[]; if fields.is_empty() { span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); return; } - let e = ty::lookup_field_type(tcx, did, fields[0].id, substs); + let e = fields[0].subst_ty_spanned(tcx, substs, sp); if !fields.iter().all( - |f| ty::lookup_field_type(tcx, did, f.id, substs) == e) { + |f| f.subst_ty_spanned(tcx, substs, sp) == e) { span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); return; } @@ -4549,30 +4549,24 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } - fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - vs: &'tcx [P], - id: ast::NodeId, - hint: attr::ReprAttr) - -> Vec>> { + fn check_variants<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + vs: &'tcx [P], + id: ast::NodeId, + hint: attr::ReprAttr) { let rty = ty::node_id_to_type(ccx.tcx, id); - let mut variants: Vec> = Vec::new(); - let mut disr_vals: Vec = Vec::new(); - let mut prev_disr_val: Option = None; + let def = match rty.sty { + ty::ty_enum(def, _) => def, + _ => ccx.tcx.sess.bug("Checking variants of a non-enum type"), + }; - for v in vs { + let mut disr_vals: FnvHashMap = FnvHashMap(); - // If the discriminant value is specified explicitly in the enum check whether the - // initialization expression is valid, otherwise use the last value plus one. - let mut current_disr_val = match prev_disr_val { - Some(prev_disr_val) => prev_disr_val + 1, - None => ty::INITIAL_DISCRIMINANT_VALUE - }; + for (i, v) in vs.iter().enumerate() { + let variant = &def.variants[i]; match v.node.disr_expr { Some(ref e) => { - debug!("disr expr, checking {}", pprust::expr_to_string(&**e)); - let inh = static_inherited_fields(ccx); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id); let declty = match hint { @@ -4585,41 +4579,25 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, }, }; check_const_with_ty(&fcx, e.span, &**e, declty); - // check_expr (from check_const pass) doesn't guarantee - // that the expression is in a form that eval_const_expr can - // handle, so we may still get an internal compiler error - - match const_eval::eval_const_expr_partial(ccx.tcx, &**e, Some(declty)) { - Ok(const_eval::const_int(val)) => current_disr_val = val as Disr, - Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr, - Ok(_) => { - span_err!(ccx.tcx.sess, e.span, E0079, - "expected signed integer constant"); - } - Err(ref err) => { - span_err!(ccx.tcx.sess, e.span, E0080, - "expected constant: {}", *err); - } - } - }, - None => () - }; + } + None => {} + } // Check for duplicate discriminant values - match disr_vals.iter().position(|&x| x == current_disr_val) { - Some(i) => { + match disr_vals.entry(variant.disr_val).get() { + Ok(span) => { span_err!(ccx.tcx.sess, v.span, E0081, - "discriminant value `{}` already exists", disr_vals[i]); - span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].id.node), - "conflicting discriminant here") + "discriminant value `{}` already exists", variant.disr_val); + span_note!(ccx.tcx.sess, *span, + "conflicting discriminant here"); } - None => {} + Err(e) => { e.insert(v.span); } } // Check for unrepresentable discriminant values match hint { attr::ReprAny | attr::ReprExtern => (), attr::ReprInt(sp, ity) => { - if !disr_in_range(ccx, ity, current_disr_val) { + if !disr_in_range(ccx, ity, variant.disr_val) { span_err!(ccx.tcx.sess, v.span, E0082, "discriminant value outside specified type"); span_note!(ccx.tcx.sess, sp, @@ -4630,16 +4608,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ccx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum"); } } - disr_vals.push(current_disr_val); - - let variant_info = Rc::new(VariantInfo::from_ast_variant(ccx.tcx, &**v, - current_disr_val)); - prev_disr_val = Some(current_disr_val); - - variants.push(variant_info); } - - return variants; } let hint = *ty::lookup_repr_hints(ccx.tcx, ast::DefId { krate: ast::LOCAL_CRATE, node: id }) @@ -4655,10 +4624,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, }; } - let variants = do_check(ccx, vs, id, hint); - - // cache so that ty::enum_variants won't repeat this work - ccx.tcx.enum_var_cache.borrow_mut().insert(local_def(id), Rc::new(variants)); + check_variants(ccx, vs, id, hint); check_representable(ccx.tcx, sp, id, "enum"); diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index e024526d0016f..f0eca7a23add9 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -248,9 +248,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { !attr::contains_name(&item.attrs, "unsafe_destructor") { match self_ty.sty { - ty::ty_struct(def_id, _) | - ty::ty_enum(def_id, _) => { - check_struct_safe_for_destructor(fcx, item.span, def_id); + ty::ty_struct(def, _) | + ty::ty_enum(def, _) => { + check_struct_safe_for_destructor(fcx, item.span, def.def_id); } _ => { // Coherence already reports an error in this case. @@ -614,8 +614,9 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { } match t.sty{ - ty::ty_struct(type_id, substs) | - ty::ty_enum(type_id, substs) => { + ty::ty_struct(type_def, substs) | + ty::ty_enum(type_def, substs) => { + let type_id = type_def.def_id; let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id); let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_predicates); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 1913b55f1d8e6..7f450079b974f 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -60,9 +60,9 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Option { match ty.sty { - ty_enum(def_id, _) | - ty_struct(def_id, _) => { - Some(def_id) + ty_enum(def, _) | + ty_struct(def, _) => { + Some(def.def_id) } ty_trait(ref t) => { @@ -395,8 +395,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let self_type = self.get_self_type_for_implementation(impl_did); match self_type.ty.sty { - ty::ty_enum(type_def_id, _) | - ty::ty_struct(type_def_id, _) | + ty::ty_enum(&ty::DatatypeDef { def_id: type_def_id, ..}, _) | + ty::ty_struct(&ty::DatatypeDef { def_id: type_def_id, ..}, _) | ty::ty_closure(type_def_id, _, _) => { tcx.destructor_for_type .borrow_mut() diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 95dafccd866bf..7419a0455244c 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -49,9 +49,9 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx)); let self_ty = ty::lookup_item_type(self.tcx, def_id).ty; match self_ty.sty { - ty::ty_enum(def_id, _) | - ty::ty_struct(def_id, _) => { - self.check_def_id(item, def_id); + ty::ty_enum(def, _) | + ty::ty_struct(def, _) => { + self.check_def_id(item, def.def_id); } ty::ty_trait(ref data) => { self.check_def_id(item, data.principal_def_id()); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 74fed6cbf3937..c9ab381293d24 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -88,6 +88,7 @@ There are some shortcomings in this design: use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region}; use middle::def; use constrained_type_params::identify_constrained_type_params; +use middle::const_eval; use middle::lang_items::SizedTraitLangItem; use middle::region; use middle::resolve_lifetime; @@ -114,7 +115,6 @@ use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::codemap::Span; use syntax::parse::token::{special_idents}; use syntax::parse::token; -use syntax::ptr::P; use syntax::visit; /////////////////////////////////////////////////////////////////////////// @@ -515,48 +515,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.len() > 0 => { - let rs = ExplicitRscope; - let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); - ty::mk_ctor_fn(tcx, 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.tcache.borrow_mut().insert(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 collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_def: &ty::TraitDef<'tcx>, @@ -713,45 +671,6 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - struct_generics: &ty::Generics<'tcx>, - struct_predicates: &ty::GenericPredicates<'tcx>, - v: &ast::StructField, - origin: ast::DefId) - -> ty::field_ty -{ - let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &*v.node.ty); - write_ty_to_tcx(ccx.tcx, v.node.id, tt); - - /* add the field to the tcache */ - ccx.tcx.tcache.borrow_mut().insert(local_def(v.node.id), - ty::TypeScheme { - generics: struct_generics.clone(), - ty: tt - }); - ccx.tcx.predicates.borrow_mut().insert(local_def(v.node.id), - struct_predicates.clone()); - - match v.node.kind { - ast::NamedField(ident, visibility) => { - ty::field_ty { - name: ident.name, - id: local_def(v.node.id), - vis: visibility, - origin: origin, - } - } - ast::UnnamedField(visibility) => { - ty::field_ty { - name: special_idents::unnamed_field.name, - id: local_def(v.node.id), - vis: visibility, - origin: origin, - } - } - } -} - fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>, associated_type: &ast::AssociatedType) @@ -896,15 +815,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { match it.node { // These don't define types. ast::ItemExternCrate(_) | ast::ItemUse(_) | - ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => { - } - ast::ItemEnum(ref enum_definition, _) => { + ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {} + ast::ItemEnum(ref enum_def, _) => { 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); + + tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); + + convert_enum(ccx, &*enum_def, scheme, predicates, it.id); }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()), @@ -1081,7 +999,9 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { // 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); + tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); + + convert_struct(ccx, it.ident.name, &**struct_def, scheme, predicates, it.id); }, ast::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); @@ -1099,42 +1019,35 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + name: ast::Name, struct_def: &ast::StructDef, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>, id: ast::NodeId) { let tcx = ccx.tcx; - // 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)); - - if result.name != special_idents::unnamed_field.name { - let dup = match seen_fields.get(&result.name) { - Some(prev_span) => { - span_err!(tcx.sess, f.span, E0124, - "field `{}` is already declared", - token::get_name(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); - } - } + let def_id = local_def(id); + // Get the struct def + let def = get_struct_def(ccx, name, def_id, struct_def); - result - }).collect(); + for (i, f) in struct_def.fields.iter().enumerate() { + let fty = ccx.icx(&predicates).to_ty(&ExplicitRscope, &*f.node.ty); - tcx.struct_fields.borrow_mut().insert(local_def(id), Rc::new(field_tys)); + write_ty_to_tcx(tcx, f.node.id, fty); + + tcx.tcache.borrow_mut().insert( + local_def(f.node.id), + ty::TypeScheme { + generics: scheme.generics.clone(), + ty: fty + }); + + tcx.predicates.borrow_mut().insert(local_def(f.node.id), predicates.clone()); + def.variants[0].fields[i].set_ty(fty); + } let substs = mk_item_substs(ccx, &scheme.generics); - let selfty = ty::mk_struct(tcx, local_def(id), tcx.mk_substs(substs)); + let selfty = ty::mk_struct(tcx, def, tcx.mk_substs(substs)); // If this struct is enum-like or tuple-like, create the type of its // constructor. @@ -1168,6 +1081,74 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } +fn convert_enum<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + enum_def: &ast::EnumDef, + scheme: ty::TypeScheme<'tcx>, + predicates: ty::GenericPredicates<'tcx>, + id: ast::NodeId) { + let tcx = ccx.tcx; + + let def_id = local_def(id); + // Get the enum def + let def = get_enum_def(ccx, def_id, enum_def); + + let substs = mk_item_substs(ccx, &scheme.generics); + let selfty = ty::mk_enum(tcx, def, tcx.mk_substs(substs)); + + for (i, v) in enum_def.variants.iter().enumerate() { + let vty = match v.node.kind { + ast::TupleVariantKind(ref args) if args.len() > 0 => { + let mut arg_tys = Vec::new(); + for (j, f) in args.iter().enumerate() { + let fty = ccx.icx(&predicates).to_ty(&ExplicitRscope, &*f.ty); + + write_ty_to_tcx(tcx, f.id, fty); + tcx.tcache.borrow_mut().insert( + local_def(f.id), + ty::TypeScheme { + generics: scheme.generics.clone(), + ty: fty, + }); + + tcx.predicates.borrow_mut().insert(local_def(f.id), predicates.clone()); + def.variants[i].fields[j].set_ty(fty); + arg_tys.push(fty); + } + ty::mk_ctor_fn(tcx, local_def(v.node.id), &arg_tys[], selfty) + } + ast::TupleVariantKind(_) => { + selfty + } + ast::StructVariantKind(ref struct_def) => { + for (j, f) in struct_def.fields.iter().enumerate() { + let fty = ccx.icx(&predicates).to_ty(&ExplicitRscope, &*f.node.ty); + write_ty_to_tcx(tcx, f.node.id, fty); + tcx.tcache.borrow_mut().insert( + local_def(f.node.id), + ty::TypeScheme { + generics: scheme.generics.clone(), + ty: fty, + }); + + tcx.predicates.borrow_mut().insert(local_def(f.node.id), predicates.clone()); + def.variants[i].fields[j].set_ty(fty); + } + selfty + } + }; + + let scheme = ty::TypeScheme { + generics: scheme.generics.clone(), + ty: vty + }; + + tcx.tcache.borrow_mut().insert(local_def(v.node.id), scheme); + tcx.predicates.borrow_mut().insert(local_def(v.node.id), predicates.clone()); + + write_ty_to_tcx(tcx, v.node.id, vty); + } +} + fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::DefId) -> Rc> { @@ -1433,17 +1414,21 @@ 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) => { + ast::ItemEnum(ref enum_def, ref generics) => { // Create a new generic polytype. let ty_generics = ty_generics_for_type_or_impl(ccx, generics); + let def = get_enum_def(ccx, local_def(it.id), &*enum_def); + let substs = mk_item_substs(ccx, &ty_generics); - let t = ty::mk_enum(tcx, local_def(it.id), tcx.mk_substs(substs)); + let t = ty::mk_enum(tcx, def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } - ast::ItemStruct(_, ref generics) => { + ast::ItemStruct(ref struct_def, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); + let def = get_struct_def(ccx, it.ident.name, local_def(it.id), &**struct_def); + let substs = mk_item_substs(ccx, &ty_generics); - let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs)); + let t = ty::mk_struct(tcx, def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } ast::ItemDefaultImpl(..) | @@ -1535,12 +1520,183 @@ fn type_scheme_of_foreign_item<'a, 'tcx>( |_| compute_type_scheme_of_foreign_item(ccx, it, abi)) } +fn get_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + name: ast::Name, def_id: ast::DefId, + struct_def: &ast::StructDef) -> &'tcx ty::DatatypeDef<'tcx> { + let tcx = ccx.tcx; + + debug!("get_struct_def(def_id={:?}, struct_def={:?})", + def_id, struct_def); + + // Look up an existing def, if there is one + if let Some(&def) = tcx.datatype_defs.borrow().get(&def_id) { + return def; + } + + // Create the fields for the StructDef for this def_id. We don't actually get the real type + // of the field here, using a ty_err instead to allow for reference cycles. The field types + // are actually populated in `convert_struct` later. + // We also check for duplicate field names here. + + let mut seen_fields: FnvHashMap = FnvHashMap(); + let fields = struct_def.fields.iter().map(|f| { + match f.node.kind { + ast::NamedField(ident, visibility) => { + match seen_fields.entry(ident.name).get() { + Ok(prev_span) => { + span_err!(tcx.sess, f.span, E0124, + "field `{}` is already declared", + token::get_name(ident.name)); + span_note!(tcx.sess, *prev_span, "previously declared here"); + } + Err(e) => { e.insert(f.span); } + } + + ty::FieldTy::new(local_def(f.node.id), ident.name, visibility, def_id) + } + ast::UnnamedField(visibility) => { + ty::FieldTy::new(local_def(f.node.id), + special_idents::unnamed_field.name, + visibility, def_id) + } + } + + }).collect(); + + let def = ccx.tcx.mk_datatype_def(ty::DatatypeDef { + def_id: def_id, + variants: vec![ty::VariantDef { + id: def_id, + name: name, + disr_val: 0, + fields: fields, + }] + }); + + tcx.datatype_defs.borrow_mut().insert(def_id, def); + + return def; +} + +fn get_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: ast::DefId, + enum_def: &ast::EnumDef) -> &'tcx ty::DatatypeDef<'tcx> { + + let tcx = ccx.tcx; + debug!("get_enum_def(def_id={:?}, enum_def={:?})", + def_id, enum_def); + + if let Some(&def) = tcx.datatype_defs.borrow().get(&def_id) { + return def; + } + + let mut last_discriminant : Option = None; + let variants = enum_def.variants.iter().map(|v| { + let mut discriminant = match last_discriminant { + Some(val) => val + 1, + None => ty::INITIAL_DISCRIMINANT_VALUE, + }; + + match v.node.disr_expr { + Some(ref e) => { + let ty = Some(tcx.types.i64); + match const_eval::eval_const_expr_partial(tcx, &**e, ty) { + Ok(const_eval::const_int(val)) => { + discriminant = val as ty::Disr + } + Ok(const_eval::const_uint(val)) => { + discriminant = val as ty::Disr + } + Ok(_) => { + span_err!(tcx.sess, e.span, E0264, + "expected integer constant"); + } + Err(ref err) => { + span_err!(tcx.sess, e.span, E0265, + "expected constant: {}", *err); + } + } + } + None => {} + } + + last_discriminant = Some(discriminant); + + let vid = local_def(v.node.id); + + match v.node.kind { + ast::TupleVariantKind(ref args) if args.len() > 0 => { + let fields = args.iter().map(|f| { + ty::FieldTy::new(local_def(f.id), + special_idents::unnamed_field.name, + ast::Public, + def_id) + }).collect(); + ty::VariantDef { + id: vid, + name: v.node.name.name, + disr_val: discriminant, + fields: fields, + } + } + ast::TupleVariantKind(_) => { + ty::VariantDef { + id: vid, + name: v.node.name.name, + disr_val: discriminant, + fields: Vec::new(), + } + } + ast::StructVariantKind(ref struct_def) => { + let mut seen_fields: FnvHashMap = FnvHashMap(); + let fields = struct_def.fields.iter().map(|f| { + match f.node.kind { + ast::NamedField(ident, visibility) => { + match seen_fields.entry(ident.name).get() { + Ok(prev_span) => { + span_err!(tcx.sess, f.span, E0125, + "field `{}` is already declared", + token::get_name(ident.name)); + span_note!(tcx.sess, *prev_span, "previously declared here"); + } + Err(e) => { e.insert(f.span); } + } + + ty::FieldTy::new(local_def(f.node.id), + ident.name, visibility, def_id) + } + ast::UnnamedField(visibility) => { + ty::FieldTy::new(local_def(f.node.id), + special_idents::unnamed_field.name, + visibility, def_id) + } + } + + }).collect(); + + ty::VariantDef { + id: vid, + name: v.node.name.name, + disr_val: discriminant, + fields: fields, + } + } + } + }).collect(); + + let def = tcx.mk_datatype_def(ty::DatatypeDef { + def_id: def_id, + variants: variants, + }); + + tcx.datatype_defs.borrow_mut().insert(def_id, def); + + return def; +} + fn compute_type_scheme_of_foreign_item<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, it: &ast::ForeignItem, - abi: abi::Abi) - -> ty::TypeScheme<'tcx> -{ + abi: abi::Abi) -> ty::TypeScheme<'tcx> { match it.node { ast::ForeignItemFn(ref fn_decl, ref generics) => { compute_type_scheme_of_foreign_fn_decl(ccx, fn_decl, generics, abi) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7b43a9fef06dc..a2ab2d255b358 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -82,6 +82,7 @@ register_diagnostics! { E0122, E0123, E0124, + E0125, E0127, E0128, E0129, @@ -173,9 +174,10 @@ register_diagnostics! { E0248, // found value name used as a type E0249, // expected constant expr for array length E0250, // expected constant expr for array length + E0264, // expected integer constant for discriminant value + E0265, // expected constant for discriminant value E0318, // can't create default impls for traits outside their crates E0319 // trait impls for defaulted traits allowed just for structs/enums } __build_diagnostic_array! { DIAGNOSTICS } - diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 1fba4a21ccd37..79a965e738ed0 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -595,50 +595,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { item.repr(tcx)); match item.node { - ast::ItemEnum(ref enum_definition, _) => { - let scheme = ty::lookup_item_type(tcx, did); - - // Not entirely obvious: constraints on structs/enums do not - // affect the variance of their type parameters. See discussion - // in comment at top of module. - // - // self.add_constraints_from_generics(&scheme.generics); - - // Hack: If we directly call `ty::enum_variants`, it - // annoyingly takes it upon itself to run off and - // evaluate the discriminants eagerly (*grumpy* that's - // not the typical pattern). This results in double - // error messages because typeck goes off and does - // this at a later time. All we really care about is - // the types of the variant arguments, so we just call - // `ty::VariantInfo::from_ast_variant()` ourselves - // here, mainly so as to mask the differences between - // struct-like enums and so forth. - for ast_variant in &enum_definition.variants { - let variant = - ty::VariantInfo::from_ast_variant(tcx, - &**ast_variant, - /*discriminant*/ 0); - for arg_ty in &variant.args { - self.add_constraints_from_ty(&scheme.generics, *arg_ty, self.covariant); - } - } - } - + ast::ItemEnum(..) | ast::ItemStruct(..) => { - let scheme = ty::lookup_item_type(tcx, did); - - // Not entirely obvious: constraints on structs/enums do not - // affect the variance of their type parameters. See discussion - // in comment at top of module. - // - // self.add_constraints_from_generics(&scheme.generics); - - let struct_fields = ty::lookup_struct_fields(tcx, did); - for field_info in &struct_fields { - assert_eq!(field_info.id.krate, ast::LOCAL_CRATE); - let field_ty = ty::node_id_to_type(tcx, field_info.id.node); - self.add_constraints_from_ty(&scheme.generics, field_ty, self.covariant); + let generics = &ty::lookup_item_type(tcx, did).generics; + let adt_def = ty::lookup_datatype_def(tcx, did); + for fld in adt_def.variants.iter().flat_map(|v| v.fields.iter()) { + assert_eq!(fld.id.krate, ast::LOCAL_CRATE); + let fld_ty = fld.ty(); + self.add_constraints_from_ty(generics, fld_ty, self.covariant); } } @@ -925,9 +889,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - ty::ty_enum(def_id, substs) | - ty::ty_struct(def_id, substs) => { - let item_type = ty::lookup_item_type(self.tcx(), def_id); + ty::ty_enum(def, substs) | + ty::ty_struct(def, substs) => { + let item_type = ty::lookup_item_type(self.tcx(), def.def_id); // All type parameters on enums and structs should be // in the TypeSpace. @@ -938,7 +902,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs( generics, - def_id, + def.def_id, item_type.generics.types.get_slice(subst::TypeSpace), item_type.generics.regions.get_slice(subst::TypeSpace), substs, @@ -1350,4 +1314,3 @@ fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance { (x, ty::Bivariant) | (ty::Bivariant, x) => x, } } - diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 24b9d03400cb3..8e538e0cdb3c4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -194,8 +194,12 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru use syntax::parse::token::special_idents::unnamed_field; let t = ty::lookup_item_type(tcx, did); + let predicates = ty::lookup_predicates(tcx, did); - let fields = ty::lookup_struct_fields(tcx, did); + let fields = match t.ty.sty { + ty::ty_struct(def, _) => &def.variants[0].fields[], + _ => panic!("bad struct"), + }; clean::Struct { struct_type: match &*fields { @@ -205,7 +209,7 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru _ => doctree::Plain, }, generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), - fields: fields.clean(cx), + fields: fields.iter().map(|f| f.clean(cx)).collect(), fields_stripped: false, } } @@ -214,11 +218,11 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn let t = ty::lookup_item_type(tcx, did); let predicates = ty::lookup_predicates(tcx, did); match t.ty.sty { - ty::ty_enum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => { + ty::ty_enum(def, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => { return clean::EnumItem(clean::Enum { generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), variants_stripped: false, - variants: ty::enum_variants(tcx, edid).clean(cx), + variants: def.variants.clean(cx), }) } _ => {} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 36d39fa58ba7e..d10f5a66459f5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1572,9 +1572,9 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (ast_util::local_def(0), &fty.sig).clean(cx), abi: fty.abi.to_string(), }), - ty::ty_struct(did, substs) | - ty::ty_enum(did, substs) => { - let fqn = csearch::get_item_path(cx.tcx(), did); + ty::ty_struct(def, substs) | + ty::ty_enum(def, substs) => { + let fqn = csearch::get_item_path(cx.tcx(), def.def_id); let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect(); let kind = match self.sty { ty::ty_struct(..) => TypeStruct, @@ -1582,11 +1582,11 @@ impl<'tcx> Clean for ty::Ty<'tcx> { }; let path = external_path(cx, &fqn.last().unwrap().to_string(), None, vec![], substs); - cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind)); + cx.external_paths.borrow_mut().as_mut().unwrap().insert(def.def_id, (fqn, kind)); ResolvedPath { path: path, typarams: None, - did: did, + did: def.def_id, } } ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { @@ -1651,7 +1651,7 @@ impl Clean for ast::StructField { } } -impl Clean for ty::field_ty { +impl<'tcx> Clean for ty::FieldTy<'tcx> { fn clean(&self, cx: &DocContext) -> Item { use syntax::parse::token::special_idents::unnamed_field; use rustc::metadata::csearch; @@ -1664,7 +1664,7 @@ impl Clean for ty::field_ty { (Some(self.name), Some(attr_map.get(&self.id.node).unwrap())) }; - let ty = ty::lookup_item_type(cx.tcx(), self.id); + let ty = self.ty(); Item { name: name.clean(cx), @@ -1673,7 +1673,7 @@ impl Clean for ty::field_ty { visibility: Some(self.vis), stability: get_stability(cx, self.id), def_id: self.id, - inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))), + inner: StructFieldItem(TypedStructField(ty.clean(cx))), } } } @@ -1779,40 +1779,30 @@ impl Clean for doctree::Variant { } } -impl<'tcx> Clean for ty::VariantInfo<'tcx> { +impl<'tcx> Clean for ty::VariantDef<'tcx> { fn clean(&self, cx: &DocContext) -> Item { - // use syntax::parse::token::special_idents::unnamed_field; - let kind = match self.arg_names.as_ref().map(|s| &**s) { - None | Some([]) if self.args.len() == 0 => CLikeVariant, - None | Some([]) => { - TupleVariant(self.args.clean(cx)) - } - Some(s) => { - StructVariant(VariantStruct { - struct_type: doctree::Plain, - fields_stripped: false, - fields: s.iter().zip(self.args.iter()).map(|(name, ty)| { - Item { - source: Span::empty(), - name: Some(name.clean(cx)), - attrs: Vec::new(), - visibility: Some(ast::Public), - // FIXME: this is not accurate, we need an id for - // the specific field but we're using the id - // for the whole variant. Thus we read the - // stability from the whole variant as well. - // Struct variants are experimental and need - // more infrastructure work before we can get - // at the needed information here. - def_id: self.id, - stability: get_stability(cx, self.id), - inner: StructFieldItem( - TypedStructField(ty.clean(cx)) - ) - } - }).collect() - }) - } + let kind = if self.fields.len() == 0 { + CLikeVariant + } else if self.is_tuple_variant() { + let clean_args = self.fields.iter().map(|f| f.ty().clean(cx)).collect(); + TupleVariant(clean_args) + } else { + StructVariant(VariantStruct { + struct_type: doctree::Plain, + fields_stripped: false, + fields: self.fields.iter().map(|fld| { + Item { + source: Span::empty(), + name: Some(fld.name.clean(cx)), + attrs: inline::load_attrs(cx, cx.tcx(), fld.id), + visibility: Some(ast::Public), + def_id: fld.id, + stability: get_stability(cx, fld.id), + inner: StructFieldItem( + TypedStructField(fld.ty().clean(cx))) + } + }).collect() + }) }; Item { name: Some(self.name.clean(cx)),