From 03ee3f5c204cb9b20c58a5cd2d61dc792727dad7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 20 Jul 2015 15:48:24 +0300 Subject: [PATCH 01/14] add an Ivar for write-only variables --- src/librustc_data_structures/ivar.rs | 70 ++++++++++++++++++++++++++++ src/librustc_data_structures/lib.rs | 1 + 2 files changed, 71 insertions(+) create mode 100644 src/librustc_data_structures/ivar.rs diff --git a/src/librustc_data_structures/ivar.rs b/src/librustc_data_structures/ivar.rs new file mode 100644 index 0000000000000..c16a2ea077c40 --- /dev/null +++ b/src/librustc_data_structures/ivar.rs @@ -0,0 +1,70 @@ +// Copyright 2015 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 is_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_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1f8f7694ff90d..558d15610dff2 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -36,4 +36,5 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod snapshot_vec; pub mod graph; pub mod bitvec; +pub mod ivar; pub mod unify; From 764310e7bb90ec14a6c6a399e703f6b455ba52d3 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 20 Jul 2015 22:13:36 +0300 Subject: [PATCH 02/14] introduce an ADTDef struct for struct/enum definitions --- src/librustc/metadata/csearch.rs | 6 + src/librustc/metadata/decoder.rs | 7 + src/librustc/metadata/tydecode.rs | 6 +- src/librustc/metadata/tyencode.rs | 4 +- src/librustc/middle/check_const.rs | 4 +- src/librustc/middle/check_match.rs | 22 +- src/librustc/middle/dead.rs | 8 +- src/librustc/middle/expr_use_visitor.rs | 5 +- src/librustc/middle/fast_reject.rs | 6 +- src/librustc/middle/implicator.rs | 8 +- src/librustc/middle/stability.rs | 18 +- src/librustc/middle/traits/coherence.rs | 10 +- src/librustc/middle/traits/select.rs | 40 +- src/librustc/middle/ty.rs | 353 +++++++++++++----- src/librustc/middle/ty_relate/mod.rs | 16 +- src/librustc/util/ppaux.rs | 20 +- src/librustc_borrowck/borrowck/check_loans.rs | 34 +- src/librustc_borrowck/borrowck/fragments.rs | 8 +- .../borrowck/gather_loans/gather_moves.rs | 4 +- .../borrowck/gather_loans/move_error.rs | 4 +- src/librustc_lint/builtin.rs | 40 +- src/librustc_privacy/lib.rs | 23 +- src/librustc_trans/save/dump_csv.rs | 4 +- src/librustc_trans/save/mod.rs | 8 +- src/librustc_trans/trans/_match.rs | 6 +- src/librustc_trans/trans/adt.rs | 32 +- src/librustc_trans/trans/base.rs | 4 +- src/librustc_trans/trans/common.rs | 6 +- .../trans/debuginfo/metadata.rs | 20 +- .../trans/debuginfo/type_names.rs | 6 +- src/librustc_trans/trans/expr.rs | 9 +- src/librustc_trans/trans/glue.rs | 14 +- src/librustc_trans/trans/type_of.rs | 8 +- src/librustc_typeck/check/_match.rs | 27 +- src/librustc_typeck/check/cast.rs | 4 +- src/librustc_typeck/check/dropck.rs | 118 +----- src/librustc_typeck/check/method/probe.rs | 7 +- src/librustc_typeck/check/method/suggest.rs | 8 +- src/librustc_typeck/check/mod.rs | 151 ++++---- src/librustc_typeck/check/wf.rs | 10 +- src/librustc_typeck/coherence/mod.rs | 25 +- src/librustc_typeck/coherence/orphan.rs | 10 +- src/librustc_typeck/collect.rs | 64 ++-- src/librustc_typeck/variance.rs | 8 +- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 5 +- 46 files changed, 654 insertions(+), 550 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 21d5dac7e5ddb..b54e7707f6315 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -222,6 +222,12 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe decoder::get_trait_def(&*cdata, def.node, tcx) } +pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> &'tcx ty::ADTDef<'tcx> { + let cstore = &tcx.sess.cstore; + let cdata = cstore.get_crate_data(def.krate); + decoder::get_adt_def(&*cdata, def.node, tcx) +} + pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::GenericPredicates<'tcx> { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b3ddd3869cb9f..7e955ad7338c1 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -390,6 +390,13 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, } } +pub fn get_adt_def<'tcx>(cdata: Cmd, + item_id: ast::NodeId, + tcx: &ty::ctxt<'tcx>) -> &'tcx ty::ADTDef<'tcx> +{ + tcx.intern_adt_def(ast::DefId { krate: cdata.cnum, node: item_id }) +} + pub fn get_predicates<'tcx>(cdata: Cmd, item_id: ast::NodeId, tcx: &ty::ctxt<'tcx>) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 54c55d76a8270..679213874f964 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -468,9 +468,10 @@ 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 did = parse_def_(st, NominalType, conv); let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); + let def = st.tcx.lookup_adt_def(did); return tcx.mk_enum(def, st.tcx.mk_substs(substs)); } 'x' => { @@ -558,7 +559,8 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w let did = parse_def_(st, NominalType, conv); let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); - return st.tcx.mk_struct(did, st.tcx.mk_substs(substs)); + let def = st.tcx.lookup_adt_def(did); + return st.tcx.mk_struct(def, st.tcx.mk_substs(substs)); } 'k' => { assert_eq!(next(st), '['); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 1831c3518d709..88666be6c2cc2 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -86,7 +86,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { } } ty::TyEnum(def, substs) => { - mywrite!(w, "t[{}|", (cx.ds)(def)); + mywrite!(w, "t[{}|", (cx.ds)(def.did)); enc_substs(w, cx, substs); mywrite!(w, "]"); } @@ -138,7 +138,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), name) } ty::TyStruct(def, substs) => { - mywrite!(w, "a[{}|", (cx.ds)(def)); + mywrite!(w, "a[{}|", (cx.ds)(def.did)); enc_substs(w, cx, substs); mywrite!(w, "]"); } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 9667312b37057..4ee8f403e4282 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -546,8 +546,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::TyStruct(did, _) | - ty::TyEnum(did, _) if v.tcx.has_dtor(did) => { + ty::TyStruct(def, _) | + ty::TyEnum(def, _) if def.has_dtor(v.tcx) => { v.add_qualif(ConstQualif::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 f17cb673a5f2d..e7a349265ba98 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -234,10 +234,10 @@ 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 = cx.tcx.pat_ty(p); - if let ty::TyEnum(def_id, _) = pat_ty.sty { + if let ty::TyEnum(edef, _) = pat_ty.sty { let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); if let Some(DefLocal(_)) = def { - if cx.tcx.enum_variants(def_id).iter().any(|variant| + if cx.tcx.enum_variants(edef.did).iter().any(|variant| variant.name == ident.node.name && variant.args.is_empty() ) { @@ -501,8 +501,8 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { /// /// left_ty: struct X { a: (bool, &'static str), b: usize} /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } -fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, - pats: Vec<&Pat>, left_ty: Ty) -> P { +fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, + pats: Vec<&Pat>, left_ty: Ty<'tcx>) -> P { let pats_len = pats.len(); let mut pats = pats.into_iter().map(|p| P((*p).clone())); let pat = match left_ty.sty { @@ -511,9 +511,9 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, ty::TyEnum(cid, _) | ty::TyStruct(cid, _) => { let (vid, is_structure) = match ctor { &Variant(vid) => - (vid, cx.tcx.enum_variant_with_id(cid, vid).arg_names.is_some()), + (vid, cx.tcx.enum_variant_with_id(cid.did, vid).arg_names.is_some()), _ => - (cid, !cx.tcx.is_tuple_struct(cid)) + (cid.did, !cid.is_tuple_struct(cx.tcx)) }; if is_structure { let fields = cx.tcx.lookup_struct_fields(vid); @@ -606,8 +606,8 @@ fn all_constructors(cx: &MatchCheckCtxt, left_ty: Ty, _ => vec!(Single) }, - ty::TyEnum(eid, _) => - cx.tcx.enum_variants(eid) + ty::TyEnum(edef, _) => + cx.tcx.enum_variants(edef.did) .iter() .map(|va| Variant(va.id)) .collect(), @@ -817,13 +817,13 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usi ty::TyStr => 0, _ => 1 }, - ty::TyEnum(eid, _) => { + ty::TyEnum(edef, _) => { match *ctor { - Variant(id) => cx.tcx.enum_variant_with_id(eid, id).args.len(), + Variant(id) => cx.tcx.enum_variant_with_id(edef.did, id).args.len(), _ => unreachable!() } } - ty::TyStruct(cid, _) => cx.tcx.lookup_struct_fields(cid).len(), + ty::TyStruct(cdef, _) => cx.tcx.lookup_struct_fields(cdef.did).len(), ty::TyArray(_, n) => n, _ => 0 } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 8d2d6889b5efa..7899f928e9d15 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -101,8 +101,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_access(&mut self, lhs: &ast::Expr, name: ast::Name) { match self.tcx.expr_ty_adjusted(lhs).sty { - ty::TyStruct(id, _) => { - let fields = self.tcx.lookup_struct_fields(id); + ty::TyStruct(def, _) => { + let fields = self.tcx.lookup_struct_fields(def.did); let field_id = fields.iter() .find(|field| field.name == name).unwrap().id; self.live_symbols.insert(field_id.node); @@ -113,8 +113,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: usize) { match self.tcx.expr_ty_adjusted(lhs).sty { - ty::TyStruct(id, _) => { - let fields = self.tcx.lookup_struct_fields(id); + ty::TyStruct(def, _) => { + let fields = self.tcx.lookup_struct_fields(def.did); let field_id = fields[idx].id; self.live_symbols.insert(field_id.node); }, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 469aacaf50677..8f63aca0dd69a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -695,8 +695,8 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { // Select just those fields of the `with` // expression that will actually be used let with_fields = match with_cmt.ty.sty { - ty::TyStruct(did, substs) => { - self.tcx().struct_fields(did, substs) + ty::TyStruct(def, substs) => { + self.tcx().struct_fields(def.did, substs) } _ => { // the base expression should always evaluate to a @@ -708,7 +708,6 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { with_expr.span, "with expression doesn't evaluate to a struct"); } - assert!(self.tcx().sess.has_errors()); vec!() } }; diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index de7582a137166..8ff81635416a4 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::TyInt(int_type) => Some(IntSimplifiedType(int_type)), ty::TyUint(uint_type) => Some(UintSimplifiedType(uint_type)), ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)), - ty::TyEnum(def_id, _) => Some(EnumSimplifiedType(def_id)), + ty::TyEnum(def, _) => Some(EnumSimplifiedType(def.did)), ty::TyStr => Some(StrSimplifiedType), ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), ty::TyRawPtr(_) => Some(PtrSimplifiedType), ty::TyTrait(ref trait_info) => { Some(TraitSimplifiedType(trait_info.principal_def_id())) } - ty::TyStruct(def_id, _) => { - Some(StructSimplifiedType(def_id)) + ty::TyStruct(def, _) => { + Some(StructSimplifiedType(def.did)) } ty::TyRef(_, mt) => { // since we introduce auto-refs during method lookup, we diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index 799d9a653ae38..84fc2f7b2e540 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -144,10 +144,10 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds) } - ty::TyEnum(def_id, substs) | - ty::TyStruct(def_id, substs) => { - let item_scheme = self.tcx().lookup_item_type(def_id); - self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs) + ty::TyEnum(def, substs) | + ty::TyStruct(def, substs) => { + let item_scheme = def.type_scheme(self.tcx()); + self.accumulate_from_adt(ty, def.did, &item_scheme.generics, substs) } ty::TyArray(t, _) | diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 7dcf63fcafb40..1261f10aaffee 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -415,8 +415,8 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, ast::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(did, _) => { - tcx.lookup_struct_fields(did) + ty::TyStruct(def, _) => { + tcx.lookup_struct_fields(def.did) .iter() .find(|f| f.name == field.node.name) .unwrap_or_else(|| { @@ -432,8 +432,8 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, ast::ExprTupField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(did, _) => { - tcx.lookup_struct_fields(did) + ty::TyStruct(def, _) => { + tcx.lookup_struct_fields(def.did) .get(field.node) .unwrap_or_else(|| { tcx.sess.span_bug(field.span, @@ -450,8 +450,8 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, ast::ExprStruct(_, ref expr_fields, _) => { let type_ = tcx.expr_ty(e); match type_.sty { - ty::TyStruct(did, _) => { - let struct_fields = tcx.lookup_struct_fields(did); + ty::TyStruct(def, _) => { + let struct_fields = tcx.lookup_struct_fields(def.did); // check the stability of each field that appears // in the construction expression. for field in expr_fields { @@ -505,11 +505,11 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let did = match tcx.pat_ty_opt(pat) { - Some(&ty::TyS { sty: ty::TyStruct(did, _), .. }) => did, + let def = match tcx.pat_ty_opt(pat) { + Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def, Some(_) | None => return, }; - let struct_fields = tcx.lookup_struct_fields(did); + let struct_fields = tcx.lookup_struct_fields(def.did); match pat.node { // Foo(a, b, c) ast::PatEnum(_, Some(ref pat_fields)) => { diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 977d0577e480f..e9bd6304fcad4 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -278,8 +278,8 @@ fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool match ty.sty { ty::TyBox(..) | ty::TyRef(..) => true, - ty::TyEnum(def_id, _) | ty::TyStruct(def_id, _) => - tcx.has_attr(def_id, "fundamental"), + ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.is_fundamental() + , ty::TyTrait(ref data) => tcx.has_attr(data.principal_def_id(), "fundamental"), _ => @@ -316,9 +316,9 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, infer_is_local.0 } - ty::TyEnum(def_id, _) | - ty::TyStruct(def_id, _) => { - def_id.krate == ast::LOCAL_CRATE + ty::TyEnum(def, _) | + ty::TyStruct(def, _) => { + def.did.krate == ast::LOCAL_CRATE } ty::TyBox(_) => { // Box diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 5727f07edb1d0..fee1c83ba2cce 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1721,17 +1721,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ok_if(substs.upvar_tys.clone()) } - ty::TyStruct(def_id, substs) => { + ty::TyStruct(def, substs) => { let types: Vec = - self.tcx().struct_fields(def_id, substs).iter() - .map(|f| f.mt.ty) - .collect(); + self.tcx().struct_fields(def.did, substs).iter() + .map(|f| f.mt.ty) + .collect(); nominal(bound, types) } - ty::TyEnum(def_id, substs) => { + ty::TyEnum(def, substs) => { let types: Vec = - self.tcx().substd_enum_variants(def_id, substs) + self.tcx().substd_enum_variants(def.did, substs) .iter() .flat_map(|variant| &variant.args) .cloned() @@ -1861,25 +1861,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // for `PhantomData`, we pass `T` - ty::TyStruct(def_id, substs) - if Some(def_id) == self.tcx().lang_items.phantom_data() => - { + ty::TyStruct(def, substs) if def.is_phantom_data() => { substs.types.get_slice(TypeSpace).to_vec() } - ty::TyStruct(def_id, substs) => { - self.tcx().struct_fields(def_id, substs) + ty::TyStruct(def, substs) => { + self.tcx().struct_fields(def.did, substs) .iter() .map(|f| f.mt.ty) .collect() } - ty::TyEnum(def_id, substs) => { - self.tcx().substd_enum_variants(def_id, substs) - .iter() - .flat_map(|variant| &variant.args) - .map(|&ty| ty) - .collect() + ty::TyEnum(def, substs) => { + self.tcx().substd_enum_variants(def.did, substs) + .iter() + .flat_map(|variant| &variant.args) + .map(|&ty| ty) + .collect() } } } @@ -2523,9 +2521,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Struct -> Struct. - (&ty::TyStruct(def_id, substs_a), &ty::TyStruct(_, substs_b)) => { - let fields = tcx.lookup_struct_fields(def_id).iter().map(|f| { - tcx.lookup_field_type_unsubstituted(def_id, f.id) + (&ty::TyStruct(def, substs_a), &ty::TyStruct(_, substs_b)) => { + let fields = tcx.lookup_struct_fields(def.did).iter().map(|f| { + tcx.lookup_field_type_unsubstituted(def.did, f.id) }).collect::>(); // The last field of the structure has to exist and contain type parameters. @@ -2572,7 +2570,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let param_b = *substs_b.types.get(TypeSpace, i); new_substs.types.get_mut_slice(TypeSpace)[i] = param_b; } - let new_struct = tcx.mk_struct(def_id, tcx.mk_substs(new_substs)); + let new_struct = tcx.mk_struct(def, tcx.mk_substs(new_substs)); let origin = infer::Misc(obligation.cause.span); if self.infcx.sub_types(false, origin, new_struct, target).is_err() { return Err(Unimplemented); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 88fc6181f9241..9b5943e7d3035 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -721,6 +721,7 @@ pub struct CtxtArenas<'tcx> { // references trait_defs: TypedArena>, + adt_defs: TypedArena>, } impl<'tcx> CtxtArenas<'tcx> { @@ -732,7 +733,8 @@ impl<'tcx> CtxtArenas<'tcx> { region: TypedArena::new(), stability: TypedArena::new(), - trait_defs: TypedArena::new() + trait_defs: TypedArena::new(), + adt_defs: TypedArena::new() } } } @@ -847,6 +849,7 @@ pub struct ctxt<'tcx> { pub impl_trait_refs: RefCell>>>, pub trait_defs: RefCell>>, + pub adt_defs: RefCell>>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its /// associated predicates. @@ -1017,6 +1020,13 @@ impl<'tcx> ctxt<'tcx> { interned } + pub fn intern_adt_def(&self, did: DefId) -> &'tcx ADTDef<'tcx> { + let def = ADTDef::new(self, did); + let interned = self.arenas.adt_defs.alloc(def); + self.adt_defs.borrow_mut().insert(did, interned); + interned + } + pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability { if let Some(st) = self.stability_interner.borrow().get(&stab) { return st; @@ -1761,12 +1771,12 @@ pub enum TypeVariants<'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 `TyStruct` as /// well. - TyEnum(DefId, &'tcx Substs<'tcx>), + TyEnum(&'tcx ADTDef<'tcx>, &'tcx Substs<'tcx>), /// A structure type, defined with `struct`. /// /// See warning about substitutions for enumerated types. - TyStruct(DefId, &'tcx Substs<'tcx>), + TyStruct(&'tcx ADTDef<'tcx>, &'tcx Substs<'tcx>), /// `Box`; this is nominally a struct in the documentation, but is /// special-cased internally. For example, it is possible to implicitly @@ -2984,18 +2994,18 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { // FIXME: (@jroesch) float this code up let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(self.clone()), false); - let did = match self_type.sty { - ty::TyStruct(struct_did, substs) => { - let fields = tcx.struct_fields(struct_did, substs); + let adt = match self_type.sty { + ty::TyStruct(struct_def, substs) => { + let fields = tcx.struct_fields(struct_def.did, substs); for field in &fields { if infcx.type_moves_by_default(field.mt.ty, span) { return Err(FieldDoesNotImplementCopy(field.name)) } } - struct_did + struct_def } - ty::TyEnum(enum_did, substs) => { - let enum_variants = tcx.enum_variants(enum_did); + ty::TyEnum(enum_def, substs) => { + let enum_variants = tcx.enum_variants(enum_def.did); for variant in enum_variants.iter() { for variant_arg_type in &variant.args { let substd_arg_type = @@ -3005,12 +3015,12 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } } } - enum_did + enum_def } _ => return Err(TypeIsStructural), }; - if tcx.has_dtor(did) { + if adt.has_dtor(tcx) { return Err(TypeHasDestructor) } @@ -3193,6 +3203,100 @@ impl<'tcx> TraitDef<'tcx> { } +bitflags! { + flags ADTFlags: u32 { + const NO_ADT_FLAGS = 0, + const IS_FUNDAMENTAL = 1 << 0, + const IS_PHANTOM_DATA = 1 << 1, + const IS_DTORCK = 1 << 2, // is this a dtorck type? + const IS_DTORCK_VALID = 1 << 3, + } +} + +/// The definition of an abstract data type - a struct or enum. +pub struct ADTDef<'tcx> { + pub did: DefId, + flags: Cell, + marker: ::std::marker::PhantomData<&'tcx ()>, +} + +impl<'tcx> PartialEq for ADTDef<'tcx> { + // ADTDef are always interned and this is part of TyS equality + #[inline] + fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } +} + +impl<'tcx> Eq for ADTDef<'tcx> {} + +impl<'tcx> Hash for ADTDef<'tcx> { + #[inline] + fn hash(&self, s: &mut H) { + (self as *const ADTDef).hash(s) + } +} + +impl<'tcx> ADTDef<'tcx> { + fn new(tcx: &ctxt<'tcx>, did: DefId) -> Self { + let mut flags = ADTFlags::NO_ADT_FLAGS; + if tcx.has_attr(did, "fundamental") { + flags = flags | ADTFlags::IS_FUNDAMENTAL; + } + if Some(did) == tcx.lang_items.phantom_data() { + flags = flags | ADTFlags::IS_PHANTOM_DATA; + } + ADTDef { + did: did, + flags: Cell::new(flags), + marker: ::std::marker::PhantomData + } + } + + fn calculate_dtorck(&'tcx self, tcx: &ctxt<'tcx>) { + if tcx.is_adt_dtorck(self) { + self.flags.set(self.flags.get() | ADTFlags::IS_DTORCK); + } + self.flags.set(self.flags.get() | ADTFlags::IS_DTORCK_VALID) + } + + #[inline] + pub fn is_dtorck(&'tcx self, tcx: &ctxt<'tcx>) -> bool { + if !self.flags.get().intersects(ADTFlags::IS_DTORCK_VALID) { + self.calculate_dtorck(tcx) + } + self.flags.get().intersects(ADTFlags::IS_DTORCK) + } + + #[inline] + pub fn is_fundamental(&self) -> bool { + self.flags.get().intersects(ADTFlags::IS_FUNDAMENTAL) + } + + #[inline] + pub fn is_phantom_data(&self) -> bool { + self.flags.get().intersects(ADTFlags::IS_PHANTOM_DATA) + } + + #[inline(never)] + pub fn has_dtor(&self, tcx: &ctxt<'tcx>) -> bool { + tcx.destructor_for_type.borrow().contains_key(&self.did) + } + + pub fn is_tuple_struct(&self, tcx: &ctxt<'tcx>) -> bool { + let fields = tcx.lookup_struct_fields(self.did); + !fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field) + } + + #[inline] + pub fn type_scheme(&self, tcx: &ctxt<'tcx>) -> TypeScheme<'tcx> { + tcx.lookup_item_type(self.did) + } + + #[inline] + pub fn predicates(&self, tcx: &ctxt<'tcx>) -> GenericPredicates<'tcx> { + tcx.lookup_predicates(self.did) + } +} + /// Records the substitutions used to translate the polytype for an /// item into the monotype of an item reference. #[derive(Clone)] @@ -3498,6 +3602,7 @@ impl<'tcx> ctxt<'tcx> { tables: RefCell::new(Tables::empty()), impl_trait_refs: RefCell::new(DefIdMap()), trait_defs: RefCell::new(DefIdMap()), + adt_defs: RefCell::new(DefIdMap()), predicates: RefCell::new(DefIdMap()), super_predicates: RefCell::new(DefIdMap()), fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()), @@ -3679,9 +3784,9 @@ impl<'tcx> ctxt<'tcx> { self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) } - pub fn mk_enum(&self, did: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + pub fn mk_enum(&self, def: &'tcx ADTDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside - self.mk_ty(TyEnum(did, substs)) + self.mk_ty(TyEnum(def, substs)) } pub fn mk_box(&self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -3781,10 +3886,9 @@ impl<'tcx> ctxt<'tcx> { self.mk_ty(TyProjection(inner)) } - pub fn mk_struct(&self, struct_id: ast::DefId, - substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + pub fn mk_struct(&self, def: &'tcx ADTDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside - self.mk_ty(TyStruct(struct_id, substs)) + self.mk_ty(TyStruct(def, substs)) } pub fn mk_closure(&self, @@ -3946,7 +4050,7 @@ impl<'tcx> TyS<'tcx> { pub fn is_empty(&self, cx: &ctxt) -> bool { match self.sty { - TyEnum(did, _) => cx.enum_variants(did).is_empty(), + TyEnum(def, _) => cx.enum_variants(def.did).is_empty(), _ => false } } @@ -3987,7 +4091,7 @@ impl<'tcx> TyS<'tcx> { pub fn is_simd(&self, cx: &ctxt) -> bool { match self.sty { - TyStruct(did, _) => cx.lookup_simd(did), + TyStruct(def, _) => cx.lookup_simd(def.did), _ => false } } @@ -4003,9 +4107,9 @@ impl<'tcx> TyS<'tcx> { pub fn simd_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { match self.sty { - TyStruct(did, substs) => { - let fields = cx.lookup_struct_fields(did); - cx.lookup_field_type(did, fields[0].id, substs) + TyStruct(def, substs) => { + let fields = cx.lookup_struct_fields(def.did); + cx.lookup_field_type(def.did, fields[0].id, substs) } _ => panic!("simd_type called on invalid type") } @@ -4013,8 +4117,8 @@ impl<'tcx> TyS<'tcx> { pub fn simd_size(&self, cx: &ctxt) -> usize { match self.sty { - TyStruct(did, _) => { - cx.lookup_struct_fields(did).len() + TyStruct(def, _) => { + cx.lookup_struct_fields(def.did).len() } _ => panic!("simd_size called on invalid type") } @@ -4067,8 +4171,8 @@ impl<'tcx> TyS<'tcx> { pub fn ty_to_def_id(&self) -> Option { match self.sty { TyTrait(ref tt) => Some(tt.principal_def_id()), - TyStruct(id, _) | - TyEnum(id, _) | + TyStruct(def, _) | + TyEnum(def, _) => Some(def.did), TyClosure(id, _) => Some(id), _ => None } @@ -4275,16 +4379,16 @@ impl<'tcx> TyS<'tcx> { } TyStr => TC::None, - TyStruct(did, substs) => { - let flds = cx.struct_fields(did, substs); + TyStruct(def, substs) => { + let flds = cx.struct_fields(def.did, substs); let mut res = TypeContents::union(&flds[..], |f| tc_ty(cx, f.mt.ty, cache)); - if cx.has_dtor(did) { + if def.has_dtor(cx) { res = res | TC::OwnsDtor; } - apply_lang_items(cx, did, res) + apply_lang_items(cx, def.did, res) } TyClosure(_, ref substs) => { @@ -4296,8 +4400,8 @@ impl<'tcx> TyS<'tcx> { |ty| tc_ty(cx, *ty, cache)) } - TyEnum(did, substs) => { - let variants = cx.substd_enum_variants(did, substs); + TyEnum(def, substs) => { + let variants = cx.substd_enum_variants(def.did, substs); let mut res = TypeContents::union(&variants[..], |variant| { TypeContents::union(&variant.args, @@ -4306,11 +4410,11 @@ impl<'tcx> TyS<'tcx> { }) }); - if cx.has_dtor(did) { + if def.has_dtor(cx) { res = res | TC::OwnsDtor; } - apply_lang_items(cx, did, res) + apply_lang_items(cx, def.did, res) } TyProjection(..) | @@ -4431,7 +4535,7 @@ impl<'tcx> TyS<'tcx> { // True if instantiating an instance of `r_ty` requires an instance of `r_ty`. pub fn is_instantiable(&'tcx self, cx: &ctxt<'tcx>) -> bool { - fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec, + fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<&'tcx ADTDef<'tcx>>, r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { debug!("type_requires({:?}, {:?})?", r_ty, ty); @@ -4443,7 +4547,7 @@ impl<'tcx> TyS<'tcx> { return r; } - fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec, + fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<&'tcx ADTDef<'tcx>>, r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { debug!("subtypes_require({:?}, {:?})?", r_ty, ty); @@ -4486,9 +4590,9 @@ impl<'tcx> TyS<'tcx> { false } - TyStruct(did, substs) => { - seen.push(did); - let fields = cx.struct_fields(did, substs); + TyStruct(def, substs) => { + seen.push(def); + let fields = cx.struct_fields(def.did, substs); let r = fields.iter().any(|f| type_requires(cx, seen, r_ty, f.mt.ty)); seen.pop().unwrap(); r @@ -4506,13 +4610,13 @@ impl<'tcx> TyS<'tcx> { ts.iter().any(|ty| type_requires(cx, seen, r_ty, *ty)) } - TyEnum(ref did, _) if seen.contains(did) => { + TyEnum(ref def, _) if seen.contains(def) => { false } - TyEnum(did, substs) => { - seen.push(did); - let vs = cx.enum_variants(did); + TyEnum(def, substs) => { + seen.push(def); + let vs = cx.enum_variants(def.did); let r = !vs.is_empty() && vs.iter().all(|variant| { variant.args.iter().any(|aty| { let sty = aty.subst(cx, substs); @@ -4576,12 +4680,12 @@ impl<'tcx> TyS<'tcx> { TyArray(ty, _) => { is_type_structurally_recursive(cx, sp, seen, ty) } - TyStruct(did, substs) => { - let fields = cx.struct_fields(did, substs); + TyStruct(def, substs) => { + let fields = cx.struct_fields(def.did, substs); find_nonrepresentable(cx, sp, seen, fields.iter().map(|f| f.mt.ty)) } - TyEnum(did, substs) => { - let vs = cx.enum_variants(did); + TyEnum(def, substs) => { + let vs = cx.enum_variants(def.did); let iter = vs.iter() .flat_map(|variant| &variant.args) .map(|aty| { aty.subst_spanned(cx, substs, Some(sp)) }); @@ -4597,10 +4701,10 @@ impl<'tcx> TyS<'tcx> { } } - fn same_struct_or_enum_def_id(ty: Ty, did: DefId) -> bool { + fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ADTDef<'tcx>) -> bool { match ty.sty { - TyStruct(ty_did, _) | TyEnum(ty_did, _) => { - ty_did == did + TyStruct(ty_def, _) | TyEnum(ty_def, _) => { + ty_def == def } _ => false } @@ -4635,7 +4739,7 @@ impl<'tcx> TyS<'tcx> { debug!("is_type_structurally_recursive: {:?}", ty); match ty.sty { - TyStruct(did, _) | TyEnum(did, _) => { + TyStruct(def, _) | TyEnum(def, _) => { { // Iterate through stack of previously seen types. let mut iter = seen.iter(); @@ -4650,7 +4754,7 @@ impl<'tcx> TyS<'tcx> { match iter.next() { Some(&seen_type) => { - if same_struct_or_enum_def_id(seen_type, did) { + if same_struct_or_enum(seen_type, def) { debug!("SelfRecursive: {:?} contains {:?}", seen_type, ty); @@ -4786,8 +4890,8 @@ impl<'tcx> TyS<'tcx> { // constructors pub fn is_c_like_enum(&self, cx: &ctxt) -> bool { match self.sty { - TyEnum(did, _) => { - let variants = cx.enum_variants(did); + TyEnum(def, _) => { + let variants = cx.enum_variants(def.did); if variants.is_empty() { false } else { @@ -4959,7 +5063,7 @@ impl<'tcx> TyS<'tcx> { TyUint(_) | TyFloat(_) | TyStr => self.to_string(), TyTuple(ref tys) if tys.is_empty() => self.to_string(), - TyEnum(id, _) => format!("enum `{}`", cx.item_path_str(id)), + TyEnum(def, _) => format!("enum `{}`", cx.item_path_str(def.did)), TyBox(_) => "box".to_string(), TyArray(_, n) => format!("array of {} elements", n), TySlice(_) => "slice".to_string(), @@ -4970,8 +5074,8 @@ impl<'tcx> TyS<'tcx> { TyTrait(ref inner) => { format!("trait {}", cx.item_path_str(inner.principal_def_id())) } - TyStruct(id, _) => { - format!("struct `{}`", cx.item_path_str(id)) + TyStruct(def, _) => { + format!("struct `{}`", cx.item_path_str(def.did)) } TyClosure(..) => "closure".to_string(), TyTuple(_) => "tuple".to_string(), @@ -5201,18 +5305,18 @@ impl<'tcx> ctxt<'tcx> { (&TyTuple(ref v), None) => v.get(i).cloned(), - (&TyStruct(def_id, substs), None) => self.lookup_struct_fields(def_id) + (&TyStruct(def, substs), None) => self.lookup_struct_fields(def.did) .get(i) .map(|&t| self.lookup_item_type(t.id).ty.subst(self, substs)), - (&TyEnum(def_id, substs), Some(variant_def_id)) => { - let variant_info = self.enum_variant_with_id(def_id, variant_def_id); + (&TyEnum(def, substs), Some(variant_def_id)) => { + let variant_info = self.enum_variant_with_id(def.did, variant_def_id); variant_info.args.get(i).map(|t|t.subst(self, substs)) } - (&TyEnum(def_id, substs), None) => { - assert!(self.enum_is_univariant(def_id)); - let enum_variants = self.enum_variants(def_id); + (&TyEnum(def, substs), None) => { + assert!(self.enum_is_univariant(def.did)); + let enum_variants = self.enum_variants(def.did); let variant_info = &enum_variants[0]; variant_info.args.get(i).map(|t|t.subst(self, substs)) } @@ -5229,13 +5333,13 @@ impl<'tcx> ctxt<'tcx> { variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def_id, substs), None) => { - let r = self.lookup_struct_fields(def_id); + (&TyStruct(def, substs), None) => { + let r = self.lookup_struct_fields(def.did); r.iter().find(|f| f.name == n) - .map(|&f| self.lookup_field_type(def_id, f.id, substs)) + .map(|&f| self.lookup_field_type(def.did, f.id, substs)) } - (&TyEnum(def_id, substs), Some(variant_def_id)) => { - let variant_info = self.enum_variant_with_id(def_id, variant_def_id); + (&TyEnum(def, substs), Some(variant_def_id)) => { + let variant_info = self.enum_variant_with_id(def.did, 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) @@ -5744,10 +5848,6 @@ impl<'tcx> ctxt<'tcx> { } } - pub fn has_dtor(&self, struct_id: DefId) -> bool { - self.destructor_for_type.borrow().contains_key(&struct_id) - } - pub fn with_path(&self, id: ast::DefId, f: F) -> T where F: FnOnce(ast_map::PathElems) -> T, { @@ -5938,6 +6038,14 @@ impl<'tcx> ctxt<'tcx> { ) } + /// Given the did of a trait, returns its canonical trait ref. + pub fn lookup_adt_def(&self, did: ast::DefId) -> &'tcx ADTDef<'tcx> { + lookup_locally_or_in_crate_store( + "adt_defs", did, &self.adt_defs, + || csearch::get_adt_def(self, did) + ) + } + /// Given the did of an item, returns its full set of predicates. pub fn lookup_predicates(&self, did: ast::DefId) -> GenericPredicates<'tcx> { lookup_locally_or_in_crate_store( @@ -5978,6 +6086,7 @@ impl<'tcx> ctxt<'tcx> { /// Obtain the representation annotation for a struct definition. pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { + // TODO: remove memoized(&self.repr_hint_cache, did, |did: DefId| { Rc::new(if did.krate == LOCAL_CRATE { self.get_attrs(did).iter().flat_map(|meta| { @@ -6013,7 +6122,7 @@ impl<'tcx> ctxt<'tcx> { self.lookup_field_type_unsubstituted(struct_id, id).subst(self, substs) } - // Look up the list of field names and IDs for a given struct. + // Look up the list of field names and IDs for a given struct or struct-variant. // Panics if the id is not bound to a struct. pub fn lookup_struct_fields(&self, did: ast::DefId) -> Vec { if did.krate == ast::LOCAL_CRATE { @@ -6031,11 +6140,6 @@ impl<'tcx> ctxt<'tcx> { } } - pub fn is_tuple_struct(&self, did: ast::DefId) -> bool { - let fields = self.lookup_struct_fields(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(&self, did: ast::DefId, substs: &Substs<'tcx>) @@ -6055,8 +6159,8 @@ impl<'tcx> ctxt<'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def_id, substs) = ty.sty { - match self.struct_fields(def_id, substs).last() { + while let TyStruct(def, substs) = ty.sty { + match self.struct_fields(def.did, substs).last() { Some(f) => ty = f.mt.ty, None => break } @@ -6074,12 +6178,12 @@ impl<'tcx> ctxt<'tcx> { target: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); - while let (&TyStruct(a_did, a_substs), &TyStruct(b_did, b_substs)) = (&a.sty, &b.sty) { - if a_did != b_did { + while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { + if a_def != b_def { break; } - if let Some(a_f) = self.struct_fields(a_did, a_substs).last() { - if let Some(b_f) = self.struct_fields(b_did, b_substs).last() { + if let Some(a_f) = self.struct_fields(a_def.did, a_substs).last() { + if let Some(b_f) = self.struct_fields(b_def.did, b_substs).last() { a = a_f.mt.ty; b = b_f.mt.ty; } else { @@ -6452,7 +6556,7 @@ impl<'tcx> ctxt<'tcx> { } TyEnum(d, _) => { byte!(8); - did(state, d); + did(state, d.did); } TyBox(_) => { byte!(9); @@ -6495,7 +6599,7 @@ impl<'tcx> ctxt<'tcx> { } TyStruct(d, _) => { byte!(18); - did(state, d); + did(state, d.did); } TyTuple(ref inner) => { byte!(19); @@ -6633,6 +6737,85 @@ impl<'tcx> ctxt<'tcx> { pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } + + + /// Returns true if this ADT is a dtorck type, i.e. whether it being + /// safe for destruction requires it to be alive + fn is_adt_dtorck(&self, adt: &'tcx ADTDef<'tcx>) -> bool { + let dtor_method = match self.destructor_for_type.borrow().get(&adt.did) { + Some(dtor) => *dtor, + None => return false + }; + let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| { + self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt)) + }); + let generics = adt.type_scheme(self).generics; + + // In `impl<'a> Drop ...`, we automatically assume + // `'a` is meaningful and thus represents a bound + // through which we could reach borrowed data. + // + // FIXME (pnkfelix): In the future it would be good to + // extend the language to allow the user to express, + // in the impl signature, that a lifetime is not + // actually used (something like `where 'a: ?Live`). + if generics.has_region_params(subst::TypeSpace) { + debug!("typ: {:?} has interesting dtor due to region params", + adt); + return true; + } + + let mut seen_items = Vec::new(); + let mut items_to_inspect = vec![impl_did]; + while let Some(item_def_id) = items_to_inspect.pop() { + if seen_items.contains(&item_def_id) { + continue; + } + + for pred in self.lookup_predicates(item_def_id).predicates { + let result = match pred { + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::Projection(..) => { + // For now, assume all these where-clauses + // may give drop implementation capabilty + // to access borrowed data. + true + } + + ty::Predicate::Trait(ty::Binder(ref t_pred)) => { + let def_id = t_pred.trait_ref.def_id; + if self.trait_items(def_id).len() != 0 { + // If trait has items, assume it adds + // capability to access borrowed data. + true + } else { + // Trait without items is itself + // uninteresting from POV of dropck. + // + // However, may have parent w/ items; + // so schedule checking of predicates, + items_to_inspect.push(def_id); + // and say "no capability found" for now. + false + } + } + }; + + if result { + debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}", + adt, pred); + return true; + } + } + + seen_items.push(item_def_id); + } + + debug!("typ: {:?} is dtorck-safe", adt); + false + } } /// The category of explicit self. diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs index f8678b4d8e3bd..05b08b356efdf 100644 --- a/src/librustc/middle/ty_relate/mod.rs +++ b/src/librustc/middle/ty_relate/mod.rs @@ -485,11 +485,11 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, Ok(a) } - (&ty::TyEnum(a_id, a_substs), &ty::TyEnum(b_id, b_substs)) - if a_id == b_id => + (&ty::TyEnum(a_def, a_substs), &ty::TyEnum(b_def, b_substs)) + if a_def == b_def => { - let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); - Ok(tcx.mk_enum(a_id, tcx.mk_substs(substs))) + let substs = try!(relate_item_substs(relation, a_def.did, a_substs, b_substs)); + Ok(tcx.mk_enum(a_def, tcx.mk_substs(substs))) } (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) => @@ -499,11 +499,11 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, Ok(tcx.mk_trait(principal, bounds)) } - (&ty::TyStruct(a_id, a_substs), &ty::TyStruct(b_id, b_substs)) - if a_id == b_id => + (&ty::TyStruct(a_def, a_substs), &ty::TyStruct(b_def, b_substs)) + if a_def == b_def => { - let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); - Ok(tcx.mk_struct(a_id, tcx.mk_substs(substs))) + let substs = try!(relate_item_substs(relation, a_def.did, a_substs, b_substs)); + Ok(tcx.mk_struct(a_def, tcx.mk_substs(substs))) } (&ty::TyClosure(a_id, ref a_substs), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d215813b7400d..24e18099d8b8f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -366,6 +366,14 @@ impl<'tcx> fmt::Debug for ty::TraitDef<'tcx> { } } +impl<'tcx> fmt::Debug for ty::ADTDef<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ty::tls::with(|tcx| { + write!(f, "{}", tcx.item_path_str(self.did)) + }) + } +} + impl fmt::Display for ty::BoundRegion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if verbose() { @@ -648,14 +656,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), - TyEnum(did, substs) | TyStruct(did, substs) => { + TyEnum(def, substs) | TyStruct(def, substs) => { ty::tls::with(|tcx| { - if did.krate == ast::LOCAL_CRATE && - !tcx.tcache.borrow().contains_key(&did) { - write!(f, "{}<..>", tcx.item_path_str(did)) + if def.did.krate == ast::LOCAL_CRATE && + !tcx.tcache.borrow().contains_key(&def.did) { + write!(f, "{}<..>", tcx.item_path_str(def.did)) } else { - parameterized(f, substs, did, &[], - |tcx| tcx.lookup_item_type(did).generics) + parameterized(f, substs, def.did, &[], + |tcx| tcx.lookup_item_type(def.did).generics) } }) } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 8d7c964c7b21e..62cb1f73cf853 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -746,24 +746,22 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => { match lp_base.to_type().sty { - ty::TyStruct(def_id, _) | ty::TyEnum(def_id, _) => { - if self.tcx().has_dtor(def_id) { - // In the case where the owner implements drop, then - // the path must be initialized to prevent a case of - // partial reinitialization - // - // FIXME (22079): could refactor via hypothetical - // generalized check_if_path_is_moved - let loan_path = owned_ptr_base_path_rc(lp_base); - self.move_data.each_move_of(id, &loan_path, |_, _| { - self.bccx - .report_partial_reinitialization_of_uninitialized_structure( - span, - &*loan_path); - false - }); - return; - } + ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor(self.tcx()) => { + // In the case where the owner implements drop, then + // the path must be initialized to prevent a case of + // partial reinitialization + // + // FIXME (22079): could refactor via hypothetical + // generalized check_if_path_is_moved + let loan_path = owned_ptr_base_path_rc(lp_base); + self.move_data.each_move_of(id, &loan_path, |_, _| { + self.bccx + .report_partial_reinitialization_of_uninitialized_structure( + span, + &*loan_path); + false + }); + return; }, _ => {}, } diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 864bd7190a361..b398b6817f732 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -438,8 +438,8 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } } - (&ty::TyStruct(def_id, ref _substs), None) => { - let fields = tcx.lookup_struct_fields(def_id); + (&ty::TyStruct(def, ref _substs), None) => { + let fields = tcx.lookup_struct_fields(def.did); match *origin_field_name { mc::NamedField(ast_name) => { for f in &fields { @@ -462,9 +462,9 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } } - (&ty::TyEnum(enum_def_id, substs), ref enum_variant_info) => { + (&ty::TyEnum(enum_def, substs), ref enum_variant_info) => { let variant_info = { - let mut variants = tcx.substd_enum_variants(enum_def_id, substs); + let mut variants = tcx.substd_enum_variants(enum_def.did, substs); match *enum_variant_info { Some((variant_def_id, ref _lp2)) => variants.iter() diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 2b33dde2cbe2d..308ae42c16f07 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::TyStruct(did, _) | ty::TyEnum(did, _) => { - if bccx.tcx.has_dtor(did) { + ty::TyStruct(def, _) | ty::TyEnum(def, _) => { + if def.has_dtor(bccx.tcx) { 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 5baabebea116b..1246449327d96 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -136,8 +136,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::TyStruct(did, _) | - ty::TyEnum(did, _) if bccx.tcx.has_dtor(did) => { + ty::TyStruct(def, _) | + ty::TyEnum(def, _) if def.has_dtor(bccx.tcx) => { bccx.span_err( move_from.span, &format!("cannot move out of type `{}`, \ diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ffd09326abc35..3ed359cbc3d0a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -463,8 +463,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match ty.sty { - ty::TyStruct(did, substs) => { - if !cx.lookup_repr_hints(did).contains(&attr::ReprExtern) { + ty::TyStruct(def, substs) => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { return FfiUnsafe( "found struct without foreign-function-safe \ representation annotation in foreign module, \ @@ -474,7 +474,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // We can't completely trust repr(C) markings; make sure the // fields are actually safe. - let fields = cx.struct_fields(did, substs); + let fields = cx.struct_fields(def.did, substs); if fields.is_empty() { return FfiUnsafe( @@ -488,13 +488,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match r { FfiSafe => {} FfiBadStruct(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadStruct(did, s); } + FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } } } FfiSafe } - ty::TyEnum(did, substs) => { - let variants = cx.substd_enum_variants(did, substs); + ty::TyEnum(def, substs) => { + let variants = cx.substd_enum_variants(def.did, substs); if variants.is_empty() { // Empty enums are okay... although sort of useless. return FfiSafe @@ -502,7 +502,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Check for a repr() attribute to specify the size of the // discriminant. - let repr_hints = cx.lookup_repr_hints(did); + let repr_hints = cx.lookup_repr_hints(def.did); match &**repr_hints { [] => { // Special-case types like `Option`. @@ -544,7 +544,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match r { FfiSafe => {} FfiBadStruct(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadEnum(did, s); } + FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } } } } @@ -842,8 +842,8 @@ impl LintPass for RawPointerDerive { } match cx.tcx.node_id_to_type(item.id).sty { - ty::TyEnum(did, _) => did, - ty::TyStruct(did, _) => did, + ty::TyEnum(def, _) => def.did, + ty::TyStruct(def, _) => def.did, _ => return, } } @@ -989,16 +989,16 @@ impl LintPass for UnusedResults { let warned = match t.sty { ty::TyTuple(ref tys) if tys.is_empty() => return, ty::TyBool => return, - ty::TyStruct(did, _) | - ty::TyEnum(did, _) => { - if ast_util::is_local(did) { - if let ast_map::NodeItem(it) = cx.tcx.map.get(did.node) { + ty::TyStruct(def, _) | + ty::TyEnum(def, _) => { + if ast_util::is_local(def.did) { + if let ast_map::NodeItem(it) = cx.tcx.map.get(def.did.node) { check_must_use(cx, &it.attrs, s.span) } else { false } } else { - let attrs = csearch::get_item_attrs(&cx.sess().cstore, did); + let attrs = csearch::get_item_attrs(&cx.sess().cstore, def.did); check_must_use(cx, &attrs[..], s.span) } } @@ -1956,14 +1956,14 @@ impl LintPass for MissingCopyImplementations { if ast_generics.is_parameterized() { return; } - cx.tcx.mk_struct(local_def(item.id), + cx.tcx.mk_struct(cx.tcx.lookup_adt_def(local_def(item.id)), cx.tcx.mk_substs(Substs::empty())) } ast::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } - cx.tcx.mk_enum(local_def(item.id), + cx.tcx.mk_enum(cx.tcx.lookup_adt_def(local_def(item.id)), cx.tcx.mk_substs(Substs::empty())) } _ => return, @@ -2575,9 +2575,9 @@ impl LintPass for DropWithReprExtern { }; match dtor_self_type.sty { - ty::TyEnum(self_type_did, _) | - ty::TyStruct(self_type_did, _) | - ty::TyClosure(self_type_did, _) => { + ty::TyEnum(self_type_def, _) | + ty::TyStruct(self_type_def, _) => { + let self_type_did = self_type_def.did; let hints = ctx.tcx.lookup_repr_hints(self_type_did); if hints.iter().any(|attr| *attr == attr::ReprExtern) && ctx.tcx.ty_dtor(self_type_did).has_drop_flag() { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 2ffb4cbd4bfb0..b59cc65248165 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -690,6 +690,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { span: Span, id: ast::DefId, name: FieldName) { + // TODO: refactor to variant API let fields = self.tcx.lookup_struct_fields(id); let field = match name { NamedField(f_name) => { @@ -883,13 +884,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::TyStruct(id, _) = self.tcx.expr_ty_adjusted(&**base).sty { - self.check_field(expr.span, id, NamedField(ident.node.name)); + if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty { + self.check_field(expr.span, def.did, NamedField(ident.node.name)); } } ast::ExprTupField(ref base, idx) => { - if let ty::TyStruct(id, _) = self.tcx.expr_ty_adjusted(&**base).sty { - self.check_field(expr.span, id, UnnamedField(idx.node)); + if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty { + self.check_field(expr.span, def.did, UnnamedField(idx.node)); } } ast::ExprMethodCall(ident, _, _) => { @@ -900,13 +901,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } ast::ExprStruct(_, ref fields, _) => { match self.tcx.expr_ty(expr).sty { - ty::TyStruct(ctor_id, _) => { + ty::TyStruct(ctor_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 = self.tcx.lookup_struct_fields(ctor_id); + let all_fields = self.tcx.lookup_struct_fields(ctor_def.did); for field in all_fields { - self.check_field(expr.span, ctor_id, + self.check_field(expr.span, ctor_def.did, NamedField(field.name)); } } @@ -977,9 +978,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match pattern.node { ast::PatStruct(_, ref fields, _) => { match self.tcx.pat_ty(pattern).sty { - ty::TyStruct(id, _) => { + ty::TyStruct(def, _) => { for field in fields { - self.check_field(pattern.span, id, + self.check_field(pattern.span, def.did, NamedField(field.node.ident.name)); } } @@ -1008,12 +1009,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { // elsewhere). ast::PatEnum(_, Some(ref fields)) => { match self.tcx.pat_ty(pattern).sty { - ty::TyStruct(id, _) => { + ty::TyStruct(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.did, UnnamedField(i)); } } ty::TyEnum(..) => { diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 1fbec6f66cfdf..7500a959931e2 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -1119,8 +1119,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { let ty = &self.tcx.expr_ty_adjusted(&**sub_ex).sty; match *ty { - ty::TyStruct(def_id, _) => { - let fields = self.tcx.lookup_struct_fields(def_id); + ty::TyStruct(def, _) => { + let fields = self.tcx.lookup_struct_fields(def.did); 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/save/mod.rs b/src/librustc_trans/save/mod.rs index 796850ad6f28b..dbab7f4a0a970 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -447,8 +447,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ast::ExprField(ref sub_ex, ident) => { let ty = &self.tcx.expr_ty_adjusted(&sub_ex).sty; match *ty { - ty::TyStruct(def_id, _) => { - let fields = self.tcx.lookup_struct_fields(def_id); + ty::TyStruct(def, _) => { + let fields = self.tcx.lookup_struct_fields(def.did); for f in &fields { if f.name == ident.node.name { let sub_span = self.span_utils.span_for_last_ident(expr.span); @@ -474,12 +474,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ast::ExprStruct(ref path, _, _) => { let ty = &self.tcx.expr_ty_adjusted(expr).sty; match *ty { - ty::TyStruct(def_id, _) => { + ty::TyStruct(def, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), scope: self.enclosing_scope(expr.id), - ref_id: def_id, + ref_id: def.did, })) } _ => { diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index fb3afd16ea0f4..79fe9b90e7d9c 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1186,13 +1186,13 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, ).collect(); match left_ty.sty { - ty::TyStruct(def_id, substs) if !type_is_sized(bcx.tcx(), left_ty) => { + ty::TyStruct(def, substs) if !type_is_sized(bcx.tcx(), left_ty) => { // The last field is technically unsized but // since we can only ever match that field behind // a reference we construct a fat ptr here. - let fields = bcx.tcx().lookup_struct_fields(def_id); + let fields = bcx.tcx().lookup_struct_fields(def.did); let unsized_ty = fields.iter().last().map(|field| { - let fty = bcx.tcx().lookup_field_type(def_id, field.id, substs); + let fty = bcx.tcx().lookup_field_type(def.did, field.id, substs); monomorphize::normalize_associated_type(bcx.tcx(), &fty) }).unwrap(); let llty = type_of::type_of(bcx.ccx(), unsized_ty); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index e79618893c7f8..62286b7995aa4 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -245,14 +245,14 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elems) => { Univariant(mk_struct(cx, &elems[..], false, t), 0) } - ty::TyStruct(def_id, substs) => { - let fields = cx.tcx().lookup_struct_fields(def_id); + ty::TyStruct(def, substs) => { + let fields = cx.tcx().lookup_struct_fields(def.did); let mut ftys = fields.iter().map(|field| { - let fty = cx.tcx().lookup_field_type(def_id, field.id, substs); + let fty = cx.tcx().lookup_field_type(def.did, field.id, substs); monomorphize::normalize_associated_type(cx.tcx(), &fty) }).collect::>(); - let packed = cx.tcx().lookup_packed(def_id); - let dtor = cx.tcx().ty_dtor(def_id).has_drop_flag(); + let packed = cx.tcx().lookup_packed(def.did); + let dtor = cx.tcx().ty_dtor(def.did).has_drop_flag(); if dtor { ftys.push(cx.tcx().dtor_type()); } @@ -262,12 +262,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyClosure(_, ref substs) => { Univariant(mk_struct(cx, &substs.upvar_tys, false, t), 0) } - ty::TyEnum(def_id, substs) => { - let cases = get_cases(cx.tcx(), def_id, substs); - let hint = *cx.tcx().lookup_repr_hints(def_id).get(0) + ty::TyEnum(def, substs) => { + let cases = get_cases(cx.tcx(), def.did, substs); + let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) .unwrap_or(&attr::ReprAny); - let dtor = cx.tcx().ty_dtor(def_id).has_drop_flag(); + let dtor = cx.tcx().ty_dtor(def.did).has_drop_flag(); if cases.is_empty() { // Uninhabitable; represent as unit @@ -296,7 +296,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as Disr)) { cx.sess().bug(&format!("non-C-like enum {} with specified \ discriminants", - cx.tcx().item_path_str(def_id))); + cx.tcx().item_path_str(def.did))); } if cases.len() == 1 { @@ -443,10 +443,10 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty::TyBareFn(..) => Some(path), // Is this the NonZero lang item wrapping a pointer or integer type? - ty::TyStruct(did, substs) if Some(did) == tcx.lang_items.non_zero() => { - let nonzero_fields = tcx.lookup_struct_fields(did); + ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { + let nonzero_fields = tcx.lookup_struct_fields(def.did); assert_eq!(nonzero_fields.len(), 1); - let nonzero_field = tcx.lookup_field_type(did, nonzero_fields[0].id, substs); + let nonzero_field = tcx.lookup_field_type(def.did, nonzero_fields[0].id, substs); match nonzero_field.sty { ty::TyRawPtr(ty::TypeAndMut { ty, .. }) if !type_is_sized(tcx, ty) => { path.push_all(&[0, FAT_PTR_ADDR]); @@ -462,10 +462,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::TyStruct(def_id, substs) => { - let fields = tcx.lookup_struct_fields(def_id); + ty::TyStruct(def, substs) => { + let fields = tcx.lookup_struct_fields(def.did); for (j, field) in fields.iter().enumerate() { - let field_ty = tcx.lookup_field_type(def_id, field.id, substs); + let field_ty = tcx.lookup_field_type(def.did, field.id, substs); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { fpath.push(j); return Some(fpath); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index adc678f2c0e20..25e139474bd4d 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -455,12 +455,12 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, cx = f(cx, llfld_a, *arg); } } - ty::TyEnum(tid, substs) => { + ty::TyEnum(en, substs) => { let fcx = cx.fcx; let ccx = fcx.ccx; let repr = adt::represent_type(ccx, t); - let variants = ccx.tcx().enum_variants(tid); + let variants = ccx.tcx().enum_variants(en.did); let n_variants = (*variants).len(); // NB: we must hit the discriminant first so that structural diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 0de870de7c6d4..cfb8770084254 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -173,10 +173,10 @@ fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyStruct(def_id, substs) => { - let fields = ccx.tcx().lookup_struct_fields(def_id); + ty::TyStruct(def, substs) => { + let fields = ccx.tcx().lookup_struct_fields(def.did); fields.len() == 1 && { - let ty = ccx.tcx().lookup_field_type(def_id, fields[0].id, substs); + let ty = ccx.tcx().lookup_field_type(def.did, fields[0].id, substs); let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty); type_is_immediate(ccx, ty) } diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index b8feecd0a5559..e7499ad9301ad 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -178,13 +178,13 @@ impl<'tcx> TypeMap<'tcx> { ty::TyFloat(_) => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, - ty::TyEnum(def_id, substs) => { + ty::TyEnum(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.did, substs, &mut unique_type_id); }, - ty::TyStruct(def_id, substs) => { + ty::TyStruct(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.did, substs, &mut unique_type_id); }, ty::TyTuple(ref component_types) if component_types.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); @@ -710,8 +710,12 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::TyEnum(def_id, _) => { - prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx) + ty::TyEnum(def, _) => { + prepare_enum_metadata(cx, + t, + def.did, + unique_type_id, + usage_site_span).finalize(cx) } ty::TyArray(typ, len) => { fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span) @@ -780,10 +784,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } - ty::TyStruct(def_id, substs) => { + ty::TyStruct(def, substs) => { prepare_struct_metadata(cx, t, - def_id, + def.did, substs, unique_type_id, usage_site_span).finalize(cx) diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs index 4835cfc4a253f..120134800b000 100644 --- a/src/librustc_trans/trans/debuginfo/type_names.rs +++ b/src/librustc_trans/trans/debuginfo/type_names.rs @@ -54,9 +54,9 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyUint(ast::TyU64) => output.push_str("u64"), ty::TyFloat(ast::TyF32) => output.push_str("f32"), ty::TyFloat(ast::TyF64) => output.push_str("f64"), - ty::TyStruct(def_id, substs) | - ty::TyEnum(def_id, substs) => { - push_item_name(cx, def_id, qualified, output); + ty::TyStruct(def, substs) | + ty::TyEnum(def, substs) => { + push_item_name(cx, def.did, qualified, output); push_type_params(cx, substs, output); }, ty::TyTuple(ref component_types) => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 01173b7f6dff3..36eff73199506 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1125,7 +1125,8 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, None, expr.span, expr.id, - tcx.mk_struct(did, tcx.mk_substs(substs)), + tcx.mk_struct(tcx.lookup_adt_def(did), + tcx.mk_substs(substs)), dest) } else { tcx.sess.span_bug(expr.span, @@ -1268,7 +1269,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def::DefStruct(_) => { let ty = expr_ty(bcx, ref_expr); match ty.sty { - ty::TyStruct(did, _) if bcx.tcx().has_dtor(did) => { + ty::TyStruct(def, _) if def.has_dtor(bcx.tcx()) => { let repr = adt::represent_type(bcx.ccx(), ty); adt::trans_set_discr(bcx, &*repr, lldest, 0); } @@ -1372,8 +1373,8 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, F: FnOnce(ty::Disr, &[ty::Field<'tcx>]) -> R, { match ty.sty { - ty::TyStruct(did, substs) => { - let fields = tcx.struct_fields(did, substs); + ty::TyStruct(def, substs) => { + let fields = tcx.struct_fields(def.did, substs); let fields = monomorphize::normalize_associated_type(tcx, &fields); op(0, &fields[..]) } diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 18fedda49193c..d07776c3d9190 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -415,7 +415,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in return (size, align); } match t.sty { - ty::TyStruct(id, substs) => { + ty::TyStruct(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. @@ -432,7 +432,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in // Recurse to get the size of the dynamically sized field (must be // the last field). - let fields = bcx.tcx().struct_fields(id, substs); + let fields = bcx.tcx().struct_fields(def.did, substs); let last_field = fields[fields.len()-1]; let field_ty = last_field.mt.ty; let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info); @@ -562,27 +562,27 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK }) } } - ty::TyStruct(did, substs) | ty::TyEnum(did, substs) => { + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { let tcx = bcx.tcx(); - match (tcx.ty_dtor(did), skip_dtor) { + match (tcx.ty_dtor(def.did), skip_dtor) { (ty::TraitDtor(dtor, true), false) => { // FIXME(16758) Since the struct is unsized, it is hard to // find the drop flag (which is at the end of the struct). // Lets just ignore the flag and pretend everything will be // OK. if type_is_sized(bcx.tcx(), t) { - trans_struct_drop_flag(bcx, t, v0, dtor, did, substs) + trans_struct_drop_flag(bcx, t, v0, dtor, def.did, substs) } else { // Give the user a heads up that we are doing something // stupid and dangerous. bcx.sess().warn(&format!("Ignoring drop flag in destructor for {}\ because the struct is unsized. See issue\ #16758", t)); - trans_struct_drop(bcx, t, v0, dtor, did, substs) + trans_struct_drop(bcx, t, v0, dtor, def.did, substs) } } (ty::TraitDtor(dtor, false), false) => { - trans_struct_drop(bcx, t, v0, dtor, did, substs) + trans_struct_drop(bcx, t, v0, dtor, def.did, substs) } (ty::NoDtor, _) | (_, true) => { // No dtor? Just the default case diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index c5161a8bc2e78..91247ebd7919d 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -333,14 +333,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::TyInt(t) => Type::int_from_ty(cx, t), ty::TyUint(t) => Type::uint_from_ty(cx, t), ty::TyFloat(t) => Type::float_from_ty(cx, t), - ty::TyEnum(did, ref substs) => { + ty::TyEnum(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.did, tps); adt::incomplete_type_of(cx, &*repr, &name[..]) } ty::TyClosure(..) => { @@ -403,7 +403,7 @@ 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::TyStruct(did, ref substs) => { + ty::TyStruct(def, ref substs) => { if t.is_simd(cx.tcx()) { let llet = in_memory_type_of(cx, t.simd_type(cx.tcx())); let n = t.simd_size(cx.tcx()) as u64; @@ -415,7 +415,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.did, 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 b853a5300e2b0..b0b1acb445c2b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -528,7 +528,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, let tcx = pcx.fcx.ccx.tcx; let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); - let (enum_def_id, variant_def_id) = match def { + let (adt_def, variant_def_id) = match def { def::DefTrait(_) => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0168, @@ -543,11 +543,12 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, _ => { let def_type = tcx.lookup_item_type(def.def_id()); match def_type.ty.sty { - ty::TyStruct(struct_def_id, _) => - (struct_def_id, struct_def_id), - ty::TyEnum(enum_def_id, _) - if def == def::DefVariant(enum_def_id, def.def_id(), true) => - (enum_def_id, def.def_id()), + ty::TyStruct(struct_def, _) => + (struct_def, struct_def.did), + ty::TyEnum(enum_def, _) + // TODO: wut? + if def == def::DefVariant(enum_def.did, def.def_id(), true) => + (enum_def, def.def_id()), _ => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0163, @@ -565,8 +566,8 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, instantiate_path(pcx.fcx, &path.segments, - tcx.lookup_item_type(enum_def_id), - &tcx.lookup_predicates(enum_def_id), + adt_def.type_scheme(tcx), + &adt_def.predicates(tcx), None, def, pat.span, @@ -647,17 +648,17 @@ 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::TyEnum(enum_def_id, expected_substs) - if def == def::DefVariant(enum_def_id, def.def_id(), false) => + ty::TyEnum(enum_def, expected_substs) + if def == def::DefVariant(enum_def.did, def.def_id(), false) => { - let variant = tcx.enum_variant_with_id(enum_def_id, def.def_id()); + let variant = tcx.enum_variant_with_id(enum_def.did, def.def_id()); (variant.args.iter() .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t)) .collect(), "variant") } - ty::TyStruct(struct_def_id, expected_substs) => { - let struct_fields = tcx.struct_fields(struct_def_id, expected_substs); + ty::TyStruct(struct_def, expected_substs) => { + let struct_fields = tcx.struct_fields(struct_def.did, expected_substs); (struct_fields.iter() .map(|field| fcx.instantiate_type_scheme(pat.span, expected_substs, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 883b972872f50..5d93e2ae5d379 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -79,8 +79,8 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), - ty::TyStruct(did, substs) => { - match fcx.tcx().struct_fields(did, substs).pop() { + ty::TyStruct(def, substs) => { + match fcx.tcx().struct_fields(def.did, substs).pop() { None => None, Some(f) => unsize_kind(fcx, f.mt.ty) } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 24e67860998d5..7cb2198c68ddf 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -41,18 +41,18 @@ pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ty: dtor_self_type } = tcx.lookup_item_type(drop_impl_did); let dtor_predicates = tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { - ty::TyEnum(self_type_did, self_to_impl_substs) | - ty::TyStruct(self_type_did, self_to_impl_substs) => { + ty::TyEnum(adt_def, self_to_impl_substs) | + ty::TyStruct(adt_def, self_to_impl_substs) => { try!(ensure_drop_params_and_item_params_correspond(tcx, drop_impl_did, dtor_generics, &dtor_self_type, - self_type_did)); + adt_def.did)); ensure_drop_predicates_are_implied_by_item_defn(tcx, drop_impl_did, &dtor_predicates, - self_type_did, + adt_def.did, self_to_impl_substs) } _ => { @@ -357,8 +357,6 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( return Err(Error::Overflow(context, ty)) } - let opt_phantom_data_def_id = tcx.lang_items.phantom_data(); - if !cx.breadcrumbs.insert(ty) { debug!("iterate_over_potentially_unsafe_regions_in_type \ {}ty: {} scope: {:?} - cached", @@ -399,7 +397,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( // type parameters are unbounded. If both conditions hold, we // simply skip the `type_must_outlive` call entirely (but // resume the recursive checking of the type-substructure). - if has_dtor_of_interest(tcx, ty, cx.span) { + if has_dtor_of_interest(tcx, ty) { debug!("iterate_over_potentially_unsafe_regions_in_type \ {}ty: {} - is a dtorck type!", (0..depth).map(|_| ' ').collect::(), @@ -432,14 +430,15 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( cx, context, ity, depth+1) } - ty::TyStruct(did, substs) if Some(did) == opt_phantom_data_def_id => { + ty::TyStruct(def, substs) if def.is_phantom_data() => { // PhantomData - behaves identically to T let ity = *substs.types.get(subst::TypeSpace, 0); iterate_over_potentially_unsafe_regions_in_type( cx, context, ity, depth+1) } - ty::TyStruct(did, substs) => { + ty::TyStruct(def, substs) => { + let did = def.did; let fields = tcx.lookup_struct_fields(did); for field in &fields { let fty = tcx.lookup_field_type(did, field.id, substs); @@ -457,7 +456,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( Ok(()) } - ty::TyEnum(did, substs) => { + ty::TyEnum(def, substs) => { + let did = def.did; let all_variant_info = tcx.substd_enum_variants(did, substs); for variant_info in &all_variant_info { for (i, fty) in variant_info.args.iter().enumerate() { @@ -510,102 +510,10 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( } fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>, - ty: ty::Ty<'tcx>, - span: Span) -> bool { + ty: ty::Ty<'tcx>) -> bool { match ty.sty { - ty::TyEnum(def_id, _) | ty::TyStruct(def_id, _) => { - let dtor_method_did = match tcx.destructor_for_type.borrow().get(&def_id) { - Some(def_id) => *def_id, - None => { - debug!("ty: {:?} has no dtor, and thus isn't a dropck type", ty); - return false; - } - }; - let impl_did = tcx.impl_of_method(dtor_method_did) - .unwrap_or_else(|| { - tcx.sess.span_bug( - span, "no Drop impl found for drop method") - }); - - let dtor_typescheme = tcx.lookup_item_type(impl_did); - let dtor_generics = dtor_typescheme.generics; - - let mut has_pred_of_interest = false; - - let mut seen_items = Vec::new(); - let mut items_to_inspect = vec![impl_did]; - 'items: while let Some(item_def_id) = items_to_inspect.pop() { - if seen_items.contains(&item_def_id) { - continue; - } - - for pred in tcx.lookup_predicates(item_def_id).predicates { - let result = match pred { - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::Projection(..) => { - // For now, assume all these where-clauses - // may give drop implementation capabilty - // to access borrowed data. - true - } - - ty::Predicate::Trait(ty::Binder(ref t_pred)) => { - let def_id = t_pred.trait_ref.def_id; - if tcx.trait_items(def_id).len() != 0 { - // If trait has items, assume it adds - // capability to access borrowed data. - true - } else { - // Trait without items is itself - // uninteresting from POV of dropck. - // - // However, may have parent w/ items; - // so schedule checking of predicates, - items_to_inspect.push(def_id); - // and say "no capability found" for now. - false - } - } - }; - - if result { - has_pred_of_interest = true; - debug!("ty: {:?} has interesting dtor due to generic preds, e.g. {:?}", - ty, pred); - break 'items; - } - } - - seen_items.push(item_def_id); - } - - // In `impl<'a> Drop ...`, we automatically assume - // `'a` is meaningful and thus represents a bound - // through which we could reach borrowed data. - // - // FIXME (pnkfelix): In the future it would be good to - // extend the language to allow the user to express, - // in the impl signature, that a lifetime is not - // actually used (something like `where 'a: ?Live`). - let has_region_param_of_interest = - dtor_generics.has_region_params(subst::TypeSpace); - - let has_dtor_of_interest = - has_region_param_of_interest || - has_pred_of_interest; - - if has_dtor_of_interest { - debug!("ty: {:?} has interesting dtor, due to \ - region params: {} or pred: {}", - ty, - has_region_param_of_interest, - has_pred_of_interest); - } else { - debug!("ty: {:?} has dtor, but it is uninteresting", ty); - } - has_dtor_of_interest + ty::TyEnum(def, _) | ty::TyStruct(def, _) => { + def.is_dtorck(tcx) } ty::TyTrait(..) | ty::TyProjection(..) => { debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 44d769a799f1d..2ff40b3590d29 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -286,10 +286,9 @@ 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::TyEnum(did, _) | - ty::TyStruct(did, _) | - ty::TyClosure(did, _) => { - self.assemble_inherent_impl_candidates_for_type(did); + ty::TyEnum(def, _) | + ty::TyStruct(def, _) => { + self.assemble_inherent_impl_candidates_for_type(def.did); } ty::TyBox(_) => { if let Some(box_did) = self.tcx().lang_items.owned_box() { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f14886606c218..970589fb9c50e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -65,8 +65,8 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None); // If the item has the name of a field, give a help note - if let (&ty::TyStruct(did, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { - let fields = cx.lookup_struct_fields(did); + if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { + let fields = cx.lookup_struct_fields(def.did); if let Some(field) = fields.iter().find(|f| f.name == item_name) { let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { @@ -89,7 +89,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; // Determine if the field can be used as a function in some way - let field_ty = cx.lookup_field_type(did, field.id, substs); + let field_ty = cx.lookup_field_type(def.did, field.id, substs); if let Ok(fn_once_trait_did) = cx.lang_items.require(FnOnceTraitLangItem) { let infcx = fcx.infcx(); infcx.probe(|_| { @@ -303,7 +303,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::TyEnum(did, _) | ty::TyStruct(did, _) => ast_util::is_local(did), + ty::TyEnum(def, _) | ty::TyStruct(def, _) => ast_util::is_local(def.did), ty::TyTrait(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 6851fb4667015..5e5886cd13ce2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1678,27 +1678,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Indifferent to privacy flags pub fn lookup_field_ty(&self, span: Span, - class_id: ast::DefId, + struct_def: &'tcx ty::ADTDef<'tcx>, items: &[ty::FieldTy], fieldname: ast::Name, substs: &subst::Substs<'tcx>) -> Option> { let o_field = items.iter().find(|f| f.name == fieldname); - o_field.map(|f| self.tcx().lookup_field_type(class_id, f.id, substs)) + o_field.map(|f| self.tcx().lookup_field_type(struct_def.did, f.id, substs)) .map(|t| self.normalize_associated_types_in(span, &t)) } pub fn lookup_tup_field_ty(&self, span: Span, - class_id: ast::DefId, + struct_def: &'tcx ty::ADTDef<'tcx>, items: &[ty::FieldTy], idx: usize, substs: &subst::Substs<'tcx>) -> Option> { let o_field = if idx < items.len() { Some(&items[idx]) } else { None }; - o_field.map(|f| self.tcx().lookup_field_type(class_id, f.id, substs)) + o_field.map(|f| self.tcx().lookup_field_type(struct_def.did, f.id, substs)) .map(|t| self.normalize_associated_types_in(span, &t)) } @@ -2878,10 +2878,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref, |base_t, _| { match base_t.sty { - ty::TyStruct(base_id, substs) => { + ty::TyStruct(base_def, substs) => { debug!("struct named {:?}", base_t); - let fields = tcx.lookup_struct_fields(base_id); - fcx.lookup_field_ty(expr.span, base_id, &fields[..], + let fields = tcx.lookup_struct_fields(base_def.did); + fcx.lookup_field_ty(expr.span, base_def, &fields[..], field.node.name, &(*substs)) } _ => None @@ -2919,8 +2919,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, actual) }, expr_t, None); - if let ty::TyStruct(did, _) = expr_t.sty { - suggest_field_names(did, field, tcx, vec![]); + if let ty::TyStruct(def, _) = expr_t.sty { + suggest_field_names(def.did, field, tcx, vec![]); } } @@ -2928,14 +2928,14 @@ 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, - field : &ast::SpannedIdent, - tcx : &ty::ctxt<'tcx>, + fn suggest_field_names<'tcx>(variant_id: ast::DefId, + field: &ast::SpannedIdent, + tcx: &ty::ctxt<'tcx>, skip : Vec) { let name = field.node.name.as_str(); // only find fits with at least one matching letter let mut best_dist = name.len(); - let fields = tcx.lookup_struct_fields(id); + let fields = tcx.lookup_struct_fields(variant_id); let mut best = None; for elem in &fields { let n = elem.name.as_str(); @@ -2944,7 +2944,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, continue; } // ignore private fields from non-local crates - if id.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public { + if variant_id.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public { continue; } let dist = lev_distance(&n, &name); @@ -2979,12 +2979,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref, |base_t, _| { match base_t.sty { - ty::TyStruct(base_id, substs) => { - tuple_like = tcx.is_tuple_struct(base_id); + ty::TyStruct(base_def, substs) => { + tuple_like = base_def.is_tuple_struct(tcx); if tuple_like { debug!("tuple struct named {:?}", base_t); - let fields = tcx.lookup_struct_fields(base_id); - fcx.lookup_tup_field_ty(expr.span, base_id, &fields[..], + let fields = tcx.lookup_struct_fields(base_def.did); + fcx.lookup_tup_field_ty(expr.span, base_def, &fields[..], idx.node, &(*substs)) } else { None @@ -3026,16 +3026,19 @@ 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>, + adt_ty: Ty<'tcx>, span: Span, - class_id: ast::DefId, - node_id: ast::NodeId, + variant_id: ast::DefId, substitutions: &'tcx subst::Substs<'tcx>, field_types: &[ty::FieldTy], ast_fields: &'tcx [ast::Field], - check_completeness: bool, - enum_id_opt: Option) { + check_completeness: bool) -> Result<(),()> { let tcx = fcx.ccx.tcx; + let (adt_def, is_enum) = match adt_ty.sty { + ty::TyStruct(def, _) => (def, false), + ty::TyEnum(def, _) => (def, true), + _ => tcx.sess.span_bug(span, "non-ADT passed to check_struct_or_variant_fields") + }; let mut class_field_map = FnvHashMap(); let mut fields_found = 0; @@ -3054,29 +3057,22 @@ 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 = tcx.enum_variant_with_id(enum_id, - class_id); - format!("struct variant `{}::{}` has no field named `{}`", - actual, variant_type.name.as_str(), + |actual| if is_enum { + let variant_type = tcx.enum_variant_with_id(adt_def.did, + variant_id); + format!("struct variant `{}::{}` has no field named `{}`", + actual, variant_type.name.as_str(), field.ident.node) - } - None => { - format!("structure `{}` has no field named `{}`", - actual, + } else { + format!("structure `{}` has no field named `{}`", + actual, field.ident.node) - } }, - struct_ty, + adt_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 => struct_ty.ty_to_def_id().unwrap() - }; - suggest_field_names(actual_id, &field.ident, tcx, skip_fields.collect()); + suggest_field_names(variant_id, &field.ident, tcx, skip_fields.collect()); error_happened = true; } Some((_, true)) => { @@ -3087,7 +3083,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } Some((field_id, false)) => { expected_field_type = - tcx.lookup_field_type(class_id, field_id, substitutions); + tcx.lookup_field_type(variant_id, field_id, substitutions); expected_field_type = fcx.normalize_associated_types_in( field.span, &expected_field_type); @@ -3102,10 +3098,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type); } - if error_happened { - fcx.write_error(node_id); - } - if check_completeness && !error_happened { // Make sure the programmer specified all the fields. assert!(fields_found <= field_types.len()); @@ -3127,15 +3119,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } - if !error_happened { - fcx.write_ty(node_id, fcx.ccx.tcx.mk_struct(class_id, substitutions)); - } + if error_happened { Err(()) } else { Ok(()) } } fn check_struct_constructor<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, id: ast::NodeId, span: codemap::Span, - class_id: ast::DefId, + struct_def: &'tcx ty::ADTDef<'tcx>, fields: &'tcx [ast::Field], base_expr: Option<&'tcx ast::Expr>) { let tcx = fcx.ccx.tcx; @@ -3144,21 +3134,19 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let TypeAndSubsts { ty: mut struct_type, substs: struct_substs - } = fcx.instantiate_type(span, class_id); + } = fcx.instantiate_type(span, struct_def.did); // Look up and check the fields. - let class_fields = tcx.lookup_struct_fields(class_id); - check_struct_or_variant_fields(fcx, - struct_type, - span, - class_id, - id, - fcx.ccx.tcx.mk_substs(struct_substs), - &class_fields[..], - fields, - base_expr.is_none(), - None); - if fcx.node_ty(id).references_error() { + let class_fields = tcx.lookup_struct_fields(struct_def.did); + let res = check_struct_or_variant_fields(fcx, + struct_type, + span, + struct_def.did, + fcx.ccx.tcx.mk_substs(struct_substs), + &class_fields[..], + fields, + base_expr.is_none()); + if res.is_err() { struct_type = tcx.types.err; } @@ -3191,16 +3179,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Look up and check the enum variant fields. let variant_fields = tcx.lookup_struct_fields(variant_id); - check_struct_or_variant_fields(fcx, - enum_type, - span, - variant_id, - id, - fcx.ccx.tcx.mk_substs(substitutions), - &variant_fields[..], - fields, - true, - Some(enum_id)); + let _ = check_struct_or_variant_fields(fcx, + enum_type, + span, + variant_id, + fcx.ccx.tcx.mk_substs(substitutions), + &variant_fields[..], + fields, + true); fcx.write_ty(id, enum_type); } @@ -3695,11 +3681,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Verify that this was actually a struct. let typ = fcx.ccx.tcx.lookup_item_type(def.def_id()); match typ.ty.sty { - ty::TyStruct(struct_did, _) => { + ty::TyStruct(struct_def, _) => { check_struct_constructor(fcx, id, expr.span, - struct_did, + struct_def, &fields[..], base_expr.as_ref().map(|e| &**e)); } @@ -3835,6 +3821,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; if let Some(did) = did { + let def = tcx.lookup_adt_def(did); let predicates = tcx.lookup_predicates(did); let substs = Substs::new_type(vec![idx_type], vec![]); let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates); @@ -3844,7 +3831,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, traits::ItemObligation(did)), &bounds); - tcx.mk_struct(did, tcx.mk_substs(substs)) + tcx.mk_struct(def, tcx.mk_substs(substs)) } else { span_err!(tcx.sess, expr.span, E0236, "no lang item for range syntax"); fcx.tcx().types.err @@ -3853,8 +3840,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, None => { // Neither start nor end => RangeFull if let Some(did) = tcx.lang_items.range_full_struct() { - let substs = Substs::new_type(vec![], vec![]); - tcx.mk_struct(did, tcx.mk_substs(substs)) + tcx.mk_struct( + tcx.lookup_adt_def(did), + tcx.mk_substs(Substs::empty()) + ) } else { span_err!(tcx.sess, expr.span, E0237, "no lang item for range syntax"); fcx.tcx().types.err @@ -4305,15 +4294,15 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { return; } match t.sty { - ty::TyStruct(did, substs) => { - let fields = tcx.lookup_struct_fields(did); + ty::TyStruct(def, substs) => { + let fields = tcx.lookup_struct_fields(def.did); if fields.is_empty() { span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); return; } - let e = tcx.lookup_field_type(did, fields[0].id, substs); + let e = tcx.lookup_field_type(def.did, fields[0].id, substs); if !fields.iter().all( - |f| tcx.lookup_field_type(did, f.id, substs) == e) { + |f| tcx.lookup_field_type(def.did, f.id, substs) == e) { span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); return; } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index cfb7dfc54aaea..7790a29db12f7 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -571,9 +571,9 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { } match t.sty{ - ty::TyStruct(type_id, substs) | - ty::TyEnum(type_id, substs) => { - let type_predicates = self.fcx.tcx().lookup_predicates(type_id); + ty::TyStruct(def, substs) | + ty::TyEnum(def, substs) => { + let type_predicates = def.predicates(self.fcx.tcx()); let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_predicates); @@ -581,7 +581,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { self.fcx.add_obligations_for_parameters( traits::ObligationCause::new(self.span, self.fcx.body_id, - traits::ItemObligation(type_id)), + traits::ItemObligation(def.did)), &bounds); } else { // There are two circumstances in which we ignore @@ -610,7 +610,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { self.fcx.add_obligations_for_parameters( traits::ObligationCause::new(self.span, self.fcx.body_id, - traits::ItemObligation(type_id)), + traits::ItemObligation(def.did)), &bounds); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 418d592c9627b..cd4063ac454ed 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -55,9 +55,9 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Option { match ty.sty { - TyEnum(def_id, _) | - TyStruct(def_id, _) => { - Some(def_id) + TyEnum(def, _) | + TyStruct(def, _) => { + Some(def.did) } TyTrait(ref t) => { @@ -310,12 +310,11 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { - ty::TyEnum(type_def_id, _) | - ty::TyStruct(type_def_id, _) | - ty::TyClosure(type_def_id, _) => { + ty::TyEnum(type_def, _) | + ty::TyStruct(type_def, _) => { tcx.destructor_for_type .borrow_mut() - .insert(type_def_id, method_def_id.def_id()); + .insert(type_def.did, method_def_id.def_id()); tcx.destructors .borrow_mut() .insert(method_def_id.def_id()); @@ -471,10 +470,10 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) } - (&ty::TyStruct(def_id_a, substs_a), &ty::TyStruct(def_id_b, substs_b)) => { - if def_id_a != def_id_b { - let source_path = tcx.item_path_str(def_id_a); - let target_path = tcx.item_path_str(def_id_b); + (&ty::TyStruct(def_a, substs_a), &ty::TyStruct(def_b, substs_b)) => { + if def_a != def_b { + let source_path = tcx.item_path_str(def_a.did); + let target_path = tcx.item_path_str(def_b.did); span_err!(tcx.sess, span, E0377, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with the same \ @@ -484,9 +483,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let origin = infer::Misc(span); - let fields = tcx.lookup_struct_fields(def_id_a); + let fields = tcx.lookup_struct_fields(def_a.did); let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { - let ty = tcx.lookup_field_type_unsubstituted(def_id_a, f.id); + let ty = tcx.lookup_field_type_unsubstituted(def_a.did, f.id); let (a, b) = (ty.subst(tcx, substs_a), ty.subst(tcx, substs_b)); if infcx.sub_types(false, origin, b, a).is_ok() { None diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 494e2eaa77bb8..8076e63cc55c5 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -69,9 +69,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { self.tcx.map.node_to_string(item.id)); let self_ty = self.tcx.lookup_item_type(def_id).ty; match self_ty.sty { - ty::TyEnum(def_id, _) | - ty::TyStruct(def_id, _) => { - self.check_def_id(item, def_id); + ty::TyEnum(def, _) | + ty::TyStruct(def, _) => { + self.check_def_id(item, def.did); } ty::TyTrait(ref data) => { self.check_def_id(item, data.principal_def_id()); @@ -279,8 +279,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { - ty::TyStruct(self_def_id, _) | ty::TyEnum(self_def_id, _) => - Some(self_def_id), + ty::TyStruct(self_def, _) | ty::TyEnum(self_def, _) => + Some(self_def.did), ty::TyBox(..) => self.tcx.lang_items.owned_box(), _ => diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5b65f78083072..0fed9343536a9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1103,39 +1103,37 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.struct_fields.borrow_mut().insert(local_def(id), Rc::new(field_tys)); - let substs = mk_item_substs(ccx, &scheme.generics); - let selfty = tcx.mk_struct(local_def(id), tcx.mk_substs(substs)); // If this struct is enum-like or tuple-like, create the type of its // constructor. - match struct_def.ctor_id { - None => {} - Some(ctor_id) => { - if struct_def.fields.is_empty() { - // Enum-like. - write_ty_to_tcx(tcx, ctor_id, selfty); - - tcx.register_item_type(local_def(ctor_id), scheme); - tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); - } else if struct_def.fields[0].node.kind.is_unnamed() { - // Tuple-like. - let inputs: Vec<_> = - struct_def.fields - .iter() - .map(|field| tcx.lookup_item_type( - local_def(field.node.id)).ty) - .collect(); - let ctor_fn_ty = tcx.mk_ctor_fn(local_def(ctor_id), - &inputs[..], - selfty); - write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); - tcx.register_item_type(local_def(ctor_id), - TypeScheme { - generics: scheme.generics, - ty: ctor_fn_ty - }); - tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); - } + if let Some(ctor_id) = struct_def.ctor_id { + let substs = mk_item_substs(ccx, &scheme.generics); + let selfty = tcx.mk_struct(tcx.lookup_adt_def(local_def(id)), + tcx.mk_substs(substs)); + if struct_def.fields.is_empty() { + // Enum-like. + write_ty_to_tcx(tcx, ctor_id, selfty); + + tcx.register_item_type(local_def(ctor_id), scheme); + tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); + } else if struct_def.fields[0].node.kind.is_unnamed() { + // Tuple-like. + let inputs: Vec<_> = + struct_def.fields + .iter() + .map(|field| tcx.lookup_item_type( + local_def(field.node.id)).ty) + .collect(); + let ctor_fn_ty = tcx.mk_ctor_fn(local_def(ctor_id), + &inputs[..], + selfty); + write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); + tcx.register_item_type(local_def(ctor_id), + TypeScheme { + generics: scheme.generics, + ty: ctor_fn_ty + }); + tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); } } } @@ -1475,13 +1473,15 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // Create a new generic polytype. let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let t = tcx.mk_enum(local_def(it.id), tcx.mk_substs(substs)); + let def = tcx.intern_adt_def(local_def(it.id)); + let t = tcx.mk_enum(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } ast::ItemStruct(_, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let t = tcx.mk_struct(local_def(it.id), tcx.mk_substs(substs)); + let def = tcx.intern_adt_def(local_def(it.id)); + let t = tcx.mk_struct(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } ast::ItemDefaultImpl(..) | diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 4af23a27c941c..3721f9a0b105c 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -902,9 +902,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - ty::TyEnum(def_id, substs) | - ty::TyStruct(def_id, substs) => { - let item_type = self.tcx().lookup_item_type(def_id); + ty::TyEnum(def, substs) | + ty::TyStruct(def, substs) => { + let item_type = self.tcx().lookup_item_type(def.did); // All type parameters on enums and structs should be // in the TypeSpace. @@ -915,7 +915,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_substs( generics, - def_id, + def.did, item_type.generics.types.get_slice(subst::TypeSpace), item_type.generics.regions.get_slice(subst::TypeSpace), substs, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 31cd8ce1b53e5..582927782a4bd 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -204,11 +204,11 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn let t = tcx.lookup_item_type(did); let predicates = tcx.lookup_predicates(did); match t.ty.sty { - ty::TyEnum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => { + ty::TyEnum(edef, _) 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: tcx.enum_variants(edid).clean(cx), + variants: tcx.enum_variants(edef.did).clean(cx), }) } _ => {} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 11a0e0eaa496e..ac8727912191f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1658,8 +1658,9 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (ast_util::local_def(0), &fty.sig).clean(cx), abi: fty.abi.to_string(), }), - ty::TyStruct(did, substs) | - ty::TyEnum(did, substs) => { + ty::TyStruct(def, substs) | + ty::TyEnum(def, substs) => { + let did = def.did; let fqn = csearch::get_item_path(cx.tcx(), did); let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect(); let kind = match self.sty { From 213b6d71f502a8568208cf549050a71cc24b1338 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 22 Jul 2015 20:10:18 +0300 Subject: [PATCH 03/14] add variant info to ADTDef, but don't actually use it --- src/librustc/lib.rs | 3 + src/librustc/metadata/decoder.rs | 3 +- src/librustc/middle/ty.rs | 117 +++++++++++++++++++++++++++---- src/librustc_typeck/collect.rs | 4 +- 4 files changed, 112 insertions(+), 15 deletions(-) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c38345a79fd70..1a15d98d53150 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -32,6 +32,7 @@ #![feature(clone_from_slice)] #![feature(collections)] #![feature(const_fn)] +#![feature(core)] #![feature(duration)] #![feature(duration_span)] #![feature(dynamic_lib)] @@ -42,6 +43,7 @@ #![feature(iter_cmp)] #![feature(iter_arith)] #![feature(libc)] +#![feature(nonzero)] #![feature(num_bits_bytes)] #![feature(path_ext)] #![feature(quote)] @@ -65,6 +67,7 @@ #![allow(trivial_casts)] extern crate arena; +extern crate core; extern crate flate; extern crate fmt_macros; extern crate getopts; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 7e955ad7338c1..9e8c5505c89eb 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -394,7 +394,8 @@ pub fn get_adt_def<'tcx>(cdata: Cmd, item_id: ast::NodeId, tcx: &ty::ctxt<'tcx>) -> &'tcx ty::ADTDef<'tcx> { - tcx.intern_adt_def(ast::DefId { krate: cdata.cnum, node: item_id }) + tcx.intern_adt_def(ast::DefId { krate: cdata.cnum, node: item_id }, + ty::ADTKind::Enum) } pub fn get_predicates<'tcx>(cdata: Cmd, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9b5943e7d3035..a491d6e65b7d8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -74,12 +74,15 @@ use std::cell::{Cell, RefCell, Ref}; use std::cmp; use std::fmt; use std::hash::{Hash, SipHasher, Hasher}; +use std::marker::PhantomData; use std::mem; use std::ops; use std::rc::Rc; use std::vec::IntoIter; use collections::enum_set::{self, EnumSet, CLike}; +use core::nonzero::NonZero; use std::collections::{HashMap, HashSet}; +use rustc_data_structures::ivar; use syntax::abi; use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; @@ -721,7 +724,7 @@ pub struct CtxtArenas<'tcx> { // references trait_defs: TypedArena>, - adt_defs: TypedArena>, + adt_defs: TypedArena>, } impl<'tcx> CtxtArenas<'tcx> { @@ -1020,9 +1023,10 @@ impl<'tcx> ctxt<'tcx> { interned } - pub fn intern_adt_def(&self, did: DefId) -> &'tcx ADTDef<'tcx> { - let def = ADTDef::new(self, did); + pub fn intern_adt_def(&self, did: DefId, kind: ADTKind) -> &'tcx ADTDef_<'tcx, 'tcx> { + let def = ADTDef_::new(self, did, kind); let interned = self.arenas.adt_defs.alloc(def); + // this will need a transmute when reverse-variance is removed self.adt_defs.borrow_mut().insert(did, interned); interned } @@ -1395,6 +1399,61 @@ impl<'tcx> Hash for TyS<'tcx> { pub type Ty<'tcx> = &'tcx TyS<'tcx>; +/// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound +/// on the lifetime of the IVar. This is required because of variance +/// problems: the IVar needs to be variant with respect to 'tcx (so +/// it can be referred to from Ty) but can only be modified if its +/// lifetime is exactly 'tcx. +/// +/// Safety invariants: +/// (A) self.0, if fulfilled, is a valid Ty<'tcx> +/// (B) no aliases to this value with a 'tcx longer than this +/// value's 'lt exist +/// +/// NonZero is used rather than Unique because Unique isn't Copy. +pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar>>, + PhantomData)->TyS<'tcx>>); + +impl<'tcx, 'lt> TyIVar<'tcx, 'lt> { + #[inline] + pub fn new() -> Self { + // Invariant (A) satisfied because the IVar is unfulfilled + // Invariant (B) because 'lt : 'tcx + TyIVar(ivar::Ivar::new(), PhantomData) + } + + #[inline] + pub fn get(&self) -> Option> { + match self.0.get() { + None => None, + // valid because of invariant (A) + Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) }) + } + } + #[inline] + pub fn unwrap(&self) -> Ty<'tcx> { + self.get().unwrap() + } + + pub fn fulfill(&self, value: Ty<'lt>) { + // Invariant (A) is fulfilled, because by (B), every alias + // of this has a 'tcx longer than 'lt. + let value: *const TyS<'lt> = value; + // FIXME(27214): unneeded [as *const ()] + let value = value as *const () as *const TyS<'static>; + self.0.fulfill(unsafe { NonZero::new(value) }) + } +} + +impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.get() { + Some(val) => write!(f, "TyIVar({:?})", val), + None => f.write_str("TyIVar()") + } + } +} + /// An entry in the type interner. pub struct InternedTy<'tcx> { ty: Ty<'tcx> @@ -3210,33 +3269,55 @@ bitflags! { const IS_PHANTOM_DATA = 1 << 1, const IS_DTORCK = 1 << 2, // is this a dtorck type? const IS_DTORCK_VALID = 1 << 3, + const IS_ENUM = 1 << 4 } } -/// The definition of an abstract data type - a struct or enum. -pub struct ADTDef<'tcx> { +pub type ADTDef<'tcx> = ADTDef_<'tcx, 'static>; + +pub struct VariantDef<'tcx, 'lt: 'tcx> { + pub did: DefId, + pub name: Name, // struct's name if this is a struct + pub disr_val: Disr, + pub fields: Vec> +} + +pub struct FieldDef<'tcx, 'lt: 'tcx> { + pub did: DefId, + pub name: Name, // XXX if tuple-like + pub vis: ast::Visibility, + // TyIVar is used here to allow for + ty: TyIVar<'tcx, 'lt> +} + +/// The definition of an abstract data type - a struct or enum. 'lt +/// is here so 'tcx can be variant. +pub struct ADTDef_<'tcx, 'lt: 'tcx> { pub did: DefId, + pub variants: Vec>, flags: Cell, - marker: ::std::marker::PhantomData<&'tcx ()>, } -impl<'tcx> PartialEq for ADTDef<'tcx> { +impl<'tcx, 'lt> PartialEq for ADTDef_<'tcx, 'lt> { // ADTDef are always interned and this is part of TyS equality #[inline] fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } } -impl<'tcx> Eq for ADTDef<'tcx> {} +impl<'tcx, 'lt> Eq for ADTDef_<'tcx, 'lt> {} -impl<'tcx> Hash for ADTDef<'tcx> { +impl<'tcx, 'lt> Hash for ADTDef_<'tcx, 'lt> { #[inline] fn hash(&self, s: &mut H) { (self as *const ADTDef).hash(s) } } -impl<'tcx> ADTDef<'tcx> { - fn new(tcx: &ctxt<'tcx>, did: DefId) -> Self { +#[derive(Copy, Clone, Debug)] +pub enum ADTKind { Struct, Enum } + +impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { + fn new(tcx: &ctxt<'tcx>, did: DefId, kind: ADTKind) -> Self { let mut flags = ADTFlags::NO_ADT_FLAGS; if tcx.has_attr(did, "fundamental") { flags = flags | ADTFlags::IS_FUNDAMENTAL; @@ -3244,10 +3325,13 @@ impl<'tcx> ADTDef<'tcx> { if Some(did) == tcx.lang_items.phantom_data() { flags = flags | ADTFlags::IS_PHANTOM_DATA; } + if let ADTKind::Enum = kind { + flags = flags | ADTFlags::IS_ENUM; + } ADTDef { did: did, + variants: vec![], flags: Cell::new(flags), - marker: ::std::marker::PhantomData } } @@ -3258,6 +3342,15 @@ impl<'tcx> ADTDef<'tcx> { self.flags.set(self.flags.get() | ADTFlags::IS_DTORCK_VALID) } + #[inline] + pub fn adt_kind(&self) -> ADTKind { + if self.flags.get().intersects(ADTFlags::IS_ENUM) { + ADTKind::Enum + } else { + ADTKind::Struct + } + } + #[inline] pub fn is_dtorck(&'tcx self, tcx: &ctxt<'tcx>) -> bool { if !self.flags.get().intersects(ADTFlags::IS_DTORCK_VALID) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0fed9343536a9..708825fc95ab0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1473,14 +1473,14 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // Create a new generic polytype. let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let def = tcx.intern_adt_def(local_def(it.id)); + let def = tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Enum); let t = tcx.mk_enum(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } ast::ItemStruct(_, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let def = tcx.intern_adt_def(local_def(it.id)); + let def = tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Struct); let t = tcx.mk_struct(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } From 4816e60667596718682ae70f6c34fed03288e07b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 22 Jul 2015 21:53:52 +0300 Subject: [PATCH 04/14] create VariantDef-s (but don't actually use them) --- src/librustc/metadata/csearch.rs | 4 +- src/librustc/metadata/decoder.rs | 109 +++++++++- src/librustc/metadata/encoder.rs | 92 ++++---- src/librustc/middle/check_match.rs | 2 +- src/librustc/middle/ty.rs | 151 +++++++++++-- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 327 +++++++++++++++++++---------- 7 files changed, 504 insertions(+), 183 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index b54e7707f6315..f97ffebaebb19 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -222,10 +222,10 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe decoder::get_trait_def(&*cdata, def.node, tcx) } -pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> &'tcx ty::ADTDef<'tcx> { +pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> &'tcx ty::ADTDef_<'tcx, 'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); - decoder::get_adt_def(&*cdata, def.node, tcx) + decoder::get_adt_def(&cstore.intr, &*cdata, def.node, tcx) } pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 9e8c5505c89eb..7a899218512f7 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -108,7 +108,7 @@ fn lookup_item<'a>(item_id: ast::NodeId, data: &'a [u8]) -> rbml::Doc<'a> { find_item(item_id, items) } -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] enum Family { ImmStatic, // c MutStatic, // b @@ -390,12 +390,111 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, } } -pub fn get_adt_def<'tcx>(cdata: Cmd, +pub fn get_adt_def<'tcx>(intr: &IdentInterner, + cdata: Cmd, item_id: ast::NodeId, - tcx: &ty::ctxt<'tcx>) -> &'tcx ty::ADTDef<'tcx> + tcx: &ty::ctxt<'tcx>) -> &'tcx ty::ADTDef_<'tcx, 'tcx> { - tcx.intern_adt_def(ast::DefId { krate: cdata.cnum, node: item_id }, - ty::ADTKind::Enum) + fn get_enum_variants<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) -> Vec> { + let mut disr_val = 0; + reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { + let did = translated_def_id(cdata, p); + let item = lookup_item(did.node, cdata.data()); + + if let Some(disr) = variant_disr_val(item) { + disr_val = disr; + } + let disr = disr_val; + disr_val = disr_val.wrapping_add(1); + + ty::VariantDef_ { + did: did, + name: item_name(intr, item), + fields: get_variant_fields(intr, cdata, item, tcx), + disr_val: disr + } + }).collect() + } + fn get_variant_fields<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>) -> Vec> { + reader::tagged_docs(doc, tag_item_field).map(|f| { + let ff = item_family(f); + match ff { + PublicField | InheritedField => {}, + _ => tcx.sess.bug(&format!("expected field, found {:?}", ff)) + }; + ty::FieldDef_::new(item_def_id(f, cdata), + item_name(intr, f), + struct_field_family_to_visibility(ff)) + }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| { + let ff = item_family(f); + ty::FieldDef_::new(item_def_id(f, cdata), + special_idents::unnamed_field.name, + struct_field_family_to_visibility(ff)) + })).collect() + } + fn get_struct_variant<'tcx>(intr: &IdentInterner, + cdata: Cmd, + doc: rbml::Doc, + did: ast::DefId, + tcx: &ty::ctxt<'tcx>) -> ty::VariantDef_<'tcx, 'tcx> { + ty::VariantDef_ { + did: did, + name: item_name(intr, doc), + fields: get_variant_fields(intr, cdata, doc, tcx), + disr_val: 0 + } + } + + let doc = lookup_item(item_id, cdata.data()); + let did = ast::DefId { krate: cdata.cnum, node: item_id }; + let (kind, variants) = match item_family(doc) { + Enum => (ty::ADTKind::Enum, + get_enum_variants(intr, cdata, doc, tcx)), + Struct => (ty::ADTKind::Struct, + vec![get_struct_variant(intr, cdata, doc, did, tcx)]), + _ => tcx.sess.bug("get_adt_def called on a non-ADT") + }; + + let adt = tcx.intern_adt_def(did, kind, variants); + + // this needs to be done *after* the variant is interned, + // to support recursive structures + for variant in &adt.variants { + if variant.kind() == ty::VariantKind::Tuple && + adt.adt_kind() == ty::ADTKind::Enum { + // tuple-like enum variant fields aren't real items - get the types + // from the ctor. + debug!("evaluating the ctor-type of {:?}", + variant.name); + let ctor_ty = get_type(cdata, variant.did.node, tcx).ty; + debug!("evaluating the ctor-type of {:?}.. {:?}", + variant.name, + ctor_ty); + let field_tys = match ctor_ty.sty { + ty::TyBareFn(_, ref f) => &f.sig.skip_binder().inputs, + _ => tcx.sess.bug("tuple-variant ctor is not an ADT") + }; + for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) { + field.fulfill_ty(ty); + } + } else { + for field in &variant.fields { + debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); + let ty = get_type(cdata, field.did.node, tcx).ty; + field.fulfill_ty(ty); + debug!("evaluating the type of {:?}::{:?}: {:?}", + variant.name, field.name, ty); + } + } + } + + adt } pub fn get_predicates<'tcx>(cdata: Cmd, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 5167014d4aba5..4c4a1e07f44c1 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -41,7 +41,6 @@ use syntax::attr::AttrMetaMethods; use syntax::diagnostic::SpanHandler; use syntax::parse::token::special_idents; use syntax::print::pprust; -use syntax::ptr::P; use syntax::visit::Visitor; use syntax::visit; use syntax; @@ -266,7 +265,7 @@ fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { } fn encode_struct_fields(rbml_w: &mut Encoder, - fields: &[ty::FieldTy], + fields: &[ty::FieldDef], origin: DefId) { for f in fields { if f.name == special_idents::unnamed_field.name { @@ -276,7 +275,7 @@ fn encode_struct_fields(rbml_w: &mut Encoder, encode_name(rbml_w, f.name); } encode_struct_field_family(rbml_w, f.vis); - encode_def_id(rbml_w, f.id); + encode_def_id(rbml_w, f.did); rbml_w.wr_tagged_u64(tag_item_field_origin, def_to_u64(origin)); rbml_w.end_tag(); } @@ -285,57 +284,56 @@ fn encode_struct_fields(rbml_w: &mut Encoder, fn encode_enum_variant_info(ecx: &EncodeContext, rbml_w: &mut Encoder, id: NodeId, - variants: &[P], + vis: ast::Visibility, index: &mut Vec>) { debug!("encode_enum_variant_info(id={})", id); let mut disr_val = 0; - let mut i = 0; - let vi = ecx.tcx.enum_variants(local_def(id)); - for variant in variants { - let def_id = local_def(variant.node.id); + let def = ecx.tcx.lookup_adt_def(local_def(id)); + for variant in &def.variants { + let vid = variant.did; + assert!(is_local(vid)); index.push(entry { - val: variant.node.id as i64, + val: vid.node as i64, pos: rbml_w.mark_stable_position(), }); rbml_w.start_tag(tag_items_data_item); - encode_def_id(rbml_w, def_id); - match variant.node.kind { - ast::TupleVariantKind(_) => encode_family(rbml_w, 'v'), - ast::StructVariantKind(_) => encode_family(rbml_w, 'V') - } - encode_name(rbml_w, variant.node.name.name); + encode_def_id(rbml_w, vid); + encode_family(rbml_w, match variant.kind() { + ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v', + ty::VariantKind::Dict => 'V' + }); + encode_name(rbml_w, variant.name); encode_parent_item(rbml_w, local_def(id)); - encode_visibility(rbml_w, variant.node.vis); - encode_attributes(rbml_w, &variant.node.attrs); - encode_repr_attrs(rbml_w, ecx, &variant.node.attrs); + encode_visibility(rbml_w, vis); + + let attrs = ecx.tcx.get_attrs(vid); + encode_attributes(rbml_w, &attrs); + encode_repr_attrs(rbml_w, ecx, &attrs); - let stab = stability::lookup(ecx.tcx, ast_util::local_def(variant.node.id)); + let stab = stability::lookup(ecx.tcx, vid); encode_stability(rbml_w, stab); - match variant.node.kind { - ast::TupleVariantKind(_) => {}, - ast::StructVariantKind(_) => { - let fields = ecx.tcx.lookup_struct_fields(def_id); - let idx = encode_info_for_struct(ecx, - rbml_w, - &fields[..], - index); - encode_struct_fields(rbml_w, &fields[..], def_id); - encode_index(rbml_w, idx, write_i64); - } + if let ty::VariantKind::Dict = variant.kind() { + let idx = encode_info_for_struct(ecx, + rbml_w, + &variant.fields, + index); + encode_index(rbml_w, idx, write_i64); } - let specified_disr_val = vi[i].disr_val; + + encode_struct_fields(rbml_w, &variant.fields, vid); + + let specified_disr_val = variant.disr_val; if specified_disr_val != disr_val { encode_disr_val(ecx, rbml_w, specified_disr_val); disr_val = specified_disr_val; } - encode_bounds_and_type_for_item(rbml_w, ecx, def_id.local_id()); + encode_bounds_and_type_for_item(rbml_w, ecx, vid.node); - ecx.tcx.map.with_path(variant.node.id, |path| encode_path(rbml_w, path)); + ecx.tcx.map.with_path(vid.node, |path| encode_path(rbml_w, path)); rbml_w.end_tag(); disr_val = disr_val.wrapping_add(1); - i += 1; } } @@ -630,11 +628,11 @@ fn encode_provided_source(rbml_w: &mut Encoder, } /* Returns an index of items in this class */ -fn encode_info_for_struct(ecx: &EncodeContext, - rbml_w: &mut Encoder, - fields: &[ty::FieldTy], - global_index: &mut Vec>) - -> Vec> { +fn encode_info_for_struct<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + fields: &[ty::FieldDef<'tcx>], + global_index: &mut Vec>) + -> Vec> { /* Each class has its own index, since different classes may have fields with the same name */ let mut index = Vec::new(); @@ -642,7 +640,7 @@ fn encode_info_for_struct(ecx: &EncodeContext, private fields to get the offsets right */ for field in fields { let nm = field.name; - let id = field.id.node; + let id = field.did.node; let pos = rbml_w.mark_stable_position(); index.push(entry {val: id as i64, pos: pos}); @@ -658,7 +656,7 @@ fn encode_info_for_struct(ecx: &EncodeContext, encode_bounds_and_type_for_item(rbml_w, ecx, id); encode_def_id(rbml_w, local_def(id)); - let stab = stability::lookup(ecx.tcx, field.id); + let stab = stability::lookup(ecx.tcx, field.did); encode_stability(rbml_w, stab); rbml_w.end_tag(); @@ -1150,20 +1148,18 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_enum_variant_info(ecx, rbml_w, item.id, - &(*enum_definition).variants, + vis, index); } ast::ItemStruct(ref struct_def, _) => { - let fields = tcx.lookup_struct_fields(def_id); + let def = ecx.tcx.lookup_adt_def(def_id); + let fields = &def.struct_variant().fields; /* First, encode the fields These come first because we need to write them to make the index, and the index needs to be in the item for the class itself */ - let idx = encode_info_for_struct(ecx, - rbml_w, - &fields[..], - index); + let idx = encode_info_for_struct(ecx, rbml_w, &fields, index); /* Index the class*/ add_to_index(item, rbml_w, index); @@ -1185,7 +1181,7 @@ fn encode_info_for_item(ecx: &EncodeContext, /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - encode_struct_fields(rbml_w, &fields[..], def_id); + encode_struct_fields(rbml_w, &fields, def_id); encode_inlined_item(ecx, rbml_w, IIItemRef(item)); diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index e7a349265ba98..5cef50be77097 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -513,7 +513,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, &Variant(vid) => (vid, cx.tcx.enum_variant_with_id(cid.did, vid).arg_names.is_some()), _ => - (cid.did, !cid.is_tuple_struct(cx.tcx)) + (cid.did, !cid.struct_variant().is_tuple_struct()) }; if is_structure { let fields = cx.tcx.lookup_struct_fields(vid); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a491d6e65b7d8..0354918acf8fc 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -74,10 +74,12 @@ use std::cell::{Cell, RefCell, Ref}; use std::cmp; use std::fmt; use std::hash::{Hash, SipHasher, Hasher}; +use std::iter; use std::marker::PhantomData; use std::mem; use std::ops; use std::rc::Rc; +use std::slice; use std::vec::IntoIter; use collections::enum_set::{self, EnumSet, CLike}; use core::nonzero::NonZero; @@ -90,7 +92,7 @@ use syntax::ast::{StructField, UnnamedField, Visibility}; use syntax::ast_util::{self, is_local, local_def}; use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; use syntax::codemap::Span; -use syntax::parse::token::{self, InternedString, special_idents}; +use syntax::parse::token::{InternedString, special_idents}; use syntax::print::pprust; use syntax::ptr::P; use syntax::ast; @@ -211,7 +213,7 @@ impl DtorKind { } } -trait IntTypeExt { +pub trait IntTypeExt { fn to_ty<'tcx>(&self, cx: &ctxt<'tcx>) -> Ty<'tcx>; fn i64_to_disr(&self, val: i64) -> Option; fn u64_to_disr(&self, val: u64) -> Option; @@ -852,7 +854,7 @@ pub struct ctxt<'tcx> { pub impl_trait_refs: RefCell>>>, pub trait_defs: RefCell>>, - pub adt_defs: RefCell>>, + pub adt_defs: RefCell>>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its /// associated predicates. @@ -1023,8 +1025,12 @@ impl<'tcx> ctxt<'tcx> { interned } - pub fn intern_adt_def(&self, did: DefId, kind: ADTKind) -> &'tcx ADTDef_<'tcx, 'tcx> { - let def = ADTDef_::new(self, did, kind); + pub fn intern_adt_def(&self, + did: DefId, + kind: ADTKind, + variants: Vec>) + -> &'tcx ADTDef_<'tcx, 'tcx> { + let def = ADTDef_::new(self, did, kind, variants); let interned = self.arenas.adt_defs.alloc(def); // this will need a transmute when reverse-variance is removed self.adt_defs.borrow_mut().insert(did, interned); @@ -2190,7 +2196,7 @@ pub struct ExistentialBounds<'tcx> { pub struct BuiltinBounds(EnumSet); impl BuiltinBounds { - pub fn empty() -> BuiltinBounds { + pub fn empty() -> BuiltinBounds { BuiltinBounds(EnumSet::new()) } @@ -3274,17 +3280,21 @@ bitflags! { } pub type ADTDef<'tcx> = ADTDef_<'tcx, 'static>; +pub type VariantDef<'tcx> = VariantDef_<'tcx, 'static>; +pub type FieldDef<'tcx> = FieldDef_<'tcx, 'static>; -pub struct VariantDef<'tcx, 'lt: 'tcx> { +pub struct VariantDef_<'tcx, 'lt: 'tcx> { pub did: DefId, pub name: Name, // struct's name if this is a struct pub disr_val: Disr, - pub fields: Vec> + pub fields: Vec> } -pub struct FieldDef<'tcx, 'lt: 'tcx> { +pub struct FieldDef_<'tcx, 'lt: 'tcx> { pub did: DefId, - pub name: Name, // XXX if tuple-like + // special_idents::unnamed_field.name + // if this is a tuple-like field + pub name: Name, pub vis: ast::Visibility, // TyIVar is used here to allow for ty: TyIVar<'tcx, 'lt> @@ -3294,7 +3304,7 @@ pub struct FieldDef<'tcx, 'lt: 'tcx> { /// is here so 'tcx can be variant. pub struct ADTDef_<'tcx, 'lt: 'tcx> { pub did: DefId, - pub variants: Vec>, + pub variants: Vec>, flags: Cell, } @@ -3313,11 +3323,18 @@ impl<'tcx, 'lt> Hash for ADTDef_<'tcx, 'lt> { } } -#[derive(Copy, Clone, Debug)] + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ADTKind { Struct, Enum } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum VariantKind { Dict, Tuple, Unit } + impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { - fn new(tcx: &ctxt<'tcx>, did: DefId, kind: ADTKind) -> Self { + fn new(tcx: &ctxt<'tcx>, + did: DefId, + kind: ADTKind, + variants: Vec>) -> Self { let mut flags = ADTFlags::NO_ADT_FLAGS; if tcx.has_attr(did, "fundamental") { flags = flags | ADTFlags::IS_FUNDAMENTAL; @@ -3330,7 +3347,7 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { } ADTDef { did: did, - variants: vec![], + variants: variants, flags: Cell::new(flags), } } @@ -3374,9 +3391,9 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { tcx.destructor_for_type.borrow().contains_key(&self.did) } - pub fn is_tuple_struct(&self, tcx: &ctxt<'tcx>) -> bool { - let fields = tcx.lookup_struct_fields(self.did); - !fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field) + pub fn struct_variant(&self) -> &ty::VariantDef_<'tcx, 'lt> { + assert!(self.adt_kind() == ADTKind::Struct); + &self.variants[0] } #[inline] @@ -3388,6 +3405,104 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { pub fn predicates(&self, tcx: &ctxt<'tcx>) -> GenericPredicates<'tcx> { tcx.lookup_predicates(self.did) } + + #[inline] + pub fn all_fields(&self) -> + iter::FlatMap< + slice::Iter>, + slice::Iter>, + for<'s> fn(&'s VariantDef_<'tcx, 'lt>) + -> slice::Iter<'s, FieldDef_<'tcx, 'lt>> + > { + self.variants.iter().flat_map(VariantDef_::fields_iter) + } + + #[inline] + pub fn is_empty(&self) -> bool { + // FIXME(#TODO(wxyz)): be smarter here + self.variants.is_empty() + } + + #[inline] + pub fn is_univariant(&self) -> bool { + self.variants.len() == 1 + } + + pub fn is_payloadfree(&self) -> bool { + !self.variants.is_empty() && + self.variants.iter().all(|v| v.fields.is_empty()) + } + + pub fn variant_with_id(&self, vid: DefId) -> &VariantDef_<'tcx, 'lt> { + self.variants + .iter() + .find(|v| v.did == vid) + .expect("variant_with_id: unknown variant") + } + + pub fn variant_of_def(&self, def: def::Def) -> &VariantDef_<'tcx, 'lt> { + match def { + def::DefVariant(_, vid, _) => self.variant_with_id(vid), + def::DefStruct(..) | def::DefTy(..) => self.struct_variant(), + _ => panic!("unexpected def {:?} in variant_of_def", def) + } + } +} + +impl<'tcx, 'lt> VariantDef_<'tcx, 'lt> { + #[inline] + fn fields_iter(&self) -> slice::Iter> { + self.fields.iter() + } + + pub fn kind(&self) -> VariantKind { + match self.fields.get(0) { + None => VariantKind::Unit, + Some(&FieldDef_ { name, .. }) if name == special_idents::unnamed_field.name => { + VariantKind::Tuple + } + Some(_) => VariantKind::Dict + } + } + + pub fn is_tuple_struct(&self) -> bool { + self.kind() == VariantKind::Tuple + } + + #[inline] + pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef_<'tcx, 'lt>> { + self.fields.iter().find(|f| f.name == name) + } + + #[inline] + pub fn field_named(&self, name: ast::Name) -> &FieldDef_<'tcx, 'lt> { + self.find_field_named(name).unwrap() + } +} + +impl<'tcx, 'lt> FieldDef_<'tcx, 'lt> { + pub fn new(did: DefId, + name: Name, + vis: ast::Visibility) -> Self { + FieldDef_ { + did: did, + name: name, + vis: vis, + ty: TyIVar::new() + } + } + + pub fn ty(&self, tcx: &ctxt<'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { + self.unsubst_ty().subst(tcx, subst) + } + + pub fn unsubst_ty(&self) -> Ty<'tcx> { + self.ty.unwrap() + } + + pub fn fulfill_ty(&self, ty: Ty<'lt>) { + self.ty.fulfill(ty); + } } /// Records the substitutions used to translate the polytype for an @@ -6132,7 +6247,7 @@ impl<'tcx> ctxt<'tcx> { } /// Given the did of a trait, returns its canonical trait ref. - pub fn lookup_adt_def(&self, did: ast::DefId) -> &'tcx ADTDef<'tcx> { + pub fn lookup_adt_def(&self, did: ast::DefId) -> &'tcx ADTDef_<'tcx, 'tcx> { lookup_locally_or_in_crate_store( "adt_defs", did, &self.adt_defs, || csearch::get_adt_def(self, did) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5e5886cd13ce2..2f63d7abe4afc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2980,7 +2980,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, |base_t, _| { match base_t.sty { ty::TyStruct(base_def, substs) => { - tuple_like = base_def.is_tuple_struct(tcx); + tuple_like = base_def.struct_variant().is_tuple_struct(); if tuple_like { debug!("tuple struct named {:?}", base_t); let fields = tcx.lookup_struct_fields(base_def.did); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 708825fc95ab0..c9f6ccb8cb2e7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -71,9 +71,12 @@ use middle::lang_items::SizedTraitLangItem; use middle::free_region::FreeRegionMap; use middle::region; use middle::resolve_lifetime; +use middle::const_eval::{self, ConstVal}; +use middle::const_eval::EvalHint::UncheckedExprHint; use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme}; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme, IntTypeExt}; +use middle::ty::{VariantKind}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; @@ -89,8 +92,10 @@ use std::rc::Rc; use syntax::abi; use syntax::ast; use syntax::ast_util::local_def; +use syntax::attr; use syntax::codemap::Span; use syntax::parse::token::special_idents; +use syntax::print::pprust; use syntax::ptr::P; use syntax::visit; @@ -563,48 +568,6 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, } } -fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - enum_scheme: ty::TypeScheme<'tcx>, - enum_predicates: ty::GenericPredicates<'tcx>, - variants: &[P]) { - let tcx = ccx.tcx; - let icx = ccx.icx(&enum_predicates); - - // Create a set of parameter types shared among all the variants. - for variant in variants { - let variant_def_id = local_def(variant.node.id); - - // Nullary enum constructors get turned into constants; n-ary enum - // constructors get turned into functions. - let result_ty = match variant.node.kind { - ast::TupleVariantKind(ref args) if !args.is_empty() => { - let rs = ExplicitRscope; - let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); - tcx.mk_ctor_fn(variant_def_id, &input_tys, enum_scheme.ty) - } - - ast::TupleVariantKind(_) => { - enum_scheme.ty - } - - ast::StructVariantKind(ref struct_def) => { - convert_struct(ccx, &**struct_def, enum_scheme.clone(), - enum_predicates.clone(), variant.node.id); - enum_scheme.ty - } - }; - - let variant_scheme = TypeScheme { - generics: enum_scheme.generics.clone(), - ty: result_ty - }; - - tcx.register_item_type(variant_def_id, variant_scheme.clone()); - tcx.predicates.borrow_mut().insert(variant_def_id, enum_predicates.clone()); - write_ty_to_tcx(tcx, variant.node.id, result_ty); - } -} - fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, sig: &ast::MethodSig, @@ -657,10 +620,12 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_generics: &ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, v: &ast::StructField, + ty_f: &'tcx ty::FieldDef_<'tcx, 'tcx>, origin: ast::DefId) -> ty::FieldTy { let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &*v.node.ty); + ty_f.fulfill_ty(tt); write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ @@ -803,10 +768,11 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { ast::ItemEnum(ref enum_definition, _) => { let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); - get_enum_variant_types(ccx, - scheme, - predicates, - &enum_definition.variants); + convert_enum_variant_types(ccx, + tcx.lookup_adt_def(local_def(it.id)), + scheme, + predicates, + &enum_definition.variants); }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { let trait_ref = @@ -1048,10 +1014,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } }, ast::ItemStruct(ref struct_def, _) => { - // Write the class type. let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); - convert_struct(ccx, &**struct_def, scheme, predicates, it.id); + + let variant = tcx.lookup_adt_def(local_def(it.id)).struct_variant(); + convert_struct_variant_types(ccx, &struct_def, variant, &scheme, &predicates); + if let Some(ctor_id) = struct_def.ctor_id { + convert_variant_ctor(tcx, ctor_id, variant, scheme, predicates); + } }, ast::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); @@ -1068,74 +1038,216 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } } -fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - struct_def: &ast::StructDef, - scheme: ty::TypeScheme<'tcx>, - predicates: ty::GenericPredicates<'tcx>, - id: ast::NodeId) { +fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, + ctor_id: ast::NodeId, + variant: &'tcx ty::VariantDef<'tcx>, + scheme: ty::TypeScheme<'tcx>, + predicates: ty::GenericPredicates<'tcx>) { + let ctor_ty = match variant.kind() { + VariantKind::Unit | VariantKind::Dict => scheme.ty, + VariantKind::Tuple => { + let inputs: Vec<_> = + variant.fields + .iter() + .map(|field| field.unsubst_ty()) + .collect(); + tcx.mk_ctor_fn(local_def(ctor_id), + &inputs[..], + scheme.ty) + } + }; + write_ty_to_tcx(tcx, ctor_id, ctor_ty); + tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); + tcx.register_item_type(local_def(ctor_id), + TypeScheme { + generics: scheme.generics, + ty: ctor_ty + }); +} + +fn convert_struct_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + def: &ast::StructDef, + variant: &'tcx ty::VariantDef_<'tcx, 'tcx>, + scheme: &ty::TypeScheme<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) { + let field_tys = def.fields.iter().zip(variant.fields.iter()).map(|(f, ty_f)| { + convert_field(ccx, &scheme.generics, &predicates, f, ty_f, variant.did) + }).collect(); + ccx.tcx.struct_fields.borrow_mut().insert(variant.did, Rc::new(field_tys)); +} + +fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + def: &'tcx ty::ADTDef_<'tcx, 'tcx>, + scheme: ty::TypeScheme<'tcx>, + predicates: ty::GenericPredicates<'tcx>, + variants: &[P]) { let tcx = ccx.tcx; + let icx = ccx.icx(&predicates); - // Write the type of each of the members and check for duplicate fields. - let mut seen_fields: FnvHashMap = FnvHashMap(); - let field_tys = struct_def.fields.iter().map(|f| { - let result = convert_field(ccx, &scheme.generics, &predicates, f, local_def(id)); + // Create a set of parameter types shared among all the variants. + for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { + match variant.node.kind { + ast::TupleVariantKind(ref args) => { + let rs = ExplicitRscope; + let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); + for (field, &ty) in ty_variant.fields.iter().zip(input_tys.iter()) { + field.fulfill_ty(ty); + } + } + + ast::StructVariantKind(ref struct_def) => { + convert_struct_variant_types(ccx, &struct_def, ty_variant, &scheme, &predicates); + } + }; - if result.name != special_idents::unnamed_field.name { - let dup = match seen_fields.get(&result.name) { - Some(prev_span) => { + convert_variant_ctor( + tcx, + variant.node.id, + ty_variant, + scheme.clone(), + predicates.clone() + ); + } +} + +fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, + did: ast::DefId, + name: ast::Name, + disr_val: ty::Disr, + def: &ast::StructDef) -> ty::VariantDef_<'tcx, 'tcx> { + let mut seen_fields: FnvHashMap = FnvHashMap(); + let fields = def.fields.iter().map(|f| { + let fid = local_def(f.node.id); + match f.node.kind { + ast::NamedField(ident, vis) => { + let dup_span = seen_fields.get(&ident.name).cloned(); + if let Some(prev_span) = dup_span { span_err!(tcx.sess, f.span, E0124, "field `{}` is already declared", - result.name); - span_note!(tcx.sess, *prev_span, "previously declared here"); - true - }, - None => false, - }; - // FIXME(#6393) this whole dup thing is just to satisfy - // the borrow checker :-( - if !dup { - seen_fields.insert(result.name, f.span); + ident.name); + span_note!(tcx.sess, prev_span, "previously declared here"); + } else { + seen_fields.insert(ident.name, f.span); + } + + ty::FieldDef_::new(fid, ident.name, vis) + }, + ast::UnnamedField(vis) => { + ty::FieldDef_::new(fid, special_idents::unnamed_field.name, vis) } } - - result }).collect(); + ty::VariantDef_ { + did: did, + name: name, + disr_val: disr_val, + fields: fields + } +} - tcx.struct_fields.borrow_mut().insert(local_def(id), Rc::new(field_tys)); +fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>, + it: &ast::Item, + def: &ast::StructDef) + -> &'tcx ty::ADTDef_<'tcx, 'tcx> +{ + let did = local_def(it.id); + tcx.intern_adt_def( + did, + ty::ADTKind::Struct, + vec![convert_struct_variant(tcx, did, it.ident.name, 0, def)] + ) +} - // If this struct is enum-like or tuple-like, create the type of its - // constructor. - if let Some(ctor_id) = struct_def.ctor_id { - let substs = mk_item_substs(ccx, &scheme.generics); - let selfty = tcx.mk_struct(tcx.lookup_adt_def(local_def(id)), - tcx.mk_substs(substs)); - if struct_def.fields.is_empty() { - // Enum-like. - write_ty_to_tcx(tcx, ctor_id, selfty); +fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, + it: &ast::Item, + def: &ast::EnumDef) + -> &'tcx ty::ADTDef_<'tcx, 'tcx> +{ + fn evaluate_disr_expr<'tcx>(tcx: &ty::ctxt<'tcx>, + repr_ty: Ty<'tcx>, + e: &ast::Expr) -> Option { + debug!("disr expr, checking {}", pprust::expr_to_string(e)); + + let hint = UncheckedExprHint(repr_ty); + match const_eval::eval_const_expr_partial(tcx, e, hint) { + Ok(ConstVal::Int(val)) => Some(val as ty::Disr), + Ok(ConstVal::Uint(val)) => Some(val as ty::Disr), + Ok(_) => { +// let sign_desc = if repr_type.is_signed() { +// "signed" +// } else { +// "unsigned" +// }; +// span_err!(self.sess, e.span, E0079, +// "expected {} integer constant", +// sign_desc); + None + }, + Err(_) => { +// span_err!(self.sess, err.span, E0080, +// "constant evaluation error: {}", +// err.description()); + None + } + } + } - tcx.register_item_type(local_def(ctor_id), scheme); - tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); - } else if struct_def.fields[0].node.kind.is_unnamed() { - // Tuple-like. - let inputs: Vec<_> = - struct_def.fields - .iter() - .map(|field| tcx.lookup_item_type( - local_def(field.node.id)).ty) - .collect(); - let ctor_fn_ty = tcx.mk_ctor_fn(local_def(ctor_id), - &inputs[..], - selfty); - write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); - tcx.register_item_type(local_def(ctor_id), - TypeScheme { - generics: scheme.generics, - ty: ctor_fn_ty - }); - tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); + fn next_disr(repr_type: attr::IntType, + prev_disr_val: Option) -> Option { + if let Some(prev_disr_val) = prev_disr_val { + let result = repr_type.disr_incr(prev_disr_val); +// if let None = result { +// self.report_discrim_overflow(v.span, &v.node.name.name.as_str(), +// repr_type, prev_disr_val); +// } + result + } else { + Some(ty::INITIAL_DISCRIMINANT_VALUE) } } + fn convert_enum_variant<'tcx>(tcx: &ty::ctxt<'tcx>, + v: &ast::Variant, + disr: ty::Disr) + -> ty::VariantDef_<'tcx, 'tcx> + { + let did = local_def(v.node.id); + let name = v.node.name.name; + match v.node.kind { + ast::TupleVariantKind(ref va) => { + ty::VariantDef_ { + did: did, + name: name, + disr_val: disr, + fields: va.iter().map(|&ast::VariantArg { id, .. }| { + ty::FieldDef_::new( + local_def(id), + special_idents::unnamed_field.name, + ast::Visibility::Public + ) + }).collect() + } + } + ast::StructVariantKind(ref def) => { + convert_struct_variant(tcx, did, name, disr, &def) + } + } + } + let did = local_def(it.id); + let repr_hints = tcx.lookup_repr_hints(did); + let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0)); + let mut prev_disr = None; + let variants = def.variants.iter().map(|v| { + let disr = match v.node.disr_expr { + Some(ref e) => evaluate_disr_expr(tcx, repr_type_ty, e), + None => next_disr(repr_type, prev_disr) + }.unwrap_or(repr_type.disr_wrap_incr(prev_disr)); + + let v = convert_enum_variant(tcx, v, disr); + prev_disr = Some(disr); + v + }).collect(); + tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Enum, variants) } /// Ensures that the super-predicates of the trait with def-id @@ -1469,18 +1581,17 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let ty = ccx.icx(generics).to_ty(&ExplicitRscope, &**t); ty::TypeScheme { ty: ty, generics: ty_generics } } - ast::ItemEnum(_, ref generics) => { - // Create a new generic polytype. + ast::ItemEnum(ref ei, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let def = tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Enum); + let def = convert_enum_def(tcx, it, ei); let t = tcx.mk_enum(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } - ast::ItemStruct(_, ref generics) => { + ast::ItemStruct(ref si, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); - let def = tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Struct); + let def = convert_struct_def(tcx, it, si); let t = tcx.mk_struct(def, tcx.mk_substs(substs)); ty::TypeScheme { ty: t, generics: ty_generics } } From 5f3c1412ad8224e0fea0bc2b4f67894619045c54 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 2 Aug 2015 22:52:50 +0300 Subject: [PATCH 05/14] use VariantDef instead of struct_fields --- src/librustc/diagnostics.rs | 59 --- src/librustc/middle/cast.rs | 5 +- src/librustc/middle/check_match.rs | 92 ++-- src/librustc/middle/dead.rs | 43 +- src/librustc/middle/expr_use_visitor.rs | 50 +-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/stability.rs | 52 +-- src/librustc/middle/traits/select.rs | 41 +- src/librustc/middle/ty.rs | 398 +++--------------- src/librustc_borrowck/borrowck/fragments.rs | 38 +- src/librustc_lint/builtin.rs | 41 +- src/librustc_privacy/lib.rs | 147 +++---- src/librustc_trans/save/dump_csv.rs | 80 ++-- src/librustc_trans/save/mod.rs | 50 +-- src/librustc_trans/trans/_match.rs | 39 +- src/librustc_trans/trans/adt.rs | 30 +- src/librustc_trans/trans/base.rs | 56 ++- src/librustc_trans/trans/callee.rs | 6 +- src/librustc_trans/trans/common.rs | 91 +++- src/librustc_trans/trans/consts.rs | 64 +-- .../trans/debuginfo/metadata.rs | 114 ++--- src/librustc_trans/trans/expr.rs | 192 +++------ src/librustc_trans/trans/glue.rs | 5 +- src/librustc_trans/trans/inline.rs | 46 +- src/librustc_trans/trans/monomorphize.rs | 31 +- src/librustc_typeck/check/_match.rs | 56 +-- src/librustc_typeck/check/cast.rs | 9 +- src/librustc_typeck/check/dropck.rs | 81 ++-- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 198 ++++----- src/librustc_typeck/coherence/mod.rs | 5 +- src/librustc_typeck/collect.rs | 53 ++- src/librustc_typeck/diagnostics.rs | 59 +++ src/librustc_typeck/variance.rs | 42 +- src/librustdoc/clean/inline.rs | 8 +- src/librustdoc/clean/mod.rs | 44 +- 36 files changed, 892 insertions(+), 1441 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9c2cdba0ae47b..baa9750d311aa 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -692,64 +692,6 @@ There's no easy fix for this, generally code will need to be refactored so that you no longer need to derive from `Super`. "####, -E0079: r##" -Enum variants which contain no data can be given a custom integer -representation. This error indicates that the value provided is not an integer -literal and is therefore invalid. - -For example, in the following code, - -``` -enum Foo { - Q = "32" -} -``` - -we try to set the representation to a string. - -There's no general fix for this; if you can work with an integer then just set -it to one: - -``` -enum Foo { - Q = 32 -} -``` - -however if you actually wanted a mapping between variants and non-integer -objects, it may be preferable to use a method with a match instead: - -``` -enum Foo { Q } -impl Foo { - fn get_str(&self) -> &'static str { - match *self { - Foo::Q => "32", - } - } -} -``` -"##, - -E0080: r##" -This error indicates that the compiler was unable to sensibly evaluate an -integer expression provided as an enum discriminant. Attempting to divide by 0 -or causing integer overflow are two ways to induce this error. For example: - -``` -enum Enum { - X = (1 << 500), - Y = (1 / 0) -} -``` - -Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: - -https://doc.rust-lang.org/reference.html#ffi-attributes -"##, - E0109: r##" You tried to give a type parameter to a type which doesn't need it. Erroneous code example: @@ -1937,6 +1879,5 @@ register_diagnostics! { E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes - E0370, // discriminant overflow E0400 // overloaded derefs are not allowed in constants } diff --git a/src/librustc/middle/cast.rs b/src/librustc/middle/cast.rs index bbd452b35acdf..8233b6b2b2b6e 100644 --- a/src/librustc/middle/cast.rs +++ b/src/librustc/middle/cast.rs @@ -58,15 +58,14 @@ pub enum CastKind { } impl<'tcx> CastTy<'tcx> { - pub fn from_ty(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) - -> Option> { + pub fn from_ty(t: Ty<'tcx>) -> Option> { match t.sty { ty::TyBool => Some(CastTy::Int(IntTy::Bool)), ty::TyChar => Some(CastTy::Int(IntTy::Char)), ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), ty::TyFloat(_) => Some(CastTy::Float), - ty::TyEnum(..) if t.is_c_like_enum(tcx) => + ty::TyEnum(d,_) if d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 5cef50be77097..2c835b35cc209 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -237,9 +237,9 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) if let ty::TyEnum(edef, _) = pat_ty.sty { let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); if let Some(DefLocal(_)) = def { - if cx.tcx.enum_variants(edef.did).iter().any(|variant| + if edef.variants.iter().any(|variant| variant.name == ident.node.name - && variant.args.is_empty() + && variant.kind() == VariantKind::Unit ) { span_warn!(cx.tcx.sess, p.span, E0170, "pattern binding `{}` is named the same as one \ @@ -508,16 +508,10 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pat = match left_ty.sty { ty::TyTuple(_) => ast::PatTup(pats.collect()), - ty::TyEnum(cid, _) | ty::TyStruct(cid, _) => { - let (vid, is_structure) = match ctor { - &Variant(vid) => - (vid, cx.tcx.enum_variant_with_id(cid.did, vid).arg_names.is_some()), - _ => - (cid.did, !cid.struct_variant().is_tuple_struct()) - }; - if is_structure { - let fields = cx.tcx.lookup_struct_fields(vid); - let field_pats: Vec<_> = fields.into_iter() + ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { + let v = adt.variant_of_ctor(ctor); + if let VariantKind::Dict = v.kind() { + let field_pats: Vec<_> = v.fields.iter() .zip(pats) .filter(|&(_, ref pat)| pat.node != ast::PatWild(ast::PatWildSingle)) .map(|(field, pat)| Spanned { @@ -529,9 +523,9 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, 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, v.did), field_pats, has_more_fields) } else { - ast::PatEnum(def_to_path(cx.tcx, vid), Some(pats.collect())) + ast::PatEnum(def_to_path(cx.tcx, v.did), Some(pats.collect())) } } @@ -580,6 +574,15 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, }) } +impl<'tcx> ADTDef<'tcx> { + fn variant_of_ctor(&'tcx self, ctor: &Constructor) -> &'tcx VariantDef<'tcx> { + match ctor { + &Variant(vid) => self.variant_with_id(vid), + _ => self.struct_variant() + } + } +} + fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix, left_ty: Ty, max_slice_length: usize) -> Option { let used_constructors: Vec = rows.iter() @@ -594,7 +597,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, +fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, max_slice_length: usize) -> Vec { match left_ty.sty { ty::TyBool => @@ -603,17 +606,11 @@ fn all_constructors(cx: &MatchCheckCtxt, left_ty: Ty, ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty { ty::TySlice(_) => range_inclusive(0, max_slice_length).map(|length| Slice(length)).collect(), - _ => vec!(Single) + _ => vec![Single] }, - ty::TyEnum(edef, _) => - cx.tcx.enum_variants(edef.did) - .iter() - .map(|va| Variant(va.id)) - .collect(), - - _ => - vec!(Single) + ty::TyEnum(def, _) => def.variants.iter().map(|v| Variant(v.did)).collect(), + _ => vec![Single] } } @@ -804,7 +801,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) -> usize { +pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize { match ty.sty { ty::TyTuple(ref fs) => fs.len(), ty::TyBox(_) => 1, @@ -817,13 +814,9 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usi ty::TyStr => 0, _ => 1 }, - ty::TyEnum(edef, _) => { - match *ctor { - Variant(id) => cx.tcx.enum_variant_with_id(edef.did, id).args.len(), - _ => unreachable!() - } + ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { + adt.variant_of_ctor(ctor).fields.len() } - ty::TyStruct(cdef, _) => cx.tcx.lookup_struct_fields(cdef.did).len(), ty::TyArray(_, n) => n, _ => 0 } @@ -902,39 +895,20 @@ 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().get(&pat_id).unwrap().full_def(); - let class_id = match def { - DefConst(..) | DefAssociatedConst(..) => - cx.tcx.sess.span_bug(pat_span, "const pattern should've \ - been rewritten"), - DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) { - Some(variant_id) - } else { - None - }, - _ => { - // Assume this is a struct. - match cx.tcx.node_id_to_type(pat_id).ty_to_def_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), - } - } - }; - class_id.map(|variant_id| { - let struct_fields = cx.tcx.lookup_struct_fields(variant_id); - let args = struct_fields.iter().map(|sf| { + let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap(); + let variant = adt.variant_of_ctor(constructor); + let def_variant = adt.variant_of_def(def); + if variant.did == def_variant.did { + Some(variant.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 } - }).collect(); - args - }) + }).collect()) + } else { + None + } } ast::PatTup(ref args) => diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 7899f928e9d15..bd8a666ffecb2 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -100,51 +100,32 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn handle_field_access(&mut self, lhs: &ast::Expr, name: ast::Name) { - match self.tcx.expr_ty_adjusted(lhs).sty { - ty::TyStruct(def, _) => { - let fields = self.tcx.lookup_struct_fields(def.did); - let field_id = fields.iter() - .find(|field| field.name == name).unwrap().id; - self.live_symbols.insert(field_id.node); - }, - _ => () + if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { + self.live_symbols.insert(def.struct_variant().field_named(name).did.node); + } else { + self.tcx.sess.span_bug(lhs.span, "named field access on non-struct") } } fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: usize) { - match self.tcx.expr_ty_adjusted(lhs).sty { - ty::TyStruct(def, _) => { - let fields = self.tcx.lookup_struct_fields(def.did); - let field_id = fields[idx].id; - self.live_symbols.insert(field_id.node); - }, - _ => () + if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { + self.live_symbols.insert(def.struct_variant().fields[idx].did.node); } } fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[codemap::Spanned]) { - let id = match self.tcx.def_map.borrow().get(&lhs.id).unwrap().full_def() { - def::DefVariant(_, id, _) => id, - _ => { - match self.tcx.node_id_to_type(lhs.id).ty_to_def_id() { - None => { - self.tcx.sess.span_bug(lhs.span, - "struct pattern wasn't of a \ - type with a def ID?!") - } - Some(def_id) => def_id, - } - } + let def = self.tcx.def_map.borrow().get(&lhs.id).unwrap().full_def(); + let pat_ty = self.tcx.node_id_to_type(lhs.id); + let variant = match pat_ty.sty { + ty::TyStruct(adt, _) | ty::TyEnum(adt, _) => adt.variant_of_def(def), + _ => self.tcx.sess.span_bug(lhs.span, "non-ADT in struct pattern") }; - let fields = self.tcx.lookup_struct_fields(id); for pat in pats { if let ast::PatWild(ast::PatWildSingle) = pat.node.pat.node { continue; } - let field_id = fields.iter() - .find(|field| field.name == pat.node.ident.name).unwrap().id; - self.live_symbols.insert(field_id.node); + self.live_symbols.insert(variant.field_named(pat.node.ident.name).did.node); } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8f63aca0dd69a..8e827257f7e9e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -694,40 +694,36 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { // Select just those fields of the `with` // expression that will actually be used - let with_fields = match with_cmt.ty.sty { - ty::TyStruct(def, substs) => { - self.tcx().struct_fields(def.did, substs) - } - _ => { - // the base expression should always evaluate to a - // struct; however, when EUV is run during typeck, it - // may not. This will generate an error earlier in typeck, - // so we can just ignore it. - if !self.tcx().sess.has_errors() { - self.tcx().sess.span_bug( - with_expr.span, - "with expression doesn't evaluate to a struct"); + if let ty::TyStruct(def, substs) = with_cmt.ty.sty { + // Consume those fields of the with expression that are needed. + for with_field in &def.struct_variant().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.ty(self.tcx(), substs) + ); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); } - 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); + } else { + // the base expression should always evaluate to a + // struct; however, when EUV is run during typeck, it + // may not. This will generate an error earlier in typeck, + // so we can just ignore it. + if !self.tcx().sess.has_errors() { + self.tcx().sess.span_bug( + with_expr.span, + "with expression doesn't evaluate to a struct"); } - } + }; // walk the with expression so that complex expressions // are properly handled. self.walk_expr(with_expr); - fn contains_field_named(field: &ty::Field, + fn contains_field_named(field: &ty::FieldDef, fields: &Vec) -> bool { @@ -1105,7 +1101,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { Some(def::DefVariant(enum_did, variant_did, _is_struct)) => { let downcast_cmt = - if tcx.enum_is_univariant(enum_did) { + if tcx.lookup_adt_def(enum_did).is_univariant() { cmt_pat } else { let cmt_pat_ty = cmt_pat.ty; diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ee7079bb47d59..3ab0d4c04d73c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1216,7 +1216,7 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { let cmt = match opt_def { Some(def::DefVariant(enum_did, variant_did, _)) // univariant enums do not need downcasts - if !self.tcx().enum_is_univariant(enum_did) => { + if !self.tcx().lookup_adt_def(enum_did).is_univariant() => { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) } _ => cmt diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 1261f10aaffee..16f744b6887ab 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -415,16 +415,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, ast::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => { - tcx.lookup_struct_fields(def.did) - .iter() - .find(|f| f.name == field.node.name) - .unwrap_or_else(|| { - tcx.sess.span_bug(field.span, - "stability::check_expr: unknown named field access") - }) - .id - } + ty::TyStruct(def, _) => def.struct_variant().field_named(field.node.name).did, _ => tcx.sess.span_bug(e.span, "stability::check_expr: named field access on non-struct") } @@ -432,15 +423,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, ast::ExprTupField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => { - tcx.lookup_struct_fields(def.did) - .get(field.node) - .unwrap_or_else(|| { - tcx.sess.span_bug(field.span, - "stability::check_expr: unknown unnamed field access") - }) - .id - } + ty::TyStruct(def, _) => def.struct_variant().fields[field.node].did, ty::TyTuple(..) => return, _ => tcx.sess.span_bug(e.span, "stability::check_expr: unnamed field access on \ @@ -451,19 +434,12 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, let type_ = tcx.expr_ty(e); match type_.sty { ty::TyStruct(def, _) => { - let struct_fields = tcx.lookup_struct_fields(def.did); // check the stability of each field that appears // in the construction expression. for field in expr_fields { - let did = struct_fields - .iter() - .find(|f| f.name == field.ident.node.name) - .unwrap_or_else(|| { - tcx.sess.span_bug(field.span, - "stability::check_expr: unknown named \ - field access") - }) - .id; + let did = def.struct_variant() + .field_named(field.ident.node.name) + .did; maybe_do_stability_check(tcx, did, field.span, cb); } @@ -505,34 +481,26 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let def = match tcx.pat_ty_opt(pat) { - Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def, + let v = match tcx.pat_ty_opt(pat) { + Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def.struct_variant(), Some(_) | None => return, }; - let struct_fields = tcx.lookup_struct_fields(def.did); match pat.node { // Foo(a, b, c) ast::PatEnum(_, Some(ref pat_fields)) => { - for (field, struct_field) in pat_fields.iter().zip(&struct_fields) { + for (field, struct_field) in pat_fields.iter().zip(&v.fields) { // a .. pattern is fine, but anything positional is // not. if let ast::PatWild(ast::PatWildMulti) = field.node { continue } - maybe_do_stability_check(tcx, struct_field.id, field.span, cb) + maybe_do_stability_check(tcx, struct_field.did, field.span, cb) } } // Foo { a, b, c } ast::PatStruct(_, ref pat_fields, _) => { for field in pat_fields { - let did = struct_fields - .iter() - .find(|f| f.name == field.node.ident.name) - .unwrap_or_else(|| { - tcx.sess.span_bug(field.span, - "stability::check_pat: unknown named field access") - }) - .id; + let did = v.field_named(field.node.ident.name).did; maybe_do_stability_check(tcx, did, field.span, cb); } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index fee1c83ba2cce..0c9cf1a68b732 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1721,21 +1721,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ok_if(substs.upvar_tys.clone()) } - ty::TyStruct(def, substs) => { - let types: Vec = - self.tcx().struct_fields(def.did, substs).iter() - .map(|f| f.mt.ty) - .collect(); - nominal(bound, types) - } - - ty::TyEnum(def, substs) => { - let types: Vec = - self.tcx().substd_enum_variants(def.did, substs) - .iter() - .flat_map(|variant| &variant.args) - .cloned() - .collect(); + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + let types: Vec = def.all_fields().map(|f| { + f.ty(self.tcx(), substs) + }).collect(); nominal(bound, types) } @@ -1865,18 +1854,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs.types.get_slice(TypeSpace).to_vec() } - ty::TyStruct(def, substs) => { - self.tcx().struct_fields(def.did, substs) - .iter() - .map(|f| f.mt.ty) - .collect() - } - - ty::TyEnum(def, substs) => { - self.tcx().substd_enum_variants(def.did, substs) - .iter() - .flat_map(|variant| &variant.args) - .map(|&ty| ty) + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + def.all_fields() + .map(|f| f.ty(self.tcx(), substs)) .collect() } } @@ -2522,9 +2502,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Struct -> Struct. (&ty::TyStruct(def, substs_a), &ty::TyStruct(_, substs_b)) => { - let fields = tcx.lookup_struct_fields(def.did).iter().map(|f| { - tcx.lookup_field_type_unsubstituted(def.did, f.id) - }).collect::>(); + let fields = def + .all_fields() + .map(|f| f.unsubst_ty()) + .collect::>(); // The last field of the structure has to exist and contain type parameters. let field = if let Some(&field) = fields.last() { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 0354918acf8fc..d41ca44ceea5e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -93,8 +93,6 @@ use syntax::ast_util::{self, is_local, local_def}; use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; use syntax::codemap::Span; use syntax::parse::token::{InternedString, special_idents}; -use syntax::print::pprust; -use syntax::ptr::P; use syntax::ast; pub type Disr = u64; @@ -3061,21 +3059,19 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { let adt = match self_type.sty { ty::TyStruct(struct_def, substs) => { - let fields = tcx.struct_fields(struct_def.did, substs); - for field in &fields { - if infcx.type_moves_by_default(field.mt.ty, span) { + for field in struct_def.all_fields() { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { return Err(FieldDoesNotImplementCopy(field.name)) } } struct_def } ty::TyEnum(enum_def, substs) => { - let enum_variants = tcx.enum_variants(enum_def.did); - for variant in enum_variants.iter() { - for variant_arg_type in &variant.args { - let substd_arg_type = - variant_arg_type.subst(tcx, substs); - if infcx.type_moves_by_default(substd_arg_type, span) { + for variant in &enum_def.variants { + for field in &variant.fields { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { return Err(VariantDoesNotImplementCopy(variant.name)) } } @@ -4256,9 +4252,9 @@ impl<'tcx> TyS<'tcx> { } } - pub fn is_empty(&self, cx: &ctxt) -> bool { + pub fn is_empty(&self, _cx: &ctxt) -> bool { match self.sty { - TyEnum(def, _) => cx.enum_variants(def.did).is_empty(), + TyEnum(def, _) | TyStruct(def, _) => def.is_empty(), _ => false } } @@ -4316,18 +4312,15 @@ impl<'tcx> TyS<'tcx> { pub fn simd_type(&self, cx: &ctxt<'tcx>) -> Ty<'tcx> { match self.sty { TyStruct(def, substs) => { - let fields = cx.lookup_struct_fields(def.did); - cx.lookup_field_type(def.did, fields[0].id, substs) + def.struct_variant().fields[0].ty(cx, substs) } _ => panic!("simd_type called on invalid type") } } - pub fn simd_size(&self, cx: &ctxt) -> usize { + pub fn simd_size(&self, _cx: &ctxt) -> usize { match self.sty { - TyStruct(def, _) => { - cx.lookup_struct_fields(def.did).len() - } + TyStruct(def, _) => def.struct_variant().fields.len(), _ => panic!("simd_size called on invalid type") } } @@ -4385,6 +4378,13 @@ impl<'tcx> TyS<'tcx> { _ => None } } + + pub fn ty_adt_def(&self) -> Option<&'tcx ADTDef<'tcx>> { + match self.sty { + TyStruct(adt, _) | TyEnum(adt, _) => Some(adt), + _ => None + } + } } /// Type contents is how the type checker reasons about kinds. @@ -4587,18 +4587,6 @@ impl<'tcx> TyS<'tcx> { } TyStr => TC::None, - TyStruct(def, substs) => { - let flds = cx.struct_fields(def.did, substs); - let mut res = - TypeContents::union(&flds[..], - |f| tc_ty(cx, f.mt.ty, cache)); - - if def.has_dtor(cx) { - res = res | TC::OwnsDtor; - } - apply_lang_items(cx, def.did, res) - } - TyClosure(_, ref substs) => { TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache)) } @@ -4608,13 +4596,11 @@ impl<'tcx> TyS<'tcx> { |ty| tc_ty(cx, *ty, cache)) } - TyEnum(def, substs) => { - let variants = cx.substd_enum_variants(def.did, substs); + TyStruct(def, substs) | TyEnum(def, substs) => { let mut res = - TypeContents::union(&variants[..], |variant| { - TypeContents::union(&variant.args, - |arg_ty| { - tc_ty(cx, *arg_ty, cache) + TypeContents::union(&def.variants, |v| { + TypeContents::union(&v.fields, |f| { + tc_ty(cx, f.ty(cx, substs), cache) }) }); @@ -4794,16 +4780,22 @@ impl<'tcx> TyS<'tcx> { false } - TyStruct(ref did, _) if seen.contains(did) => { - false - } - - TyStruct(def, substs) => { - seen.push(def); - let fields = cx.struct_fields(def.did, substs); - let r = fields.iter().any(|f| type_requires(cx, seen, r_ty, f.mt.ty)); - seen.pop().unwrap(); - r + TyStruct(def, substs) | TyEnum(def, substs) => { + if seen.contains(&def) { + // FIXME(#27497) ??? + false + } else if def.is_empty() { + // HACK: required for empty types to work. This + // check is basically a lint anyway. + false + } else { + seen.push(def); + let r = def.variants.iter().all(|v| v.fields.iter().any(|f| { + type_requires(cx, seen, r_ty, f.ty(cx, substs)) + })); + seen.pop().unwrap(); + r + } } TyError | @@ -4817,23 +4809,6 @@ impl<'tcx> TyS<'tcx> { TyTuple(ref ts) => { ts.iter().any(|ty| type_requires(cx, seen, r_ty, *ty)) } - - TyEnum(ref def, _) if seen.contains(def) => { - false - } - - TyEnum(def, substs) => { - seen.push(def); - let vs = cx.enum_variants(def.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({:?}, {:?})? {:?}", @@ -4888,17 +4863,11 @@ impl<'tcx> TyS<'tcx> { TyArray(ty, _) => { is_type_structurally_recursive(cx, sp, seen, ty) } - TyStruct(def, substs) => { - let fields = cx.struct_fields(def.did, substs); - find_nonrepresentable(cx, sp, seen, fields.iter().map(|f| f.mt.ty)) - } - TyEnum(def, substs) => { - let vs = cx.enum_variants(def.did); - let iter = vs.iter() - .flat_map(|variant| &variant.args) - .map(|aty| { aty.subst_spanned(cx, substs, Some(sp)) }); - - find_nonrepresentable(cx, sp, seen, iter) + TyStruct(def, substs) | TyEnum(def, substs) => { + find_nonrepresentable(cx, + sp, + seen, + def.all_fields().map(|f| f.ty(cx, substs))) } TyClosure(..) => { // this check is run on type definitions, so we don't expect @@ -5094,22 +5063,6 @@ impl<'tcx> TyS<'tcx> { } } - // Whether a type is enum like, that is an enum type with only nullary - // constructors - pub fn is_c_like_enum(&self, cx: &ctxt) -> bool { - match self.sty { - TyEnum(def, _) => { - let variants = cx.enum_variants(def.did); - if variants.is_empty() { - false - } else { - variants.iter().all(|v| v.args.is_empty()) - } - } - _ => false - } - } - // Returns the type and mutability of *ty. // // The parameter `explicit` indicates if this is an *explicit* dereference. @@ -5508,27 +5461,18 @@ impl<'tcx> ctxt<'tcx> { ty: Ty<'tcx>, i: usize, variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyTuple(ref v), None) => v.get(i).cloned(), - - - (&TyStruct(def, substs), None) => self.lookup_struct_fields(def.did) - .get(i) - .map(|&t| self.lookup_item_type(t.id).ty.subst(self, substs)), - - (&TyEnum(def, substs), Some(variant_def_id)) => { - let variant_info = self.enum_variant_with_id(def.did, variant_def_id); - variant_info.args.get(i).map(|t|t.subst(self, substs)) + (&TyStruct(def, substs), None) => { + def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) + } + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) } - (&TyEnum(def, substs), None) => { - assert!(self.enum_is_univariant(def.did)); - let enum_variants = self.enum_variants(def.did); - let variant_info = &enum_variants[0]; - variant_info.args.get(i).map(|t|t.subst(self, substs)) + assert!(def.is_univariant()); + def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) } - + (&TyTuple(ref v), None) => v.get(i).cloned(), _ => None } } @@ -5539,22 +5483,14 @@ impl<'tcx> ctxt<'tcx> { ty: Ty<'tcx>, n: ast::Name, variant: Option) -> Option> { - match (&ty.sty, variant) { (&TyStruct(def, substs), None) => { - let r = self.lookup_struct_fields(def.did); - r.iter().find(|f| f.name == n) - .map(|&f| self.lookup_field_type(def.did, f.id, substs)) - } - (&TyEnum(def, substs), Some(variant_def_id)) => { - let variant_info = self.enum_variant_with_id(def.did, 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) - .find(|&(&name, _)| name == n) - .map(|(_name, arg_t)| arg_t.subst(self, substs)) + def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) } - _ => None + (&TyEnum(def, substs), Some(vid)) => { + def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) + } + _ => return None } } @@ -6022,24 +5958,6 @@ impl<'tcx> ctxt<'tcx> { } } - pub fn substd_enum_variants(&self, - id: ast::DefId, - substs: &Substs<'tcx>) - -> Vec>> { - self.enum_variants(id).iter().map(|variant_info| { - let substd_args = variant_info.args.iter() - .map(|aty| aty.subst(self, substs)).collect::>(); - - let substd_ctor_ty = variant_info.ctor_ty.subst(self, substs); - - Rc::new(VariantInfo { - args: substd_args, - ctor_ty: substd_ctor_ty, - ..(**variant_info).clone() - }) - }).collect() - } - pub fn item_path_str(&self, id: ast::DefId) -> String { self.with_path(id, |path| ast_map::path_to_string(path)) } @@ -6066,10 +5984,6 @@ impl<'tcx> ctxt<'tcx> { } } - pub fn enum_is_univariant(&self, id: ast::DefId) -> bool { - self.enum_variants(id).len() == 1 - } - /// Returns `(normalized_type, ty)`, where `normalized_type` is the /// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8}, /// and `ty` is the original type (i.e. may include `isize` or @@ -6098,133 +6012,6 @@ impl<'tcx> ctxt<'tcx> { (repr_type, repr_type_ty) } - fn report_discrim_overflow(&self, - variant_span: Span, - variant_name: &str, - repr_type: attr::IntType, - prev_val: Disr) { - let computed_value = repr_type.disr_wrap_incr(Some(prev_val)); - let computed_value = repr_type.disr_string(computed_value); - let prev_val = repr_type.disr_string(prev_val); - let repr_type = repr_type.to_ty(self); - span_err!(self.sess, variant_span, E0370, - "enum discriminant overflowed on value after {}: {}; \ - set explicitly via {} = {} if that is desired outcome", - prev_val, repr_type, variant_name, computed_value); - } - - // This computes the discriminant values for the sequence of Variants - // attached to a particular enum, taking into account the #[repr] (if - // any) provided via the `opt_hint`. - fn compute_enum_variants(&self, - vs: &'tcx [P], - opt_hint: Option<&attr::ReprAttr>) - -> Vec>> { - let mut variants: Vec> = Vec::new(); - let mut prev_disr_val: Option = None; - - let (repr_type, repr_type_ty) = self.enum_repr_type(opt_hint); - - for v in vs { - // 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 current_disr_val; - - // This closure marks cases where, when an error occurs during - // the computation, attempt to assign a (hopefully) fresh - // value to avoid spurious error reports downstream. - let attempt_fresh_value = move || -> Disr { - repr_type.disr_wrap_incr(prev_disr_val) - }; - - match v.node.disr_expr { - Some(ref e) => { - debug!("disr expr, checking {}", pprust::expr_to_string(&**e)); - - let hint = UncheckedExprHint(repr_type_ty); - match const_eval::eval_const_expr_partial(self, &**e, hint) { - Ok(ConstVal::Int(val)) => current_disr_val = val as Disr, - Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr, - Ok(_) => { - let sign_desc = if repr_type.is_signed() { - "signed" - } else { - "unsigned" - }; - span_err!(self.sess, e.span, E0079, - "expected {} integer constant", - sign_desc); - current_disr_val = attempt_fresh_value(); - }, - Err(ref err) => { - span_err!(self.sess, err.span, E0080, - "constant evaluation error: {}", - err.description()); - current_disr_val = attempt_fresh_value(); - }, - } - }, - None => { - current_disr_val = match prev_disr_val { - Some(prev_disr_val) => { - if let Some(v) = repr_type.disr_incr(prev_disr_val) { - v - } else { - self.report_discrim_overflow(v.span, &v.node.name.name.as_str(), - repr_type, prev_disr_val); - attempt_fresh_value() - } - } - None => ty::INITIAL_DISCRIMINANT_VALUE, - } - }, - } - - let variant_info = Rc::new(VariantInfo::from_ast_variant(self, &**v, current_disr_val)); - prev_disr_val = Some(current_disr_val); - - variants.push(variant_info); - } - - variants - } - - pub fn enum_variants(&self, id: ast::DefId) -> Rc>>> { - memoized(&self.enum_var_cache, id, |id: ast::DefId| { - if ast::LOCAL_CRATE != id.krate { - Rc::new(csearch::get_enum_variants(self, id)) - } else { - match self.map.get(id.node) { - ast_map::NodeItem(ref item) => { - match item.node { - ast::ItemEnum(ref enum_definition, _) => { - Rc::new(self.compute_enum_variants( - &enum_definition.variants, - self.lookup_repr_hints(id).get(0))) - } - _ => { - self.sess.bug("enum_variants: id not bound to an enum") - } - } - } - _ => self.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(&self, - enum_id: ast::DefId, - variant_id: ast::DefId) - -> Rc> { - self.enum_variants(enum_id).iter() - .find(|variant| variant.id == variant_id) - .expect("enum_variant_with_id(): no variant exists with that ID") - .clone() - } - // Register a given item type pub fn register_item_type(&self, did: ast::DefId, ty: TypeScheme<'tcx>) { self.tcache.borrow_mut().insert(did, ty); @@ -6306,70 +6093,13 @@ impl<'tcx> ctxt<'tcx> { }) } - // Look up a field ID, whether or not it's local - pub fn lookup_field_type_unsubstituted(&self, - struct_id: DefId, - id: DefId) - -> Ty<'tcx> { - if id.krate == ast::LOCAL_CRATE { - self.node_id_to_type(id.node) - } else { - memoized(&self.tcache, id, - |id| csearch::get_field_type(self, struct_id, id)).ty - } - } - - - // 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(&self, - struct_id: DefId, - id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - self.lookup_field_type_unsubstituted(struct_id, id).subst(self, substs) - } - - // Look up the list of field names and IDs for a given struct or struct-variant. - // Panics if the id is not bound to a struct. - pub fn lookup_struct_fields(&self, did: ast::DefId) -> Vec { - if did.krate == ast::LOCAL_CRATE { - let struct_fields = self.struct_fields.borrow(); - match struct_fields.get(&did) { - Some(fields) => (**fields).clone(), - _ => { - self.sess.bug( - &format!("ID not mapped to struct fields: {}", - self.map.node_to_string(did.node))); - } - } - } else { - csearch::get_struct_fields(&self.sess.cstore, did) - } - } - - // 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(&self, did: ast::DefId, substs: &Substs<'tcx>) - -> Vec> { - self.lookup_struct_fields(did).iter().map(|f| { - Field { - name: f.name, - mt: TypeAndMut { - ty: self.lookup_field_type(did, f.id, substs), - mutbl: MutImmutable - } - } - }).collect() - } - /// Returns the deeply last field of nested structures, or the same type, /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { while let TyStruct(def, substs) = ty.sty { - match self.struct_fields(def.did, substs).last() { - Some(f) => ty = f.mt.ty, + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), None => break } } @@ -6390,13 +6120,9 @@ impl<'tcx> ctxt<'tcx> { if a_def != b_def { break; } - if let Some(a_f) = self.struct_fields(a_def.did, a_substs).last() { - if let Some(b_f) = self.struct_fields(b_def.did, b_substs).last() { - a = a_f.mt.ty; - b = b_f.mt.ty; - } else { - break; - } + if let Some(f) = a_def.struct_variant().fields.last() { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); } else { break; } diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index b398b6817f732..e30b85919e281 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -438,11 +438,10 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } } - (&ty::TyStruct(def, ref _substs), None) => { - let fields = tcx.lookup_struct_fields(def.did); + (&ty::TyStruct(def, _), None) => { match *origin_field_name { mc::NamedField(ast_name) => { - for f in &fields { + for f in &def.struct_variant().fields { if f.name == ast_name { continue; } @@ -451,7 +450,7 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } } mc::PositionalField(tuple_idx) => { - for (i, _f) in fields.iter().enumerate() { + for (i, _f) in def.struct_variant().fields.iter().enumerate() { if i == tuple_idx { continue } @@ -462,35 +461,26 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, } } - (&ty::TyEnum(enum_def, substs), ref enum_variant_info) => { - let variant_info = { - let mut variants = tcx.substd_enum_variants(enum_def.did, substs); - 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(), - None => { - assert_eq!(variants.len(), 1); - variants.pop().unwrap() - } + (&ty::TyEnum(def, _), ref enum_variant_info) => { + let variant = match *enum_variant_info { + Some((vid, ref _lp2)) => def.variant_with_id(vid), + None => { + assert!(def.is_univariant()); + &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_name in variant_arg_names { - if variant_arg_name == ast_name { + for field in &variant.fields { + if field.name == ast_name { continue; } - let field_name = mc::NamedField(variant_arg_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.did)); } } mc::PositionalField(tuple_idx) => { - let variant_arg_types = &variant_info.args; - for (i, _variant_arg_ty) in variant_arg_types.iter().enumerate() { + for (i, _f) in variant.fields.iter().enumerate() { if tuple_idx == i { continue; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3ed359cbc3d0a..695cfd43e1424 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -45,7 +45,6 @@ use std::collections::{HashSet, BitSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::{cmp, slice}; use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; -use std::rc::Rc; use syntax::{abi, ast}; use syntax::ast_util::{self, is_shift_binop, local_def}; @@ -413,18 +412,23 @@ enum FfiResult { /// to function pointers and references, but could be /// expanded to cover NonZero raw pointers and newtypes. /// FIXME: This duplicates code in trans. -fn is_repr_nullable_ptr<'tcx>(variants: &Vec>>) -> bool { - if variants.len() == 2 { - let mut data_idx = 0; - - if variants[0].args.is_empty() { +fn is_repr_nullable_ptr<'tcx>(tcx: &ty::ctxt<'tcx>, + def: &ty::ADTDef<'tcx>, + substs: &Substs<'tcx>) + -> bool { + if def.variants.len() == 2 { + let data_idx; + + if def.variants[0].fields.is_empty() { data_idx = 1; - } else if !variants[1].args.is_empty() { + } else if def.variants[1].fields.is_empty() { + data_idx = 0; + } else { return false; } - if variants[data_idx].args.len() == 1 { - match variants[data_idx].args[0].sty { + if def.variants[data_idx].fields.len() == 1 { + match def.variants[data_idx].fields[0].ty(tcx, substs).sty { ty::TyBareFn(None, _) => { return true; } ty::TyRef(..) => { return true; } _ => { } @@ -474,16 +478,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // We can't completely trust repr(C) markings; make sure the // fields are actually safe. - let fields = cx.struct_fields(def.did, substs); - - if fields.is_empty() { + if def.struct_variant().fields.is_empty() { return FfiUnsafe( "found zero-size struct in foreign module, consider \ adding a member to this struct"); } - for field in fields { - let field_ty = infer::normalize_associated_type(cx, &field.mt.ty); + for field in &def.struct_variant().fields { + let field_ty = infer::normalize_associated_type(cx, &field.ty(cx, substs)); let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => {} @@ -494,8 +496,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } ty::TyEnum(def, substs) => { - let variants = cx.substd_enum_variants(def.did, substs); - if variants.is_empty() { + if def.variants.is_empty() { // Empty enums are okay... although sort of useless. return FfiSafe } @@ -506,7 +507,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match &**repr_hints { [] => { // Special-case types like `Option`. - if !is_repr_nullable_ptr(&variants) { + if !is_repr_nullable_ptr(cx, def, substs) { return FfiUnsafe( "found enum without foreign-function-safe \ representation annotation in foreign module, \ @@ -537,9 +538,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } // Check the contained variants. - for variant in variants { - for arg in &variant.args { - let arg = infer::normalize_associated_type(cx, arg); + for variant in &def.variants { + for field in &variant.fields { + let arg = infer::normalize_associated_type(cx, &field.ty(cx, substs)); let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index b59cc65248165..38eabd2e8c3c8 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -34,7 +34,6 @@ use self::FieldName::*; use std::mem::replace; use rustc::ast_map; -use rustc::metadata::csearch; use rustc::middle::def; use rustc::middle::privacy::ImportUse::*; use rustc::middle::privacy::LastPrivate::*; @@ -688,29 +687,26 @@ 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::ADTDef<'tcx>, + v: &'tcx ty::VariantDef<'tcx>, name: FieldName) { - // TODO: refactor to variant API - let fields = self.tcx.lookup_struct_fields(id); let field = match name { NamedField(f_name) => { - debug!("privacy - check named field {} in struct {:?}", f_name, id); - fields.iter().find(|f| f.name == f_name).unwrap() + debug!("privacy - check named field {} in struct {:?}", f_name, def); + v.field_named(f_name) } - UnnamedField(idx) => &fields[idx] + UnnamedField(idx) => &v.fields[idx] }; if field.vis == ast::Public || - (is_local(field.id) && self.private_accessible(field.id.node)) { + (is_local(field.did) && self.private_accessible(field.did.node)) { return } - let struct_type = self.tcx.lookup_item_type(id).ty; - let struct_desc = match struct_type.sty { - ty::TyStruct(_, _) => - format!("struct `{}`", self.tcx.item_path_str(id)), + let struct_desc = match def.adt_kind() { + ty::ADTKind::Struct => + format!("struct `{}`", self.tcx.item_path_str(def.did)), // struct variant fields have inherited visibility - ty::TyEnum(..) => return, - _ => self.tcx.sess.span_bug(span, "can't find struct for field") + ty::ADTKind::Enum => return }; let msg = match name { NamedField(name) => format!("field `{}` of {} is private", @@ -885,12 +881,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match expr.node { ast::ExprField(ref base, ident) => { if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty { - self.check_field(expr.span, def.did, NamedField(ident.node.name)); + self.check_field(expr.span, + def, + def.struct_variant(), + NamedField(ident.node.name)); } } ast::ExprTupField(ref base, idx) => { if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty { - self.check_field(expr.span, def.did, UnnamedField(idx.node)); + self.check_field(expr.span, + def, + def.struct_variant(), + UnnamedField(idx.node)); } } ast::ExprMethodCall(ident, _, _) => { @@ -899,67 +901,36 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { debug!("(privacy checking) checking impl method"); self.check_method(expr.span, method.def_id, ident.node.name); } - ast::ExprStruct(_, ref fields, _) => { - match self.tcx.expr_ty(expr).sty { - ty::TyStruct(ctor_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 = self.tcx.lookup_struct_fields(ctor_def.did); - for field in all_fields { - self.check_field(expr.span, ctor_def.did, - NamedField(field.name)); - } - } - ty::TyEnum(_, _) => { - match self.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() { - def::DefVariant(_, variant_id, _) => { - for field in fields { - self.check_field(expr.span, variant_id, - NamedField(field.ident.node.name)); - } - } - _ => self.tcx.sess.span_bug(expr.span, - "resolve didn't \ - map enum struct \ - constructor to a \ - variant def"), - } - } - _ => self.tcx.sess.span_bug(expr.span, "struct expr \ - didn't have \ - struct type?!"), + ast::ExprStruct(..) => { + let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap(); + let variant = adt.variant_of_def(self.tcx.resolve_expr(expr)); + // 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. + for field in &variant.fields { + self.check_field(expr.span, adt, variant, NamedField(field.name)); } } ast::ExprPath(..) => { - let guard = |did: ast::DefId| { - let fields = self.tcx.lookup_struct_fields(did); - let any_priv = fields.iter().any(|f| { + + if let def::DefStruct(_) = self.tcx.resolve_expr(expr) { + let expr_ty = self.tcx.expr_ty(expr); + let def = match expr_ty.sty { + ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + output: ty::FnConverging(ty), .. + }), ..}) => ty, + _ => expr_ty + }.ty_adt_def().unwrap(); + let any_priv = def.struct_variant().fields.iter().any(|f| { f.vis != ast::Public && ( - !is_local(f.id) || - !self.private_accessible(f.id.node)) - }); + !is_local(f.did) || + !self.private_accessible(f.did.node)) + }); if any_priv { self.tcx.sess.span_err(expr.span, - "cannot invoke tuple struct constructor \ - with private fields"); - } - }; - match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) { - Some(def::DefStruct(did)) => { - guard(if is_local(did) { - local_def(self.tcx.map.get_parent(did.node)) - } else { - // "tuple structs" with zero fields (such as - // `pub struct Foo;`) don't have a ctor_id, hence - // the unwrap_or to the same struct id. - let maybe_did = - csearch::get_tuple_struct_definition_if_ctor( - &self.tcx.sess.cstore, did); - maybe_did.unwrap_or(did) - }) + "cannot invoke tuple struct constructor \ + with private fields"); } - _ => {} } } _ => {} @@ -977,31 +948,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match pattern.node { ast::PatStruct(_, ref fields, _) => { - match self.tcx.pat_ty(pattern).sty { - ty::TyStruct(def, _) => { - for field in fields { - self.check_field(pattern.span, def.did, - NamedField(field.node.ident.name)); - } - } - ty::TyEnum(_, _) => { - 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, - NamedField(field.node.ident.name)); - } - } - _ => self.tcx.sess.span_bug(pattern.span, - "resolve didn't \ - map enum struct \ - pattern to a \ - variant def"), - } - } - _ => self.tcx.sess.span_bug(pattern.span, - "struct pattern didn't have \ - struct type?!"), + let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap(); + let def = self.tcx.def_map.borrow().get(&pattern.id).unwrap().full_def(); + let variant = adt.variant_of_def(def); + for field in fields { + self.check_field(pattern.span, adt, variant, + NamedField(field.node.ident.name)); } } @@ -1014,7 +966,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { if let ast::PatWild(..) = field.node { continue } - self.check_field(field.span, def.did, UnnamedField(i)); + self.check_field(field.span, + def, + def.struct_variant(), + UnnamedField(i)); } } ty::TyEnum(..) => { diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 7500a959931e2..deef88fede7d1 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -742,6 +742,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { ex: &ast::Expr, path: &ast::Path, fields: &Vec, + variant: &ty::VariantDef, base: &Option>) { if generated_code(path.span) { return @@ -756,7 +757,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { Some(struct_lit_data.span), struct_lit_data.ref_id, struct_lit_data.scope); - let struct_def = struct_lit_data.ref_id; let scope = self.save_ctxt.enclosing_scope(ex.id); for field in fields { @@ -765,7 +765,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } let field_data = self.save_ctxt.get_field_ref_data(field, - struct_def, + variant, scope); self.fmt.ref_str(recorder::VarRef, field.ident.span, @@ -804,43 +804,24 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { match p.node { ast::PatStruct(ref path, ref fields, _) => { visit::walk_path(self, path); + let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap(); + let def = self.tcx.def_map.borrow()[&p.id].full_def(); + let variant = adt.variant_of_def(def); - let def = self.tcx.def_map.borrow().get(&p.id).unwrap().full_def(); - let struct_def = match def { - def::DefConst(..) | def::DefAssociatedConst(..) => None, - def::DefVariant(_, variant_id, _) => Some(variant_id), - _ => { - match self.tcx.node_id_to_type(p.id).ty_to_def_id() { - None => { - self.sess.span_bug(p.span, - &format!("Could not find struct_def for `{}`", - self.span.snippet(p.span))); - } - Some(def_id) => Some(def_id), - } + for &Spanned { node: ref field, span } in fields { + if generated_code(span) { + continue; } - }; - if let Some(struct_def) = struct_def { - let struct_fields = self.tcx.lookup_struct_fields(struct_def); - for &Spanned { node: ref field, span } in fields { - if generated_code(span) { - continue; - } - - let sub_span = self.span.span_for_first_ident(span); - for f in &struct_fields { - if f.name == field.ident.name { - self.fmt.ref_str(recorder::VarRef, - span, - sub_span, - f.id, - self.cur_scope); - break; - } - } - self.visit_pat(&field.pat); + let sub_span = self.span.span_for_first_ident(span); + if let Some(f) = variant.find_field_named(field.ident.name) { + self.fmt.ref_str(recorder::VarRef, + span, + sub_span, + f.did, + self.cur_scope); } + self.visit_pat(&field.pat); } } _ => visit::walk_pat(self, p) @@ -1091,8 +1072,15 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { self.process_path(ex.id, path, None); visit::walk_expr(self, ex); } - ast::ExprStruct(ref path, ref fields, ref base) => - self.process_struct_lit(ex, path, fields, base), + ast::ExprStruct(ref path, ref fields, ref base) => { + let adt = self.tcx.expr_ty(ex).ty_adt_def().unwrap(); + let def = self.tcx.resolve_expr(ex); + self.process_struct_lit(ex, + path, + fields, + adt.variant_of_def(def), + base) + } ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args), ast::ExprField(ref sub_ex, _) => { if generated_code(sub_ex.span) { @@ -1120,18 +1108,12 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { let ty = &self.tcx.expr_ty_adjusted(&**sub_ex).sty; match *ty { ty::TyStruct(def, _) => { - let fields = self.tcx.lookup_struct_fields(def.did); - for (i, f) in fields.iter().enumerate() { - if i == idx.node { - let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); - self.fmt.ref_str(recorder::VarRef, - ex.span, - sub_span, - f.id, - self.cur_scope); - break; - } - } + let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); + self.fmt.ref_str(recorder::VarRef, + ex.span, + sub_span, + def.struct_variant().fields[idx.node].did, + self.cur_scope); } ty::TyTuple(_) => {} _ => self.sess.span_bug(ex.span, diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index dbab7f4a0a970..78c224131f19c 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -448,22 +448,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ty = &self.tcx.expr_ty_adjusted(&sub_ex).sty; match *ty { ty::TyStruct(def, _) => { - let fields = self.tcx.lookup_struct_fields(def.did); - for f in &fields { - if f.name == ident.node.name { - let sub_span = self.span_utils.span_for_last_ident(expr.span); - return Some(Data::VariableRefData(VariableRefData { - name: ident.node.to_string(), - span: sub_span.unwrap(), - scope: self.enclosing_scope(expr.id), - ref_id: f.id, - })); - } - } - - self.tcx.sess.span_bug(expr.span, - &format!("Couldn't find field {} on {:?}", - ident.node, ty)) + let f = def.struct_variant().field_named(ident.node.name); + let sub_span = self.span_utils.span_for_last_ident(expr.span); + return Some(Data::VariableRefData(VariableRefData { + name: ident.node.to_string(), + span: sub_span.unwrap(), + scope: self.enclosing_scope(expr.id), + ref_id: f.did, + })); } _ => { debug!("Expected struct type, found {:?}", ty); @@ -621,26 +613,18 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_field_ref_data(&self, field_ref: &ast::Field, - struct_id: DefId, + variant: &ty::VariantDef, parent: NodeId) -> VariableRefData { - let fields = self.tcx.lookup_struct_fields(struct_id); - let field_name = field_ref.ident.node.to_string(); - for f in &fields { - if f.name == field_ref.ident.node.name { - // We don't really need a sub-span here, but no harm done - let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); - return VariableRefData { - name: field_name, - span: sub_span.unwrap(), - scope: parent, - ref_id: f.id, - }; - } + let f = variant.field_named(field_ref.ident.node.name); + // We don't really need a sub-span here, but no harm done + let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); + VariableRefData { + name: field_ref.ident.node.to_string(), + span: sub_span.unwrap(), + scope: parent, + ref_id: f.did, } - - self.tcx.sess.span_bug(field_ref.span, - &format!("Couldn't find field {}", field_name)); } pub fn get_data_for_id(&self, _id: &NodeId) -> Data { diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 79fe9b90e7d9c..bd7c67fa8bb8d 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -656,7 +656,7 @@ 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 = tcx.enum_variant_with_id(enum_id, var_id); + let variant = tcx.lookup_adt_def(enum_id).variant_with_id(var_id); Variant(variant.disr_val, adt::represent_node(bcx, cur.id), var_id, @@ -1190,10 +1190,8 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // The last field is technically unsized but // since we can only ever match that field behind // a reference we construct a fat ptr here. - let fields = bcx.tcx().lookup_struct_fields(def.did); - let unsized_ty = fields.iter().last().map(|field| { - let fty = bcx.tcx().lookup_field_type(def.did, field.id, substs); - monomorphize::normalize_associated_type(bcx.tcx(), &fty) + let unsized_ty = def.struct_variant().fields.last().map(|field| { + monomorphize::field_ty(bcx.tcx(), substs, field) }).unwrap(); let llty = type_of::type_of(bcx.ccx(), unsized_ty); let scratch = alloca_no_lifetime(bcx, llty, "__struct_field_fat_ptr"); @@ -1833,7 +1831,7 @@ pub 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 = ccx.tcx().enum_variant_with_id(enum_id, var_id); + let vinfo = ccx.tcx().lookup_adt_def(enum_id).variant_with_id(var_id); let args = extract_variant_args(bcx, &*repr, vinfo.disr_val, @@ -1877,21 +1875,20 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let tcx = bcx.tcx(); let pat_ty = node_id_type(bcx, pat.id); 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 = tcx.field_idx_strict(f.node.ident.name, field_tys); - let fldptr = adt::trans_field_ptr( - bcx, - &*pat_repr, - val.val, - discr, - ix); - bcx = bind_irrefutable_pat(bcx, - &*f.node.pat, - MatchInput::from_val(fldptr), - cleanup_scope); - } - }) + let pat_v = VariantInfo::of_node(tcx, pat_ty, pat.id); + for f in fields { + let name = f.node.ident.name; + let fldptr = adt::trans_field_ptr( + bcx, + &*pat_repr, + val.val, + pat_v.discr, + pat_v.field_index(name)); + bcx = bind_irrefutable_pat(bcx, + &*f.node.pat, + MatchInput::from_val(fldptr), + cleanup_scope); + } } ast::PatTup(ref elems) => { let repr = adt::represent_node(bcx, pat.id); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 62286b7995aa4..9fb808a7d2d93 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -246,10 +246,8 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &elems[..], false, t), 0) } ty::TyStruct(def, substs) => { - let fields = cx.tcx().lookup_struct_fields(def.did); - let mut ftys = fields.iter().map(|field| { - let fty = cx.tcx().lookup_field_type(def.did, field.id, substs); - monomorphize::normalize_associated_type(cx.tcx(), &fty) + let mut ftys = def.struct_variant().fields.iter().map(|field| { + monomorphize::field_ty(cx.tcx(), substs, field) }).collect::>(); let packed = cx.tcx().lookup_packed(def.did); let dtor = cx.tcx().ty_dtor(def.did).has_drop_flag(); @@ -263,7 +261,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &substs.upvar_tys, false, t), 0) } ty::TyEnum(def, substs) => { - let cases = get_cases(cx.tcx(), def.did, substs); + let cases = get_cases(cx.tcx(), def, substs); let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) .unwrap_or(&attr::ReprAny); @@ -444,10 +442,10 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // Is this the NonZero lang item wrapping a pointer or integer type? ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { - let nonzero_fields = tcx.lookup_struct_fields(def.did); + let nonzero_fields = &def.struct_variant().fields; assert_eq!(nonzero_fields.len(), 1); - let nonzero_field = tcx.lookup_field_type(def.did, nonzero_fields[0].id, substs); - match nonzero_field.sty { + let field_ty = monomorphize::field_ty(tcx, substs, &nonzero_fields[0]); + match field_ty.sty { ty::TyRawPtr(ty::TypeAndMut { ty, .. }) if !type_is_sized(tcx, ty) => { path.push_all(&[0, FAT_PTR_ADDR]); Some(path) @@ -463,9 +461,9 @@ 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::TyStruct(def, substs) => { - let fields = tcx.lookup_struct_fields(def.did); - for (j, field) in fields.iter().enumerate() { - let field_ty = tcx.lookup_field_type(def.did, field.id, substs); + for (j, field) in def.struct_variant().fields.iter().enumerate() { + // TODO(#27532) + let field_ty = field.ty(tcx, substs); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { fpath.push(j); return Some(fpath); @@ -530,14 +528,14 @@ impl<'tcx> Case<'tcx> { } fn get_cases<'tcx>(tcx: &ty::ctxt<'tcx>, - def_id: ast::DefId, + adt: &ty::ADTDef<'tcx>, substs: &subst::Substs<'tcx>) -> Vec> { - tcx.enum_variants(def_id).iter().map(|vi| { - let arg_tys = vi.args.iter().map(|&raw_ty| { - monomorphize::apply_param_substs(tcx, substs, &raw_ty) + adt.variants.iter().map(|vi| { + let field_tys = vi.fields.iter().map(|field| { + monomorphize::field_ty(tcx, substs, field) }).collect(); - Case { discr: vi.disr_val, tys: arg_tys } + Case { discr: vi.disr_val, tys: field_tys } }).collect() } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 25e139474bd4d..d119e0006c661 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -55,8 +55,8 @@ use trans::cleanup::{self, CleanupMethods, DropHint}; use trans::closure; use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral}; use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; -use trans::common::{CrateContext, DropFlagHintsMap, FunctionContext}; -use trans::common::{Result, NodeIdAndSpan}; +use trans::common::{CrateContext, DropFlagHintsMap, Field, FunctionContext}; +use trans::common::{Result, NodeIdAndSpan, VariantInfo}; use trans::common::{node_id_type, return_type_is_void}; use trans::common::{type_is_immediate, type_is_zero_size, val_ty}; use trans::common; @@ -386,7 +386,7 @@ 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>, + variant: &ty::VariantDef<'tcx>, substs: &Substs<'tcx>, f: &mut F) -> Block<'blk, 'tcx> where @@ -396,8 +396,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, field) in variant.fields.iter().enumerate() { + let arg = monomorphize::field_ty(tcx, substs, field); cx = f(cx, adt::trans_field_ptr(cx, repr, av, variant.disr_val, i), arg); } return cx; @@ -415,22 +415,20 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, match t.sty { ty::TyStruct(..) => { 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 llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i); - - let val = if common::type_is_sized(cx.tcx(), field_ty) { - llfld_a - } else { - let scratch = datum::rvalue_scratch_datum(cx, field_ty, "__fat_ptr_iter"); - Store(cx, llfld_a, GEPi(cx, scratch.val, &[0, abi::FAT_PTR_ADDR])); - Store(cx, info.unwrap(), GEPi(cx, scratch.val, &[0, abi::FAT_PTR_EXTRA])); - scratch.val - }; - cx = f(cx, val, field_ty); - } - }) + let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); + for (i, &Field(_, field_ty)) in fields.iter().enumerate() { + let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i); + + let val = if common::type_is_sized(cx.tcx(), field_ty) { + llfld_a + } else { + let scratch = datum::rvalue_scratch_datum(cx, field_ty, "__fat_ptr_iter"); + Store(cx, llfld_a, GEPi(cx, scratch.val, &[0, abi::FAT_PTR_ADDR])); + Store(cx, info.unwrap(), GEPi(cx, scratch.val, &[0, abi::FAT_PTR_EXTRA])); + scratch.val + }; + cx = f(cx, val, field_ty); + } } ty::TyClosure(_, ref substs) => { let repr = adt::represent_type(cx.ccx(), t); @@ -460,8 +458,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, let ccx = fcx.ccx; let repr = adt::represent_type(ccx, t); - let variants = ccx.tcx().enum_variants(en.did); - let n_variants = (*variants).len(); + let n_variants = en.variants.len(); // NB: we must hit the discriminant first so that structural // comparison know not to proceed when the discriminants differ. @@ -470,7 +467,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, (_match::Single, None) => { if n_variants != 0 { assert!(n_variants == 1); - cx = iter_variant(cx, &*repr, av, &*(*variants)[0], + cx = iter_variant(cx, &*repr, av, &en.variants[0], substs, &mut f); } } @@ -496,7 +493,7 @@ 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) { + for variant in &en.variants { let variant_cx = fcx.new_temp_block( &format!("enum-iter-variant-{}", @@ -513,7 +510,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); @@ -1694,9 +1691,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } pub fn trans_enum_variant<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - _enum_id: ast::NodeId, - variant: &ast::Variant, - _args: &[ast::VariantArg], + ctor_id: ast::NodeId, disr: ty::Disr, param_substs: &'tcx Substs<'tcx>, llfndecl: ValueRef) { @@ -1704,7 +1699,7 @@ pub fn trans_enum_variant<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trans_enum_variant_or_tuple_like_struct( ccx, - variant.node.id, + ctor_id, disr, param_substs, llfndecl); @@ -1776,7 +1771,6 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } pub fn trans_tuple_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - _fields: &[ast::StructField], ctor_id: ast::NodeId, param_substs: &'tcx Substs<'tcx>, llfndecl: ValueRef) { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index a60217be40988..d0d5b46ab2839 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -182,10 +182,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) fn_callee(bcx, fn_datum) } def::DefVariant(tid, vid, _) => { - let vinfo = bcx.tcx().enum_variant_with_id(tid, vid); - - // Nullary variants are not callable - assert!(!vinfo.args.is_empty()); + let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid); + assert_eq!(vinfo.kind(), ty::VariantKind::Tuple); Callee { bcx: bcx, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index cfb8770084254..15c81b114d307 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -49,6 +49,7 @@ use std::cell::{Cell, RefCell}; use std::result::Result as StdResult; use std::vec::Vec; use syntax::ast; +use syntax::ast_util::local_def; use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::InternedString; use syntax::parse::token; @@ -174,11 +175,9 @@ fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { ty::TyStruct(def, substs) => { - let fields = ccx.tcx().lookup_struct_fields(def.did); + let fields = &def.struct_variant().fields; fields.len() == 1 && { - let ty = ccx.tcx().lookup_field_type(def.did, fields[0].id, substs); - let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty); - type_is_immediate(ccx, ty) + type_is_immediate(ccx, monomorphize::field_ty(ccx.tcx(), substs, &fields[0])) } } _ => false @@ -271,6 +270,67 @@ pub fn expr_info(expr: &ast::Expr) -> NodeIdAndSpan { NodeIdAndSpan { id: expr.id, span: expr.span } } +/// The concrete version of ty::FieldDef. The name is the field index if +/// the field is numeric. +pub struct Field<'tcx>(pub ast::Name, pub Ty<'tcx>); + +/// The concrete version of ty::VariantDef +pub struct VariantInfo<'tcx> { + pub discr: ty::Disr, + pub fields: Vec> +} + +impl<'tcx> VariantInfo<'tcx> { + pub fn from_ty(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + opt_def: Option) + -> Self + { + match ty.sty { + ty::TyStruct(adt, substs) | ty::TyEnum(adt, substs) => { + let variant = match opt_def { + None => adt.struct_variant(), + Some(def) => adt.variant_of_def(def) + }; + + VariantInfo { + discr: variant.disr_val, + fields: variant.fields.iter().map(|f| { + Field(f.name, monomorphize::field_ty(tcx, substs, f)) + }).collect() + } + } + + ty::TyTuple(ref v) => { + VariantInfo { + discr: 0, + fields: v.iter().enumerate().map(|(i, &t)| { + Field(token::intern(&i.to_string()), t) + }).collect() + } + } + + _ => { + tcx.sess.bug(&format!( + "cannot get field types from the type {:?}", + ty)); + } + } + } + + /// Return the variant corresponding to a given node (e.g. expr) + pub fn of_node(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, id: ast::NodeId) -> Self { + let node_def = tcx.def_map.borrow().get(&id).map(|v| v.full_def()); + Self::from_ty(tcx, ty, node_def) + } + + pub fn field_index(&self, name: ast::Name) -> usize { + self.fields.iter().position(|&Field(n,_)| n == name).unwrap_or_else(|| { + panic!("unknown field `{}`", name) + }) + } +} + pub struct BuilderRef_res { pub b: BuilderRef, } @@ -1178,3 +1238,26 @@ pub fn langcall(bcx: Block, } } } + +/// Return the VariantDef corresponding to an inlined variant node +pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + inlined_vid: ast::NodeId) + -> &'tcx ty::VariantDef<'tcx> +{ + + let ctor_ty = ccx.tcx().node_id_to_type(inlined_vid); + debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty, + inlined_vid); + let adt_def = match ctor_ty.sty { + ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + output: ty::FnConverging(ty), .. + }), ..}) => ty, + _ => ctor_ty + }.ty_adt_def().unwrap(); + adt_def.variants.iter().find(|v| { + local_def(inlined_vid) == v.did || + ccx.external().borrow().get(&v.did) == Some(&Some(inlined_vid)) + }).unwrap_or_else(|| { + ccx.sess().bug(&format!("no variant for {:?}::{}", adt_def, inlined_vid)) + }) +} diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 71ba4d73dace0..7a9ddf5a99cd4 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -579,17 +579,15 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ast::ExprField(ref base, field) => { let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); let brepr = adt::represent_type(cx, bt); - expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { - let ix = cx.tcx().field_idx_strict(field.node.name, field_tys); - adt::const_get_field(cx, &*brepr, bv, discr, ix) - }) + let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); + let ix = vinfo.field_index(field.node.name); + adt::const_get_field(cx, &*brepr, bv, vinfo.discr, ix) }, ast::ExprTupField(ref base, idx) => { let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); let brepr = adt::represent_type(cx, bt); - expr::with_field_tys(cx.tcx(), bt, None, |discr, _| { - adt::const_get_field(cx, &*brepr, bv, discr, idx.node) - }) + let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None); + adt::const_get_field(cx, &*brepr, bv, vinfo.discr, idx.node) }, ast::ExprIndex(ref base, ref index) => { @@ -664,8 +662,8 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } unsafe { match ( - CastTy::from_ty(cx.tcx(), t_expr).expect("bad input type for cast"), - CastTy::from_ty(cx.tcx(), t_cast).expect("bad output type for cast"), + CastTy::from_ty(t_expr).expect("bad input type for cast"), + CastTy::from_ty(t_cast).expect("bad output type for cast"), ) { (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => { let repr = adt::represent_type(cx, t_expr); @@ -748,21 +746,19 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, None => None }; - expr::with_field_tys(cx.tcx(), ety, Some(e.id), |discr, field_tys| { - let cs = field_tys.iter().enumerate() - .map(|(ix, &field_ty)| { - match (fs.iter().find(|f| field_ty.name == f.ident.node.name), base_val) { - (Some(ref f), _) => const_expr(cx, &*f.expr, param_substs, fn_args).0, - (_, Some((bv, _))) => adt::const_get_field(cx, &*repr, bv, discr, ix), - (_, None) => cx.sess().span_bug(e.span, "missing struct field"), - } - }).collect::>(); - if ety.is_simd(cx.tcx()) { - C_vector(&cs[..]) - } else { - adt::trans_const(cx, &*repr, discr, &cs[..]) + let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id); + let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| { + match (fs.iter().find(|f| f_name == f.ident.node.name), base_val) { + (Some(ref f), _) => const_expr(cx, &*f.expr, param_substs, fn_args).0, + (_, Some((bv, _))) => adt::const_get_field(cx, &*repr, bv, discr, ix), + (_, None) => cx.sess().span_bug(e.span, "missing struct field"), } - }) + }).collect::>(); + if ety.is_simd(cx.tcx()) { + C_vector(&cs[..]) + } else { + adt::trans_const(cx, &*repr, discr, &cs[..]) + } }, ast::ExprVec(ref es) => { let unit_ty = ety.sequence_element_type(cx.tcx()); @@ -806,14 +802,18 @@ 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 = cx.tcx().enum_variant_with_id(enum_did, variant_did); - if !vinfo.args.is_empty() { - // 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, &[]) + let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); + match vinfo.kind() { + ty::VariantKind::Unit => { + let repr = adt::represent_type(cx, ety); + adt::trans_const(cx, &*repr, vinfo.disr_val, &[]) + } + ty::VariantKind::Tuple => { + expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val + } + ty::VariantKind::Dict => { + cx.sess().span_bug(e.span, "path-expr refers to a dict variant!") + } } } def::DefStruct(_) => { @@ -859,7 +859,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } def::DefVariant(enum_did, variant_did, _) => { let repr = adt::represent_type(cx, ety); - let vinfo = cx.tcx().enum_variant_with_id(enum_did, variant_did); + let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); adt::trans_const(cx, &*repr, vinfo.disr_val, diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index e7499ad9301ad..98188a40e1036 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -44,7 +44,7 @@ use std::rc::Rc; use syntax::util::interner::Interner; use syntax::codemap::Span; use syntax::{ast, codemap, ast_util}; -use syntax::parse::token::{self, special_idents}; +use syntax::parse::token; const DW_LANG_RUST: c_uint = 0x9000; @@ -784,11 +784,9 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } - ty::TyStruct(def, substs) => { + ty::TyStruct(..) => { prepare_struct_metadata(cx, t, - def.did, - substs, unique_type_id, usage_site_span).finalize(cx) } @@ -1096,7 +1094,8 @@ impl<'tcx> MemberDescriptionFactory<'tcx> { // Creates MemberDescriptions for the fields of a struct struct StructMemberDescriptionFactory<'tcx> { - fields: Vec>, + variant: &'tcx ty::VariantDef<'tcx>, + substs: &'tcx subst::Substs<'tcx>, is_simd: bool, span: Span, } @@ -1104,34 +1103,40 @@ struct StructMemberDescriptionFactory<'tcx> { impl<'tcx> StructMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { - if self.fields.is_empty() { + if let ty::VariantKind::Unit = self.variant.kind() { return Vec::new(); } let field_size = if self.is_simd { - machine::llsize_of_alloc(cx, type_of::type_of(cx, self.fields[0].mt.ty)) as usize + let fty = monomorphize::field_ty(cx.tcx(), + self.substs, + &self.variant.fields[0]); + Some(machine::llsize_of_alloc( + cx, + type_of::type_of(cx, fty) + ) as usize) } else { - 0xdeadbeef + None }; - self.fields.iter().enumerate().map(|(i, field)| { - let name = if field.name == special_idents::unnamed_field.name { + self.variant.fields.iter().enumerate().map(|(i, f)| { + let name = if let ty::VariantKind::Tuple = self.variant.kind() { format!("__{}", i) } else { - field.name.to_string() + f.name.to_string() }; + let fty = monomorphize::field_ty(cx.tcx(), self.substs, f); let offset = if self.is_simd { - assert!(field_size != 0xdeadbeef); - FixedMemberOffset { bytes: i * field_size } + FixedMemberOffset { bytes: i * field_size.unwrap() } } else { ComputedMemberOffset }; 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, fty), + type_metadata: type_metadata(cx, fty, self.span), offset: offset, flags: FLAGS_NONE, } @@ -1142,15 +1147,18 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, struct_type: Ty<'tcx>, - def_id: ast::DefId, - substs: &subst::Substs<'tcx>, unique_type_id: UniqueTypeId, span: Span) -> RecursiveTypeDescription<'tcx> { let struct_name = compute_debuginfo_type_name(cx, struct_type, false); let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type); - let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); + let (variant, substs) = match struct_type.sty { + ty::TyStruct(def, substs) => (def.struct_variant(), substs), + _ => cx.tcx().sess.bug("prepare_struct_metadata on a non-struct") + }; + + let (containing_scope, _) = get_namespace_and_span_for_item(cx, variant.did); let struct_metadata_stub = create_struct_stub(cx, struct_llvm_type, @@ -1158,14 +1166,6 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, containing_scope); - let mut fields = cx.tcx().struct_fields(def_id, substs); - - // The `Ty` values returned by `ty::struct_fields` can still contain - // `TyProjection` variants, so normalize those away. - for field in &mut fields { - field.mt.ty = monomorphize::normalize_associated_type(cx.tcx(), &field.mt.ty); - } - create_and_register_recursive_type_forward_declaration( cx, struct_type, @@ -1173,7 +1173,8 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, struct_metadata_stub, struct_llvm_type, StructMDF(StructMemberDescriptionFactory { - fields: fields, + variant: variant, + substs: substs, is_simd: struct_type.is_simd(cx.tcx()), span: span, }) @@ -1248,7 +1249,6 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, struct EnumMemberDescriptionFactory<'tcx> { enum_type: Ty<'tcx>, type_rep: Rc>, - variants: Rc>>>, discriminant_type_metadata: Option, containing_scope: DIScope, file_metadata: DIFile, @@ -1258,11 +1258,11 @@ struct EnumMemberDescriptionFactory<'tcx> { impl<'tcx> EnumMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { + let adt = &self.enum_type.ty_adt_def().unwrap(); match *self.type_rep { adt::General(_, ref struct_defs, _) => { let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata .expect("")); - struct_defs .iter() .enumerate() @@ -1273,7 +1273,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { describe_enum_variant(cx, self.enum_type, struct_def, - &*self.variants[i], + &adt.variants[i], discriminant_info, self.containing_scope, self.span); @@ -1295,9 +1295,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { }).collect() }, adt::Univariant(ref struct_def, _) => { - assert!(self.variants.len() <= 1); + assert!(adt.variants.len() <= 1); - if self.variants.is_empty() { + if adt.variants.is_empty() { vec![] } else { let (variant_type_metadata, @@ -1306,7 +1306,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { describe_enum_variant(cx, self.enum_type, struct_def, - &*self.variants[0], + &adt.variants[0], NoDiscriminant, self.containing_scope, self.span); @@ -1335,7 +1335,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // DWARF representation of enums uniform. // First create a description of the artificial wrapper struct: - let non_null_variant = &self.variants[non_null_variant_index as usize]; + let non_null_variant = &adt.variants[non_null_variant_index as usize]; let non_null_variant_name = non_null_variant.name.as_str(); // The llvm type and metadata of the pointer @@ -1350,9 +1350,12 @@ 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) => names[0].to_string(), - None => "__0".to_string() + name: match non_null_variant.kind() { + ty::VariantKind::Tuple => "__0".to_string(), + ty::VariantKind::Dict => { + non_null_variant.fields[0].name.to_string() + } + ty::VariantKind::Unit => unreachable!() }, llvm_type: non_null_llvm_type, type_metadata: non_null_type_metadata, @@ -1381,7 +1384,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // Encode the information about the null variant in the union // member's name. let null_variant_index = (1 - non_null_variant_index) as usize; - let null_variant_name = self.variants[null_variant_index].name; + let null_variant_name = adt.variants[null_variant_index].name; let union_member_name = format!("RUST$ENCODED$ENUM${}${}", 0, null_variant_name); @@ -1406,7 +1409,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { describe_enum_variant(cx, self.enum_type, struct_def, - &*self.variants[nndiscr as usize], + &adt.variants[nndiscr as usize], OptimizedDiscriminant, self.containing_scope, self.span); @@ -1422,7 +1425,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // Encode the information about the null variant in the union // member's name. let null_variant_index = (1 - nndiscr) as usize; - let null_variant_name = self.variants[null_variant_index].name; + let null_variant_name = adt.variants[null_variant_index].name; let discrfield = discrfield.iter() .skip(1) .map(|x| x.to_string()) @@ -1486,7 +1489,7 @@ enum EnumDiscriminantInfo { fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, enum_type: Ty<'tcx>, struct_def: &adt::Struct<'tcx>, - variant_info: &ty::VariantInfo<'tcx>, + variant: &ty::VariantDef<'tcx>, discriminant_info: EnumDiscriminantInfo, containing_scope: DIScope, span: Span) @@ -1500,7 +1503,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, struct_def.packed); // Could do some consistency checks here: size, align, field count, discr type - let variant_name = variant_info.name.as_str(); + let variant_name = variant.name.as_str(); let unique_type_id = debug_context(cx).type_map .borrow_mut() .get_unique_type_id_of_enum_variant( @@ -1515,18 +1518,20 @@ 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(|name| name.to_string()) - .collect() + let mut arg_names: Vec<_> = match variant.kind() { + ty::VariantKind::Unit => vec![], + ty::VariantKind::Tuple => { + variant.fields + .iter() + .enumerate() + .map(|(i, _)| format!("__{}", i)) + .collect() } - None => { - variant_info.args - .iter() - .enumerate() - .map(|(i, _)| format!("__{}", i)) - .collect() + ty::VariantKind::Dict => { + variant.fields + .iter() + .map(|f| f.name.to_string()) + .collect() } }; @@ -1569,7 +1574,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let loc = span_start(cx, definition_span); let file_metadata = file_metadata(cx, &loc.file.name); - let variants = cx.tcx().enum_variants(enum_def_id); + let variants = &enum_type.ty_adt_def().unwrap().variants; let enumerators_metadata: Vec = variants .iter() @@ -1671,7 +1676,6 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, EnumMDF(EnumMemberDescriptionFactory { enum_type: enum_type, type_rep: type_rep.clone(), - variants: variants, discriminant_type_metadata: discriminant_type_metadata, containing_scope: containing_scope, file_metadata: file_metadata, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 36eff73199506..baf14df5b804d 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -68,7 +68,6 @@ use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; use trans::glue; use trans::machine; use trans::meth; -use trans::monomorphize; use trans::tvec; use trans::type_of; use middle::cast::{CastKind, CastTy}; @@ -708,7 +707,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>]) -> usize, + F: FnOnce(&'blk ty::ctxt<'tcx>, &VariantInfo<'tcx>) -> usize, { let mut bcx = bcx; let _icx = push_ctxt("trans_rec_field"); @@ -716,27 +715,26 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field")); 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 d = base_datum.get_element( - bcx, - field_tys[ix].mt.ty, - |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix)); - - if type_is_sized(bcx.tcx(), d.ty) { - DatumBlock { datum: d.to_expr_datum(), bcx: bcx } - } else { - let scratch = rvalue_scratch_datum(bcx, d.ty, ""); - Store(bcx, d.val, get_dataptr(bcx, scratch.val)); - let info = Load(bcx, get_len(bcx, base_datum.val)); - Store(bcx, info, get_len(bcx, scratch.val)); + let vinfo = VariantInfo::from_ty(bcx.tcx(), bare_ty, None); - // Always generate an lvalue datum, because this pointer doesn't own - // the data and cleanup is scheduled elsewhere. - DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr(d.kind))) - } - }) + let ix = get_idx(bcx.tcx(), &vinfo); + let d = base_datum.get_element( + bcx, + vinfo.fields[ix].1, + |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, vinfo.discr, ix)); + if type_is_sized(bcx.tcx(), d.ty) { + DatumBlock { datum: d.to_expr_datum(), bcx: bcx } + } else { + let scratch = rvalue_scratch_datum(bcx, d.ty, ""); + Store(bcx, d.val, get_dataptr(bcx, scratch.val)); + let info = Load(bcx, get_len(bcx, base_datum.val)); + Store(bcx, info, get_len(bcx, scratch.val)); + + // Always generate an lvalue datum, because this pointer doesn't own + // the data and cleanup is scheduled elsewhere. + DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr(d.kind))) + } } /// Translates `base.field`. @@ -744,7 +742,7 @@ fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, base: &ast::Expr, field: ast::Name) -> DatumBlock<'blk, 'tcx, Expr> { - trans_field(bcx, base, |tcx, field_tys| tcx.field_idx_strict(field, field_tys)) + trans_field(bcx, base, |_, vinfo| vinfo.field_index(field)) } /// Translates `base.`. @@ -1249,8 +1247,8 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match def { def::DefVariant(tid, vid, _) => { - let variant_info = bcx.tcx().enum_variant_with_id(tid, vid); - if !variant_info.args.is_empty() { + let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid); + if let ty::VariantKind::Tuple = variant.kind() { // N-ary variant. let llfn = callee::trans_fn_ref(bcx.ccx(), vid, ExprId(ref_expr.id), @@ -1261,8 +1259,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Nullary variant. 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); + adt::trans_set_discr(bcx, &*repr, lldest, variant.disr_val); return bcx; } } @@ -1362,71 +1359,6 @@ pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, '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). -pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>, - ty: Ty<'tcx>, - node_id_opt: Option, - op: F) - -> R where - F: FnOnce(ty::Disr, &[ty::Field<'tcx>]) -> R, -{ - match ty.sty { - ty::TyStruct(def, substs) => { - let fields = tcx.struct_fields(def.did, substs); - let fields = monomorphize::normalize_associated_type(tcx, &fields); - op(0, &fields[..]) - } - - ty::TyTuple(ref v) => { - let fields: Vec<_> = v.iter().enumerate().map(|(i, &f)| { - ty::Field { - name: token::intern(&i.to_string()), - mt: ty::TypeAndMut { - ty: f, - mutbl: ast::MutImmutable - } - } - }).collect(); - op(0, &fields) - } - - ty::TyEnum(_, substs) => { - // We want the *variant* ID here, not the enum ID. - match node_id_opt { - None => { - tcx.sess.bug(&format!( - "cannot get field types from the enum type {:?} \ - without a node ID", - ty)); - } - Some(node_id) => { - let def = tcx.def_map.borrow().get(&node_id).unwrap().full_def(); - match def { - def::DefVariant(enum_id, variant_id, _) => { - let variant_info = tcx.enum_variant_with_id(enum_id, variant_id); - let fields = tcx.struct_fields(variant_id, substs); - let fields = monomorphize::normalize_associated_type(tcx, &fields); - op(variant_info.disr_val, &fields[..]) - } - _ => { - tcx.sess.bug("resolve didn't map this expr to a \ - variant ID") - } - } - } - } - } - - _ => { - tcx.sess.bug(&format!( - "cannot get field types from the type {:?}", - ty)); - } - } -} - fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fields: &[ast::Field], base: Option<&ast::Expr>, @@ -1437,52 +1369,42 @@ fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_rec"); let tcx = bcx.tcx(); - with_field_tys(tcx, ty, Some(expr_id), |discr, field_tys| { - let mut need_base = vec![true; field_tys.len()]; - - let numbered_fields = fields.iter().map(|field| { - let opt_pos = - field_tys.iter().position(|field_ty| - field_ty.name == field.ident.node.name); - let result = match opt_pos { - Some(i) => { - need_base[i] = false; - (i, &*field.expr) - } - None => { - tcx.sess.span_bug(field.span, - "Couldn't find field in struct type") + let vinfo = VariantInfo::of_node(tcx, ty, expr_id); + + let mut need_base = vec![true; vinfo.fields.len()]; + + let numbered_fields = fields.iter().map(|field| { + let pos = vinfo.field_index(field.ident.node.name); + need_base[pos] = false; + (pos, &*field.expr) + }).collect::>(); + + let optbase = match base { + Some(base_expr) => { + let mut leftovers = Vec::new(); + for (i, b) in need_base.iter().enumerate() { + if *b { + leftovers.push((i, vinfo.fields[i].1)); } - }; - result - }).collect::>(); - let optbase = match base { - Some(base_expr) => { - let mut leftovers = Vec::new(); - for (i, b) in need_base.iter().enumerate() { - if *b { - leftovers.push((i, field_tys[i].mt.ty)); - } - } - Some(StructBaseInfo {expr: base_expr, - fields: leftovers }) } - None => { - if need_base.iter().any(|b| *b) { - tcx.sess.span_bug(expr_span, "missing fields and no base expr") - } - None + Some(StructBaseInfo {expr: base_expr, + fields: leftovers }) + } + None => { + if need_base.iter().any(|b| *b) { + tcx.sess.span_bug(expr_span, "missing fields and no base expr") } - }; + None + } + }; - trans_adt(bcx, - ty, - discr, - &numbered_fields, - optbase, - dest, - DebugLoc::At(expr_id, expr_span)) - }) + trans_adt(bcx, + ty, + vinfo.discr, + &numbered_fields, + optbase, + dest, + DebugLoc::At(expr_id, expr_span)) } /// Information that `trans_adt` needs in order to fill in the fields @@ -2126,8 +2048,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } - let r_t_in = CastTy::from_ty(bcx.tcx(), t_in).expect("bad input type for cast"); - let r_t_out = CastTy::from_ty(bcx.tcx(), t_out).expect("bad output type for cast"); + let r_t_in = CastTy::from_ty(t_in).expect("bad input type for cast"); + let r_t_out = CastTy::from_ty(t_out).expect("bad output type for cast"); let (llexpr, signed) = if let Int(CEnum) = r_t_in { let repr = adt::represent_type(ccx, t_in); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index d07776c3d9190..30cf6f519fbd1 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -432,9 +432,8 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in // Recurse to get the size of the dynamically sized field (must be // the last field). - let fields = bcx.tcx().struct_fields(def.did, substs); - let last_field = fields[fields.len()-1]; - let field_ty = last_field.mt.ty; + let last_field = def.struct_variant().fields.last().unwrap(); + let field_ty = monomorphize::field_ty(bcx.tcx(), substs, last_field); let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info); let dbloc = DebugLoc::None; diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 75c80690f2ad4..01bfc51a5c0de 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -100,30 +100,32 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) ccx.external().borrow_mut().insert(parent_id, Some(item.id)); ccx.external_srcs().borrow_mut().insert(item.id, parent_id); - let mut my_id = 0; - match item.node { - ast::ItemEnum(_, _) => { - let vs_here = ccx.tcx().enum_variants(local_def(item.id)); - let vs_there = ccx.tcx().enum_variants(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::ItemStruct(ref struct_def, _) => { - match struct_def.ctor_id { - None => {} - Some(ctor_id) => { - ccx.external().borrow_mut().insert(fn_id, Some(ctor_id)); - my_id = ctor_id; + let mut my_id = 0; + match item.node { + ast::ItemEnum(ref ast_def, _) => { + let ast_vs = &ast_def.variants; + let ty_vs = &ccx.tcx().lookup_adt_def(parent_id).variants; + assert_eq!(ast_vs.len(), ty_vs.len()); + for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { + if ty_v.did == fn_id { my_id = ast_v.node.id; } + ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.id)); + } } - } - } - _ => ccx.sess().bug("instantiate_inline: item has a \ + ast::ItemStruct(ref struct_def, _) => { + match struct_def.ctor_id { + None => ccx.sess().bug("instantiate_inline: called on a \ + non-tuple struct"), + Some(ctor_id) => { + ccx.external().borrow_mut().insert(fn_id, Some(ctor_id)); + my_id = ctor_id; + } + } + } + _ => ccx.sess().bug("instantiate_inline: item has a \ non-enum, non-struct parent") - } - trans_item(ccx, &**item); - my_id + } + trans_item(ccx, &**item); + my_id } csearch::FoundAst::FoundParent(_, _) => { ccx.sess().bug("maybe_get_item_ast returned a FoundParent \ diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 31e4b9c48e20b..242ba6f207c56 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -29,7 +29,6 @@ use middle::ty::{self, HasTypeFlags, Ty}; use syntax::abi; use syntax::ast; -use syntax::ast_util::local_def; use syntax::attr; use syntax::codemap::DUMMY_SP; use std::hash::{Hasher, Hash, SipHasher}; @@ -192,24 +191,11 @@ 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 = ccx.tcx().enum_variants(local_def(parent)); - let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); + let variant = inlined_variant_def(ccx, fn_id.node); + assert_eq!(v.node.name.name, variant.name); let d = mk_lldecl(abi::Rust); attributes::inline(d, attributes::InlineAttr::Hint); - match v.node.kind { - ast::TupleVariantKind(ref args) => { - trans_enum_variant(ccx, - parent, - &*v, - &args[..], - this_tv.disr_val, - psubsts, - d); - } - ast::StructVariantKind(_) => - ccx.sess().bug("can't monomorphize struct variants"), - } + trans_enum_variant(ccx, fn_id.node, variant.disr_val, psubsts, d); d } ast_map::NodeImplItem(impl_item) => { @@ -255,7 +241,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let d = mk_lldecl(abi::Rust); attributes::inline(d, attributes::InlineAttr::Hint); base::trans_tuple_struct(ccx, - &struct_def.fields, struct_def.ctor_id.expect("ast-mapped tuple struct \ didn't have a ctor id"), psubsts, @@ -302,6 +287,16 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>, normalize_associated_type(tcx, &substituted) } + +/// Returns the normalized type of a struct field +pub fn field_ty<'tcx>(tcx: &ty::ctxt<'tcx>, + param_substs: &Substs<'tcx>, + f: &ty::FieldDef<'tcx>) + -> Ty<'tcx> +{ + normalize_associated_type(tcx, &f.ty(tcx, param_substs)) +} + /// Removes associated types, if any. Since this during /// monomorphization, we know that only concrete types are involved, /// and hence we can be sure that all associated types will be diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b0b1acb445c2b..bc583a67d933e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -528,7 +528,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, let tcx = pcx.fcx.ccx.tcx; let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); - let (adt_def, variant_def_id) = match def { + let (adt_def, variant) = match def { def::DefTrait(_) => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0168, @@ -544,11 +544,10 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, let def_type = tcx.lookup_item_type(def.def_id()); match def_type.ty.sty { ty::TyStruct(struct_def, _) => - (struct_def, struct_def.did), + (struct_def, struct_def.struct_variant()), ty::TyEnum(enum_def, _) - // TODO: wut? if def == def::DefVariant(enum_def.did, def.def_id(), true) => - (enum_def, def.def_id()), + (enum_def, enum_def.variant_of_def(def)), _ => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0163, @@ -582,9 +581,7 @@ 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 = tcx.struct_fields(variant_def_id, &item_substs); - check_struct_pat_fields(pcx, pat.span, fields, &struct_fields, - variant_def_id, etc); + check_struct_pat_fields(pcx, pat.span, fields, variant, &item_substs, etc); } pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, @@ -651,19 +648,23 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ty::TyEnum(enum_def, expected_substs) if def == def::DefVariant(enum_def.did, def.def_id(), false) => { - let variant = tcx.enum_variant_with_id(enum_def.did, def.def_id()); - (variant.args.iter() - .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t)) - .collect(), + let variant = enum_def.variant_of_def(def); + (variant.fields + .iter() + .map(|f| fcx.instantiate_type_scheme(pat.span, + expected_substs, + &f.unsubst_ty())) + .collect(), "variant") } ty::TyStruct(struct_def, expected_substs) => { - let struct_fields = tcx.struct_fields(struct_def.did, expected_substs); - (struct_fields.iter() - .map(|field| fcx.instantiate_type_scheme(pat.span, - expected_substs, - &field.mt.ty)) - .collect(), + (struct_def.struct_variant() + .fields + .iter() + .map(|f| fcx.instantiate_type_scheme(pat.span, + expected_substs, + &f.unsubst_ty())) + .collect(), "struct") } _ => { @@ -716,15 +717,15 @@ 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_id: ast::DefId, + variant: &ty::VariantDef<'tcx>, + substs: &Substs<'tcx>, etc: bool) { let tcx = pcx.fcx.ccx.tcx; // Index the struct fields' types. - let field_type_map = struct_fields + let field_map = variant.fields .iter() - .map(|field| (field.name, field.mt.ty)) + .map(|field| (field.name, field)) .collect::>(); // Keep track of which fields have already appeared in the pattern. @@ -732,7 +733,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Typecheck each field. for &Spanned { node: ref field, span } in fields { - let field_type = match used_fields.entry(field.ident.name) { + let field_ty = match used_fields.entry(field.ident.name) { Occupied(occupied) => { span_err!(tcx.sess, span, E0025, "field `{}` bound multiple times in the pattern", @@ -744,25 +745,24 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } Vacant(vacant) => { vacant.insert(span); - field_type_map.get(&field.ident.name).cloned() + field_map.get(&field.ident.name) + .map(|f| pcx.fcx.field_ty(span, f, substs)) .unwrap_or_else(|| { span_err!(tcx.sess, span, E0026, "struct `{}` does not have a field named `{}`", - tcx.item_path_str(struct_id), + tcx.item_path_str(variant.did), field.ident); tcx.types.err }) } }; - let field_type = pcx.fcx.normalize_associated_types_in(span, &field_type); - - check_pat(pcx, &*field.pat, field_type); + check_pat(pcx, &*field.pat, field_ty); } // Report an error if not all the fields were specified. if !etc { - for field in struct_fields + for field in variant.fields .iter() .filter(|field| !used_fields.contains_key(&field.name)) { span_err!(tcx.sess, span, E0027, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 5d93e2ae5d379..b6ba62e4f0965 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -80,9 +80,10 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), ty::TyStruct(def, substs) => { - match fcx.tcx().struct_fields(def.did, substs).pop() { + // FIXME(arielb1): do some kind of normalization + match def.struct_variant().fields.last() { None => None, - Some(f) => unsize_kind(fcx, f.mt.ty) + Some(f) => unsize_kind(fcx, f.ty(fcx.tcx(), substs)) } } // We should really try to normalize here. @@ -223,8 +224,8 @@ impl<'tcx> CastCheck<'tcx> { use middle::cast::IntTy::*; use middle::cast::CastTy::*; - let (t_from, t_cast) = match (CastTy::from_ty(fcx.tcx(), self.expr_ty), - CastTy::from_ty(fcx.tcx(), self.cast_ty)) { + let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), + CastTy::from_ty(self.cast_ty)) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), _ => { return Err(CastError::NonScalar) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 7cb2198c68ddf..57f2f063c71c4 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -285,26 +285,28 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> // no need for an additional note if the overflow // was somehow on the root. } - TypeContext::EnumVariant { def_id, variant, arg_index } => { + TypeContext::ADT { def_id, variant, field, field_index } => { // FIXME (pnkfelix): eventually lookup arg_name // for the given index on struct variants. - span_note!( - rcx.tcx().sess, - span, - "overflowed on enum {} variant {} argument {} type: {}", - tcx.item_path_str(def_id), - variant, - arg_index, - detected_on_typ); - } - TypeContext::Struct { def_id, field } => { - span_note!( - rcx.tcx().sess, - span, - "overflowed on struct {} field {} type: {}", - tcx.item_path_str(def_id), - field, - detected_on_typ); + // TODO: be saner + if let ty::ADTKind::Enum = tcx.lookup_adt_def(def_id).adt_kind() { + span_note!( + rcx.tcx().sess, + span, + "overflowed on enum {} variant {} argument {} type: {}", + tcx.item_path_str(def_id), + variant, + field_index, + detected_on_typ); + } else { + span_note!( + rcx.tcx().sess, + span, + "overflowed on struct {} field {} type: {}", + tcx.item_path_str(def_id), + field, + detected_on_typ); + } } } } @@ -318,14 +320,11 @@ enum Error<'tcx> { #[derive(Copy, Clone)] enum TypeContext { Root, - EnumVariant { + ADT { def_id: ast::DefId, variant: ast::Name, - arg_index: usize, - }, - Struct { - def_id: ast::DefId, field: ast::Name, + field_index: usize } } @@ -437,41 +436,23 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) => { - let did = def.did; - let fields = tcx.lookup_struct_fields(did); - for field in &fields { - let fty = tcx.lookup_field_type(did, field.id, substs); - let fty = cx.rcx.fcx.resolve_type_vars_if_possible( - cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty)); - try!(iterate_over_potentially_unsafe_regions_in_type( - cx, - TypeContext::Struct { - def_id: did, - field: field.name, - }, - fty, - depth+1)) - } - Ok(()) - } - - ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { let did = def.did; - let all_variant_info = tcx.substd_enum_variants(did, substs); - for variant_info in &all_variant_info { - for (i, fty) in variant_info.args.iter().enumerate() { + for variant in &def.variants { + for (i, field) in variant.fields.iter().enumerate() { + let fty = field.ty(tcx, substs); let fty = cx.rcx.fcx.resolve_type_vars_if_possible( cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty)); try!(iterate_over_potentially_unsafe_regions_in_type( cx, - TypeContext::EnumVariant { + TypeContext::ADT { def_id: did, - variant: variant_info.name, - arg_index: i, + field: field.name, + variant: variant.name, + field_index: i }, fty, - depth+1)); + depth+1)) } } Ok(()) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 970589fb9c50e..15cc5ee6eb801 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -66,9 +66,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If the item has the name of a field, give a help note if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { - let fields = cx.lookup_struct_fields(def.did); - - if let Some(field) = fields.iter().find(|f| f.name == item_name) { + if let Some(field) = def.struct_variant().find_field_named(item_name) { let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { Ok(expr_string) => expr_string, _ => "s".into() // Default to a generic placeholder for the @@ -89,7 +87,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; // Determine if the field can be used as a function in some way - let field_ty = cx.lookup_field_type(def.did, field.id, substs); + let field_ty = field.ty(cx, substs); if let Ok(fn_once_trait_did) = cx.lang_items.require(FnOnceTraitLangItem) { let infcx = fcx.infcx(); infcx.probe(|_| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2f63d7abe4afc..ac3733db9c2e4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1674,34 +1674,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Only for fields! Returns for methods> - // Indifferent to privacy flags - pub fn lookup_field_ty(&self, - span: Span, - struct_def: &'tcx ty::ADTDef<'tcx>, - items: &[ty::FieldTy], - fieldname: ast::Name, - substs: &subst::Substs<'tcx>) - -> Option> - { - let o_field = items.iter().find(|f| f.name == fieldname); - o_field.map(|f| self.tcx().lookup_field_type(struct_def.did, f.id, substs)) - .map(|t| self.normalize_associated_types_in(span, &t)) - } - - pub fn lookup_tup_field_ty(&self, - span: Span, - struct_def: &'tcx ty::ADTDef<'tcx>, - items: &[ty::FieldTy], - idx: usize, - substs: &subst::Substs<'tcx>) - -> Option> + // FIXME(arielb1): use this instead of field.ty everywhere + pub fn field_ty(&self, + span: Span, + field: &ty::FieldDef<'tcx>, + substs: &Substs<'tcx>) + -> Ty<'tcx> { - let o_field = if idx < items.len() { Some(&items[idx]) } else { None }; - o_field.map(|f| self.tcx().lookup_field_type(struct_def.did, f.id, substs)) - .map(|t| self.normalize_associated_types_in(span, &t)) + self.normalize_associated_types_in(span, + &field.ty(self.tcx(), substs)) } + // Only for fields! Returns for methods> + // Indifferent to privacy flags fn check_casts(&self) { let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut(); for cast in deferred_cast_checks.drain(..) { @@ -2880,9 +2865,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match base_t.sty { ty::TyStruct(base_def, substs) => { debug!("struct named {:?}", base_t); - let fields = tcx.lookup_struct_fields(base_def.did); - fcx.lookup_field_ty(expr.span, base_def, &fields[..], - field.node.name, &(*substs)) + base_def.struct_variant() + .find_field_named(field.node.name) + .map(|f| fcx.field_ty(expr.span, f, substs)) } _ => None } @@ -2920,7 +2905,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, expr_t, None); if let ty::TyStruct(def, _) = expr_t.sty { - suggest_field_names(def.did, field, tcx, vec![]); + suggest_field_names(def.struct_variant(), field, tcx, vec![]); } } @@ -2928,23 +2913,22 @@ 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>(variant_id: ast::DefId, + fn suggest_field_names<'tcx>(variant: &ty::VariantDef<'tcx>, field: &ast::SpannedIdent, tcx: &ty::ctxt<'tcx>, skip : Vec) { let name = field.node.name.as_str(); // only find fits with at least one matching letter let mut best_dist = name.len(); - let fields = tcx.lookup_struct_fields(variant_id); let mut best = None; - for elem in &fields { + for elem in &variant.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 variant_id.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public { + if variant.did.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public { continue; } let dist = lev_distance(&n, &name); @@ -2965,7 +2949,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lvalue_pref: LvaluePreference, base: &'tcx ast::Expr, idx: codemap::Spanned) { - let tcx = fcx.ccx.tcx; check_expr_with_lvalue_pref(fcx, base, lvalue_pref); let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base)); @@ -2983,9 +2966,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, tuple_like = base_def.struct_variant().is_tuple_struct(); if tuple_like { debug!("tuple struct named {:?}", base_t); - let fields = tcx.lookup_struct_fields(base_def.did); - fcx.lookup_tup_field_ty(expr.span, base_def, &fields[..], - idx.node, &(*substs)) + base_def.struct_variant() + .fields + .get(idx.node) + .map(|f| fcx.field_ty(expr.span, f, substs)) } else { None } @@ -3025,71 +3009,63 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.write_error(expr.id); } + fn report_unknown_field<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + ty: Ty<'tcx>, + variant: &ty::VariantDef<'tcx>, + field: &ast::Field, + skip_fields: &[ast::Field]) { + fcx.type_error_message( + field.ident.span, + |actual| if let ty::TyEnum(..) = ty.sty { + format!("struct variant `{}::{}` has no field named `{}`", + actual, variant.name.as_str(), field.ident.node) + } else { + format!("structure `{}` has no field named `{}`", + actual, field.ident.node) + }, + ty, + None); + // prevent all specified fields from being suggested + let skip_fields = skip_fields.iter().map(|ref x| x.ident.node.name.as_str()); + suggest_field_names(variant, &field.ident, fcx.tcx(), skip_fields.collect()); + } + + fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, adt_ty: Ty<'tcx>, span: Span, variant_id: ast::DefId, - substitutions: &'tcx subst::Substs<'tcx>, - field_types: &[ty::FieldTy], ast_fields: &'tcx [ast::Field], check_completeness: bool) -> Result<(),()> { let tcx = fcx.ccx.tcx; - let (adt_def, is_enum) = match adt_ty.sty { - ty::TyStruct(def, _) => (def, false), - ty::TyEnum(def, _) => (def, true), + let (adt_def, substs) = match adt_ty.sty { + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => (def, substs), _ => tcx.sess.span_bug(span, "non-ADT passed to check_struct_or_variant_fields") }; + let variant = adt_def.variant_with_id(variant_id); - 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)); + let mut remaining_fields = FnvHashMap(); + for field in &variant.fields { + remaining_fields.insert(field.name, field); } let mut error_happened = false; // Typecheck each field. for field in ast_fields { - let mut expected_field_type = tcx.types.err; - - let pair = class_field_map.get(&field.ident.node.name).cloned(); - match pair { - None => { - fcx.type_error_message( - field.ident.span, - |actual| if is_enum { - let variant_type = tcx.enum_variant_with_id(adt_def.did, - variant_id); - format!("struct variant `{}::{}` has no field named `{}`", - actual, variant_type.name.as_str(), - field.ident.node) - } else { - format!("structure `{}` has no field named `{}`", - actual, - field.ident.node) - }, - adt_ty, - None); - // prevent all specified fields from being suggested - let skip_fields = ast_fields.iter().map(|ref x| x.ident.node.name.as_str()); - suggest_field_names(variant_id, &field.ident, tcx, skip_fields.collect()); - error_happened = true; - } - Some((_, true)) => { + let expected_field_type; + + if let Some(v_field) = remaining_fields.remove(&field.ident.node.name) { + expected_field_type = fcx.field_ty(field.span, v_field, substs); + } else { + error_happened = true; + expected_field_type = tcx.types.err; + if let Some(_) = variant.find_field_named(field.ident.node.name) { span_err!(fcx.tcx().sess, field.ident.span, E0062, "field `{}` specified more than once", field.ident.node); - error_happened = true; - } - Some((field_id, false)) => { - expected_field_type = - tcx.lookup_field_type(variant_id, field_id, substitutions); - expected_field_type = - fcx.normalize_associated_types_in( - field.span, &expected_field_type); - class_field_map.insert( - field.ident.node.name, (field_id, true)); - fields_found += 1; + } else { + report_unknown_field(fcx, adt_ty, variant, field, ast_fields); } } @@ -3098,25 +3074,19 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type); } - if check_completeness && !error_happened { // Make sure the programmer specified all the fields. - assert!(fields_found <= field_types.len()); - if fields_found < field_types.len() { - let mut missing_fields = Vec::new(); - for class_field in field_types { - let name = class_field.name; - let (_, seen) = *class_field_map.get(&name).unwrap(); - if !seen { - missing_fields.push( - format!("`{}`", name)) - } - } - - span_err!(tcx.sess, span, E0063, - "missing field{}: {}", - if missing_fields.len() == 1 {""} else {"s"}, - missing_fields.join(", ")); - } + if check_completeness && + !error_happened && + !remaining_fields.is_empty() + { + error_happened = true; + span_err!(tcx.sess, span, E0063, + "missing field{}: {}", + if remaining_fields.len() == 1 {""} else {"s"}, + remaining_fields.keys() + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", ")); } if error_happened { Err(()) } else { Ok(()) } @@ -3133,17 +3103,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Generate the struct type. let TypeAndSubsts { ty: mut struct_type, - substs: struct_substs + substs: _ } = fcx.instantiate_type(span, struct_def.did); // Look up and check the fields. - let class_fields = tcx.lookup_struct_fields(struct_def.did); let res = check_struct_or_variant_fields(fcx, struct_type, span, struct_def.did, - fcx.ccx.tcx.mk_substs(struct_substs), - &class_fields[..], fields, base_expr.is_none()); if res.is_err() { @@ -3168,23 +3135,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, enum_id: ast::DefId, variant_id: ast::DefId, fields: &'tcx [ast::Field]) { - let tcx = fcx.ccx.tcx; - // Look up the number of type parameters and the raw type, and // determine whether the enum is region-parameterized. let TypeAndSubsts { ty: enum_type, - substs: substitutions + substs: _ } = fcx.instantiate_type(span, enum_id); // Look up and check the enum variant fields. - let variant_fields = tcx.lookup_struct_fields(variant_id); let _ = check_struct_or_variant_fields(fcx, enum_type, span, variant_id, - fcx.ccx.tcx.mk_substs(substitutions), - &variant_fields[..], fields, true); fcx.write_ty(id, enum_type); @@ -4295,14 +4257,13 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { } match t.sty { ty::TyStruct(def, substs) => { - let fields = tcx.lookup_struct_fields(def.did); + let fields = &def.struct_variant().fields; if fields.is_empty() { span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); return; } - let e = tcx.lookup_field_type(def.did, fields[0].id, substs); - if !fields.iter().all( - |f| tcx.lookup_field_type(def.did, f.id, substs) == e) { + let e = fields[0].ty(tcx, substs); + if !fields.iter().all(|f| f.ty(tcx, substs) == e) { span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); return; } @@ -4370,10 +4331,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let def_id = local_def(id); - // ty::enum_variants guards against discriminant overflows, so - // we need not check for that. - let variants = ccx.tcx.enum_variants(def_id); - + let variants = &ccx.tcx.lookup_adt_def(def_id).variants; for (v, variant) in vs.iter().zip(variants.iter()) { let current_disr_val = variant.disr_val; @@ -4382,7 +4340,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, Some(i) => { 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), + span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].did.node), "conflicting discriminant here") } None => {} diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index cd4063ac454ed..7ab8d327a8097 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -483,10 +483,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let origin = infer::Misc(span); - let fields = tcx.lookup_struct_fields(def_a.did); + let fields = &def_a.struct_variant().fields; let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { - let ty = tcx.lookup_field_type_unsubstituted(def_a.did, f.id); - let (a, b) = (ty.subst(tcx, substs_a), ty.subst(tcx, substs_b)); + let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); if infcx.sub_types(false, origin, b, a).is_ok() { None } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c9f6ccb8cb2e7..ddc900b1d25b5 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1174,33 +1174,50 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, Ok(ConstVal::Int(val)) => Some(val as ty::Disr), Ok(ConstVal::Uint(val)) => Some(val as ty::Disr), Ok(_) => { -// let sign_desc = if repr_type.is_signed() { -// "signed" -// } else { -// "unsigned" -// }; -// span_err!(self.sess, e.span, E0079, -// "expected {} integer constant", -// sign_desc); + let sign_desc = if repr_ty.is_signed() { + "signed" + } else { + "unsigned" + }; + span_err!(tcx.sess, e.span, E0079, + "expected {} integer constant", + sign_desc); None }, - Err(_) => { -// span_err!(self.sess, err.span, E0080, -// "constant evaluation error: {}", -// err.description()); + Err(err) => { + span_err!(tcx.sess, err.span, E0080, + "constant evaluation error: {}", + err.description()); None } } } - fn next_disr(repr_type: attr::IntType, + fn report_discrim_overflow(tcx: &ty::ctxt, + variant_span: Span, + variant_name: &str, + repr_type: attr::IntType, + prev_val: ty::Disr) { + let computed_value = repr_type.disr_wrap_incr(Some(prev_val)); + let computed_value = repr_type.disr_string(computed_value); + let prev_val = repr_type.disr_string(prev_val); + let repr_type = repr_type.to_ty(tcx); + span_err!(tcx.sess, variant_span, E0370, + "enum discriminant overflowed on value after {}: {}; \ + set explicitly via {} = {} if that is desired outcome", + prev_val, repr_type, variant_name, computed_value); + } + + fn next_disr(tcx: &ty::ctxt, + v: &ast::Variant, + repr_type: attr::IntType, prev_disr_val: Option) -> Option { if let Some(prev_disr_val) = prev_disr_val { let result = repr_type.disr_incr(prev_disr_val); -// if let None = result { -// self.report_discrim_overflow(v.span, &v.node.name.name.as_str(), -// repr_type, prev_disr_val); -// } + if let None = result { + report_discrim_overflow(tcx, v.span, &v.node.name.name.as_str(), + repr_type, prev_disr_val); + } result } else { Some(ty::INITIAL_DISCRIMINANT_VALUE) @@ -1240,7 +1257,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, let variants = def.variants.iter().map(|v| { let disr = match v.node.disr_expr { Some(ref e) => evaluate_disr_expr(tcx, repr_type_ty, e), - None => next_disr(repr_type, prev_disr) + None => next_disr(tcx, v, repr_type, prev_disr) }.unwrap_or(repr_type.disr_wrap_incr(prev_disr)); let v = convert_enum_variant(tcx, v, disr); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 07c1b5e3d2013..4660adaffaec0 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -883,6 +883,64 @@ struct Good(u32, u32, u32); // This will not ``` "##, +E0079: r##" +Enum variants which contain no data can be given a custom integer +representation. This error indicates that the value provided is not an integer +literal and is therefore invalid. + +For example, in the following code, + +``` +enum Foo { + Q = "32" +} +``` + +we try to set the representation to a string. + +There's no general fix for this; if you can work with an integer then just set +it to one: + +``` +enum Foo { + Q = 32 +} +``` + +however if you actually wanted a mapping between variants and non-integer +objects, it may be preferable to use a method with a match instead: + +``` +enum Foo { Q } +impl Foo { + fn get_str(&self) -> &'static str { + match *self { + Foo::Q => "32", + } + } +} +``` +"##, + +E0080: r##" +This error indicates that the compiler was unable to sensibly evaluate an +integer expression provided as an enum discriminant. Attempting to divide by 0 +or causing integer overflow are two ways to induce this error. For example: + +``` +enum Enum { + X = (1 << 500), + Y = (1 / 0) +} +``` + +Ensure that the expressions given can be evaluated as the desired integer type. +See the FFI section of the Reference for more information about using a custom +integer type: + +https://doc.rust-lang.org/reference.html#ffi-attributes +"##, + E0081: r##" Enum discriminants are used to differentiate enum variants stored in memory. This error indicates that the same value was used for two or more variants, @@ -2510,6 +2568,7 @@ register_diagnostics! { E0366, // dropck forbid specialization to concrete type or region E0367, // dropck forbid specialization to predicate not in struct/enum E0369, // binary operation `` cannot be applied to types + E0370, // discriminant overflow E0374, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with one field being coerced, none found E0375, // the trait `CoerceUnsized` may only be implemented for a coercion diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 3721f9a0b105c..69e2141b17b07 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -602,7 +602,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { debug!("visit_item item={}", tcx.map.node_to_string(item.id)); match item.node { - ast::ItemEnum(ref enum_definition, _) => { + ast::ItemEnum(..) | ast::ItemStruct(..) => { let scheme = tcx.lookup_item_type(did); // Not entirely obvious: constraints on structs/enums do not @@ -611,44 +611,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { // // 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); - } + for field in tcx.lookup_adt_def(did).all_fields() { + self.add_constraints_from_ty(&scheme.generics, + field.unsubst_ty(), + self.covariant); } } - - ast::ItemStruct(..) => { - let scheme = tcx.lookup_item_type(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 = tcx.lookup_struct_fields(did); - for field_info in &struct_fields { - assert_eq!(field_info.id.krate, ast::LOCAL_CRATE); - let field_ty = tcx.node_id_to_type(field_info.id.node); - self.add_constraints_from_ty(&scheme.generics, field_ty, self.covariant); - } - } - ast::ItemTrait(..) => { let trait_def = tcx.lookup_trait_def(did); self.add_constraints_from_trait_ref(&trait_def.generics, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 582927782a4bd..7fd1555d06654 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -185,17 +185,17 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru let t = tcx.lookup_item_type(did); let predicates = tcx.lookup_predicates(did); - let fields = tcx.lookup_struct_fields(did); + let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Struct { - struct_type: match &*fields { + struct_type: match &*variant.fields { [] => doctree::Unit, [ref f] if f.name == unnamed_field.name => doctree::Newtype, [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple, _ => doctree::Plain, }, generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), - fields: fields.clean(cx), + fields: variant.fields.clean(cx), fields_stripped: false, } } @@ -208,7 +208,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn return clean::EnumItem(clean::Enum { generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), variants_stripped: false, - variants: tcx.enum_variants(edef.did).clean(cx), + variants: edef.variants.clean(cx), }) } _ => {} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac8727912191f..f4a21ee4f4e05 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1730,29 +1730,27 @@ impl Clean for ast::StructField { } } -impl Clean for ty::FieldTy { +impl<'tcx> Clean for ty::FieldDef<'tcx> { fn clean(&self, cx: &DocContext) -> Item { use syntax::parse::token::special_idents::unnamed_field; use rustc::metadata::csearch; - let attr_map = csearch::get_struct_field_attrs(&cx.tcx().sess.cstore, self.id); + let attr_map = csearch::get_struct_field_attrs(&cx.tcx().sess.cstore, self.did); let (name, attrs) = if self.name == unnamed_field.name { (None, None) } else { - (Some(self.name), Some(attr_map.get(&self.id.node).unwrap())) + (Some(self.name), Some(attr_map.get(&self.did.node).unwrap())) }; - let ty = cx.tcx().lookup_item_type(self.id); - Item { name: name.clean(cx), attrs: attrs.unwrap_or(&Vec::new()).clean(cx), source: Span::empty(), visibility: Some(self.vis), - stability: get_stability(cx, self.id), - def_id: self.id, - inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))), + stability: get_stability(cx, self.did), + def_id: self.did, + inner: StructFieldItem(TypedStructField(self.unsubst_ty().clean(cx))), } } } @@ -1858,22 +1856,24 @@ 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.is_empty() => CLikeVariant, - None | Some([]) => { - TupleVariant(self.args.clean(cx)) + let kind = match self.kind() { + ty::VariantKind::Unit => CLikeVariant, + ty::VariantKind::Tuple => { + TupleVariant( + self.fields.iter().map(|f| f.unsubst_ty().clean(cx)).collect() + ) } - Some(s) => { + ty::VariantKind::Dict => { StructVariant(VariantStruct { struct_type: doctree::Plain, fields_stripped: false, - fields: s.iter().zip(&self.args).map(|(name, ty)| { + fields: self.fields.iter().map(|field| { Item { source: Span::empty(), - name: Some(name.clean(cx)), + name: Some(field.name.clean(cx)), attrs: Vec::new(), visibility: Some(ast::Public), // FIXME: this is not accurate, we need an id for @@ -1883,10 +1883,10 @@ impl<'tcx> Clean for ty::VariantInfo<'tcx> { // 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), + def_id: self.did, + stability: get_stability(cx, self.did), inner: StructFieldItem( - TypedStructField(ty.clean(cx)) + TypedStructField(field.unsubst_ty().clean(cx)) ) } }).collect() @@ -1895,12 +1895,12 @@ impl<'tcx> Clean for ty::VariantInfo<'tcx> { }; Item { name: Some(self.name.clean(cx)), - attrs: inline::load_attrs(cx, cx.tcx(), self.id), + attrs: inline::load_attrs(cx, cx.tcx(), self.did), source: Span::empty(), visibility: Some(ast::Public), - def_id: self.id, + def_id: self.did, inner: VariantItem(Variant { kind: kind }), - stability: get_stability(cx, self.id), + stability: get_stability(cx, self.did), } } } From 4c9971eb0d3235888b1f7086fa12051fce509fe7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Aug 2015 01:29:52 +0300 Subject: [PATCH 06/14] remove struct_fields & enum_variants from the tcx --- src/librustc/middle/ty.rs | 4 --- src/librustc_typeck/collect.rs | 48 +++++++++------------------------- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d41ca44ceea5e..b817dca1212e6 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -872,13 +872,11 @@ pub struct ctxt<'tcx> { pub rcache: RefCell>>, pub tc_cache: RefCell, TypeContents>>, pub ast_ty_to_ty_cache: RefCell>>, - pub enum_var_cache: RefCell>>>>>, pub ty_param_defs: 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. @@ -3816,7 +3814,6 @@ impl<'tcx> ctxt<'tcx> { rcache: 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()), @@ -3824,7 +3821,6 @@ impl<'tcx> ctxt<'tcx> { 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()), inherent_impls: RefCell::new(DefIdMap()), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ddc900b1d25b5..4f8aeceb558df 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -620,9 +620,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_generics: &ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, v: &ast::StructField, - ty_f: &'tcx ty::FieldDef_<'tcx, 'tcx>, - origin: ast::DefId) - -> ty::FieldTy + ty_f: &'tcx ty::FieldDef_<'tcx, 'tcx>) { let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &*v.node.ty); ty_f.fulfill_ty(tt); @@ -636,25 +634,6 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }); ccx.tcx.predicates.borrow_mut().insert(local_def(v.node.id), struct_predicates.clone()); - - match v.node.kind { - ast::NamedField(ident, visibility) => { - ty::FieldTy { - name: ident.name, - id: local_def(v.node.id), - vis: visibility, - origin: origin, - } - } - ast::UnnamedField(visibility) => { - ty::FieldTy { - name: special_idents::unnamed_field.name, - id: local_def(v.node.id), - vis: visibility, - origin: origin, - } - } - } } fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -1018,7 +997,11 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { write_ty_to_tcx(tcx, it.id, scheme.ty); let variant = tcx.lookup_adt_def(local_def(it.id)).struct_variant(); - convert_struct_variant_types(ccx, &struct_def, variant, &scheme, &predicates); + + for (f, ty_f) in struct_def.fields.iter().zip(variant.fields.iter()) { + convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + } + if let Some(ctor_id) = struct_def.ctor_id { convert_variant_ctor(tcx, ctor_id, variant, scheme, predicates); } @@ -1065,17 +1048,6 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, }); } -fn convert_struct_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - def: &ast::StructDef, - variant: &'tcx ty::VariantDef_<'tcx, 'tcx>, - scheme: &ty::TypeScheme<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) { - let field_tys = def.fields.iter().zip(variant.fields.iter()).map(|(f, ty_f)| { - convert_field(ccx, &scheme.generics, &predicates, f, ty_f, variant.did) - }).collect(); - ccx.tcx.struct_fields.borrow_mut().insert(variant.did, Rc::new(field_tys)); -} - fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def: &'tcx ty::ADTDef_<'tcx, 'tcx>, scheme: ty::TypeScheme<'tcx>, @@ -1084,7 +1056,7 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let tcx = ccx.tcx; let icx = ccx.icx(&predicates); - // Create a set of parameter types shared among all the variants. + // fill the field types for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { match variant.node.kind { ast::TupleVariantKind(ref args) => { @@ -1096,10 +1068,14 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } ast::StructVariantKind(ref struct_def) => { - convert_struct_variant_types(ccx, &struct_def, ty_variant, &scheme, &predicates); + for (f, ty_f) in struct_def.fields.iter().zip(ty_variant.fields.iter()) { + convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + } } }; + // Convert the ctor, if any. This also registers the variant as + // an item. convert_variant_ctor( tcx, variant.node.id, From 49e7432b000424aba7bd0fc82f338f2d7f8570f8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Aug 2015 01:32:04 +0300 Subject: [PATCH 07/14] resolve todo --- src/librustc/middle/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index b817dca1212e6..9d339aef250e1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3413,7 +3413,6 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { #[inline] pub fn is_empty(&self) -> bool { - // FIXME(#TODO(wxyz)): be smarter here self.variants.is_empty() } @@ -4249,6 +4248,7 @@ impl<'tcx> TyS<'tcx> { } pub fn is_empty(&self, _cx: &ctxt) -> bool { + // FIXME(#24885): be smarter here match self.sty { TyEnum(def, _) | TyStruct(def, _) => def.is_empty(), _ => false From 34942331a3288bbebc5a00fef57b6976afc0eb75 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Aug 2015 01:55:13 +0300 Subject: [PATCH 08/14] remove ty::{VariantInfo, FieldTy} --- src/librustc/metadata/csearch.rs | 13 +-- src/librustc/metadata/decoder.rs | 84 ++------------- src/librustc/middle/ty.rs | 112 +------------------- src/librustc/middle/ty_fold.rs | 9 -- src/librustc_resolve/build_reduced_graph.rs | 4 +- 5 files changed, 10 insertions(+), 212 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index f97ffebaebb19..f0607010bf3f0 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -113,13 +113,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_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 { @@ -195,11 +188,9 @@ 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_struct_field_names(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) + decoder::get_struct_field_names(&cstore.intr, &*cdata, def.node) } pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: ast::DefId) -> HashMap(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeI } } -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; - reader::tagged_docs(item, tag_items_data_item_variant).map(|p| { - let did = translated_def_id(cdata, p); - 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::TyBareFn(_, 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(field_ty.name); - get_type(cdata, field_ty.id.node, tcx).ty - }) - .collect(); - let arg_names = if arg_names.is_empty() { 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 = disr_val.wrapping_add(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 { @@ -1136,37 +1087,14 @@ 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_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId) + -> Vec { let data = cdata.data(); let item = lookup_item(id, data); - reader::tagged_docs(item, tag_item_field).filter_map(|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 = translated_def_id(cdata, tagdoc); - Some(ty::FieldTy { - name: name, - id: did, - vis: struct_field_family_to_visibility(f), - origin: origin_id, - }) - } else { - None - } - }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|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 = translated_def_id(cdata, tagdoc); - ty::FieldTy { - name: special_idents::unnamed_field.name, - id: did, - vis: struct_field_family_to_visibility(f), - origin: origin_id, - } + reader::tagged_docs(item, tag_item_field).map(|an_item| { + item_name(intr, an_item) + }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|_| { + special_idents::unnamed_field.name })).collect() } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9d339aef250e1..733fa0e71b4ee 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -87,8 +87,7 @@ use std::collections::{HashMap, HashSet}; use rustc_data_structures::ivar; use syntax::abi; use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE}; -use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; -use syntax::ast::{StructField, UnnamedField, Visibility}; +use syntax::ast::{MutImmutable, MutMutable, Name, NodeId, Visibility}; use syntax::ast_util::{self, is_local, local_def}; use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; use syntax::codemap::Span; @@ -112,83 +111,6 @@ pub struct CrateAnalysis { pub glob_map: Option, } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct Field<'tcx> { - pub name: ast::Name, - pub mt: TypeAndMut<'tcx> -} - -// 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 = cx.node_id_to_type(ast_variant.node.id); - - match ast_variant.node.kind { - ast::TupleVariantKind(ref args) => { - let arg_tys = if !args.is_empty() { - // the regions in the argument types come from the - // enum def'n, and hence will all be early bound - cx.no_late_bound_regions(&ctor_ty.fn_args()).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.is_empty()); - - let arg_tys = struct_def.fields.iter() - .map(|field| cx.node_id_to_type(field.node.id)).collect(); - let arg_names = fields.iter().map(|field| { - match field.node.kind { - NamedField(ident, _) => ident.name, - 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 - }; - } - } - } -} - #[derive(Copy, Clone)] pub enum DtorKind { NoDtor, @@ -495,14 +417,6 @@ pub struct TypeAndMut<'tcx> { pub mutbl: ast::Mutability, } -#[derive(Clone, Copy, Debug)] -pub struct FieldTy { - 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. -} - #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] pub struct ItemVariances { pub types: VecPerParamSpace, @@ -5667,18 +5581,6 @@ impl<'tcx> ctxt<'tcx> { } } - pub fn field_idx_strict(&self, name: ast::Name, fields: &[Field<'tcx>]) - -> usize { - let mut i = 0; - for f in fields { if f.name == name { return i; } i += 1; } - self.sess.bug(&format!( - "no field named `{}` found in the list of fields `{:?}`", - name, - fields.iter() - .map(|f| f.name.to_string()) - .collect::>())); - } - pub fn note_and_explain_type_err(&self, err: &TypeError<'tcx>, sp: Span) { use self::TypeError::*; @@ -7341,12 +7243,6 @@ impl<'tcx> HasTypeFlags for FnSig<'tcx> { } } -impl<'tcx> HasTypeFlags for Field<'tcx> { - fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.mt.ty.has_type_flags(flags) - } -} - impl<'tcx> HasTypeFlags for BareFnTy<'tcx> { fn has_type_flags(&self, flags: TypeFlags) -> bool { self.sig.has_type_flags(flags) @@ -7377,12 +7273,6 @@ impl<'tcx> fmt::Debug for ClosureUpvar<'tcx> { } } -impl<'tcx> fmt::Debug for Field<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "field({},{})", self.name, self.mt) - } -} - impl<'a, 'tcx> fmt::Debug for ParameterEnvironment<'a, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "ParameterEnvironment(\ diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 0c694926ba4b5..cc1efeaea080f 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -275,15 +275,6 @@ 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::Region { fn fold_with>(&self, folder: &mut F) -> ty::Region { folder.fold_region(*self) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 656d6a3661470..190e217aac15d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -791,9 +791,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { 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::>(); + let fields = csearch::get_struct_field_names(&self.session.cstore, def_id); if fields.is_empty() { child_name_bindings.define_value(def, DUMMY_SP, modifiers); From c533f963d9f7f6c665c4d6e9c8c02c5a2d62c9e6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Aug 2015 17:00:41 +0300 Subject: [PATCH 09/14] handle associated types correctly in null pointer optimization Fixes #27532 Thanks @eefriedman for the test. --- src/librustc_trans/trans/adt.rs | 3 +-- src/test/run-pass/enum-null-pointer-opt.rs | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 9fb808a7d2d93..ec6823e762255 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -462,8 +462,7 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, // let's recurse and find out ty::TyStruct(def, substs) => { for (j, field) in def.struct_variant().fields.iter().enumerate() { - // TODO(#27532) - let field_ty = field.ty(tcx, substs); + let field_ty = monomorphize::field_ty(tcx, substs, field); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { fpath.push(j); return Some(fpath); diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index dd88dc11ea70e..e296aff2782c5 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -18,6 +18,10 @@ use std::rc::Rc; use std::sync::Arc; trait Trait { fn dummy(&self) { } } +trait Mirror { type Image; } +impl Mirror for T { type Image = T; } +struct ParamTypeStruct(T); +struct AssocTypeStruct(::Image); fn main() { // Functions @@ -66,4 +70,7 @@ fn main() { // Should apply to types that have NonZero transitively assert_eq!(size_of::(), size_of::>()); + // Should apply to types where the pointer is substituted + assert_eq!(size_of::<&u8>(), size_of::>>()); + assert_eq!(size_of::<&u8>(), size_of::>>()); } From 612760bea06e55dc4cb7bf7cdf430e8b1ba8d8e7 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Aug 2015 17:43:08 +0300 Subject: [PATCH 10/14] fix dropck overflow error message Perf numbers: Before this patchset: 572.70user 5.52system 7:33.21elapsed 127%CPU (0avgtext+0avgdata 1173368maxresident)k llvm-time: 385.858 After this patch: 557.84user 5.73system 7:22.10elapsed 127%CPU (0avgtext+0avgdata 1142848maxresident)k llvm-time: 385.834 nice 2.5% perf improvement --- src/librustc_typeck/check/dropck.rs | 40 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 57f2f063c71c4..4ae65a15c26b2 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -18,6 +18,7 @@ use util::nodemap::FnvHashSet; use syntax::ast; use syntax::codemap::{self, Span}; +use syntax::parse::token::special_idents; /// check_drop_impl confirms that the Drop implementation identfied by /// `drop_impl_did` is not any more specialized than the type it is @@ -286,27 +287,26 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> // was somehow on the root. } TypeContext::ADT { def_id, variant, field, field_index } => { - // FIXME (pnkfelix): eventually lookup arg_name - // for the given index on struct variants. - // TODO: be saner - if let ty::ADTKind::Enum = tcx.lookup_adt_def(def_id).adt_kind() { - span_note!( - rcx.tcx().sess, - span, - "overflowed on enum {} variant {} argument {} type: {}", - tcx.item_path_str(def_id), - variant, - field_index, - detected_on_typ); + let adt = tcx.lookup_adt_def(def_id); + let variant_name = match adt.adt_kind() { + ty::ADTKind::Enum => format!("enum {} variant {}", + tcx.item_path_str(def_id), + variant), + ty::ADTKind::Struct => format!("struct {}", + tcx.item_path_str(def_id)) + }; + let field_name = if field == special_idents::unnamed_field.name { + format!("#{}", field_index) } else { - span_note!( - rcx.tcx().sess, - span, - "overflowed on struct {} field {} type: {}", - tcx.item_path_str(def_id), - field, - detected_on_typ); - } + format!("`{}`", field) + }; + span_note!( + rcx.tcx().sess, + span, + "overflowed on {} field {} type: {}", + variant_name, + field_name, + detected_on_typ); } } } From 015300109d96a70d63ee12c012cc5170defbf133 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 6 Aug 2015 18:25:15 +0300 Subject: [PATCH 11/14] cache Ty::is_simd --- src/librustc/middle/ty.rs | 28 +++++++++++++------ src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/common.rs | 2 +- src/librustc_trans/trans/consts.rs | 6 ++-- .../trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/trans/expr.rs | 6 ++-- src/librustc_trans/trans/foreign.rs | 2 +- src/librustc_trans/trans/glue.rs | 2 +- src/librustc_trans/trans/type_of.rs | 6 ++-- src/librustc_typeck/check/op.rs | 25 ++++++++--------- 10 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 733fa0e71b4ee..d54271b753170 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3179,11 +3179,12 @@ impl<'tcx> TraitDef<'tcx> { bitflags! { flags ADTFlags: u32 { const NO_ADT_FLAGS = 0, - const IS_FUNDAMENTAL = 1 << 0, - const IS_PHANTOM_DATA = 1 << 1, - const IS_DTORCK = 1 << 2, // is this a dtorck type? - const IS_DTORCK_VALID = 1 << 3, - const IS_ENUM = 1 << 4 + const IS_ENUM = 1 << 0, + const IS_DTORCK = 1 << 1, // is this a dtorck type? + const IS_DTORCK_VALID = 1 << 2, + const IS_PHANTOM_DATA = 1 << 3, + const IS_SIMD = 1 << 4, + const IS_FUNDAMENTAL = 1 << 5, } } @@ -3244,9 +3245,13 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { kind: ADTKind, variants: Vec>) -> Self { let mut flags = ADTFlags::NO_ADT_FLAGS; - if tcx.has_attr(did, "fundamental") { + let attrs = tcx.get_attrs(did); + if attrs.iter().any(|item| item.check_name("fundamental")) { flags = flags | ADTFlags::IS_FUNDAMENTAL; } + if attrs.iter().any(|item| item.check_name("simd")) { + flags = flags | ADTFlags::IS_SIMD; + } if Some(did) == tcx.lang_items.phantom_data() { flags = flags | ADTFlags::IS_PHANTOM_DATA; } @@ -3289,6 +3294,11 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { self.flags.get().intersects(ADTFlags::IS_FUNDAMENTAL) } + #[inline] + pub fn is_simd(&self) -> bool { + self.flags.get().intersects(ADTFlags::IS_SIMD) + } + #[inline] pub fn is_phantom_data(&self) -> bool { self.flags.get().intersects(ADTFlags::IS_PHANTOM_DATA) @@ -4203,9 +4213,10 @@ impl<'tcx> TyS<'tcx> { } } - pub fn is_simd(&self, cx: &ctxt) -> bool { + #[inline] + pub fn is_simd(&self) -> bool { match self.sty { - TyStruct(def, _) => cx.lookup_simd(def.did), + TyStruct(def, _) => def.is_simd(), _ => false } } @@ -5979,7 +5990,6 @@ impl<'tcx> ctxt<'tcx> { /// Obtain the representation annotation for a struct definition. pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { - // TODO: remove memoized(&self.repr_hint_cache, did, |did: DefId| { Rc::new(if did.krate == LOCAL_CRATE { self.get_attrs(did).iter().flat_map(|meta| { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index d119e0006c661..a0dd489cd8a9b 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -621,7 +621,7 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>( let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false); (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false) } - ty::TyStruct(_, _) if rhs_t.is_simd(cx.tcx()) => { + ty::TyStruct(def, _) if def.is_simd() => { let mut res = C_bool(cx.ccx(), false); for i in 0 .. rhs_t.simd_size(cx.tcx()) { res = Or(cx, res, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 15c81b114d307..7bc6f4c8fe96c 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -192,7 +192,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - let simple = ty.is_scalar() || ty.is_unique() || ty.is_region_ptr() || type_is_newtype_immediate(ccx, ty) || - ty.is_simd(tcx); + ty.is_simd(); if simple && !type_is_fat_ptr(tcx, ty) { return true; } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 7a9ddf5a99cd4..7aaed035f2127 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -500,7 +500,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, debug!("const_expr_unadjusted: te1={}, ty={:?}", cx.tn().val_to_string(te1), ty); - let is_simd = ty.is_simd(cx.tcx()); + let is_simd = ty.is_simd(); let intype = if is_simd { ty.simd_type(cx.tcx()) } else { @@ -754,7 +754,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, (_, None) => cx.sess().span_bug(e.span, "missing struct field"), } }).collect::>(); - if ety.is_simd(cx.tcx()) { + if ety.is_simd() { C_vector(&cs[..]) } else { adt::trans_const(cx, &*repr, discr, &cs[..]) @@ -850,7 +850,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs) } def::DefStruct(_) => { - if ety.is_simd(cx.tcx()) { + if ety.is_simd() { C_vector(&arg_vals[..]) } else { let repr = adt::represent_type(cx, ety); diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 98188a40e1036..3ca639cc36702 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1175,7 +1175,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, StructMDF(StructMemberDescriptionFactory { variant: variant, substs: substs, - is_simd: struct_type.is_simd(cx.tcx()), + is_simd: struct_type.is_simd(), span: span, }) ) diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index baf14df5b804d..c5043f867ded0 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1453,7 +1453,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // panic occur before the ADT as a whole is ready. let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); - if ty.is_simd(bcx.tcx()) { + if ty.is_simd() { // Issue 23112: The original logic appeared vulnerable to same // order-of-eval bug. But, SIMD values are tuple-structs; // i.e. functional record update (FRU) syntax is unavailable. @@ -1697,7 +1697,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_eager_binop"); let tcx = bcx.tcx(); - let is_simd = lhs_t.is_simd(tcx); + let is_simd = lhs_t.is_simd(); let intype = if is_simd { lhs_t.simd_type(tcx) } else { @@ -2502,7 +2502,7 @@ fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // #1877, #10183: Ensure that input is always valid let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc); let tcx = bcx.tcx(); - let is_simd = lhs_t.is_simd(tcx); + let is_simd = lhs_t.is_simd(); let intype = if is_simd { lhs_t.simd_type(tcx) } else { diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index cafc0be74ba89..225ff52a63c59 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -449,7 +449,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn gate_simd_ffi(tcx: &ty::ctxt, decl: &ast::FnDecl, ty: &ty::BareFnTy) { if !tcx.sess.features.borrow().simd_ffi { let check = |ast_ty: &ast::Ty, ty: ty::Ty| { - if ty.is_simd(tcx) { + if ty.is_simd() { tcx.sess.span_err(ast_ty.span, &format!("use of SIMD type `{}` in FFI is highly experimental and \ may result in invalid code", diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 30cf6f519fbd1..cf3cde8907f7f 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -419,7 +419,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in 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. - assert!(!t.is_simd(bcx.tcx())); + assert!(!t.is_simd()); let repr = adt::represent_type(ccx, t); let sizing_type = adt::sizing_type_context_of(ccx, &*repr, true); debug!("DST {} sizing_type: {}", t, sizing_type.to_string()); diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 91247ebd7919d..0b969360f537e 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -222,7 +222,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ } ty::TyStruct(..) => { - if t.is_simd(cx.tcx()) { + if t.is_simd() { let llet = type_of(cx, t.simd_type(cx.tcx())); let n = t.simd_size(cx.tcx()) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); @@ -404,7 +404,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> adt::type_of(cx, &*repr) } ty::TyStruct(def, ref substs) => { - if t.is_simd(cx.tcx()) { + if t.is_simd() { let llet = in_memory_type_of(cx, t.simd_type(cx.tcx())); let n = t.simd_size(cx.tcx()) as u64; ensure_array_fits_in_address_space(cx, llet, n, t); @@ -436,7 +436,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..) - if !t.is_simd(cx.tcx()) => { + if !t.is_simd() => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &*repr, &mut llty); } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index c6d13d3b0a5ca..b139cb45bf207 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -21,7 +21,7 @@ use super::{ structurally_resolved_type, }; use middle::traits; -use middle::ty::{self, Ty, HasTypeFlags}; +use middle::ty::{Ty, HasTypeFlags}; use syntax::ast; use syntax::ast_util; use syntax::parse::token; @@ -41,7 +41,7 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, let lhs_ty = structurally_resolved_type(fcx, lhs_expr.span, fcx.expr_ty(lhs_expr)); let rhs_ty = structurally_resolved_type(fcx, rhs_expr.span, fcx.expr_ty(rhs_expr)); - if is_builtin_binop(fcx.tcx(), lhs_ty, rhs_ty, op) { + if is_builtin_binop(lhs_ty, rhs_ty, op) { enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); fcx.write_nil(expr.id); } else { @@ -86,7 +86,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // traits, because their return type is not bool. Perhaps this // should change, but for now if LHS is SIMD we go down a // different path that bypassess all traits. - if lhs_ty.is_simd(fcx.tcx()) { + if lhs_ty.is_simd() { check_expr_coercable_to_type(fcx, rhs_expr, lhs_ty); let rhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); let return_ty = enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); @@ -123,7 +123,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty); if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && - is_builtin_binop(fcx.tcx(), lhs_ty, rhs_ty, op) + is_builtin_binop(lhs_ty, rhs_ty, op) { let builtin_return_ty = enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); @@ -143,7 +143,7 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, op: ast::BinOp) -> Ty<'tcx> { - debug_assert!(is_builtin_binop(fcx.tcx(), lhs_ty, rhs_ty, op)); + debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op)); let tcx = fcx.tcx(); match BinOpCategory::from(op) { @@ -156,7 +156,7 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, BinOpCategory::Shift => { // For integers, the shift amount can be of any integral // type. For simd, the type must match exactly. - if lhs_ty.is_simd(tcx) { + if lhs_ty.is_simd() { demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); } @@ -176,7 +176,7 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); // if this is simd, result is same as lhs, else bool - if lhs_ty.is_simd(tcx) { + if lhs_ty.is_simd() { let unit_ty = lhs_ty.simd_type(tcx); debug!("enforce_builtin_binop_types: lhs_ty={:?} unit_ty={:?}", lhs_ty, @@ -415,8 +415,7 @@ impl BinOpCategory { /// Reason #2 is the killer. I tried for a while to always use /// overloaded logic and just check the types in constants/trans after /// the fact, and it worked fine, except for SIMD types. -nmatsakis -fn is_builtin_binop<'tcx>(cx: &ty::ctxt<'tcx>, - lhs: Ty<'tcx>, +fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: ast::BinOp) -> bool @@ -429,28 +428,28 @@ fn is_builtin_binop<'tcx>(cx: &ty::ctxt<'tcx>, BinOpCategory::Shift => { lhs.references_error() || rhs.references_error() || lhs.is_integral() && rhs.is_integral() || - lhs.is_simd(cx) && rhs.is_simd(cx) + lhs.is_simd() && rhs.is_simd() } BinOpCategory::Math => { lhs.references_error() || rhs.references_error() || lhs.is_integral() && rhs.is_integral() || lhs.is_floating_point() && rhs.is_floating_point() || - lhs.is_simd(cx) && rhs.is_simd(cx) + lhs.is_simd() && rhs.is_simd() } BinOpCategory::Bitwise => { lhs.references_error() || rhs.references_error() || lhs.is_integral() && rhs.is_integral() || lhs.is_floating_point() && rhs.is_floating_point() || - lhs.is_simd(cx) && rhs.is_simd(cx) || + lhs.is_simd() && rhs.is_simd() || lhs.is_bool() && rhs.is_bool() } BinOpCategory::Comparison => { lhs.references_error() || rhs.references_error() || lhs.is_scalar() && rhs.is_scalar() || - lhs.is_simd(cx) && rhs.is_simd(cx) + lhs.is_simd() && rhs.is_simd() } } } From 7d32533eabb5321a0b2690bf16d07077b4f91562 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 7 Aug 2015 13:48:29 +0300 Subject: [PATCH 12/14] add documentation --- src/librustc/middle/ty.rs | 87 +++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d54271b753170..86fe1f8b0b520 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3192,40 +3192,56 @@ pub type ADTDef<'tcx> = ADTDef_<'tcx, 'static>; pub type VariantDef<'tcx> = VariantDef_<'tcx, 'static>; pub type FieldDef<'tcx> = FieldDef_<'tcx, 'static>; -pub struct VariantDef_<'tcx, 'lt: 'tcx> { +pub struct VariantDef_<'tcx, 'container: 'tcx> { pub did: DefId, pub name: Name, // struct's name if this is a struct pub disr_val: Disr, - pub fields: Vec> + pub fields: Vec> } -pub struct FieldDef_<'tcx, 'lt: 'tcx> { +pub struct FieldDef_<'tcx, 'container: 'tcx> { + /// The field's DefId. NOTE: the fields of tuple-like enum variants + /// are not real items, and don't have entries in tcache etc. pub did: DefId, - // special_idents::unnamed_field.name - // if this is a tuple-like field + /// special_idents::unnamed_field.name + /// if this is a tuple-like field pub name: Name, pub vis: ast::Visibility, - // TyIVar is used here to allow for - ty: TyIVar<'tcx, 'lt> + /// TyIVar is used here to allow for variance (see the doc at + /// ADTDef_). + ty: TyIVar<'tcx, 'container> } -/// The definition of an abstract data type - a struct or enum. 'lt -/// is here so 'tcx can be variant. -pub struct ADTDef_<'tcx, 'lt: 'tcx> { +/// The definition of an abstract data type - a struct or enum. +/// +/// These are all interned (by intern_adt_def) into the adt_defs +/// table. +/// +/// Because of the possibility of nested tcx-s, this type +/// needs 2 lifetimes: the traditional variant lifetime ('tcx) +/// bounding the lifetime of the inner types is of course necessary. +/// However, it is not sufficient - types from a child tcx must +/// not be leaked into the master tcx by being stored in an ADTDef_. +/// +/// The 'container lifetime ensures that by outliving the container +/// tcx and preventing shorter-lived types from being inserted. When +/// write access is not needed, the 'container lifetime can be +/// erased to 'static, which can be done by the ADTDef wrapper. +pub struct ADTDef_<'tcx, 'container: 'tcx> { pub did: DefId, - pub variants: Vec>, + pub variants: Vec>, flags: Cell, } -impl<'tcx, 'lt> PartialEq for ADTDef_<'tcx, 'lt> { +impl<'tcx, 'container> PartialEq for ADTDef_<'tcx, 'container> { // ADTDef are always interned and this is part of TyS equality #[inline] fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } } -impl<'tcx, 'lt> Eq for ADTDef_<'tcx, 'lt> {} +impl<'tcx, 'container> Eq for ADTDef_<'tcx, 'container> {} -impl<'tcx, 'lt> Hash for ADTDef_<'tcx, 'lt> { +impl<'tcx, 'container> Hash for ADTDef_<'tcx, 'container> { #[inline] fn hash(&self, s: &mut H) { (self as *const ADTDef).hash(s) @@ -3239,11 +3255,11 @@ pub enum ADTKind { Struct, Enum } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum VariantKind { Dict, Tuple, Unit } -impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { +impl<'tcx, 'container> ADTDef_<'tcx, 'container> { fn new(tcx: &ctxt<'tcx>, did: DefId, kind: ADTKind, - variants: Vec>) -> Self { + variants: Vec>) -> Self { let mut flags = ADTFlags::NO_ADT_FLAGS; let attrs = tcx.get_attrs(did); if attrs.iter().any(|item| item.check_name("fundamental")) { @@ -3272,6 +3288,7 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { self.flags.set(self.flags.get() | ADTFlags::IS_DTORCK_VALID) } + /// Returns the kind of the ADT - Struct or Enum. #[inline] pub fn adt_kind(&self) -> ADTKind { if self.flags.get().intersects(ADTFlags::IS_ENUM) { @@ -3281,6 +3298,9 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { } } + /// Returns whether this is a dtorck type. If this returns + /// true, this type being safe for destruction requires it to be + /// alive; Otherwise, only the contents are required to be. #[inline] pub fn is_dtorck(&'tcx self, tcx: &ctxt<'tcx>) -> bool { if !self.flags.get().intersects(ADTFlags::IS_DTORCK_VALID) { @@ -3289,6 +3309,8 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { self.flags.get().intersects(ADTFlags::IS_DTORCK) } + /// Returns whether this type is #[fundamental] for the purposes + /// of coherence checking. #[inline] pub fn is_fundamental(&self) -> bool { self.flags.get().intersects(ADTFlags::IS_FUNDAMENTAL) @@ -3299,17 +3321,20 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { self.flags.get().intersects(ADTFlags::IS_SIMD) } + /// Returns true if this is PhantomData. #[inline] pub fn is_phantom_data(&self) -> bool { self.flags.get().intersects(ADTFlags::IS_PHANTOM_DATA) } - #[inline(never)] + /// Returns whether this type has a destructor. pub fn has_dtor(&self, tcx: &ctxt<'tcx>) -> bool { tcx.destructor_for_type.borrow().contains_key(&self.did) } - pub fn struct_variant(&self) -> &ty::VariantDef_<'tcx, 'lt> { + /// Asserts this is a struct and returns the struct's unique + /// variant. + pub fn struct_variant(&self) -> &ty::VariantDef_<'tcx, 'container> { assert!(self.adt_kind() == ADTKind::Struct); &self.variants[0] } @@ -3324,13 +3349,15 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { tcx.lookup_predicates(self.did) } + /// Returns an iterator over all fields contained + /// by this ADT. #[inline] pub fn all_fields(&self) -> iter::FlatMap< - slice::Iter>, - slice::Iter>, - for<'s> fn(&'s VariantDef_<'tcx, 'lt>) - -> slice::Iter<'s, FieldDef_<'tcx, 'lt>> + slice::Iter>, + slice::Iter>, + for<'s> fn(&'s VariantDef_<'tcx, 'container>) + -> slice::Iter<'s, FieldDef_<'tcx, 'container>> > { self.variants.iter().flat_map(VariantDef_::fields_iter) } @@ -3350,14 +3377,14 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { self.variants.iter().all(|v| v.fields.is_empty()) } - pub fn variant_with_id(&self, vid: DefId) -> &VariantDef_<'tcx, 'lt> { + pub fn variant_with_id(&self, vid: DefId) -> &VariantDef_<'tcx, 'container> { self.variants .iter() .find(|v| v.did == vid) .expect("variant_with_id: unknown variant") } - pub fn variant_of_def(&self, def: def::Def) -> &VariantDef_<'tcx, 'lt> { + pub fn variant_of_def(&self, def: def::Def) -> &VariantDef_<'tcx, 'container> { match def { def::DefVariant(_, vid, _) => self.variant_with_id(vid), def::DefStruct(..) | def::DefTy(..) => self.struct_variant(), @@ -3366,9 +3393,9 @@ impl<'tcx, 'lt> ADTDef_<'tcx, 'lt> { } } -impl<'tcx, 'lt> VariantDef_<'tcx, 'lt> { +impl<'tcx, 'container> VariantDef_<'tcx, 'container> { #[inline] - fn fields_iter(&self) -> slice::Iter> { + fn fields_iter(&self) -> slice::Iter> { self.fields.iter() } @@ -3387,17 +3414,17 @@ impl<'tcx, 'lt> VariantDef_<'tcx, 'lt> { } #[inline] - pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef_<'tcx, 'lt>> { + pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef_<'tcx, 'container>> { self.fields.iter().find(|f| f.name == name) } #[inline] - pub fn field_named(&self, name: ast::Name) -> &FieldDef_<'tcx, 'lt> { + pub fn field_named(&self, name: ast::Name) -> &FieldDef_<'tcx, 'container> { self.find_field_named(name).unwrap() } } -impl<'tcx, 'lt> FieldDef_<'tcx, 'lt> { +impl<'tcx, 'container> FieldDef_<'tcx, 'container> { pub fn new(did: DefId, name: Name, vis: ast::Visibility) -> Self { @@ -3417,7 +3444,7 @@ impl<'tcx, 'lt> FieldDef_<'tcx, 'lt> { self.ty.unwrap() } - pub fn fulfill_ty(&self, ty: Ty<'lt>) { + pub fn fulfill_ty(&self, ty: Ty<'container>) { self.ty.fulfill(ty); } } From 62cd3cc46b533c3d1b6c94cc1d13a3be8a8c23ab Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 7 Aug 2015 13:57:39 +0300 Subject: [PATCH 13/14] stop using skip_binder --- src/librustc/metadata/decoder.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 38f90e682be06..b0f7bab6c5930 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -30,7 +30,7 @@ use middle::def; use middle::lang_items; use middle::subst; use middle::ty::{ImplContainer, TraitContainer}; -use middle::ty::{self, Ty}; +use middle::ty::{self, RegionEscape, Ty}; use util::nodemap::FnvHashMap; use std::cell::{Cell, RefCell}; @@ -477,7 +477,13 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, variant.name, ctor_ty); let field_tys = match ctor_ty.sty { - ty::TyBareFn(_, ref f) => &f.sig.skip_binder().inputs, + ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ref inputs, .. + }), ..}) => { + // tuple-struct constructors don't have escaping regions + assert!(!inputs.has_escaping_regions()); + inputs + }, _ => tcx.sess.bug("tuple-variant ctor is not an ADT") }; for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) { From eedb1cc5765b043f31ca4316c42f2ac8d7df1919 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 7 Aug 2015 14:41:33 +0300 Subject: [PATCH 14/14] rename ADTDef to AdtDef etc. --- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 30 ++-- src/librustc/metadata/encoder.rs | 21 +-- src/librustc/middle/check_match.rs | 6 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/traits/coherence.rs | 4 +- src/librustc/middle/ty.rs | 162 ++++++++++-------- src/librustc/util/ppaux.rs | 2 +- src/librustc_data_structures/ivar.rs | 4 + src/librustc_lint/builtin.rs | 2 +- src/librustc_privacy/lib.rs | 8 +- src/librustc_trans/save/dump_csv.rs | 2 +- src/librustc_trans/save/mod.rs | 2 +- src/librustc_trans/trans/adt.rs | 2 +- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/common.rs | 2 +- .../trans/debuginfo/metadata.rs | 4 +- src/librustc_trans/trans/monomorphize.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/dropck.rs | 4 +- src/librustc_typeck/check/mod.rs | 8 +- src/librustc_typeck/collect.rs | 32 ++-- src/librustdoc/clean/mod.rs | 4 +- 23 files changed, 164 insertions(+), 145 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index f0607010bf3f0..217868f1b9c69 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -213,7 +213,7 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe decoder::get_trait_def(&*cdata, def.node, tcx) } -pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> &'tcx ty::ADTDef_<'tcx, 'tcx> { +pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::AdtDefMaster<'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); decoder::get_adt_def(&cstore.intr, &*cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b0f7bab6c5930..df5f798217f4b 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -393,12 +393,12 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, pub fn get_adt_def<'tcx>(intr: &IdentInterner, cdata: Cmd, item_id: ast::NodeId, - tcx: &ty::ctxt<'tcx>) -> &'tcx ty::ADTDef_<'tcx, 'tcx> + tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx> { fn get_enum_variants<'tcx>(intr: &IdentInterner, cdata: Cmd, doc: rbml::Doc, - tcx: &ty::ctxt<'tcx>) -> Vec> { + tcx: &ty::ctxt<'tcx>) -> Vec> { let mut disr_val = 0; reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { let did = translated_def_id(cdata, p); @@ -410,7 +410,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, let disr = disr_val; disr_val = disr_val.wrapping_add(1); - ty::VariantDef_ { + ty::VariantDefData { did: did, name: item_name(intr, item), fields: get_variant_fields(intr, cdata, item, tcx), @@ -421,29 +421,29 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, fn get_variant_fields<'tcx>(intr: &IdentInterner, cdata: Cmd, doc: rbml::Doc, - tcx: &ty::ctxt<'tcx>) -> Vec> { + tcx: &ty::ctxt<'tcx>) -> Vec> { reader::tagged_docs(doc, tag_item_field).map(|f| { let ff = item_family(f); match ff { PublicField | InheritedField => {}, _ => tcx.sess.bug(&format!("expected field, found {:?}", ff)) }; - ty::FieldDef_::new(item_def_id(f, cdata), - item_name(intr, f), - struct_field_family_to_visibility(ff)) + ty::FieldDefData::new(item_def_id(f, cdata), + item_name(intr, f), + struct_field_family_to_visibility(ff)) }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| { let ff = item_family(f); - ty::FieldDef_::new(item_def_id(f, cdata), - special_idents::unnamed_field.name, - struct_field_family_to_visibility(ff)) + ty::FieldDefData::new(item_def_id(f, cdata), + special_idents::unnamed_field.name, + struct_field_family_to_visibility(ff)) })).collect() } fn get_struct_variant<'tcx>(intr: &IdentInterner, cdata: Cmd, doc: rbml::Doc, did: ast::DefId, - tcx: &ty::ctxt<'tcx>) -> ty::VariantDef_<'tcx, 'tcx> { - ty::VariantDef_ { + tcx: &ty::ctxt<'tcx>) -> ty::VariantDefData<'tcx, 'tcx> { + ty::VariantDefData { did: did, name: item_name(intr, doc), fields: get_variant_fields(intr, cdata, doc, tcx), @@ -454,9 +454,9 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, let doc = lookup_item(item_id, cdata.data()); let did = ast::DefId { krate: cdata.cnum, node: item_id }; let (kind, variants) = match item_family(doc) { - Enum => (ty::ADTKind::Enum, + Enum => (ty::AdtKind::Enum, get_enum_variants(intr, cdata, doc, tcx)), - Struct => (ty::ADTKind::Struct, + Struct => (ty::AdtKind::Struct, vec![get_struct_variant(intr, cdata, doc, did, tcx)]), _ => tcx.sess.bug("get_adt_def called on a non-ADT") }; @@ -467,7 +467,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, // to support recursive structures for variant in &adt.variants { if variant.kind() == ty::VariantKind::Tuple && - adt.adt_kind() == ty::ADTKind::Enum { + adt.adt_kind() == ty::AdtKind::Enum { // tuple-like enum variant fields aren't real items - get the types // from the ctor. debug!("evaluating the ctor-type of {:?}", diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 4c4a1e07f44c1..d5c189ff044d2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -265,9 +265,9 @@ fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { } fn encode_struct_fields(rbml_w: &mut Encoder, - fields: &[ty::FieldDef], + variant: ty::VariantDef, origin: DefId) { - for f in fields { + for f in &variant.fields { if f.name == special_idents::unnamed_field.name { rbml_w.start_tag(tag_item_unnamed_field); } else { @@ -315,14 +315,11 @@ fn encode_enum_variant_info(ecx: &EncodeContext, encode_stability(rbml_w, stab); if let ty::VariantKind::Dict = variant.kind() { - let idx = encode_info_for_struct(ecx, - rbml_w, - &variant.fields, - index); + let idx = encode_info_for_struct(ecx, rbml_w, variant, index); encode_index(rbml_w, idx, write_i64); } - encode_struct_fields(rbml_w, &variant.fields, vid); + encode_struct_fields(rbml_w, variant, vid); let specified_disr_val = variant.disr_val; if specified_disr_val != disr_val { @@ -630,7 +627,7 @@ fn encode_provided_source(rbml_w: &mut Encoder, /* Returns an index of items in this class */ fn encode_info_for_struct<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - fields: &[ty::FieldDef<'tcx>], + variant: ty::VariantDef<'tcx>, global_index: &mut Vec>) -> Vec> { /* Each class has its own index, since different classes @@ -638,7 +635,7 @@ fn encode_info_for_struct<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let mut index = Vec::new(); /* We encode both private and public fields -- need to include private fields to get the offsets right */ - for field in fields { + for field in &variant.fields { let nm = field.name; let id = field.did.node; @@ -1153,13 +1150,13 @@ fn encode_info_for_item(ecx: &EncodeContext, } ast::ItemStruct(ref struct_def, _) => { let def = ecx.tcx.lookup_adt_def(def_id); - let fields = &def.struct_variant().fields; + let variant = def.struct_variant(); /* First, encode the fields These come first because we need to write them to make the index, and the index needs to be in the item for the class itself */ - let idx = encode_info_for_struct(ecx, rbml_w, &fields, index); + let idx = encode_info_for_struct(ecx, rbml_w, variant, index); /* Index the class*/ add_to_index(item, rbml_w, index); @@ -1181,7 +1178,7 @@ fn encode_info_for_item(ecx: &EncodeContext, /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - encode_struct_fields(rbml_w, &fields, def_id); + encode_struct_fields(rbml_w, variant, def_id); encode_inlined_item(ecx, rbml_w, IIItemRef(item)); diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 2c835b35cc209..b9d8e4b842d01 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -574,8 +574,10 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, }) } -impl<'tcx> ADTDef<'tcx> { - fn variant_of_ctor(&'tcx self, ctor: &Constructor) -> &'tcx VariantDef<'tcx> { +impl<'tcx, 'container> ty::AdtDefData<'tcx, 'container> { + fn variant_of_ctor(&self, + ctor: &Constructor) + -> &VariantDefData<'tcx, 'container> { match ctor { &Variant(vid) => self.variant_with_id(vid), _ => self.struct_variant() diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8e827257f7e9e..3755b4c57c3ec 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -723,7 +723,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { // are properly handled. self.walk_expr(with_expr); - fn contains_field_named(field: &ty::FieldDef, + fn contains_field_named(field: ty::FieldDef, fields: &Vec) -> bool { diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index e9bd6304fcad4..534a2fc054da7 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -278,8 +278,8 @@ fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool match ty.sty { ty::TyBox(..) | ty::TyRef(..) => true, - ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.is_fundamental() - , + ty::TyEnum(def, _) | ty::TyStruct(def, _) => + def.is_fundamental(), ty::TyTrait(ref data) => tcx.has_attr(data.principal_def_id(), "fundamental"), _ => diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 86fe1f8b0b520..2fe1f14d521ba 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -638,7 +638,7 @@ pub struct CtxtArenas<'tcx> { // references trait_defs: TypedArena>, - adt_defs: TypedArena>, + adt_defs: TypedArena>, } impl<'tcx> CtxtArenas<'tcx> { @@ -766,7 +766,7 @@ pub struct ctxt<'tcx> { pub impl_trait_refs: RefCell>>>, pub trait_defs: RefCell>>, - pub adt_defs: RefCell>>, + pub adt_defs: RefCell>>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its /// associated predicates. @@ -937,10 +937,10 @@ impl<'tcx> ctxt<'tcx> { pub fn intern_adt_def(&self, did: DefId, - kind: ADTKind, - variants: Vec>) - -> &'tcx ADTDef_<'tcx, 'tcx> { - let def = ADTDef_::new(self, did, kind, variants); + kind: AdtKind, + variants: Vec>) + -> AdtDefMaster<'tcx> { + let def = AdtDefData::new(self, did, kind, variants); let interned = self.arenas.adt_defs.alloc(def); // this will need a transmute when reverse-variance is removed self.adt_defs.borrow_mut().insert(did, interned); @@ -1746,12 +1746,12 @@ pub enum TypeVariants<'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 `TyStruct` as /// well. - TyEnum(&'tcx ADTDef<'tcx>, &'tcx Substs<'tcx>), + TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>), /// A structure type, defined with `struct`. /// /// See warning about substitutions for enumerated types. - TyStruct(&'tcx ADTDef<'tcx>, &'tcx Substs<'tcx>), + TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), /// `Box`; this is nominally a struct in the documentation, but is /// special-cased internally. For example, it is possible to implicitly @@ -3177,7 +3177,7 @@ impl<'tcx> TraitDef<'tcx> { } bitflags! { - flags ADTFlags: u32 { + flags AdtFlags: u32 { const NO_ADT_FLAGS = 0, const IS_ENUM = 1 << 0, const IS_DTORCK = 1 << 1, // is this a dtorck type? @@ -3188,18 +3188,23 @@ bitflags! { } } -pub type ADTDef<'tcx> = ADTDef_<'tcx, 'static>; -pub type VariantDef<'tcx> = VariantDef_<'tcx, 'static>; -pub type FieldDef<'tcx> = FieldDef_<'tcx, 'static>; +pub type AdtDef<'tcx> = &'tcx AdtDefData<'tcx, 'static>; +pub type VariantDef<'tcx> = &'tcx VariantDefData<'tcx, 'static>; +pub type FieldDef<'tcx> = &'tcx FieldDefData<'tcx, 'static>; -pub struct VariantDef_<'tcx, 'container: 'tcx> { +// See comment on AdtDefData for explanation +pub type AdtDefMaster<'tcx> = &'tcx AdtDefData<'tcx, 'tcx>; +pub type VariantDefMaster<'tcx> = &'tcx VariantDefData<'tcx, 'tcx>; +pub type FieldDefMaster<'tcx> = &'tcx FieldDefData<'tcx, 'tcx>; + +pub struct VariantDefData<'tcx, 'container: 'tcx> { pub did: DefId, pub name: Name, // struct's name if this is a struct pub disr_val: Disr, - pub fields: Vec> + pub fields: Vec> } -pub struct FieldDef_<'tcx, 'container: 'tcx> { +pub struct FieldDefData<'tcx, 'container: 'tcx> { /// The field's DefId. NOTE: the fields of tuple-like enum variants /// are not real items, and don't have entries in tcache etc. pub did: DefId, @@ -3208,7 +3213,7 @@ pub struct FieldDef_<'tcx, 'container: 'tcx> { pub name: Name, pub vis: ast::Visibility, /// TyIVar is used here to allow for variance (see the doc at - /// ADTDef_). + /// AdtDefData). ty: TyIVar<'tcx, 'container> } @@ -3221,60 +3226,60 @@ pub struct FieldDef_<'tcx, 'container: 'tcx> { /// needs 2 lifetimes: the traditional variant lifetime ('tcx) /// bounding the lifetime of the inner types is of course necessary. /// However, it is not sufficient - types from a child tcx must -/// not be leaked into the master tcx by being stored in an ADTDef_. +/// not be leaked into the master tcx by being stored in an AdtDefData. /// /// The 'container lifetime ensures that by outliving the container /// tcx and preventing shorter-lived types from being inserted. When /// write access is not needed, the 'container lifetime can be -/// erased to 'static, which can be done by the ADTDef wrapper. -pub struct ADTDef_<'tcx, 'container: 'tcx> { +/// erased to 'static, which can be done by the AdtDef wrapper. +pub struct AdtDefData<'tcx, 'container: 'tcx> { pub did: DefId, - pub variants: Vec>, - flags: Cell, + pub variants: Vec>, + flags: Cell, } -impl<'tcx, 'container> PartialEq for ADTDef_<'tcx, 'container> { - // ADTDef are always interned and this is part of TyS equality +impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> { + // AdtDefData are always interned and this is part of TyS equality #[inline] fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } } -impl<'tcx, 'container> Eq for ADTDef_<'tcx, 'container> {} +impl<'tcx, 'container> Eq for AdtDefData<'tcx, 'container> {} -impl<'tcx, 'container> Hash for ADTDef_<'tcx, 'container> { +impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { #[inline] fn hash(&self, s: &mut H) { - (self as *const ADTDef).hash(s) + (self as *const AdtDefData).hash(s) } } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ADTKind { Struct, Enum } +pub enum AdtKind { Struct, Enum } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum VariantKind { Dict, Tuple, Unit } -impl<'tcx, 'container> ADTDef_<'tcx, 'container> { +impl<'tcx, 'container> AdtDefData<'tcx, 'container> { fn new(tcx: &ctxt<'tcx>, did: DefId, - kind: ADTKind, - variants: Vec>) -> Self { - let mut flags = ADTFlags::NO_ADT_FLAGS; + kind: AdtKind, + variants: Vec>) -> Self { + let mut flags = AdtFlags::NO_ADT_FLAGS; let attrs = tcx.get_attrs(did); if attrs.iter().any(|item| item.check_name("fundamental")) { - flags = flags | ADTFlags::IS_FUNDAMENTAL; + flags = flags | AdtFlags::IS_FUNDAMENTAL; } if attrs.iter().any(|item| item.check_name("simd")) { - flags = flags | ADTFlags::IS_SIMD; + flags = flags | AdtFlags::IS_SIMD; } if Some(did) == tcx.lang_items.phantom_data() { - flags = flags | ADTFlags::IS_PHANTOM_DATA; + flags = flags | AdtFlags::IS_PHANTOM_DATA; } - if let ADTKind::Enum = kind { - flags = flags | ADTFlags::IS_ENUM; + if let AdtKind::Enum = kind { + flags = flags | AdtFlags::IS_ENUM; } - ADTDef { + AdtDefData { did: did, variants: variants, flags: Cell::new(flags), @@ -3283,18 +3288,18 @@ impl<'tcx, 'container> ADTDef_<'tcx, 'container> { fn calculate_dtorck(&'tcx self, tcx: &ctxt<'tcx>) { if tcx.is_adt_dtorck(self) { - self.flags.set(self.flags.get() | ADTFlags::IS_DTORCK); + self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK); } - self.flags.set(self.flags.get() | ADTFlags::IS_DTORCK_VALID) + self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) } /// Returns the kind of the ADT - Struct or Enum. #[inline] - pub fn adt_kind(&self) -> ADTKind { - if self.flags.get().intersects(ADTFlags::IS_ENUM) { - ADTKind::Enum + pub fn adt_kind(&self) -> AdtKind { + if self.flags.get().intersects(AdtFlags::IS_ENUM) { + AdtKind::Enum } else { - ADTKind::Struct + AdtKind::Struct } } @@ -3303,28 +3308,28 @@ impl<'tcx, 'container> ADTDef_<'tcx, 'container> { /// alive; Otherwise, only the contents are required to be. #[inline] pub fn is_dtorck(&'tcx self, tcx: &ctxt<'tcx>) -> bool { - if !self.flags.get().intersects(ADTFlags::IS_DTORCK_VALID) { + if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) { self.calculate_dtorck(tcx) } - self.flags.get().intersects(ADTFlags::IS_DTORCK) + self.flags.get().intersects(AdtFlags::IS_DTORCK) } /// Returns whether this type is #[fundamental] for the purposes /// of coherence checking. #[inline] pub fn is_fundamental(&self) -> bool { - self.flags.get().intersects(ADTFlags::IS_FUNDAMENTAL) + self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL) } #[inline] pub fn is_simd(&self) -> bool { - self.flags.get().intersects(ADTFlags::IS_SIMD) + self.flags.get().intersects(AdtFlags::IS_SIMD) } /// Returns true if this is PhantomData. #[inline] pub fn is_phantom_data(&self) -> bool { - self.flags.get().intersects(ADTFlags::IS_PHANTOM_DATA) + self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA) } /// Returns whether this type has a destructor. @@ -3334,8 +3339,8 @@ impl<'tcx, 'container> ADTDef_<'tcx, 'container> { /// Asserts this is a struct and returns the struct's unique /// variant. - pub fn struct_variant(&self) -> &ty::VariantDef_<'tcx, 'container> { - assert!(self.adt_kind() == ADTKind::Struct); + pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> { + assert!(self.adt_kind() == AdtKind::Struct); &self.variants[0] } @@ -3354,12 +3359,12 @@ impl<'tcx, 'container> ADTDef_<'tcx, 'container> { #[inline] pub fn all_fields(&self) -> iter::FlatMap< - slice::Iter>, - slice::Iter>, - for<'s> fn(&'s VariantDef_<'tcx, 'container>) - -> slice::Iter<'s, FieldDef_<'tcx, 'container>> + slice::Iter>, + slice::Iter>, + for<'s> fn(&'s VariantDefData<'tcx, 'container>) + -> slice::Iter<'s, FieldDefData<'tcx, 'container>> > { - self.variants.iter().flat_map(VariantDef_::fields_iter) + self.variants.iter().flat_map(VariantDefData::fields_iter) } #[inline] @@ -3377,14 +3382,14 @@ impl<'tcx, 'container> ADTDef_<'tcx, 'container> { self.variants.iter().all(|v| v.fields.is_empty()) } - pub fn variant_with_id(&self, vid: DefId) -> &VariantDef_<'tcx, 'container> { + pub fn variant_with_id(&self, vid: DefId) -> &VariantDefData<'tcx, 'container> { self.variants .iter() .find(|v| v.did == vid) .expect("variant_with_id: unknown variant") } - pub fn variant_of_def(&self, def: def::Def) -> &VariantDef_<'tcx, 'container> { + pub fn variant_of_def(&self, def: def::Def) -> &VariantDefData<'tcx, 'container> { match def { def::DefVariant(_, vid, _) => self.variant_with_id(vid), def::DefStruct(..) | def::DefTy(..) => self.struct_variant(), @@ -3393,16 +3398,16 @@ impl<'tcx, 'container> ADTDef_<'tcx, 'container> { } } -impl<'tcx, 'container> VariantDef_<'tcx, 'container> { +impl<'tcx, 'container> VariantDefData<'tcx, 'container> { #[inline] - fn fields_iter(&self) -> slice::Iter> { + fn fields_iter(&self) -> slice::Iter> { self.fields.iter() } pub fn kind(&self) -> VariantKind { match self.fields.get(0) { None => VariantKind::Unit, - Some(&FieldDef_ { name, .. }) if name == special_idents::unnamed_field.name => { + Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => { VariantKind::Tuple } Some(_) => VariantKind::Dict @@ -3414,21 +3419,23 @@ impl<'tcx, 'container> VariantDef_<'tcx, 'container> { } #[inline] - pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef_<'tcx, 'container>> { + pub fn find_field_named(&self, + name: ast::Name) + -> Option<&FieldDefData<'tcx, 'container>> { self.fields.iter().find(|f| f.name == name) } #[inline] - pub fn field_named(&self, name: ast::Name) -> &FieldDef_<'tcx, 'container> { + pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> { self.find_field_named(name).unwrap() } } -impl<'tcx, 'container> FieldDef_<'tcx, 'container> { +impl<'tcx, 'container> FieldDefData<'tcx, 'container> { pub fn new(did: DefId, name: Name, vis: ast::Visibility) -> Self { - FieldDef_ { + FieldDefData { did: did, name: name, vis: vis, @@ -3934,7 +3941,7 @@ impl<'tcx> ctxt<'tcx> { self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) } - pub fn mk_enum(&self, def: &'tcx ADTDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + pub fn mk_enum(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside self.mk_ty(TyEnum(def, substs)) } @@ -4036,7 +4043,7 @@ impl<'tcx> ctxt<'tcx> { self.mk_ty(TyProjection(inner)) } - pub fn mk_struct(&self, def: &'tcx ADTDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + pub fn mk_struct(&self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside self.mk_ty(TyStruct(def, substs)) } @@ -4327,7 +4334,7 @@ impl<'tcx> TyS<'tcx> { } } - pub fn ty_adt_def(&self) -> Option<&'tcx ADTDef<'tcx>> { + pub fn ty_adt_def(&self) -> Option> { match self.sty { TyStruct(adt, _) | TyEnum(adt, _) => Some(adt), _ => None @@ -4677,7 +4684,7 @@ impl<'tcx> TyS<'tcx> { // True if instantiating an instance of `r_ty` requires an instance of `r_ty`. pub fn is_instantiable(&'tcx self, cx: &ctxt<'tcx>) -> bool { - fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<&'tcx ADTDef<'tcx>>, + fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec>, r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { debug!("type_requires({:?}, {:?})?", r_ty, ty); @@ -4689,7 +4696,7 @@ impl<'tcx> TyS<'tcx> { return r; } - fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<&'tcx ADTDef<'tcx>>, + fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec>, r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool { debug!("subtypes_require({:?}, {:?})?", r_ty, ty); @@ -4826,7 +4833,7 @@ impl<'tcx> TyS<'tcx> { } } - fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ADTDef<'tcx>) -> bool { + fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: AdtDef<'tcx>) -> bool { match ty.sty { TyStruct(ty_def, _) | TyEnum(ty_def, _) => { ty_def == def @@ -5969,14 +5976,23 @@ impl<'tcx> ctxt<'tcx> { ) } - /// Given the did of a trait, returns its canonical trait ref. - pub fn lookup_adt_def(&self, did: ast::DefId) -> &'tcx ADTDef_<'tcx, 'tcx> { + /// Given the did of an ADT, return a master reference to its + /// definition. Unless you are planning on fulfilling the ADT's fields, + /// use lookup_adt_def instead. + pub fn lookup_adt_def_master(&self, did: ast::DefId) -> AdtDefMaster<'tcx> { lookup_locally_or_in_crate_store( "adt_defs", did, &self.adt_defs, || csearch::get_adt_def(self, did) ) } + /// Given the did of an ADT, return a reference to its definition. + pub fn lookup_adt_def(&self, did: ast::DefId) -> AdtDef<'tcx> { + // when reverse-variance goes away, a transmute:: + // woud be needed here. + self.lookup_adt_def_master(did) + } + /// Given the did of an item, returns its full set of predicates. pub fn lookup_predicates(&self, did: ast::DefId) -> GenericPredicates<'tcx> { lookup_locally_or_in_crate_store( @@ -6610,7 +6626,7 @@ impl<'tcx> ctxt<'tcx> { /// Returns true if this ADT is a dtorck type, i.e. whether it being /// safe for destruction requires it to be alive - fn is_adt_dtorck(&self, adt: &'tcx ADTDef<'tcx>) -> bool { + fn is_adt_dtorck(&self, adt: AdtDef<'tcx>) -> bool { let dtor_method = match self.destructor_for_type.borrow().get(&adt.did) { Some(dtor) => *dtor, None => return false diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 24e18099d8b8f..da20f730babab 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -366,7 +366,7 @@ impl<'tcx> fmt::Debug for ty::TraitDef<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ADTDef<'tcx> { +impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| { write!(f, "{}", tcx.item_path_str(self.did)) diff --git a/src/librustc_data_structures/ivar.rs b/src/librustc_data_structures/ivar.rs index c16a2ea077c40..dabe1b984df2a 100644 --- a/src/librustc_data_structures/ivar.rs +++ b/src/librustc_data_structures/ivar.rs @@ -20,6 +20,10 @@ use std::cell::Cell; /// 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. +/// +/// The `T: Copy` bound is not strictly needed, but it is required by +/// Cell (so removing it would require using UnsafeCell), and it +/// suffices for the current purposes. #[derive(PartialEq)] pub struct Ivar { data: Cell> diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 695cfd43e1424..8f5519faf7a02 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -413,7 +413,7 @@ enum FfiResult { /// expanded to cover NonZero raw pointers and newtypes. /// FIXME: This duplicates code in trans. fn is_repr_nullable_ptr<'tcx>(tcx: &ty::ctxt<'tcx>, - def: &ty::ADTDef<'tcx>, + def: ty::AdtDef<'tcx>, substs: &Substs<'tcx>) -> bool { if def.variants.len() == 2 { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 38eabd2e8c3c8..d10dc2e05ffd0 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -687,8 +687,8 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a field is in scope. fn check_field(&mut self, span: Span, - def: &'tcx ty::ADTDef<'tcx>, - v: &'tcx ty::VariantDef<'tcx>, + def: ty::AdtDef<'tcx>, + v: ty::VariantDef<'tcx>, name: FieldName) { let field = match name { NamedField(f_name) => { @@ -703,10 +703,10 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } let struct_desc = match def.adt_kind() { - ty::ADTKind::Struct => + ty::AdtKind::Struct => format!("struct `{}`", self.tcx.item_path_str(def.did)), // struct variant fields have inherited visibility - ty::ADTKind::Enum => return + ty::AdtKind::Enum => return }; let msg = match name { NamedField(name) => format!("field `{}` of {} is private", diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index deef88fede7d1..707d4c4a84485 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -742,7 +742,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { ex: &ast::Expr, path: &ast::Path, fields: &Vec, - variant: &ty::VariantDef, + variant: ty::VariantDef, base: &Option>) { if generated_code(path.span) { return diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 78c224131f19c..5bbd8ce154904 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -613,7 +613,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_field_ref_data(&self, field_ref: &ast::Field, - variant: &ty::VariantDef, + variant: ty::VariantDef, parent: NodeId) -> VariableRefData { let f = variant.field_named(field_ref.ident.node.name); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index ec6823e762255..326d1e2361e6d 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -527,7 +527,7 @@ impl<'tcx> Case<'tcx> { } fn get_cases<'tcx>(tcx: &ty::ctxt<'tcx>, - adt: &ty::ADTDef<'tcx>, + adt: ty::AdtDef<'tcx>, substs: &subst::Substs<'tcx>) -> Vec> { adt.variants.iter().map(|vi| { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index a0dd489cd8a9b..5f73fc52446d1 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -386,7 +386,7 @@ 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::VariantDef<'tcx>, + variant: ty::VariantDef<'tcx>, substs: &Substs<'tcx>, f: &mut F) -> Block<'blk, 'tcx> where diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 7bc6f4c8fe96c..f57612789b53f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -1242,7 +1242,7 @@ pub fn langcall(bcx: Block, /// Return the VariantDef corresponding to an inlined variant node pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, inlined_vid: ast::NodeId) - -> &'tcx ty::VariantDef<'tcx> + -> ty::VariantDef<'tcx> { let ctor_ty = ccx.tcx().node_id_to_type(inlined_vid); diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 3ca639cc36702..0be155b772738 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1094,7 +1094,7 @@ impl<'tcx> MemberDescriptionFactory<'tcx> { // Creates MemberDescriptions for the fields of a struct struct StructMemberDescriptionFactory<'tcx> { - variant: &'tcx ty::VariantDef<'tcx>, + variant: ty::VariantDef<'tcx>, substs: &'tcx subst::Substs<'tcx>, is_simd: bool, span: Span, @@ -1489,7 +1489,7 @@ enum EnumDiscriminantInfo { fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, enum_type: Ty<'tcx>, struct_def: &adt::Struct<'tcx>, - variant: &ty::VariantDef<'tcx>, + variant: ty::VariantDef<'tcx>, discriminant_info: EnumDiscriminantInfo, containing_scope: DIScope, span: Span) diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 242ba6f207c56..c2d1d19935a03 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -291,7 +291,7 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>, /// Returns the normalized type of a struct field pub fn field_ty<'tcx>(tcx: &ty::ctxt<'tcx>, param_substs: &Substs<'tcx>, - f: &ty::FieldDef<'tcx>) + f: ty::FieldDef<'tcx>) -> Ty<'tcx> { normalize_associated_type(tcx, &f.ty(tcx, param_substs)) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index bc583a67d933e..883e3659720a6 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -717,7 +717,7 @@ 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], - variant: &ty::VariantDef<'tcx>, + variant: ty::VariantDef<'tcx>, substs: &Substs<'tcx>, etc: bool) { let tcx = pcx.fcx.ccx.tcx; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4ae65a15c26b2..39e67beab583d 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -289,10 +289,10 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> TypeContext::ADT { def_id, variant, field, field_index } => { let adt = tcx.lookup_adt_def(def_id); let variant_name = match adt.adt_kind() { - ty::ADTKind::Enum => format!("enum {} variant {}", + ty::AdtKind::Enum => format!("enum {} variant {}", tcx.item_path_str(def_id), variant), - ty::ADTKind::Struct => format!("struct {}", + ty::AdtKind::Struct => format!("struct {}", tcx.item_path_str(def_id)) }; let field_name = if field == special_idents::unnamed_field.name { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ac3733db9c2e4..6221134afd38a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1677,7 +1677,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(arielb1): use this instead of field.ty everywhere pub fn field_ty(&self, span: Span, - field: &ty::FieldDef<'tcx>, + field: ty::FieldDef<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { @@ -2913,7 +2913,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>(variant: &ty::VariantDef<'tcx>, + fn suggest_field_names<'tcx>(variant: ty::VariantDef<'tcx>, field: &ast::SpannedIdent, tcx: &ty::ctxt<'tcx>, skip : Vec) { @@ -3011,7 +3011,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fn report_unknown_field<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>, - variant: &ty::VariantDef<'tcx>, + variant: ty::VariantDef<'tcx>, field: &ast::Field, skip_fields: &[ast::Field]) { fcx.type_error_message( @@ -3095,7 +3095,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fn check_struct_constructor<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, id: ast::NodeId, span: codemap::Span, - struct_def: &'tcx ty::ADTDef<'tcx>, + struct_def: ty::AdtDef<'tcx>, fields: &'tcx [ast::Field], base_expr: Option<&'tcx ast::Expr>) { let tcx = fcx.ccx.tcx; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4f8aeceb558df..dabc09db68d8e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -620,7 +620,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_generics: &ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, v: &ast::StructField, - ty_f: &'tcx ty::FieldDef_<'tcx, 'tcx>) + ty_f: ty::FieldDefMaster<'tcx>) { let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &*v.node.ty); ty_f.fulfill_ty(tt); @@ -748,7 +748,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); convert_enum_variant_types(ccx, - tcx.lookup_adt_def(local_def(it.id)), + tcx.lookup_adt_def_master(local_def(it.id)), scheme, predicates, &enum_definition.variants); @@ -996,7 +996,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); - let variant = tcx.lookup_adt_def(local_def(it.id)).struct_variant(); + let variant = tcx.lookup_adt_def_master(local_def(it.id)).struct_variant(); for (f, ty_f) in struct_def.fields.iter().zip(variant.fields.iter()) { convert_field(ccx, &scheme.generics, &predicates, f, ty_f) @@ -1023,7 +1023,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, ctor_id: ast::NodeId, - variant: &'tcx ty::VariantDef<'tcx>, + variant: ty::VariantDef<'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>) { let ctor_ty = match variant.kind() { @@ -1049,7 +1049,7 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, } fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - def: &'tcx ty::ADTDef_<'tcx, 'tcx>, + def: ty::AdtDefMaster<'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>, variants: &[P]) { @@ -1090,7 +1090,7 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, did: ast::DefId, name: ast::Name, disr_val: ty::Disr, - def: &ast::StructDef) -> ty::VariantDef_<'tcx, 'tcx> { + def: &ast::StructDef) -> ty::VariantDefData<'tcx, 'tcx> { let mut seen_fields: FnvHashMap = FnvHashMap(); let fields = def.fields.iter().map(|f| { let fid = local_def(f.node.id); @@ -1106,14 +1106,14 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, seen_fields.insert(ident.name, f.span); } - ty::FieldDef_::new(fid, ident.name, vis) + ty::FieldDefData::new(fid, ident.name, vis) }, ast::UnnamedField(vis) => { - ty::FieldDef_::new(fid, special_idents::unnamed_field.name, vis) + ty::FieldDefData::new(fid, special_idents::unnamed_field.name, vis) } } }).collect(); - ty::VariantDef_ { + ty::VariantDefData { did: did, name: name, disr_val: disr_val, @@ -1124,13 +1124,13 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>, it: &ast::Item, def: &ast::StructDef) - -> &'tcx ty::ADTDef_<'tcx, 'tcx> + -> ty::AdtDefMaster<'tcx> { let did = local_def(it.id); tcx.intern_adt_def( did, - ty::ADTKind::Struct, + ty::AdtKind::Struct, vec![convert_struct_variant(tcx, did, it.ident.name, 0, def)] ) } @@ -1138,7 +1138,7 @@ fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>, fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, it: &ast::Item, def: &ast::EnumDef) - -> &'tcx ty::ADTDef_<'tcx, 'tcx> + -> ty::AdtDefMaster<'tcx> { fn evaluate_disr_expr<'tcx>(tcx: &ty::ctxt<'tcx>, repr_ty: Ty<'tcx>, @@ -1202,18 +1202,18 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, fn convert_enum_variant<'tcx>(tcx: &ty::ctxt<'tcx>, v: &ast::Variant, disr: ty::Disr) - -> ty::VariantDef_<'tcx, 'tcx> + -> ty::VariantDefData<'tcx, 'tcx> { let did = local_def(v.node.id); let name = v.node.name.name; match v.node.kind { ast::TupleVariantKind(ref va) => { - ty::VariantDef_ { + ty::VariantDefData { did: did, name: name, disr_val: disr, fields: va.iter().map(|&ast::VariantArg { id, .. }| { - ty::FieldDef_::new( + ty::FieldDefData::new( local_def(id), special_idents::unnamed_field.name, ast::Visibility::Public @@ -1240,7 +1240,7 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, prev_disr = Some(disr); v }).collect(); - tcx.intern_adt_def(local_def(it.id), ty::ADTKind::Enum, variants) + tcx.intern_adt_def(local_def(it.id), ty::AdtKind::Enum, variants) } /// Ensures that the super-predicates of the trait with def-id diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f4a21ee4f4e05..e9f9b8fb629cb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1730,7 +1730,7 @@ impl Clean for ast::StructField { } } -impl<'tcx> Clean for ty::FieldDef<'tcx> { +impl<'tcx> Clean for ty::FieldDefData<'tcx, 'static> { fn clean(&self, cx: &DocContext) -> Item { use syntax::parse::token::special_idents::unnamed_field; use rustc::metadata::csearch; @@ -1856,7 +1856,7 @@ impl Clean for doctree::Variant { } } -impl<'tcx> Clean for ty::VariantDef<'tcx> { +impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { fn clean(&self, cx: &DocContext) -> Item { // use syntax::parse::token::special_idents::unnamed_field; let kind = match self.kind() {