From d3c94b25cbf71505b6389151901a948f23bda683 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 01:31:25 +0300 Subject: [PATCH 01/11] Don't generate Def::Err if it's not stored in def_map immediately --- src/librustc_resolve/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a7fb039c295f8..576f96f12dfea 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2309,7 +2309,7 @@ impl<'a> Resolver<'a> { ); err_path_resolution() } - Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => { + Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => { // These entities are explicitly allowed // to be shadowed by fresh bindings. self.fresh_binding(ident, pat.id, outer_pat_id, @@ -2331,7 +2331,7 @@ impl<'a> Resolver<'a> { PatKind::TupleStruct(ref path, _, _) => { self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| { match def { - Def::Struct(..) | Def::Variant(..) | Def::Err => true, + Def::Struct(..) | Def::Variant(..) => true, _ => false, } }, "variant or struct"); @@ -2341,7 +2341,7 @@ impl<'a> Resolver<'a> { self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| { match def { Def::Struct(..) | Def::Variant(..) | - Def::Const(..) | Def::AssociatedConst(..) | Def::Err => true, + Def::Const(..) | Def::AssociatedConst(..) => true, _ => false, } }, "variant, struct or constant"); @@ -2351,7 +2351,7 @@ impl<'a> Resolver<'a> { self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| { match def { Def::Struct(..) | Def::Variant(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) | Def::Err => true, + Def::TyAlias(..) | Def::AssociatedTy(..) => true, _ => false, } }, "variant, struct or type alias"); @@ -2482,7 +2482,7 @@ impl<'a> Resolver<'a> { record_used: bool) -> Option { if identifier.name == keywords::Invalid.name() { - return Some(LocalDef::from_def(Def::Err)); + return None; } self.resolve_ident_in_lexical_scope(identifier, namespace, record_used) From ba419a78f3b2addd44339611cda2ddd8835af4e6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 02/11] Cleanup of some pattern related code --- src/librustc/middle/expr_use_visitor.rs | 138 ++++++---------------- src/librustc/middle/mem_categorization.rs | 124 +++++++------------ src/librustc_const_eval/check_match.rs | 20 +--- src/librustc_mir/hair/cx/pattern.rs | 24 +--- src/librustc_privacy/lib.rs | 1 - 5 files changed, 94 insertions(+), 213 deletions(-) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index c8b8c5dbdbbcb..6551e0129f884 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -945,52 +945,41 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { /// The core driver for walking a pattern; `match_mode` must be /// established up front, e.g. via `determine_pat_move_mode` (see /// also `walk_irrefutable_pat` for patterns that stand alone). - fn walk_pat(&mut self, - cmt_discr: mc::cmt<'tcx>, - pat: &hir::Pat, - match_mode: MatchMode) { - debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, - pat); + fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { + debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat); let tcx = &self.tcx(); let mc = &self.mc; let infcx = self.mc.infcx; let delegate = &mut self.delegate; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| { - match pat.node { - PatKind::Binding(bmode, _, _) => { - debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", - cmt_pat, - pat, - match_mode); - - // pat_ty: the type of the binding being produced. - let pat_ty = return_if_err!(infcx.node_ty(pat.id)); - - // Each match binding is effectively an assignment to the - // binding being produced. - if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, - tcx.expect_def(pat.id)) { - delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); - } + if let PatKind::Binding(bmode, _, _) = pat.node { + debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); - // It is also a borrow or copy/move of the value being matched. - match bmode { - hir::BindByRef(m) => { - if let ty::TyRef(&r, _) = pat_ty.sty { - let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(pat.id, pat.span, cmt_pat, - r, bk, RefBinding); - } - } - hir::BindByValue(..) => { - let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove); - debug!("walk_pat binding consuming pat"); - delegate.consume_pat(pat, cmt_pat, mode); + // pat_ty: the type of the binding being produced. + let pat_ty = return_if_err!(infcx.node_ty(pat.id)); + + // Each match binding is effectively an assignment to the + // binding being produced. + if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, + tcx.expect_def(pat.id)) { + delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); + } + + // It is also a borrow or copy/move of the value being matched. + match bmode { + hir::BindByRef(m) => { + if let ty::TyRef(&r, _) = pat_ty.sty { + let bk = ty::BorrowKind::from_mutbl(m); + delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding); } } + hir::BindByValue(..) => { + let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove); + debug!("walk_pat binding consuming pat"); + delegate.consume_pat(pat, cmt_pat, mode); + } } - _ => {} } })); @@ -999,72 +988,23 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // to the above loop's visit of than the bindings that form // the leaves of the pattern tree structure. return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { - match pat.node { - PatKind::Struct(..) | PatKind::TupleStruct(..) | - PatKind::Path(..) | PatKind::QPath(..) => { - match tcx.expect_def(pat.id) { - Def::Variant(enum_did, variant_did) => { - let downcast_cmt = - if tcx.lookup_adt_def(enum_did).is_univariant() { - cmt_pat - } else { - let cmt_pat_ty = cmt_pat.ty; - mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did) - }; - - debug!("variant downcast_cmt={:?} pat={:?}", - downcast_cmt, - pat); - - delegate.matched_pat(pat, downcast_cmt, match_mode); - } - - Def::Struct(..) | Def::TyAlias(..) => { - // A struct (in either the value or type - // namespace; we encounter the former on - // e.g. patterns for unit structs). - - debug!("struct cmt_pat={:?} pat={:?}", - cmt_pat, - pat); - - delegate.matched_pat(pat, cmt_pat, match_mode); - } - - Def::Const(..) | Def::AssociatedConst(..) => { - // This is a leaf (i.e. identifier binding - // or constant value to match); thus no - // `matched_pat` call. - } + match tcx.expect_def_or_none(pat.id) { + Some(Def::Variant(enum_did, variant_did)) => { + let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() { + cmt_pat + } else { + let cmt_pat_ty = cmt_pat.ty; + mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did) + }; - def => { - // An enum type should never be in a pattern. - // Remaining cases are e.g. Def::Fn, to - // which identifiers within patterns - // should not resolve. However, we do - // encouter this when using the - // expr-use-visitor during typeck. So just - // ignore it, an error should have been - // reported. - - if !tcx.sess.has_errors() { - span_bug!(pat.span, - "Pattern has unexpected def: {:?} and type {:?}", - def, - cmt_pat.ty); - } - } - } + debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); + delegate.matched_pat(pat, downcast_cmt, match_mode); } - - PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) | - PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) | - PatKind::Vec(..) | PatKind::Binding(..) => { - // Each of these cases does not - // correspond to an enum variant or struct, so we - // do not do any `matched_pat` calls for these - // cases either. + Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => { + debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); + delegate.matched_pat(pat, cmt_pat, match_mode); } + _ => {} } })); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a70829347f1c1..3776a904923c9 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1050,9 +1050,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } // FIXME(#19596) This is a workaround, but there should be a better way to do this - fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) - -> McResult<()> - where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat), + fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()> + where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat) { // Here, `cmt` is the categorization for the value being // matched and pat is the pattern it is being matched against. @@ -1099,21 +1098,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // step out of sync again. So you'll see below that we always // get the type of the *subpattern* and use that. - debug!("cat_pattern: {:?} cmt={:?}", - pat, - cmt); - - (*op)(self, cmt.clone(), pat); + debug!("cat_pattern: {:?} cmt={:?}", pat, cmt); - let opt_def = self.tcx().expect_def_or_none(pat.id); - if opt_def == Some(Def::Err) { - return Err(()); - } + op(self, cmt.clone(), pat); // Note: This goes up here (rather than within the PatKind::TupleStruct arm - // alone) because struct patterns can refer to struct types or - // to struct variants within enums. - let cmt = match opt_def { + // alone) because PatKind::Struct can also refer to variants. + let cmt = match self.tcx().expect_def_or_none(pat.id) { + Some(Def::Err) => return Err(()), Some(Def::Variant(enum_did, variant_did)) // univariant enums do not need downcasts if !self.tcx().lookup_adt_def(enum_did).is_univariant() => { @@ -1123,66 +1115,33 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; match pat.node { - PatKind::Wild => { - // _ - } - PatKind::TupleStruct(_, ref subpats, ddpos) => { - match opt_def { - Some(Def::Variant(enum_def, def_id)) => { - // variant(x, y, z) - let expected_len = self.tcx().lookup_adt_def(enum_def) - .variant_with_id(def_id).fields.len(); - for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { - let subpat_ty = self.pat_ty(&subpat)?; // see (*2) - - let subcmt = - self.cat_imm_interior( - pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); - - self.cat_pattern_(subcmt, &subpat, op)?; - } + let expected_len = match self.tcx().expect_def(pat.id) { + Def::Variant(enum_def, def_id) => { + self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len() } - Some(Def::Struct(..)) => { - let expected_len = match self.pat_ty(&pat)?.sty { + Def::Struct(..) => { + match self.pat_ty(&pat)?.sty { ty::TyStruct(adt_def, _) => { adt_def.struct_variant().fields.len() } ref ty => { span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty); } - }; - - for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { - let subpat_ty = self.pat_ty(&subpat)?; // see (*2) - let cmt_field = - self.cat_imm_interior( - pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); - self.cat_pattern_(cmt_field, &subpat, op)?; } } - Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => { - for subpat in subpats { - self.cat_pattern_(cmt.clone(), &subpat, op)?; - } - } - _ => { - span_bug!( - pat.span, - "enum pattern didn't resolve to enum or struct {:?}", - opt_def); + def => { + span_bug!(pat.span, "tuple struct pattern didn't resolve \ + to variant or struct {:?}", def); } - } - } - - PatKind::Path(..) | PatKind::QPath(..) | PatKind::Binding(_, _, None) => { - // Lone constant, or unit variant or identifier: ignore - } + }; - PatKind::Binding(_, _, Some(ref subpat)) => { - self.cat_pattern_(cmt, &subpat, op)?; + for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { + let subpat_ty = self.pat_ty(&subpat)?; // see (*2) + let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, + InteriorField(PositionalField(i))); + self.cat_pattern_(subcmt, &subpat, op)?; + } } PatKind::Struct(_, ref field_pats, _) => { @@ -1194,6 +1153,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } + PatKind::Binding(_, _, Some(ref subpat)) => { + self.cat_pattern_(cmt, &subpat, op)?; + } + PatKind::Tuple(ref subpats, ddpos) => { // (p1, ..., pN) let expected_len = match self.pat_ty(&pat)?.sty { @@ -1202,10 +1165,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) - let subcmt = - self.cat_imm_interior( - pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, + InteriorField(PositionalField(i))); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1215,25 +1176,26 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // PatKind::Ref since that information is already contained // in the type. let subcmt = self.cat_deref(pat, cmt, 0, None)?; - self.cat_pattern_(subcmt, &subpat, op)?; + self.cat_pattern_(subcmt, &subpat, op)?; } PatKind::Vec(ref before, ref slice, ref after) => { - let context = InteriorOffsetKind::Pattern; - let elt_cmt = self.cat_index(pat, cmt, context)?; - for before_pat in before { - self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?; - } - if let Some(ref slice_pat) = *slice { - self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?; - } - for after_pat in after { - self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?; - } + let context = InteriorOffsetKind::Pattern; + let elt_cmt = self.cat_index(pat, cmt, context)?; + for before_pat in before { + self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?; + } + if let Some(ref slice_pat) = *slice { + self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?; + } + for after_pat in after { + self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?; + } } - PatKind::Lit(_) | PatKind::Range(_, _) => { - /*always ok*/ + PatKind::Path(..) | PatKind::QPath(..) | PatKind::Binding(_, _, None) | + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => { + // always ok } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index a5a9dea61ad7c..33c778f8725d7 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -784,18 +784,14 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, left_ty: Ty, max_slice_length: usize) -> Vec { let pat = raw_pat(p); match pat.node { - PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => + PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(..) => match cx.tcx.expect_def(pat.id) { - Def::Const(..) | Def::AssociatedConst(..) => - span_bug!(pat.span, "const pattern should've \ - been rewritten"), - Def::Struct(..) | Def::TyAlias(..) => vec![Single], Def::Variant(_, id) => vec![Variant(id)], - def => span_bug!(pat.span, "pat_constructors: unexpected \ - definition {:?}", def), + Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], + Def::Const(..) | Def::AssociatedConst(..) => + span_bug!(pat.span, "const pattern should've been rewritten"), + def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def), }, - PatKind::QPath(..) => - span_bug!(pat.span, "const pattern should've been rewritten"), PatKind::Lit(ref expr) => vec![ConstantValue(eval_const_expr(cx.tcx, &expr))], PatKind::Range(ref lo, ref hi) => @@ -899,7 +895,7 @@ pub fn specialize<'a, 'b, 'tcx>( PatKind::Binding(..) | PatKind::Wild => Some(vec![dummy_pat; arity]), - PatKind::Path(..) => { + PatKind::Path(..) | PatKind::QPath(..) => { match cx.tcx.expect_def(pat_id) { Def::Const(..) | Def::AssociatedConst(..) => span_bug!(pat_span, "const pattern should've \ @@ -934,10 +930,6 @@ pub fn specialize<'a, 'b, 'tcx>( } } - PatKind::QPath(_, _) => { - span_bug!(pat_span, "const pattern should've been rewritten") - } - PatKind::Struct(_, ref pattern_fields, _) => { let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap(); let variant = constructor.variant_for_adt(adt); diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index b5da50792762f..654108c14df87 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -13,7 +13,7 @@ use hair::cx::Cx; use rustc_data_structures::indexed_vec::Idx; use rustc_const_eval as const_eval; use rustc::hir::def::Def; -use rustc::hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const}; +use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc::hir::{self, PatKind}; @@ -76,9 +76,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatternKind::Range { lo: lo, hi: hi } }, - PatKind::Path(..) | PatKind::QPath(..) - if pat_is_resolved_const(&self.cx.tcx.def_map.borrow(), pat) => - { + PatKind::Path(..) | PatKind::QPath(..) => { match self.cx.tcx.expect_def(pat.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let tcx = self.cx.tcx.global_tcx(); @@ -104,11 +102,9 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } } } - def => - span_bug!( - pat.span, - "def not a constant: {:?}", - def), + _ => { + self.variant_or_leaf(pat, vec![]) + } } } @@ -199,10 +195,6 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } } - PatKind::Path(..) => { - self.variant_or_leaf(pat, vec![]) - } - PatKind::TupleStruct(_, ref subpatterns, ddpos) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { @@ -253,10 +245,6 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { self.variant_or_leaf(pat, subpatterns) } - - PatKind::QPath(..) => { - span_bug!(pat.span, "unexpanded macro or bad constant etc"); - } }; Pattern { @@ -325,7 +313,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } } - Def::Struct(..) | Def::TyAlias(..) => { + Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => { PatternKind::Leaf { subpatterns: subpatterns } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 85a6f732dd52e..acaf9b9b2faee 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -436,7 +436,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } } hir::ExprPath(..) => { - if let Def::Struct(..) = self.tcx.expect_def(expr.id) { let expr_ty = self.tcx.expr_ty(expr); let def = match expr_ty.sty { From 4d4c7be19ec9b685aa91824051146115e5a30a5f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 03/11] Better support for associated types in struct patterns --- src/librustc/hir/pat_util.rs | 3 ++- src/librustc/ty/mod.rs | 2 +- src/librustc_trans/_match.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 3bb9b6d260255..8282cd6bfcbe3 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -76,7 +76,8 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool { PatKind::Path(..) | PatKind::Struct(..) => { match dm.get(&pat.id).map(|d| d.full_def()) { - Some(Def::Variant(..)) | Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => true, + Some(Def::Variant(..)) | Some(Def::Struct(..)) | + Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => true, _ => false } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 14db922d29810..4dc7ac4138bbc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1715,7 +1715,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> { match def { Def::Variant(_, vid) => self.variant_with_id(vid), - Def::Struct(..) | Def::TyAlias(..) => self.struct_variant(), + Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(), _ => bug!("unexpected def {:?} in variant_of_def", def) } } diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 10af326be26a3..d79278e99cb2e 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -796,7 +796,7 @@ fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool { PatKind::Tuple(..) => true, PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => { match tcx.expect_def(pat.id) { - Def::Struct(..) | Def::TyAlias(..) => true, + Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => true, _ => false, } } From eb32440d4566346294cf2f10592d9657918245d1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 04/11] Do not generate Def::Err in bindings Instead of Def::Err erroneous bindings can get usual definitions that doesn't require special cases later on and have less chances to generate ICE. --- src/librustc_resolve/lib.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 576f96f12dfea..bcfd87872628e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2180,7 +2180,8 @@ impl<'a> Resolver<'a> { // because that breaks the assumptions later // passes make about or-patterns.) let renamed = mtwt::resolve(ident.node); - let def = match bindings.get(&renamed).cloned() { + let mut def = Def::Local(self.definitions.local_def_id(pat_id), pat_id); + match bindings.get(&renamed).cloned() { Some(id) if id == outer_pat_id => { // `Variant(a, a)`, error resolve_error( @@ -2189,7 +2190,6 @@ impl<'a> Resolver<'a> { ResolutionError::IdentifierBoundMoreThanOnceInSamePattern( &ident.node.name.as_str()) ); - Def::Err } Some(..) if pat_src == PatternSource::FnParam => { // `fn f(a: u8, a: u8)`, error @@ -2199,29 +2199,24 @@ impl<'a> Resolver<'a> { ResolutionError::IdentifierBoundMoreThanOnceInParameterList( &ident.node.name.as_str()) ); - Def::Err } Some(..) if pat_src == PatternSource::Match => { // `Variant1(a) | Variant2(a)`, ok // Reuse definition from the first `a`. - self.value_ribs.last_mut().unwrap().bindings[&renamed] + def = self.value_ribs.last_mut().unwrap().bindings[&renamed]; } Some(..) => { span_bug!(ident.span, "two bindings with the same name from \ unexpected pattern source {:?}", pat_src); } None => { - // A completely fresh binding, add to the lists. - // FIXME: Later stages are not ready to deal with `Def::Err` here yet, so - // define `Invalid` bindings as `Def::Local`, just don't add them to the lists. - let def = Def::Local(self.definitions.local_def_id(pat_id), pat_id); + // A completely fresh binding, add to the lists if it's valid. if ident.node.name != keywords::Invalid.name() { bindings.insert(renamed, outer_pat_id); self.value_ribs.last_mut().unwrap().bindings.insert(renamed, def); } - def } - }; + } PathResolution::new(def) } @@ -2287,15 +2282,16 @@ impl<'a> Resolver<'a> { PatKind::Ident(bmode, ref ident, ref opt_pat) => { // First try to resolve the identifier as some existing // entity, then fall back to a fresh binding. - let local_def = self.resolve_identifier(ident.node, ValueNS, true); - let resolution = if let Some(LocalDef { def, .. }) = local_def { + let resolution = self.resolve_identifier(ident.node, ValueNS, true) + .map(|local_def| PathResolution::new(local_def.def)) + .and_then(|resolution| { let always_binding = !pat_src.is_refutable() || opt_pat.is_some() || bmode != BindingMode::ByValue(Mutability::Immutable); match def { Def::Struct(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) if !always_binding => { // A constant, unit variant, etc pattern. - PathResolution::new(def) + Some(resolution) } Def::Struct(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => { @@ -2307,23 +2303,21 @@ impl<'a> Resolver<'a> { ResolutionError::BindingShadowsSomethingUnacceptable( pat_src.descr(), kind_name, ident.node.name) ); - err_path_resolution() + None } Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => { // These entities are explicitly allowed // to be shadowed by fresh bindings. - self.fresh_binding(ident, pat.id, outer_pat_id, - pat_src, bindings) + None } def => { span_bug!(ident.span, "unexpected definition for an \ identifier in pattern {:?}", def); } } - } else { - // Fall back to a fresh binding. + }).unwrap_or_else(|| { self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings) - }; + }); self.record_def(pat.id, resolution); } From 2cdd9f1c97652ee799f6bb0af7c063115ff368ea Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 05/11] Rewrite check_pat_enum, split it into check_pat_tuple_struct and check_pat_path Update definitions in def_map for associated types written in unqualified form (like `Self::Output`) Cleanup finish_resolving_def_to_ty/resolve_ty_and_def_ufcs Make VariantDef's available through constructor IDs --- src/librustc/hir/def.rs | 9 - src/librustc/hir/pat_util.rs | 19 -- src/librustc/ty/context.rs | 12 +- src/librustc/ty/mod.rs | 14 + src/librustc_metadata/decoder.rs | 14 +- src/librustc_typeck/astconv.rs | 80 +++--- src/librustc_typeck/check/_match.rs | 270 +++++++----------- src/librustc_typeck/check/mod.rs | 63 ++-- src/librustc_typeck/collect.rs | 18 +- src/librustc_typeck/diagnostics.rs | 37 +-- .../cache/project-fn-ret-contravariant.rs | 1 + .../cache/project-fn-ret-invariant.rs | 1 + .../compile-fail/empty-struct-braces-pat-1.rs | 6 +- src/test/compile-fail/issue-32004.rs | 2 +- .../compile-fail/method-path-in-pattern.rs | 7 +- .../compile-fail/qualified-path-params.rs | 3 +- src/test/run-pass/issue-28550.rs | 2 + 17 files changed, 230 insertions(+), 328 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 72261c473e5c5..218681efb7dc1 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -137,15 +137,6 @@ impl Def { } } - pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> { - match *self { - Def::Variant(enum_id, var_id) => { - Some((enum_id, var_id)) - } - _ => None - } - } - pub fn kind_name(&self) -> &'static str { match *self { Def::Fn(..) => "function", diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 8282cd6bfcbe3..234edc647f0c8 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -12,15 +12,12 @@ use hir::def::*; use hir::def_id::DefId; use hir::{self, PatKind}; use ty::TyCtxt; -use util::nodemap::FnvHashMap; use syntax::ast; use syntax::codemap::Spanned; use syntax_pos::{Span, DUMMY_SP}; use std::iter::{Enumerate, ExactSizeIterator}; -pub type PatIdMap = FnvHashMap; - pub struct EnumerateAndAdjust { enumerate: Enumerate, gap_pos: usize, @@ -97,22 +94,6 @@ pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool { } } -// Same as above, except that partially-resolved defs cause `false` to be -// returned instead of a panic. -pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool { - match pat.node { - PatKind::Path(..) | PatKind::QPath(..) => { - match dm.get(&pat.id) - .and_then(|d| if d.depth == 0 { Some(d.base_def) } - else { None } ) { - Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true, - _ => false - } - } - _ => false - } -} - /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` pub fn pat_bindings(pat: &hir::Pat, mut f: F) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 219cb5e383a8d..4c8fa80dd0b96 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -591,6 +591,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.global_interners.arenas.trait_defs.alloc(def) } + pub fn insert_adt_def(self, did: DefId, adt_def: ty::AdtDefMaster<'gcx>) { + // this will need a transmute when reverse-variance is removed + if let Some(prev) = self.adt_defs.borrow_mut().insert(did, adt_def) { + bug!("Tried to overwrite interned AdtDef: {:?}", prev) + } + } + pub fn intern_adt_def(self, did: DefId, kind: ty::AdtKind, @@ -598,10 +605,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> ty::AdtDefMaster<'gcx> { let def = ty::AdtDefData::new(self, did, kind, variants); let interned = self.global_interners.arenas.adt_defs.alloc(def); - // this will need a transmute when reverse-variance is removed - if let Some(prev) = self.adt_defs.borrow_mut().insert(did, interned) { - bug!("Tried to overwrite interned AdtDef: {:?}", prev) - } + self.insert_adt_def(did, interned); interned } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4dc7ac4138bbc..93a4b1ac0f403 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2454,6 +2454,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.def_map.borrow().get(&id).map(|resolution| resolution.full_def()) } + // Returns `ty::VariantDef` if `def` refers to a struct, + // or variant or their constructors, panics otherwise. + pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> { + match def { + Def::Variant(enum_did, did) => { + self.lookup_adt_def(enum_did).variant_with_id(did) + } + Def::Struct(did) => { + self.lookup_adt_def(did).struct_variant() + } + _ => bug!("expect_variant_def used with unexpected def {:?}", def) + } + } + pub fn def_key(self, id: DefId) -> ast_map::DefKey { if id.is_local() { self.map.def_key(id) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index eada2a9cd7a63..4ccfcd9e90356 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -471,23 +471,29 @@ pub fn get_adt_def<'a, 'tcx>(intr: &IdentInterner, let doc = cdata.lookup_item(item_id); let did = DefId { krate: cdata.cnum, index: item_id }; + let mut ctor_did = None; let (kind, variants) = match item_family(doc) { Enum => { (ty::AdtKind::Enum, get_enum_variants(intr, cdata, doc)) } Struct(..) => { - let ctor_did = - reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor). - map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc)); + // Use separate constructor id for unit/tuple structs and reuse did for braced structs. + ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| { + translated_def_id(cdata, ctor_doc) + }); (ty::AdtKind::Struct, - vec![get_struct_variant(intr, cdata, doc, ctor_did)]) + vec![get_struct_variant(intr, cdata, doc, ctor_did.unwrap_or(did))]) } _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", item_family(doc), did) }; let adt = tcx.intern_adt_def(did, kind, variants); + if let Some(ctor_did) = ctor_did { + // Make adt definition available through constructor id as well. + tcx.insert_adt_def(ctor_did, adt); + } // this needs to be done *after* the variant is interned, // to support recursive structures diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 088ac1aac1a40..9ff30f9ede262 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,7 +53,7 @@ use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::ErrKind::ErroneousReferencedConstant; use hir::{self, SelfKind}; -use hir::def::{self, Def}; +use hir::def::{Def, PathResolution}; use hir::def_id::DefId; use hir::print as pprust; use middle::resolve_lifetime as rl; @@ -1327,7 +1327,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; if self.ensure_super_predicates(span, trait_did).is_err() { - return (tcx.types.err, ty_path_def); + return (tcx.types.err, Def::Err); } let candidates: Vec = @@ -1341,7 +1341,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { &assoc_name.as_str(), span) { Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), + Err(ErrorReported) => return (tcx.types.err, Def::Err), } } (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => { @@ -1351,7 +1351,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assoc_name, span) { Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), + Err(ErrorReported) => return (tcx.types.err, Def::Err), } } (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => { @@ -1361,7 +1361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { assoc_name, span) { Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), + Err(ErrorReported) => return (tcx.types.err, Def::Err), } } _ => { @@ -1369,7 +1369,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { &ty.to_string(), "Trait", &assoc_name.as_str()); - return (tcx.types.err, ty_path_def); + return (tcx.types.err, Def::Err); } }; @@ -1574,45 +1574,46 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - // Note that both base_segments and assoc_segments may be empty, although not at - // the same time. + // Resolve possibly associated type path into a type and final definition. + // Note that both base_segments and assoc_segments may be empty, although not at same time. pub fn finish_resolving_def_to_ty(&self, rscope: &RegionScope, span: Span, param_mode: PathParamMode, - mut def: Def, + base_def: Def, opt_self_ty: Option>, base_path_ref_id: ast::NodeId, base_segments: &[hir::PathSegment], assoc_segments: &[hir::PathSegment]) -> (Ty<'tcx>, Def) { - debug!("finish_resolving_def_to_ty(def={:?}, \ + // Convert the base type. + debug!("finish_resolving_def_to_ty(base_def={:?}, \ base_segments={:?}, \ assoc_segments={:?})", - def, + base_def, base_segments, assoc_segments); - let mut ty = self.base_def_to_ty(rscope, - span, - param_mode, - def, - opt_self_ty, - base_path_ref_id, - base_segments); - debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty); + let base_ty = self.base_def_to_ty(rscope, + span, + param_mode, + base_def, + opt_self_ty, + base_path_ref_id, + base_segments); + debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty); + // If any associated type segments remain, attempt to resolve them. + let (mut ty, mut def) = (base_ty, base_def); for segment in assoc_segments { debug!("finish_resolving_def_to_ty: segment={:?}", segment); - if ty.sty == ty::TyError { + // This is pretty bad (it will fail except for T::A and Self::A). + let (new_ty, new_def) = self.associated_path_def_to_ty(span, ty, def, segment); + ty = new_ty; + def = new_def; + + if def == Def::Err { break; } - // This is pretty bad (it will fail except for T::A and Self::A). - let (a_ty, a_def) = self.associated_path_def_to_ty(span, - ty, - def, - segment); - ty = a_ty; - def = a_def; } (ty, def) } @@ -1719,23 +1720,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyPath(ref maybe_qself, ref path) => { debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); let path_res = tcx.expect_resolution(ast_ty.id); - let def = path_res.base_def; let base_ty_end = path.segments.len() - path_res.depth; let opt_self_ty = maybe_qself.as_ref().map(|qself| { self.ast_ty_to_ty(rscope, &qself.ty) }); - let (ty, _def) = self.finish_resolving_def_to_ty(rscope, - ast_ty.span, - PathParamMode::Explicit, - def, - opt_self_ty, - ast_ty.id, - &path.segments[..base_ty_end], - &path.segments[base_ty_end..]); - - if path_res.depth != 0 && ty.sty != ty::TyError { - // Write back the new resolution. - tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution::new(def)); + let (ty, def) = self.finish_resolving_def_to_ty(rscope, + ast_ty.span, + PathParamMode::Explicit, + path_res.base_def, + opt_self_ty, + ast_ty.id, + &path.segments[..base_ty_end], + &path.segments[base_ty_end..]); + + // Write back the new resolution. + if path_res.depth != 0 { + tcx.def_map.borrow_mut().insert(ast_ty.id, PathResolution::new(def)); } ty diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 069a09183a738..82c676adc703d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -10,13 +10,12 @@ use hir::def::Def; use rustc::infer::{self, InferOk, TypeOrigin}; -use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const}; +use hir::pat_util::EnumerateAndAdjustIterator; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; +use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind}; use check::{FnCtxt, Expectation}; use lint; use util::nodemap::FnvHashMap; -use session::Session; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; @@ -28,20 +27,6 @@ use syntax_pos::Span; use rustc::hir::{self, PatKind}; use rustc::hir::print as pprust; -// This function exists due to the warning "diagnostic code E0164 already used" -fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) { - let name = pprust::path_to_string(path); - let msg = format!("`{}` does not name a tuple variant or a tuple struct", name); - if lint { - sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, - pat.id, - pat.span, - msg); - } else { - span_err!(sess, pat.span, E0164, "{}", msg); - } -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) { let tcx = self.tcx; @@ -136,22 +121,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping doesn't matter here, as the value is some kind of scalar self.demand_eqtype(pat.span, expected, lhs_ty); } - PatKind::Path(..) if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => { - let const_did = tcx.expect_def(pat.id).def_id(); - let const_scheme = tcx.lookup_item_type(const_did); - assert!(const_scheme.generics.is_empty()); - let const_ty = self.instantiate_type_scheme(pat.span, - &Substs::empty(), - &const_scheme.ty); - self.write_ty(pat.id, const_ty); - - // FIXME(#20489) -- we should limit the types here to scalars or something! - - // As with PatKind::Lit, what we really want here is that there - // exist a LUB, but for the cases that can occur, subtype - // is good enough. - self.demand_suptype(pat.span, expected, const_ty); - } PatKind::Binding(bm, _, ref sub) => { let typ = self.local_ty(pat.span, pat.id); match bm { @@ -197,33 +166,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } PatKind::TupleStruct(ref path, ref subpats, ddpos) => { - self.check_pat_enum(pat, path, &subpats, ddpos, expected, true); + self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); } PatKind::Path(ref path) => { - self.check_pat_enum(pat, path, &[], None, expected, false); + self.check_pat_path(pat, None, path, expected); } PatKind::QPath(ref qself, ref path) => { - let self_ty = self.to_ty(&qself.ty); - let path_res = tcx.expect_resolution(pat.id); - if path_res.base_def == Def::Err { - self.set_tainted_by_errors(); - self.write_error(pat.id); - return; - } - if let Some((opt_ty, segments, def)) = - self.resolve_ty_and_def_ufcs(path_res, Some(self_ty), - path, pat.span, pat.id) { - if self.check_assoc_item_is_const(def, pat.span) { - let scheme = tcx.lookup_item_type(def.def_id()); - let predicates = tcx.lookup_predicates(def.def_id()); - self.instantiate_path(segments, scheme, &predicates, - opt_ty, def, pat.span, pat.id); - let const_ty = self.node_ty(pat.id); - self.demand_suptype(pat.span, expected, const_ty); - } else { - self.write_error(pat.id) - } - } + self.check_pat_path(pat, Some(self.to_ty(&qself.ty)), path, expected); } PatKind::Struct(ref path, ref fields, etc) => { self.check_pat_struct(pat, path, fields, etc, expected); @@ -403,20 +352,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping. } - fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool { - match def { - Def::AssociatedConst(..) => true, - Def::Method(..) => { - span_err!(self.tcx.sess, span, E0327, - "associated items in match patterns must be constants"); - false - } - _ => { - span_bug!(span, "non-associated item in check_assoc_item_is_const"); - } - } - } - pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { if let PatKind::Binding(..) = inner.node { if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) { @@ -589,132 +524,137 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - fn check_pat_enum(&self, + fn check_pat_path(&self, pat: &hir::Pat, + opt_self_ty: Option>, path: &hir::Path, - subpats: &'gcx [P], - ddpos: Option, - expected: Ty<'tcx>, - is_tuple_struct_pat: bool) + expected: Ty<'tcx>) { - // Typecheck the path. let tcx = self.tcx; - - let path_res = tcx.expect_resolution(pat.id); - if path_res.base_def == Def::Err { - self.set_tainted_by_errors(); + let report_unexpected_def = || { + span_err!(tcx.sess, pat.span, E0533, + "`{}` does not name a unit variant, unit struct or a constant", + pprust::path_to_string(path)); self.write_error(pat.id); - - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } - return; - } - - let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res, - None, path, - pat.span, pat.id) { - Some(resolution) => resolution, - // Error handling done inside resolve_ty_and_def_ufcs, so if - // resolution fails just return. - None => {return;} }; - // Items that were partially resolved before should have been resolved to - // associated constants (i.e. not methods). - if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) { - self.write_error(pat.id); - return; + // Resolve the path and check the definition for errors. + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(pat.id), + opt_self_ty, path, pat.span, pat.id); + match def { + Def::Err => { + self.set_tainted_by_errors(); + self.write_error(pat.id); + return; + } + Def::Method(..) => { + report_unexpected_def(); + return; + } + Def::Variant(..) | Def::Struct(..) => { + let variant = tcx.expect_variant_def(def); + if variant.kind != VariantKind::Unit { + report_unexpected_def(); + return; + } + } + Def::Const(..) | Def::AssociatedConst(..) => {} // OK + _ => bug!("unexpected pattern definition {:?}", def) } - let enum_def = def.variant_def_ids() - .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def); + // Type check the path. + let scheme = tcx.lookup_item_type(def.def_id()); + let predicates = tcx.lookup_predicates(def.def_id()); + self.instantiate_path(segments, scheme, &predicates, opt_ty, def, pat.span, pat.id); + let pat_ty = self.node_ty(pat.id); + self.demand_suptype(pat.span, expected, pat_ty); + } - let ctor_scheme = tcx.lookup_item_type(enum_def); - let ctor_predicates = tcx.lookup_predicates(enum_def); - let path_scheme = if ctor_scheme.ty.is_fn() { - let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap(); - ty::TypeScheme { - ty: fn_ret.unwrap(), - generics: ctor_scheme.generics, - } - } else { - ctor_scheme - }; - self.instantiate_path(segments, path_scheme, &ctor_predicates, - opt_ty, def, pat.span, pat.id); - let report_bad_struct_kind = |is_warning| { - bad_struct_kind_err(tcx.sess, pat, path, is_warning); - if is_warning { return; } + fn check_pat_tuple_struct(&self, + pat: &hir::Pat, + path: &hir::Path, + subpats: &'gcx [P], + ddpos: Option, + expected: Ty<'tcx>) + { + let tcx = self.tcx; + let on_error = || { self.write_error(pat.id); for pat in subpats { self.check_pat(&pat, tcx.types.err); } }; - - // If we didn't have a fully resolved path to start with, we had an - // associated const, and we should quit now, since the rest of this - // function uses checks specific to structs and enums. - if path_res.depth != 0 { - if is_tuple_struct_pat { - report_bad_struct_kind(false); + let report_unexpected_def = |is_lint| { + let msg = format!("`{}` does not name a tuple variant or a tuple struct", + pprust::path_to_string(path)); + if is_lint { + tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, + pat.id, pat.span, msg); } else { - let pat_ty = self.node_ty(pat.id); - self.demand_suptype(pat.span, expected, pat_ty); - } - return; - } - - let pat_ty = self.node_ty(pat.id); - self.demand_eqtype(pat.span, expected, pat_ty); - - let real_path_ty = self.node_ty(pat.id); - let (kind_name, variant, expected_substs) = match real_path_ty.sty { - ty::TyEnum(enum_def, expected_substs) => { - let variant = enum_def.variant_of_def(def); - ("variant", variant, expected_substs) - } - ty::TyStruct(struct_def, expected_substs) => { - let variant = struct_def.struct_variant(); - ("struct", variant, expected_substs) - } - _ => { - report_bad_struct_kind(false); - return; + span_err!(tcx.sess, pat.span, E0164, "{}", msg); + on_error(); } }; - match (is_tuple_struct_pat, variant.kind()) { - (true, ty::VariantKind::Unit) if subpats.is_empty() && ddpos.is_some() => { - // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) - // is allowed for backward compatibility. - report_bad_struct_kind(true); + // Resolve the path and check the definition for errors. + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(pat.id), + None, path, pat.span, pat.id); + match def { + Def::Err => { + self.set_tainted_by_errors(); + on_error(); + return; } - (true, ty::VariantKind::Unit) | - (false, ty::VariantKind::Tuple) | - (_, ty::VariantKind::Struct) => { - report_bad_struct_kind(false); - return + Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { + report_unexpected_def(false); + return; } - _ => {} + Def::Variant(..) | Def::Struct(..) => {} // OK + _ => bug!("unexpected pattern definition {:?}", def) + } + let variant = tcx.expect_variant_def(def); + if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() { + // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) + // is allowed for backward compatibility. + report_unexpected_def(true); + } else if variant.kind != VariantKind::Tuple { + report_unexpected_def(false); + return; } + // Type check the path. + let scheme = tcx.lookup_item_type(def.def_id()); + let scheme = if scheme.ty.is_fn() { + // Replace constructor type with constructed type for tuple struct patterns. + let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap().unwrap(); + ty::TypeScheme { ty: fn_ret, generics: scheme.generics } + } else { + // Leave the type as is for unit structs (backward compatibility). + scheme + }; + let predicates = tcx.lookup_predicates(def.def_id()); + self.instantiate_path(segments, scheme, &predicates, opt_ty, def, pat.span, pat.id); + let pat_ty = self.node_ty(pat.id); + self.demand_eqtype(pat.span, expected, pat_ty); + + // Type check subpatterns. if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { + let expected_substs = match pat_ty.sty { + ty::TyEnum(_, expected_substs) => expected_substs, + ty::TyStruct(_, expected_substs) => expected_substs, + ref ty => bug!("unexpected pattern type {:?}", ty), + }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs); self.check_pat(&subpat, field_ty); } } else { span_err!(tcx.sess, pat.span, E0023, - "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), if subpats.len() == 1 {""} else {"s"}, - kind_name, - variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); - - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } + "this pattern has {} field{s}, but the corresponding {} has {} field{s}", + subpats.len(), def.kind_name(), variant.fields.len(), + s = if variant.fields.len() == 1 {""} else {"s"}); + on_error(); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3bc90f05d2536..8ea32ebbcc652 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,7 +84,7 @@ use astconv::{AstConv, ast_region_to_region, PathParamMode}; use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use middle::cstore::LOCAL_CRATE; -use hir::def::{self, Def}; +use hir::def::{Def, PathResolution}; use hir::def_id::DefId; use hir::pat_util; use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; @@ -3349,24 +3349,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; self.write_ty(id, oprnd_t); } - hir::ExprPath(ref maybe_qself, ref path) => { - let opt_self_ty = maybe_qself.as_ref().map(|qself| { - self.to_ty(&qself.ty) - }); - - let path_res = tcx.expect_resolution(id); - if let Some((opt_ty, segments, def)) = - self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path, - expr.span, expr.id) { - if def != Def::Err { - let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span, - def); - self.instantiate_path(segments, scheme, &predicates, - opt_ty, def, expr.span, id); - } else { - self.set_tainted_by_errors(); - self.write_ty(id, self.tcx.types.err); - } + hir::ExprPath(ref opt_qself, ref path) => { + let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(id), + opt_self_ty, path, expr.span, expr.id); + if def != Def::Err { + let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span, + def); + self.instantiate_path(segments, scheme, &predicates, opt_ty, def, expr.span, id); + } else { + self.set_tainted_by_errors(); + self.write_error(id); } // We always require that the type provided as the value for @@ -3704,37 +3697,40 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected); } + // Resolve associated value path into a base type and associated constant or method definition. + // The newly resolved definition is written into `def_map`. pub fn resolve_ty_and_def_ufcs<'b>(&self, - path_res: def::PathResolution, + path_res: PathResolution, opt_self_ty: Option>, path: &'b hir::Path, span: Span, node_id: ast::NodeId) - -> Option<(Option>, &'b [hir::PathSegment], Def)> + -> (Def, Option>, &'b [hir::PathSegment]) { - // If fully resolved already, we don't have to do anything. if path_res.depth == 0 { - Some((opt_self_ty, &path.segments, path_res.base_def)) + (path_res.base_def, opt_self_ty, &path.segments) } else { - let def = path_res.base_def; + // Try to resolve everything except for the last segment as a type. let ty_segments = path.segments.split_last().unwrap().1; let base_ty_end = path.segments.len() - path_res.depth; let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span, PathParamMode::Optional, - def, + path_res.base_def, opt_self_ty, node_id, &ty_segments[..base_ty_end], &ty_segments[base_ty_end..]); + + // Resolve an associated constant or method on the previously resolved type. let item_segment = path.segments.last().unwrap(); let item_name = item_segment.name; let def = match self.resolve_ufcs(span, item_name, ty, node_id) { - Ok(def) => Some(def), + Ok(def) => def, Err(error) => { let def = match error { - method::MethodError::PrivateMatch(def) => Some(def), - _ => None, + method::MethodError::PrivateMatch(def) => def, + _ => Def::Err, }; if item_name != keywords::Invalid.name() { self.report_method_error(span, ty, item_name, None, error); @@ -3743,14 +3739,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - if let Some(def) = def { - // Write back the new resolution. - self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution::new(def)); - Some((Some(ty), slice::ref_slice(item_segment), def)) - } else { - self.write_error(node_id); - None - } + // Write back the new resolution. + self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def)); + (def, Some(ty), slice::ref_slice(item_segment)) } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2c33d1a81556e..cc5886f8bbf16 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1040,15 +1040,17 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def: &hir::VariantData) -> ty::AdtDefMaster<'tcx> { - let did = ccx.tcx.map.local_def_id(it.id); - let ctor_id = if !def.is_struct() { - ccx.tcx.map.local_def_id(def.id()) - } else { - did - }; - ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, - vec![convert_struct_variant(ccx, ctor_id, it.name, ConstInt::Infer(0), def)]) + // Use separate constructor id for unit/tuple structs and reuse did for braced structs. + let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None }; + let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, + ConstInt::Infer(0), def)]; + let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants); + if let Some(ctor_id) = ctor_id { + // Make adt definition available through constructor id as well. + ccx.tcx.insert_adt_def(ctor_id, adt); + } + adt } fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index cdac66a227237..b4d1f710704c0 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3225,42 +3225,6 @@ impl Foo for Bar { ``` "##, -E0327: r##" -You cannot use associated items other than constant items as patterns. This -includes method items. Example of erroneous code: - -```compile_fail -enum B {} - -impl B { - fn bb() -> i32 { 0 } -} - -fn main() { - match 0 { - B::bb => {} // error: associated items in match patterns must - // be constants - } -} -``` - -Please check that you're not using a method as a pattern. Example: - -``` -enum B { - ba, - bb -} - -fn main() { - match B::ba { - B::bb => {} // ok! - _ => {} - } -} -``` -"##, - E0329: r##" An attempt was made to access an associated constant through either a generic type parameter or `Self`. This is not supported yet. An example causing this @@ -4162,4 +4126,5 @@ register_diagnostics! { E0527, // expected {} elements, found {} E0528, // expected at least {} elements, found {} E0529, // slice pattern expects array or slice, not `{}` + E0533, // `{}` does not name a unit variant, unit struct or a constant } diff --git a/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs b/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs index c5557cee7cc1d..9404803a32dd8 100644 --- a/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs +++ b/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(fn_traits)] #![feature(unboxed_closures)] #![feature(rustc_attrs)] diff --git a/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs b/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs index a15422e42d94a..99568213d9907 100644 --- a/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs +++ b/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs @@ -18,6 +18,7 @@ // revisions: ok oneuse transmute krisskross +#![feature(fn_traits)] #![allow(dead_code, unused_variables)] use std::marker::PhantomData; diff --git a/src/test/compile-fail/empty-struct-braces-pat-1.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs index a5c740d9f638a..74546152ca90f 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-1.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs @@ -31,12 +31,14 @@ fn main() { Empty1 => () // Not an error, `Empty1` is interpreted as a new binding } match e3 { - E::Empty3 => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct + E::Empty3 => () + //~^ ERROR `E::Empty3` does not name a unit variant, unit struct or a constant } match xe1 { XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding } match xe3 { - XE::XEmpty3 => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct + XE::XEmpty3 => () + //~^ ERROR `XE::XEmpty3` does not name a unit variant, unit struct or a constant } } diff --git a/src/test/compile-fail/issue-32004.rs b/src/test/compile-fail/issue-32004.rs index 8d74154655fce..576451f7292a8 100644 --- a/src/test/compile-fail/issue-32004.rs +++ b/src/test/compile-fail/issue-32004.rs @@ -18,7 +18,7 @@ struct S; fn main() { match Foo::Baz { Foo::Bar => {} - //~^ ERROR `Foo::Bar` does not name a tuple variant or a tuple struct + //~^ ERROR `Foo::Bar` does not name a unit variant, unit struct or a constant _ => {} } diff --git a/src/test/compile-fail/method-path-in-pattern.rs b/src/test/compile-fail/method-path-in-pattern.rs index faf6d255c9afc..ef011c89c622b 100644 --- a/src/test/compile-fail/method-path-in-pattern.rs +++ b/src/test/compile-fail/method-path-in-pattern.rs @@ -22,12 +22,13 @@ impl MyTrait for Foo {} fn main() { match 0u32 { - Foo::bar => {} //~ ERROR E0327 + Foo::bar => {} //~ ERROR `Foo::bar` does not name a unit variant, unit struct or a constant } match 0u32 { - ::bar => {} //~ ERROR E0327 + ::bar => {} //~ ERROR `bar` does not name a unit variant, unit struct or a constant } match 0u32 { - ::trait_bar => {} //~ ERROR E0327 + ::trait_bar => {} + //~^ ERROR `trait_bar` does not name a unit variant, unit struct or a constant } } diff --git a/src/test/compile-fail/qualified-path-params.rs b/src/test/compile-fail/qualified-path-params.rs index 86873022f0ff1..9034e24a6fee0 100644 --- a/src/test/compile-fail/qualified-path-params.rs +++ b/src/test/compile-fail/qualified-path-params.rs @@ -27,7 +27,8 @@ impl S { fn main() { match 10 { - ::A::f:: => {} //~ ERROR associated items in match patterns must be constants + ::A::f:: => {} + //~^ ERROR `Tr::A::f` does not name a unit variant, unit struct or a constant 0 ... ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range } } diff --git a/src/test/run-pass/issue-28550.rs b/src/test/run-pass/issue-28550.rs index f44a535e8176e..83e3e40b3a820 100644 --- a/src/test/run-pass/issue-28550.rs +++ b/src/test/run-pass/issue-28550.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(fn_traits)] + struct AT,T>(F::Output); struct BT,T>(A); From 49ea3d48a26c1325dd584c8420227f6e35721f66 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 06/11] Remove unnecessary accessor function VariantDefData::kind --- src/librustc/mir/repr.rs | 2 +- src/librustc/ty/mod.rs | 8 -------- src/librustc_const_eval/check_match.rs | 8 ++++---- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/encoder.rs | 4 ++-- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 8 ++++---- src/librustc_typeck/check/mod.rs | 14 ++++++-------- src/librustc_typeck/collect.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- 10 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 62d3421770c2f..93507246241de 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -1063,7 +1063,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { Some(tcx.lookup_item_type(variant_def.did).generics) })?; - match variant_def.kind() { + match variant_def.kind { ty::VariantKind::Unit => Ok(()), ty::VariantKind::Tuple => fmt_tuple(fmt, lvs), ty::VariantKind::Struct => { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 93a4b1ac0f403..03e893727d1b5 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1925,14 +1925,6 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { self.fields.iter() } - pub fn kind(&self) -> VariantKind { - self.kind - } - - pub fn is_tuple_struct(&self) -> bool { - self.kind() == VariantKind::Tuple - } - #[inline] pub fn find_field_named(&self, name: ast::Name) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 33c778f8725d7..b8283ccab24bd 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -246,9 +246,9 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) let pat_ty = cx.tcx.pat_ty(p); if let ty::TyEnum(edef, _) = pat_ty.sty { if let Def::Local(..) = cx.tcx.expect_def(p.id) { - if edef.variants.iter().any(|variant| - variant.name == name.node && variant.kind() == VariantKind::Unit - ) { + if edef.variants.iter().any(|variant| { + variant.name == name.node && variant.kind == VariantKind::Unit + }) { let ty_path = cx.tcx.item_path_str(edef.did); let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, "pattern binding `{}` is named the same as one \ @@ -563,7 +563,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { let v = ctor.variant_for_adt(adt); - match v.kind() { + match v.kind { VariantKind::Struct => { let field_pats: hir::HirVec<_> = v.fields.iter() .zip(pats) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 4ccfcd9e90356..6d3699e978794 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -498,7 +498,7 @@ pub fn get_adt_def<'a, 'tcx>(intr: &IdentInterner, // this needs to be done *after* the variant is interned, // to support recursive structures for variant in &adt.variants { - if variant.kind() == ty::VariantKind::Tuple && + if variant.kind == ty::VariantKind::Tuple && adt.adt_kind() == ty::AdtKind::Enum { // tuple-like enum variant fields aren't real items - get the types // from the ctor. diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b6f49569958d6..7314259423592 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -217,7 +217,7 @@ fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { fn encode_struct_fields(rbml_w: &mut Encoder, variant: ty::VariantDef) { for f in &variant.fields { - if variant.is_tuple_struct() { + if variant.kind == ty::VariantKind::Tuple { rbml_w.start_tag(tag_item_unnamed_field); } else { rbml_w.start_tag(tag_item_field); @@ -250,7 +250,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let _task = index.record(vid, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, vid); - encode_family(rbml_w, match variant.kind() { + encode_family(rbml_w, match variant.kind { ty::VariantKind::Struct => 'V', ty::VariantKind::Tuple => 'v', ty::VariantKind::Unit => 'w', diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 5596ab0d819e0..45c716170f5d6 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -901,7 +901,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } Def::Variant(enum_did, variant_did) => { let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did); - match vinfo.kind() { + match vinfo.kind { ty::VariantKind::Unit => { let repr = adt::represent_type(cx, ety); adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[]) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 34dedeede98e0..b84cc028d0ced 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1109,7 +1109,7 @@ struct StructMemberDescriptionFactory<'tcx> { impl<'tcx> StructMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { - if let ty::VariantKind::Unit = self.variant.kind() { + if self.variant.kind == ty::VariantKind::Unit { return Vec::new(); } @@ -1126,7 +1126,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { }; self.variant.fields.iter().enumerate().map(|(i, f)| { - let name = if let ty::VariantKind::Tuple = self.variant.kind() { + let name = if self.variant.kind == ty::VariantKind::Tuple { format!("__{}", i) } else { f.name.to_string() @@ -1356,7 +1356,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // For the metadata of the wrapper struct, we need to create a // MemberDescription of the struct's single field. let sole_struct_member_description = MemberDescription { - name: match non_null_variant.kind() { + name: match non_null_variant.kind { ty::VariantKind::Tuple => "__0".to_string(), ty::VariantKind::Struct => { non_null_variant.fields[0].name.to_string() @@ -1524,7 +1524,7 @@ 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.kind() { + let mut arg_names: Vec<_> = match variant.kind { ty::VariantKind::Unit => vec![], ty::VariantKind::Tuple => { variant.fields diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8ea32ebbcc652..08a8b124b1c8c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1671,14 +1671,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => return None }; - let var_kind = variant.kind(); - if var_kind == ty::VariantKind::Struct { + if variant.kind == ty::VariantKind::Struct || + variant.kind == ty::VariantKind::Unit { Some((adt, variant)) - } else if var_kind == ty::VariantKind::Unit { - Some((adt, variant)) - } else { - None - } + } else { + None + } } pub fn write_nil(&self, node_id: ast::NodeId) { @@ -2998,7 +2996,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { while let Some((base_t, autoderefs)) = autoderef.next() { let field = match base_t.sty { ty::TyStruct(base_def, substs) => { - tuple_like = base_def.struct_variant().is_tuple_struct(); + tuple_like = base_def.struct_variant().kind == ty::VariantKind::Tuple; if !tuple_like { continue } debug!("tuple struct named {:?}", base_t); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index cc5886f8bbf16..41e7a467fa33a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -949,7 +949,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>) { let tcx = ccx.tcx; - let ctor_ty = match variant.kind() { + let ctor_ty = match variant.kind { VariantKind::Unit | VariantKind::Struct => scheme.ty, VariantKind::Tuple => { let inputs: Vec<_> = diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7827459baa87f..b3b42b970ca84 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1904,7 +1904,7 @@ impl Clean for doctree::Variant { impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { fn clean(&self, cx: &DocContext) -> Item { - let kind = match self.kind() { + let kind = match self.kind { ty::VariantKind::Unit => CLikeVariant, ty::VariantKind::Tuple => { TupleVariant( From a397b60ebba531fb4de7e88111e0d489e44c549e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 07/11] Resolve partially resolved paths in struct patterns/expressions Treat Def::Err correctly in struct patterns Make instantiate_path and instantiate_type a bit closer to each other --- src/librustc/hir/pat_util.rs | 15 -- src/librustc_typeck/check/_match.rs | 81 ++++---- src/librustc_typeck/check/mod.rs | 196 ++++++++++-------- src/librustc_typeck/diagnostics.rs | 28 +-- src/test/compile-fail/E0163.rs | 20 -- src/test/compile-fail/issue-16058.rs | 2 +- src/test/compile-fail/issue-17001.rs | 2 +- src/test/compile-fail/issue-17405.rs | 1 - src/test/compile-fail/issue-21449.rs | 2 +- src/test/compile-fail/issue-26459.rs | 1 - src/test/compile-fail/issue-27815.rs | 6 +- src/test/compile-fail/issue-27831.rs | 2 +- src/test/compile-fail/issue-4736.rs | 2 +- src/test/compile-fail/lexical-scopes.rs | 2 +- .../trait-as-struct-constructor.rs | 2 +- 15 files changed, 156 insertions(+), 206 deletions(-) delete mode 100644 src/test/compile-fail/E0163.rs diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 234edc647f0c8..a26480114bcc0 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -67,21 +67,6 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { } } -pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool { - match pat.node { - PatKind::TupleStruct(..) | - PatKind::Path(..) | - PatKind::Struct(..) => { - match dm.get(&pat.id).map(|d| d.full_def()) { - Some(Def::Variant(..)) | Some(Def::Struct(..)) | - Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => true, - _ => false - } - } - _ => false - } -} - pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { PatKind::Path(..) | PatKind::QPath(..) => { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 82c676adc703d..4f7c8fbabdbd5 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -489,39 +489,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn check_pat_struct(&self, pat: &'gcx hir::Pat, - path: &hir::Path, fields: &'gcx [Spanned], - etc: bool, expected: Ty<'tcx>) { - let tcx = self.tcx; - - let def = tcx.expect_def(pat.id); - let variant = match self.def_struct_variant(def, path.span) { - Some((_, variant)) => variant, - None => { - let name = pprust::path_to_string(path); - span_err!(tcx.sess, pat.span, E0163, - "`{}` does not name a struct or a struct variant", name); - self.write_error(pat.id); - - for field in fields { - self.check_pat(&field.node.pat, tcx.types.err); - } - return; + fn check_pat_struct(&self, + pat: &'gcx hir::Pat, + path: &hir::Path, + fields: &'gcx [Spanned], + etc: bool, + expected: Ty<'tcx>) + { + // Resolve the path and check the definition for errors. + let def = self.finish_resolving_struct_path(path, pat.id, pat.span); + let variant = if let Some(variant) = self.check_struct_path(def, path, pat.span) { + variant + } else { + self.write_error(pat.id); + for field in fields { + self.check_pat(&field.node.pat, self.tcx.types.err); } + return; }; - let pat_ty = self.instantiate_type(def.def_id(), path); - let item_substs = match pat_ty.sty { + // Type check the path. + let pat_ty = self.instantiate_type_path(def.def_id(), path, pat.id); + self.demand_eqtype(pat.span, expected, pat_ty); + + // Type check subpatterns. + let substs = match pat_ty.sty { ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, _ => span_bug!(pat.span, "struct variant is not an ADT") }; - self.demand_eqtype(pat.span, expected, pat_ty); - self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc); - - self.write_ty(pat.id, pat_ty); - self.write_substs(pat.id, ty::ItemSubsts { - substs: item_substs - }); + self.check_struct_pat_fields(pat.span, fields, variant, substs, etc); } fn check_pat_path(&self, @@ -539,8 +535,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Resolve the path and check the definition for errors. - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(pat.id), - opt_self_ty, path, pat.span, pat.id); + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path, + pat.id, pat.span); match def { Def::Err => { self.set_tainted_by_errors(); @@ -565,8 +561,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check the path. let scheme = tcx.lookup_item_type(def.def_id()); let predicates = tcx.lookup_predicates(def.def_id()); - self.instantiate_path(segments, scheme, &predicates, opt_ty, def, pat.span, pat.id); - let pat_ty = self.node_ty(pat.id); + let pat_ty = self.instantiate_value_path(segments, scheme, &predicates, + opt_ty, def, pat.span, pat.id); self.demand_suptype(pat.span, expected, pat_ty); } @@ -597,9 +593,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Resolve the path and check the definition for errors. - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(pat.id), - None, path, pat.span, pat.id); - match def { + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(None, path, pat.id, pat.span); + let variant = match def { Def::Err => { self.set_tainted_by_errors(); on_error(); @@ -609,10 +604,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { report_unexpected_def(false); return; } - Def::Variant(..) | Def::Struct(..) => {} // OK + Def::Variant(..) | Def::Struct(..) => { + tcx.expect_variant_def(def) + } _ => bug!("unexpected pattern definition {:?}", def) - } - let variant = tcx.expect_variant_def(def); + }; if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() { // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) // is allowed for backward compatibility. @@ -633,20 +629,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { scheme }; let predicates = tcx.lookup_predicates(def.def_id()); - self.instantiate_path(segments, scheme, &predicates, opt_ty, def, pat.span, pat.id); - let pat_ty = self.node_ty(pat.id); + let pat_ty = self.instantiate_value_path(segments, scheme, &predicates, + opt_ty, def, pat.span, pat.id); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { - let expected_substs = match pat_ty.sty { - ty::TyEnum(_, expected_substs) => expected_substs, - ty::TyStruct(_, expected_substs) => expected_substs, + let substs = match pat_ty.sty { + ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, ref ty => bug!("unexpected pattern type {:?}", ty), }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { - let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs); + let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); self.check_pat(&subpat, field_ty); } } else { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 08a8b124b1c8c..929ab580fc3c1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1621,62 +1621,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// /// Note that this function is only intended to be used with type-paths, /// not with value-paths. - pub fn instantiate_type(&self, - did: DefId, - path: &hir::Path) - -> Ty<'tcx> - { - debug!("instantiate_type(did={:?}, path={:?})", did, path); - let type_scheme = - self.tcx.lookup_item_type(did); - let type_predicates = - self.tcx.lookup_predicates(did); + pub fn instantiate_type_path(&self, + did: DefId, + path: &hir::Path, + node_id: ast::NodeId) + -> Ty<'tcx> { + debug!("instantiate_type_path(did={:?}, path={:?})", did, path); + let type_scheme = self.tcx.lookup_item_type(did); + let type_predicates = self.tcx.lookup_predicates(did); let substs = AstConv::ast_path_substs_for_ty(self, self, path.span, PathParamMode::Optional, &type_scheme.generics, path.segments.last().unwrap()); - debug!("instantiate_type: ty={:?} substs={:?}", &type_scheme.ty, &substs); - let bounds = - self.instantiate_bounds(path.span, &substs, &type_predicates); - self.add_obligations_for_parameters( - traits::ObligationCause::new( - path.span, - self.body_id, - traits::ItemObligation(did)), - &bounds); - - self.instantiate_type_scheme(path.span, &substs, &type_scheme.ty) - } - - /// Return the dict-like variant corresponding to a given `Def`. - pub fn def_struct_variant(&self, - def: Def, - _span: Span) - -> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)> - { - let (adt, variant) = match def { - Def::Variant(enum_id, variant_id) => { - let adt = self.tcx.lookup_adt_def(enum_id); - (adt, adt.variant_with_id(variant_id)) - } - Def::Struct(did) | Def::TyAlias(did) => { - let typ = self.tcx.lookup_item_type(did); - if let ty::TyStruct(adt, _) = typ.ty.sty { - (adt, adt.struct_variant()) - } else { - return None; - } - } - _ => return None - }; + let substs = self.tcx.mk_substs(substs); + debug!("instantiate_type_path: ty={:?} substs={:?}", &type_scheme.ty, substs); + let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); + let cause = traits::ObligationCause::new(path.span, self.body_id, + traits::ItemObligation(did)); + self.add_obligations_for_parameters(cause, &bounds); - if variant.kind == ty::VariantKind::Struct || - variant.kind == ty::VariantKind::Unit { - Some((adt, variant)) - } else { - None - } + let ty_substituted = self.instantiate_type_scheme(path.span, substs, &type_scheme.ty); + self.write_ty(node_id, ty_substituted); + self.write_substs(node_id, ty::ItemSubsts { + substs: substs + }); + ty_substituted } pub fn write_nil(&self, node_id: ast::NodeId) { @@ -3151,34 +3121,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + pub fn check_struct_path(&self, + def: Def, + path: &hir::Path, + span: Span) + -> Option> { + let variant = match def { + Def::Err => { + self.set_tainted_by_errors(); + return None; + } + Def::Variant(..) | Def::Struct(..) => { + Some(self.tcx.expect_variant_def(def)) + } + Def::TyAlias(did) | Def::AssociatedTy(_, did) => { + if let ty::TyStruct(adt, _) = self.tcx.lookup_item_type(did).ty.sty { + Some(adt.struct_variant()) + } else { + None + } + } + _ => None + }; + if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple { + // Reject tuple structs for now, braced and unit structs are allowed. + span_err!(self.tcx.sess, span, E0071, + "`{}` does not name a struct or a struct variant", + pprust::path_to_string(path)); + return None; + } + variant + } + fn check_expr_struct(&self, expr: &hir::Expr, path: &hir::Path, fields: &'gcx [hir::Field], base_expr: &'gcx Option>) { - let tcx = self.tcx; - // Find the relevant variant - let def = tcx.expect_def(expr.id); - if def == Def::Err { - self.set_tainted_by_errors(); + let def = self.finish_resolving_struct_path(path, expr.id, expr.span); + let variant = if let Some(variant) = self.check_struct_path(def, path, expr.span) { + variant + } else { self.check_struct_fields_on_error(expr.id, fields, base_expr); return; - } - let variant = match self.def_struct_variant(def, path.span) { - Some((_, variant)) => variant, - None => { - span_err!(self.tcx.sess, path.span, E0071, - "`{}` does not name a structure", - pprust::path_to_string(path)); - self.check_struct_fields_on_error(expr.id, fields, base_expr); - return; - } }; - let expr_ty = self.instantiate_type(def.def_id(), path); - self.write_ty(expr.id, expr_ty); + let expr_ty = self.instantiate_type_path(def.def_id(), path, expr.id); self.check_expr_struct_fields(expr_ty, path.span, variant, fields, base_expr.is_none()); @@ -3190,13 +3180,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.id, adt.struct_variant().fields.iter().map(|f| { self.normalize_associated_types_in( - expr.span, &f.ty(tcx, substs) + expr.span, &f.ty(self.tcx, substs) ) }).collect() ); } _ => { - span_err!(tcx.sess, base_expr.span, E0436, + span_err!(self.tcx.sess, base_expr.span, E0436, "functional record update syntax requires a struct"); } } @@ -3349,12 +3339,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprPath(ref opt_qself, ref path) => { let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); - let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(id), - opt_self_ty, path, expr.span, expr.id); + let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path, + expr.id, expr.span); if def != Def::Err { let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span, def); - self.instantiate_path(segments, scheme, &predicates, opt_ty, def, expr.span, id); + self.instantiate_value_path(segments, scheme, &predicates, + opt_ty, def, expr.span, id); } else { self.set_tainted_by_errors(); self.write_error(id); @@ -3695,18 +3686,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected); } + // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. + // The newly resolved definition is written into `def_map`. + pub fn finish_resolving_struct_path(&self, + path: &hir::Path, + node_id: ast::NodeId, + span: Span) + -> Def + { + let path_res = self.tcx().expect_resolution(node_id); + if path_res.depth == 0 { + // If fully resolved already, we don't have to do anything. + path_res.base_def + } else { + let base_ty_end = path.segments.len() - path_res.depth; + let (_ty, def) = AstConv::finish_resolving_def_to_ty(self, self, span, + PathParamMode::Optional, + path_res.base_def, + None, + node_id, + &path.segments[..base_ty_end], + &path.segments[base_ty_end..]); + // Write back the new resolution. + self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def)); + def + } + } + // Resolve associated value path into a base type and associated constant or method definition. // The newly resolved definition is written into `def_map`. pub fn resolve_ty_and_def_ufcs<'b>(&self, - path_res: PathResolution, opt_self_ty: Option>, path: &'b hir::Path, - span: Span, - node_id: ast::NodeId) + node_id: ast::NodeId, + span: Span) -> (Def, Option>, &'b [hir::PathSegment]) { - // If fully resolved already, we don't have to do anything. + let path_res = self.tcx().expect_resolution(node_id); if path_res.depth == 0 { + // If fully resolved already, we don't have to do anything. (path_res.base_def, opt_self_ty, &path.segments) } else { // Try to resolve everything except for the last segment as a type. @@ -3975,15 +3993,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. - pub fn instantiate_path(&self, - segments: &[hir::PathSegment], - type_scheme: TypeScheme<'tcx>, - type_predicates: &ty::GenericPredicates<'tcx>, - opt_self_ty: Option>, - def: Def, - span: Span, - node_id: ast::NodeId) { - debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})", + pub fn instantiate_value_path(&self, + segments: &[hir::PathSegment], + type_scheme: TypeScheme<'tcx>, + type_predicates: &ty::GenericPredicates<'tcx>, + opt_self_ty: Option>, + def: Def, + span: Span, + node_id: ast::NodeId) + -> Ty<'tcx> { + debug!("instantiate_value_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})", segments, def, node_id, @@ -4012,7 +4031,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // actually pass through this function, but rather the // `ast_ty_to_ty` function in `astconv`. However, in the case // of struct patterns (and maybe literals) we do invoke - // `instantiate_path` to get the general type of an instance of + // `instantiate_value_path` to get the general type of an instance of // a struct. (In these cases, there are actually no type // parameters permitted at present, but perhaps we will allow // them in the future.) @@ -4235,20 +4254,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Err(_) => { span_bug!(span, - "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?", + "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", self_ty, impl_ty); } } } - debug!("instantiate_path: type of {:?} is {:?}", + debug!("instantiate_value_path: type of {:?} is {:?}", node_id, ty_substituted); self.write_ty(node_id, ty_substituted); self.write_substs(node_id, ty::ItemSubsts { substs: substs }); + ty_substituted } /// Finds the parameters that the user provided and adds them to `substs`. If too many diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index b4d1f710704c0..8769bc1a32b50 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1895,33 +1895,6 @@ fn my_start(argc: isize, argv: *const *const u8) -> isize { ``` "##, -E0163: r##" -This error means that an attempt was made to match an enum variant as a -struct type when the variant isn't a struct type: - -```compile_fail -enum Foo { B(u32) } - -fn bar(foo: Foo) -> u32 { - match foo { - B{i} => i, // error E0163 - } -} -``` - -Try using `()` instead: - -``` -enum Foo { B(u32) } - -fn bar(foo: Foo) -> u32 { - match foo { - Foo::B(i) => i, - } -} -``` -"##, - E0164: r##" This error means that an attempt was made to match a struct type enum variant as a non-struct type: @@ -4070,6 +4043,7 @@ register_diagnostics! { // E0129, // E0141, // E0159, // use of trait `{}` as struct constructor +// E0163, // merged into E0071 E0167, // E0168, // E0173, // manual implementations of unboxed closure traits are experimental diff --git a/src/test/compile-fail/E0163.rs b/src/test/compile-fail/E0163.rs deleted file mode 100644 index 5cb6f4d2803e1..0000000000000 --- a/src/test/compile-fail/E0163.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -enum Foo { B(u32) } - -fn bar(foo: Foo) -> u32 { - match foo { - Foo::B { i } => i, //~ ERROR E0163 - } -} - -fn main() { -} diff --git a/src/test/compile-fail/issue-16058.rs b/src/test/compile-fail/issue-16058.rs index 4637512216c40..671232e701f87 100644 --- a/src/test/compile-fail/issue-16058.rs +++ b/src/test/compile-fail/issue-16058.rs @@ -16,7 +16,7 @@ pub struct GslResult { impl GslResult { pub fn new() -> GslResult { - Result { //~ ERROR: `Result` does not name a structure + Result { //~ ERROR: `Result` does not name a struct or a struct variant val: 0f64, err: 0f64 } diff --git a/src/test/compile-fail/issue-17001.rs b/src/test/compile-fail/issue-17001.rs index 0fee6dc761700..218f68714ff92 100644 --- a/src/test/compile-fail/issue-17001.rs +++ b/src/test/compile-fail/issue-17001.rs @@ -11,5 +11,5 @@ mod foo {} fn main() { - let p = foo { x: () }; //~ ERROR `foo` does not name a structure + let p = foo { x: () }; //~ ERROR `foo` does not name a struct or a struct variant } diff --git a/src/test/compile-fail/issue-17405.rs b/src/test/compile-fail/issue-17405.rs index db43c1cce9947..2f2c252b947c9 100644 --- a/src/test/compile-fail/issue-17405.rs +++ b/src/test/compile-fail/issue-17405.rs @@ -15,6 +15,5 @@ enum Foo { fn main() { match Foo::Bar(1) { Foo { i } => () //~ ERROR expected variant, struct or type alias, found enum `Foo` - //~^ ERROR `Foo` does not name a struct or a struct variant } } diff --git a/src/test/compile-fail/issue-21449.rs b/src/test/compile-fail/issue-21449.rs index 93c4f4bfcef8f..090b8a0d16e64 100644 --- a/src/test/compile-fail/issue-21449.rs +++ b/src/test/compile-fail/issue-21449.rs @@ -11,5 +11,5 @@ mod MyMod {} fn main() { - let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a structure + let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a struct or a struct variant } diff --git a/src/test/compile-fail/issue-26459.rs b/src/test/compile-fail/issue-26459.rs index 6cadbef33e7f0..24b39eeff0f79 100644 --- a/src/test/compile-fail/issue-26459.rs +++ b/src/test/compile-fail/issue-26459.rs @@ -12,6 +12,5 @@ fn main() { match 'a' { char{ch} => true //~^ ERROR expected variant, struct or type alias, found builtin type `char` - //~| ERROR `char` does not name a struct or a struct variant }; } diff --git a/src/test/compile-fail/issue-27815.rs b/src/test/compile-fail/issue-27815.rs index d2f9abd2e316b..7a329bac61b22 100644 --- a/src/test/compile-fail/issue-27815.rs +++ b/src/test/compile-fail/issue-27815.rs @@ -11,12 +11,10 @@ mod A {} fn main() { - let u = A { x: 1 }; //~ ERROR `A` does not name a structure - let v = u32 { x: 1 }; //~ ERROR `u32` does not name a structure + let u = A { x: 1 }; //~ ERROR `A` does not name a struct or a struct variant + let v = u32 { x: 1 }; //~ ERROR `u32` does not name a struct or a struct variant match () { A { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found module `A` - //~^ ERROR `A` does not name a struct or a struct variant u32 { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found builtin type `u32 - //~^ ERROR `u32` does not name a struct or a struct variant } } diff --git a/src/test/compile-fail/issue-27831.rs b/src/test/compile-fail/issue-27831.rs index d014c45ad2d17..e20e6ea23198c 100644 --- a/src/test/compile-fail/issue-27831.rs +++ b/src/test/compile-fail/issue-27831.rs @@ -18,7 +18,7 @@ enum Enum { fn main() { let x = Foo(1); - Foo { ..x }; //~ ERROR `Foo` does not name a structure + Foo { ..x }; //~ ERROR `Foo` does not name a struct or a struct variant let Foo { .. } = x; //~ ERROR `Foo` does not name a struct let x = Bar; diff --git a/src/test/compile-fail/issue-4736.rs b/src/test/compile-fail/issue-4736.rs index 843ff38df49cb..55983c672aa08 100644 --- a/src/test/compile-fail/issue-4736.rs +++ b/src/test/compile-fail/issue-4736.rs @@ -11,5 +11,5 @@ struct NonCopyable(()); fn main() { - let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a structure + let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a struct or a struct variant } diff --git a/src/test/compile-fail/lexical-scopes.rs b/src/test/compile-fail/lexical-scopes.rs index dbcd3f32f3b66..505a91f223cc6 100644 --- a/src/test/compile-fail/lexical-scopes.rs +++ b/src/test/compile-fail/lexical-scopes.rs @@ -10,7 +10,7 @@ struct T { i: i32 } fn f() { - let t = T { i: 0 }; //~ ERROR `T` does not name a structure + let t = T { i: 0 }; //~ ERROR `T` does not name a struct or a struct variant } mod Foo { diff --git a/src/test/compile-fail/trait-as-struct-constructor.rs b/src/test/compile-fail/trait-as-struct-constructor.rs index 67ccd6b7cd058..13fdaa302f70a 100644 --- a/src/test/compile-fail/trait-as-struct-constructor.rs +++ b/src/test/compile-fail/trait-as-struct-constructor.rs @@ -12,5 +12,5 @@ trait TraitNotAStruct {} fn main() { TraitNotAStruct{ value: 0 }; - //~^ ERROR: `TraitNotAStruct` does not name a structure [E0071] + //~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071] } From 9c05fb29d22a7275b7b7d52b2d5d577c0b505ad1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 08/11] Merge PatKind::QPath into PatKind::Path in HIR --- src/librustc/cfg/construct.rs | 1 - src/librustc/hir/fold.rs | 11 +++++------ src/librustc/hir/intravisit.rs | 9 ++++----- src/librustc/hir/lowering.rs | 19 ++++++++----------- src/librustc/hir/mod.rs | 13 +++---------- src/librustc/hir/pat_util.rs | 4 ++-- src/librustc/hir/print.rs | 4 ++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc_const_eval/check_match.rs | 8 ++++---- src/librustc_const_eval/eval.rs | 2 +- src/librustc_lint/bad_style.rs | 2 +- src/librustc_mir/hair/cx/pattern.rs | 2 +- src/librustc_trans/_match.rs | 2 +- .../debuginfo/create_scope_map.rs | 2 +- src/librustc_typeck/check/_match.rs | 8 +++----- src/librustdoc/clean/mod.rs | 6 +++--- 16 files changed, 40 insertions(+), 55 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 18ea17f48162f..601d3866b02d4 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -101,7 +101,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { match pat.node { PatKind::Binding(_, _, None) | PatKind::Path(..) | - PatKind::QPath(..) | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => { diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 78fd2bbbe0d25..5e0e6622185f8 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -930,12 +930,11 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { PatKind::TupleStruct(folder.fold_path(pth), pats.move_map(|x| folder.fold_pat(x)), ddpos) } - PatKind::Path(pth) => { - PatKind::Path(folder.fold_path(pth)) - } - PatKind::QPath(qself, pth) => { - let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself }; - PatKind::QPath(qself, folder.fold_path(pth)) + PatKind::Path(opt_qself, pth) => { + let opt_qself = opt_qself.map(|qself| { + QSelf { ty: folder.fold_ty(qself.ty), position: qself.position } + }); + PatKind::Path(opt_qself, folder.fold_path(pth)) } PatKind::Struct(pth, fields, etc) => { let pth = folder.fold_path(pth); diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2d5c4ebf8d898..442c85af22a26 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -460,11 +460,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_path(path, pattern.id); walk_list!(visitor, visit_pat, children); } - PatKind::Path(ref path) => { - visitor.visit_path(path, pattern.id); - } - PatKind::QPath(ref qself, ref path) => { - visitor.visit_ty(&qself.ty); + PatKind::Path(ref opt_qself, ref path) => { + if let Some(ref qself) = *opt_qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(path, pattern.id) } PatKind::Struct(ref path, ref fields, _) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2cc39412182dc..3e6a82ed47617 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -862,7 +862,8 @@ impl<'a> LoweringContext<'a> { respan(pth1.span, pth1.node.name), sub.as_ref().map(|x| this.lower_pat(x))) } - _ => hir::PatKind::Path(hir::Path::from_name(pth1.span, pth1.node.name)) + _ => hir::PatKind::Path(None, hir::Path::from_name(pth1.span, + pth1.node.name)) } }) } @@ -872,15 +873,11 @@ impl<'a> LoweringContext<'a> { pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos) } - PatKind::Path(None, ref pth) => { - hir::PatKind::Path(self.lower_path(pth)) - } - PatKind::Path(Some(ref qself), ref pth) => { - let qself = hir::QSelf { - ty: self.lower_ty(&qself.ty), - position: qself.position, - }; - hir::PatKind::QPath(qself, self.lower_path(pth)) + PatKind::Path(ref opt_qself, ref path) => { + let opt_qself = opt_qself.map(|qself| { + hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position } + }); + hir::PatKind::Path(opt_qself, self.lower_path(path)) } PatKind::Struct(ref pth, ref fields, etc) => { let pth = self.lower_path(pth); @@ -1831,7 +1828,7 @@ impl<'a> LoweringContext<'a> { -> P { let def = self.resolver.resolve_generated_global_path(&path, true); let pt = if subpats.is_empty() { - hir::PatKind::Path(path) + hir::PatKind::Path(None, path) } else { hir::PatKind::TupleStruct(path, subpats, None) }; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e1e681b7aff35..655f80ec07238 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -487,8 +487,7 @@ impl Pat { PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Binding(..) | - PatKind::Path(..) | - PatKind::QPath(_, _) => { + PatKind::Path(..) => { true } } @@ -538,15 +537,9 @@ pub enum PatKind { /// 0 <= position <= subpats.len() TupleStruct(Path, HirVec>, Option), - /// A path pattern. + /// A possibly qualified path pattern. /// Such pattern can be resolved to a unit struct/variant or a constant. - Path(Path), - - /// An associated const named using the qualified path `::CONST` or - /// `::CONST`. Associated consts from inherent impls can be - /// referred to as simply `T::CONST`, in which case they will end up as - /// PatKind::Path, and the resolver will have to sort that out. - QPath(QSelf, Path), + Path(Option, Path), /// A tuple pattern `(a, b)`. /// If the `..` pattern fragment is present, then `Option` denotes its position. diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index a26480114bcc0..593d10ef4f7c4 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -53,7 +53,7 @@ impl EnumerateAndAdjustIterator for T { pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { - PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::QPath(..) => true, + PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Path(Some(..), _) => true, PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::Struct(..) => { @@ -69,7 +69,7 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { - PatKind::Path(..) | PatKind::QPath(..) => { + PatKind::Path(..) => { match dm.get(&pat.id).map(|d| d.full_def()) { Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true, _ => false diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index bf6188faa2fbd..5f2fac5c01b30 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1750,10 +1750,10 @@ impl<'a> State<'a> { } try!(self.pclose()); } - PatKind::Path(ref path) => { + PatKind::Path(None, ref path) => { self.print_path(path, true, 0)?; } - PatKind::QPath(ref qself, ref path) => { + PatKind::Path(Some(ref qself), ref path) => { self.print_qpath(path, qself, false)?; } PatKind::Struct(ref path, ref fields, etc) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3776a904923c9..28bfb460a14fa 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1193,7 +1193,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - PatKind::Path(..) | PatKind::QPath(..) | PatKind::Binding(_, _, None) | + PatKind::Path(..) | PatKind::Binding(_, _, None) | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => { // always ok } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index b8283ccab24bd..866a91b4d9510 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -489,7 +489,7 @@ impl<'map> IdVisitingOperation for RenamingRecorder<'map> { impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { fn fold_pat(&mut self, pat: P) -> P { return match pat.node { - PatKind::Path(..) | PatKind::QPath(..) => { + PatKind::Path(..) => { match self.tcx.expect_def(pat.id) { Def::AssociatedConst(did) | Def::Const(did) => { let substs = Some(self.tcx.node_id_item_substs(pat.id).substs); @@ -583,7 +583,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None) } VariantKind::Unit => { - PatKind::Path(def_to_path(cx.tcx, v.did)) + PatKind::Path(None, def_to_path(cx.tcx, v.did)) } } } @@ -784,7 +784,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, left_ty: Ty, max_slice_length: usize) -> Vec { let pat = raw_pat(p); match pat.node { - PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(..) => + PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => match cx.tcx.expect_def(pat.id) { Def::Variant(_, id) => vec![Variant(id)], Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], @@ -895,7 +895,7 @@ pub fn specialize<'a, 'b, 'tcx>( PatKind::Binding(..) | PatKind::Wild => Some(vec![dummy_pat; arity]), - PatKind::Path(..) | PatKind::QPath(..) => { + PatKind::Path(..) => { match cx.tcx.expect_def(pat_id) { Def::Const(..) | Def::AssociatedConst(..) => span_bug!(pat_span, "const pattern should've \ diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 6c37662206ce2..a3c707e82a0ff 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -323,7 +323,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir::ExprPath(_, ref path) => { match tcx.expect_def(expr.id) { - Def::Struct(..) | Def::Variant(..) => PatKind::Path(path.clone()), + Def::Struct(..) | Def::Variant(..) => PatKind::Path(None, path.clone()), Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = Some(tcx.node_id_item_substs(expr.id).substs); let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap(); diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 7e9b6f561b984..15914838acf0d 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -360,7 +360,7 @@ impl LateLintPass for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) - if let PatKind::Path(ref path) = p.node { + if let PatKind::Path(None, ref path) = p.node { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { if let Def::Const(..) = cx.tcx.expect_def(p.id) { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 654108c14df87..c54c8bfb5981e 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -76,7 +76,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatternKind::Range { lo: lo, hi: hi } }, - PatKind::Path(..) | PatKind::QPath(..) => { + PatKind::Path(..) => { match self.cx.tcx.expect_def(pat.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let tcx = self.cx.tcx.global_tcx(); diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index d79278e99cb2e..08e894ffbcfd4 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -2003,7 +2003,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, cleanup_scope) }); } - PatKind::Path(..) | PatKind::QPath(..) | PatKind::Wild | + PatKind::Path(..) | PatKind::Wild | PatKind::Lit(..) | PatKind::Range(..) => () } return bcx; diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 2b079e7dcc8d9..0b75402486812 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -313,7 +313,7 @@ fn walk_pattern(cx: &CrateContext, } } - PatKind::Path(..) | PatKind::QPath(..) => { + PatKind::Path(..) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 4f7c8fbabdbd5..e4ed4c1c0b136 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -168,11 +168,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { PatKind::TupleStruct(ref path, ref subpats, ddpos) => { self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); } - PatKind::Path(ref path) => { - self.check_pat_path(pat, None, path, expected); - } - PatKind::QPath(ref qself, ref path) => { - self.check_pat_path(pat, Some(self.to_ty(&qself.ty)), path, expected); + PatKind::Path(ref opt_qself, ref path) => { + let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); + self.check_pat_path(pat, opt_qself_ty, path, expected); } PatKind::Struct(ref path, ref fields, etc) => { self.check_pat_struct(pat, path, fields, etc, expected); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b3b42b970ca84..c33e8159d19c4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2578,9 +2578,9 @@ fn name_from_pat(p: &hir::Pat) -> String { match p.node { PatKind::Wild => "_".to_string(), PatKind::Binding(_, ref p, _) => p.node.to_string(), - PatKind::TupleStruct(ref p, _, _) | PatKind::Path(ref p) => path_to_string(p), - PatKind::QPath(..) => panic!("tried to get argument name from PatKind::QPath, \ - which is not allowed in function arguments"), + PatKind::TupleStruct(ref p, _, _) | PatKind::Path(None, ref p) => path_to_string(p), + PatKind::Path(..) => panic!("tried to get argument name from qualified PatKind::Path, \ + which is not allowed in function arguments"), PatKind::Struct(ref name, ref fields, etc) => { format!("{} {{ {}{} }}", path_to_string(name), fields.iter().map(|&Spanned { node: ref fp, .. }| From 2859f8bf3984c5871df0ee7395ec732e4a79759f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 09/11] Add tests + Fix rustdoc regression + Fix rebase --- src/librustc/hir/lowering.rs | 2 +- src/librustc_typeck/check/mod.rs | 3 +- src/librustdoc/clean/mod.rs | 2 +- src/test/compile-fail-fulldeps/issue-18986.rs | 1 - .../compile-fail/auxiliary/lint_stability.rs | 10 +++++ src/test/compile-fail/issue-22933-1.rs | 35 ++++++++++++++++++ src/test/compile-fail/issue-22933-2.rs | 21 +++++++++++ src/test/compile-fail/issue-34209.rs | 22 +++++++++++ src/test/compile-fail/lint-stability.rs | 5 +++ .../struct-pat-associated-path.rs | 37 +++++++++++++++++++ 10 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/issue-22933-1.rs create mode 100644 src/test/compile-fail/issue-22933-2.rs create mode 100644 src/test/compile-fail/issue-34209.rs create mode 100644 src/test/compile-fail/struct-pat-associated-path.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3e6a82ed47617..9d124dadb766a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -874,7 +874,7 @@ impl<'a> LoweringContext<'a> { ddpos) } PatKind::Path(ref opt_qself, ref path) => { - let opt_qself = opt_qself.map(|qself| { + let opt_qself = opt_qself.as_ref().map(|qself| { hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position } }); hir::PatKind::Path(opt_qself, self.lower_path(path)) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 929ab580fc3c1..f6f7ee069008a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3135,7 +3135,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(self.tcx.expect_variant_def(def)) } Def::TyAlias(did) | Def::AssociatedTy(_, did) => { - if let ty::TyStruct(adt, _) = self.tcx.lookup_item_type(did).ty.sty { + if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did) + .map(|scheme| &scheme.ty.sty) { Some(adt.struct_variant()) } else { None diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c33e8159d19c4..7da17b3749104 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2653,7 +2653,7 @@ fn resolve_type(cx: &DocContext, Def::SelfTy(..) if path.segments.len() == 1 => { return Generic(keywords::SelfType.name().to_string()); } - Def::SelfTy(..) | Def::TyParam(..) => true, + Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true, _ => false, }; let did = register_def(&*cx, def); diff --git a/src/test/compile-fail-fulldeps/issue-18986.rs b/src/test/compile-fail-fulldeps/issue-18986.rs index 4245786295b34..3c32cb947b382 100644 --- a/src/test/compile-fail-fulldeps/issue-18986.rs +++ b/src/test/compile-fail-fulldeps/issue-18986.rs @@ -16,6 +16,5 @@ pub use use_from_trait_xc::Trait; fn main() { match () { Trait { x: 42 } => () //~ ERROR expected variant, struct or type alias, found trait `Trait` - //~^ ERROR `Trait` does not name a struct or a struct variant } } diff --git a/src/test/compile-fail/auxiliary/lint_stability.rs b/src/test/compile-fail/auxiliary/lint_stability.rs index 3100aba4b72be..1049bcd15644f 100644 --- a/src/test/compile-fail/auxiliary/lint_stability.rs +++ b/src/test/compile-fail/auxiliary/lint_stability.rs @@ -10,6 +10,7 @@ #![crate_name="lint_stability"] #![crate_type = "lib"] #![feature(staged_api)] +#![feature(associated_type_defaults)] #![stable(feature = "lint_stability", since = "1.0.0")] #[stable(feature = "test_feature", since = "1.0.0")] @@ -92,6 +93,15 @@ pub trait Trait { fn trait_stable_text(&self) {} } +#[stable(feature = "test_feature", since = "1.0.0")] +pub trait TraitWithAssociatedTypes { + #[unstable(feature = "test_feature", issue = "0")] + type TypeUnstable = u8; + #[stable(feature = "test_feature", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "text")] + type TypeDeprecated = u8; +} + #[stable(feature = "test_feature", since = "1.0.0")] impl Trait for MethodTester {} diff --git a/src/test/compile-fail/issue-22933-1.rs b/src/test/compile-fail/issue-22933-1.rs new file mode 100644 index 0000000000000..afb972faaca0e --- /dev/null +++ b/src/test/compile-fail/issue-22933-1.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] +#![allow(warnings)] + +struct CNFParser { + token: char, +} + +impl CNFParser { + fn is_whitespace(c: char) -> bool { + c == ' ' || c == '\n' + } + + fn consume_whitespace(&mut self) { + self.consume_while(&(CNFParser::is_whitespace)) + } + + fn consume_while(&mut self, p: &Fn(char) -> bool) { + while p(self.token) { + return + } + } +} + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs new file mode 100644 index 0000000000000..7d619c270d32b --- /dev/null +++ b/src/test/compile-fail/issue-22933-2.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Delicious { + Pie = 0x1, + Apple = 0x2, + ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, + //~^ ERROR constant evaluation error: unresolved path in constant expression +} + +const FOO: [u32; u8::MIN as usize] = []; +//~^ ERROR array length constant evaluation error: unresolved path in constant expression + +fn main() {} diff --git a/src/test/compile-fail/issue-34209.rs b/src/test/compile-fail/issue-34209.rs new file mode 100644 index 0000000000000..6fae18dec10a6 --- /dev/null +++ b/src/test/compile-fail/issue-34209.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum S { + A, +} + +fn bug(l: S) { + match l { + S::B{ } => { }, + //~^ ERROR ambiguous associated type; specify the type using the syntax `::B` + } +} + +fn main () {} diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 414d2a857acc7..953cd4a2ff5ea 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -128,6 +128,11 @@ mod cross_crate { ::trait_stable_text(&foo); ::trait_stable_text(&foo); + struct S1(T::TypeUnstable); + //~^ ERROR use of unstable library feature + struct S2(T::TypeDeprecated); + //~^ ERROR use of deprecated item + let _ = DeprecatedStruct { //~ ERROR use of deprecated item i: 0 //~ ERROR use of deprecated item }; diff --git a/src/test/compile-fail/struct-pat-associated-path.rs b/src/test/compile-fail/struct-pat-associated-path.rs new file mode 100644 index 0000000000000..d3f840f4fe976 --- /dev/null +++ b/src/test/compile-fail/struct-pat-associated-path.rs @@ -0,0 +1,37 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; + +trait Tr { + type A; +} + +impl Tr for S { + type A = S; +} + +fn f() { + match S { + T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant + } +} + +fn g>() { + match S { + T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant + } +} + +fn main() { + match S { + S::A {} => {} //~ ERROR ambiguous associated type + } +} From 390b639e59adbb35b491f3080a07ba7b2ed84072 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Jun 2016 18:47:47 +0300 Subject: [PATCH 10/11] Move some common code into check_struct_path --- src/librustc_typeck/check/_match.rs | 7 +++---- src/librustc_typeck/check/mod.rs | 17 +++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e4ed4c1c0b136..e90b32cd5dfc0 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -495,9 +495,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected: Ty<'tcx>) { // Resolve the path and check the definition for errors. - let def = self.finish_resolving_struct_path(path, pat.id, pat.span); - let variant = if let Some(variant) = self.check_struct_path(def, path, pat.span) { - variant + let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id, + pat.span) { + variant_ty } else { self.write_error(pat.id); for field in fields { @@ -507,7 +507,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Type check the path. - let pat_ty = self.instantiate_type_path(def.def_id(), path, pat.id); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f6f7ee069008a..8daa16180a905 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3122,10 +3122,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_struct_path(&self, - def: Def, path: &hir::Path, + node_id: ast::NodeId, span: Span) - -> Option> { + -> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> { + let def = self.finish_resolving_struct_path(path, node_id, span); let variant = match def { Def::Err => { self.set_tainted_by_errors(); @@ -3151,7 +3152,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pprust::path_to_string(path)); return None; } - variant + + let ty = self.instantiate_type_path(def.def_id(), path, node_id); + Some((variant.unwrap(), ty)) } fn check_expr_struct(&self, @@ -3161,16 +3164,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: &'gcx Option>) { // Find the relevant variant - let def = self.finish_resolving_struct_path(path, expr.id, expr.span); - let variant = if let Some(variant) = self.check_struct_path(def, path, expr.span) { - variant + let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id, + expr.span) { + variant_ty } else { self.check_struct_fields_on_error(expr.id, fields, base_expr); return; }; - let expr_ty = self.instantiate_type_path(def.def_id(), path, expr.id); - self.check_expr_struct_fields(expr_ty, path.span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { From d27e55c5d81eaee11ff2d414793cb7278d58d578 Mon Sep 17 00:00:00 2001 From: petrochenkov Date: Fri, 8 Jul 2016 13:35:17 +0300 Subject: [PATCH 11/11] Stabilize `FnOnce::Output` + Fix rebase --- src/libcore/ops.rs | 2 +- src/librustc_resolve/lib.rs | 5 ++--- .../associated-types/cache/project-fn-ret-contravariant.rs | 1 - .../associated-types/cache/project-fn-ret-invariant.rs | 1 - src/test/run-pass/issue-28550.rs | 2 -- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 7753aae147a88..9347ac2a8c82f 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1929,7 +1929,7 @@ pub trait FnMut : FnOnce { #[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnOnce { /// The returned type after the call operator is used. - #[unstable(feature = "fn_traits", issue = "29625")] + #[stable(feature = "fn_once_output", since = "1.12.0")] type Output; /// This is called when the call operator is used. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bcfd87872628e..9079cc8ccb122 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2287,7 +2287,7 @@ impl<'a> Resolver<'a> { .and_then(|resolution| { let always_binding = !pat_src.is_refutable() || opt_pat.is_some() || bmode != BindingMode::ByValue(Mutability::Immutable); - match def { + match resolution.base_def { Def::Struct(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) if !always_binding => { // A constant, unit variant, etc pattern. @@ -2296,12 +2296,11 @@ impl<'a> Resolver<'a> { Def::Struct(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => { // A fresh binding that shadows something unacceptable. - let kind_name = PathResolution::new(def).kind_name(); resolve_error( self, ident.span, ResolutionError::BindingShadowsSomethingUnacceptable( - pat_src.descr(), kind_name, ident.node.name) + pat_src.descr(), resolution.kind_name(), ident.node.name) ); None } diff --git a/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs b/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs index 9404803a32dd8..c5557cee7cc1d 100644 --- a/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs +++ b/src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(fn_traits)] #![feature(unboxed_closures)] #![feature(rustc_attrs)] diff --git a/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs b/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs index 99568213d9907..a15422e42d94a 100644 --- a/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs +++ b/src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs @@ -18,7 +18,6 @@ // revisions: ok oneuse transmute krisskross -#![feature(fn_traits)] #![allow(dead_code, unused_variables)] use std::marker::PhantomData; diff --git a/src/test/run-pass/issue-28550.rs b/src/test/run-pass/issue-28550.rs index 83e3e40b3a820..f44a535e8176e 100644 --- a/src/test/run-pass/issue-28550.rs +++ b/src/test/run-pass/issue-28550.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(fn_traits)] - struct AT,T>(F::Output); struct BT,T>(A);