From 5f3c1412ad8224e0fea0bc2b4f67894619045c54 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 2 Aug 2015 22:52:50 +0300 Subject: [PATCH] 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 9c2cdba0ae4..baa9750d311 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -692,64 +692,6 @@ trait Super { 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 @@ fn foo<'a>(arg: &Box) { ... } 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 bbd452b35ac..8233b6b2b2b 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 5cef50be770..2c835b35cc2 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 7899f928e9d..bd8a666ffec 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -100,51 +100,32 @@ fn lookup_and_handle_method(&mut self, id: ast::NodeId) { } 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 8f63aca0dd6..8e827257f7e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -694,40 +694,36 @@ fn walk_struct_expr(&mut self, // 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 @@ fn walk_pat(&mut self, 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 ee7079bb47d..3ab0d4c04d7 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1216,7 +1216,7 @@ fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F) 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 1261f10aaff..16f744b6887 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 fee1c83ba2c..0c9cf1a68b7 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1721,21 +1721,10 @@ fn builtin_bound(&mut self, 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 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { 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 @@ fn confirm_builtin_unsize_candidate(&mut self, // 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 0354918acf8..d41ca44ceea 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -93,8 +93,6 @@ 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 @@ pub fn can_type_implement_copy(&self, self_type: Ty<'tcx>, span: Span) 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 @@ pub fn is_nil(&self) -> bool { } } - 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 @@ pub fn sequence_element_type(&self, cx: &ctxt<'tcx>) -> Ty<'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 @@ pub fn ty_to_def_id(&self) -> Option { _ => 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 @@ fn tc_ty<'tcx>(cx: &ctxt<'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 @@ fn tc_ty<'tcx>(cx: &ctxt<'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 @@ fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<&'tcx ADTDef<'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 @@ fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<&'tcx ADTDef<'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 @@ fn are_inner_types_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span, 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 @@ pub fn is_machine(&self) -> bool { } } - // 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 @@ pub fn positional_element_ty(&self, 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 @@ pub fn named_element_ty(&self, 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 @@ pub fn try_add_builtin_trait(&self, } } - 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 @@ pub fn with_path(&self, id: ast::DefId, f: F) -> T where } } - 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 @@ pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) (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 @@ pub fn lookup_repr_hints(&self, did: DefId) -> Rc> { }) } - // 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 @@ pub fn struct_lockstep_tails(&self, 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 b398b6817f7..e30b85919e2 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 3ed359cbc3d..695cfd43e14 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -45,7 +45,6 @@ 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 @@ fn check_type_for_ffi(&self, // 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 @@ fn check_type_for_ffi(&self, 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 @@ fn check_type_for_ffi(&self, 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 @@ fn check_type_for_ffi(&self, } // 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 b59cc652481..38eabd2e8c3 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -34,7 +34,6 @@ 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 @@ fn ensure_public(&self, span: Span, to_check: ast::DefId, // 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 @@ fn visit_expr(&mut self, expr: &ast::Expr) { 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 @@ fn visit_expr(&mut self, expr: &ast::Expr) { 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 @@ fn visit_pat(&mut self, pattern: &ast::Pat) { 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 @@ struct type?!"), 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 7500a959931..deef88fede7 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -742,6 +742,7 @@ fn process_struct_lit(&mut self, ex: &ast::Expr, path: &ast::Path, fields: &Vec, + variant: &ty::VariantDef, base: &Option>) { if generated_code(path.span) { return @@ -756,7 +757,6 @@ fn process_struct_lit(&mut self, 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 @@ fn process_struct_lit(&mut self, } 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 @@ fn process_pat(&mut self, p:&ast::Pat) { 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 @@ fn visit_expr(&mut self, ex: &ast::Expr) { 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 @@ fn visit_expr(&mut self, ex: &ast::Expr) { 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 dbab7f4a0a9..78c224131f1 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -448,22 +448,14 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { 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 @@ fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool { 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 79fe9b90e7d..bd7c67fa8bb 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 62286b7995a..9fb808a7d2d 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 @@ fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option { } 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 25e139474bd..d119e0006c6 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -55,8 +55,8 @@ 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 @@ fn iter_variant<'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 @@ fn iter_variant<'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 @@ fn iter_variant<'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 @@ fn iter_variant<'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 @@ fn iter_variant<'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 @@ fn iter_variant<'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 a60217be409..d0d5b46ab28 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -182,10 +182,8 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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 cfb87700842..15c81b114d3 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -49,6 +49,7 @@ 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 71ba4d73dac..7a9ddf5a99c 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 e7499ad9301..98188a40e10 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -44,7 +44,7 @@ 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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, '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 36eff731995..baf14df5b80 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -68,7 +68,6 @@ 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 float_cast(bcx: Block, } } - 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 d07776c3d91..30cf6f519fb 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 75c80690f2a..01bfc51a5c0 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 31e4b9c48e2..242ba6f207c 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -29,7 +29,6 @@ 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 b0b1acb445c..bc583a67d93 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 5d93e2ae5d3..b6ba62e4f09 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 @@ fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { 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 7cb2198c68d..57f2f063c71 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 970589fb9c5..15cc5ee6eb8 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 2f63d7abe4a..ac3733db9c2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1674,34 +1674,19 @@ pub fn add_obligations_for_parameters(&self, } } - // 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_field<'a,'tcx>(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_field<'a,'tcx>(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_field<'a,'tcx>(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_tup_field<'a,'tcx>(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_tup_field<'a,'tcx>(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_tup_field<'a,'tcx>(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_struct_or_variant_fields<'a, 'tcx>(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_struct_constructor<'a,'tcx>(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_struct_enum_variant<'a,'tcx>(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 @@ fn do_check<'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 @@ fn do_check<'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 cd4063ac454..7ab8d327a80 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -483,10 +483,9 @@ fn check_implementations_of_coerce_unsized(&self) { } 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 c9f6ccb8cb2..ddc900b1d25 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1174,33 +1174,50 @@ fn evaluate_disr_expr<'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_variant<'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 07c1b5e3d20..4660adaffae 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -883,6 +883,64 @@ struct Foo { x: Option> } ``` "##, +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 @@ struct Foo<'a, T: 'a> { 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 3721f9a0b10..69e2141b17b 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -602,7 +602,7 @@ fn visit_item(&mut self, item: &ast::Item) { 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 @@ fn visit_item(&mut self, item: &ast::Item) { // // 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 582927782a4..7fd1555d066 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 ac872791219..f4a21ee4f4e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1730,29 +1730,27 @@ fn clean(&self, cx: &DocContext) -> Item { } } -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 @@ fn clean(&self, cx: &DocContext) -> Item { } } -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 @@ fn clean(&self, cx: &DocContext) -> Item { // 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 @@ fn clean(&self, cx: &DocContext) -> Item { }; 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), } } } -- GitLab