]> git.lizzy.rs Git - rust.git/commitdiff
Rewrite check_pat_enum, split it into check_pat_tuple_struct and check_pat_path
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sat, 11 Jun 2016 15:47:47 +0000 (18:47 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Fri, 8 Jul 2016 09:42:57 +0000 (12:42 +0300)
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

17 files changed:
src/librustc/hir/def.rs
src/librustc/hir/pat_util.rs
src/librustc/ty/context.rs
src/librustc/ty/mod.rs
src/librustc_metadata/decoder.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/test/compile-fail/associated-types/cache/project-fn-ret-contravariant.rs
src/test/compile-fail/associated-types/cache/project-fn-ret-invariant.rs
src/test/compile-fail/empty-struct-braces-pat-1.rs
src/test/compile-fail/issue-32004.rs
src/test/compile-fail/method-path-in-pattern.rs
src/test/compile-fail/qualified-path-params.rs
src/test/run-pass/issue-28550.rs

index 72261c473e5c5d6a252733f988b43956f681ef78..218681efb7dc167d033b1da220acc94b901bd215 100644 (file)
@@ -137,15 +137,6 @@ pub fn def_id(&self) -> DefId {
         }
     }
 
-    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",
index 8282cd6bfcbe3ee127feca524868257e93316cea..234edc647f0c83f3699cb4cbabb5bfe959b2dbba 100644 (file)
 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<ast::Name, ast::NodeId>;
-
 pub struct EnumerateAndAdjust<I> {
     enumerate: Enumerate<I>,
     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<F>(pat: &hir::Pat, mut f: F)
index 219cb5e383a8d00ebc3b8dc270ca48bcc1e6a593..4c8fa80dd0b9669acff4ea2d9c13422681943b10 100644 (file)
@@ -591,6 +591,13 @@ pub fn alloc_trait_def(self, def: ty::TraitDef<'gcx>)
         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 @@ pub fn intern_adt_def(self,
                           -> 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
     }
 
index 4dc7ac4138bbc12a54bda75dc8c8231d91bfa1c5..93a4b1ac0f40337a18e1d846d3d8d1054d198acd 100644 (file)
@@ -2454,6 +2454,20 @@ pub fn expect_def_or_none(self, id: NodeId) -> Option<Def> {
         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)
index eada2a9cd7a63332f6b30aeb10712a785d047f3e..4ccfcd9e90356e1d43acee44a70578413bfc9d8f 100644 (file)
@@ -471,23 +471,29 @@ fn get_struct_variant<'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
index 088ac1aac1a4016926e9507b8790a43d6e3eb335..9ff30f9ede26295d85f4e94c853d817ce3bf3d84 100644 (file)
@@ -53,7 +53,7 @@
 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 @@ fn associated_path_def_to_ty(&self,
                 };
 
                 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<ty::PolyTraitRef> =
@@ -1341,7 +1341,7 @@ fn associated_path_def_to_ty(&self,
                                                     &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 @@ fn associated_path_def_to_ty(&self,
                                                      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 @@ fn associated_path_def_to_ty(&self,
                                                      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 @@ fn associated_path_def_to_ty(&self,
                                                       &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 @@ fn base_def_to_ty(&self,
         }
     }
 
-    // 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<Ty<'tcx>>,
                                       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 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
             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
index 069a09183a738e7fd8cb6cd26fa871f1bbb6ef43..82c676adc703d59606931e85984e3b7f97ecb598 100644 (file)
 
 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;
 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 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'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 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'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 @@ pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'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 @@ pub fn check_pat_struct(&self, pat: &'gcx hir::Pat,
         });
     }
 
-    fn check_pat_enum(&self,
+    fn check_pat_path(&self,
                       pat: &hir::Pat,
+                      opt_self_ty: Option<Ty<'tcx>>,
                       path: &hir::Path,
-                      subpats: &'gcx [P<hir::Pat>],
-                      ddpos: Option<usize>,
-                      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<hir::Pat>],
+                              ddpos: Option<usize>,
+                              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();
         }
     }
 
index 3bc90f05d2536c2f41ebcef9a45dcfc4bc2a5a29..8ea32ebbcc65247908072d659c8ab7d1df0294b2 100644 (file)
@@ -84,7 +84,7 @@
 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 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
             };
             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 @@ fn check_expr_with_expectation_and_lvalue_pref(&self,
                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<Ty<'tcx>>,
                                        path: &'b hir::Path,
                                        span: Span,
                                        node_id: ast::NodeId)
-                                       -> Option<(Option<Ty<'tcx>>, &'b [hir::PathSegment], Def)>
+                                       -> (Def, Option<Ty<'tcx>>, &'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 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self,
                 }
             };
 
-            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))
         }
     }
 
index 2c33d1a81556eb9f28cae32520627a8aefa6d822..cc5886f8bbf16b0b65435ff53eac512f3e94b00f 100644 (file)
@@ -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)
index cdac66a2272379f43011c6ed51162afc3d7a5338..b4d1f710704c059bdb6874a456f9dded9949fe8e 100644 (file)
@@ -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 @@ fn fly(&self) {} // And now that's ok!
     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
 }
index c5557cee7cc1dce3d01d76fc8cf86418662fa93c..9404803a32dd863418a79f699f2dec93feaa945e 100644 (file)
@@ -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)]
 
index a15422e42d94a339f617e675ff3aa590a65408f2..99568213d99073db1e8eda5e3d17c4a166bb52fe 100644 (file)
@@ -18,6 +18,7 @@
 
 // revisions: ok oneuse transmute krisskross
 
+#![feature(fn_traits)]
 #![allow(dead_code, unused_variables)]
 
 use std::marker::PhantomData;
index a5c740d9f638a65a94b8fbf9833102f8264bf472..74546152ca90fcf77b85c1742cd89768820c8e27 100644 (file)
@@ -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
     }
 }
index 8d74154655fcee4b9006a78b57786493f18aceef..576451f7292a894c1b8606e94401e5893849723b 100644 (file)
@@ -18,7 +18,7 @@ enum Foo {
 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
         _ => {}
     }
 
index faf6d255c9afc38c2b26ba93b5ea0105fbbcb59b..ef011c89c622ba184eb6e986834946681cb8165e 100644 (file)
@@ -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 {
-        <Foo>::bar => {} //~ ERROR E0327
+        <Foo>::bar => {} //~ ERROR `bar` does not name a unit variant, unit struct or a constant
     }
     match 0u32 {
-        <Foo>::trait_bar => {} //~ ERROR E0327
+        <Foo>::trait_bar => {}
+        //~^ ERROR `trait_bar` does not name a unit variant, unit struct or a constant
     }
 }
index 86873022f0ff10b666941c3cd86cdefcac106ffa..9034e24a6fee03fab57aa7f722658c8a72b806f5 100644 (file)
@@ -27,7 +27,8 @@ fn f<T>() {}
 
 fn main() {
     match 10 {
-        <S as Tr>::A::f::<u8> => {} //~ ERROR associated items in match patterns must be constants
+        <S as Tr>::A::f::<u8> => {}
+        //~^ ERROR `Tr::A::f<u8>` does not name a unit variant, unit struct or a constant
         0 ... <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
     }
 }
index f44a535e8176e25aa895dfccc16c0694348eb74c..83e3e40b3a820a47bbb92a6889a150506efcb0f4 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(fn_traits)]
+
 struct A<F: FnOnce()->T,T>(F::Output);
 struct B<F: FnOnce()->T,T>(A<F,T>);