about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2015-10-26 21:09:12 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2015-11-19 11:39:18 +0300
commit0f8519c341a53a4697f839041bc0a14dd6c6e773 (patch)
tree18b709c1f83410598d7ddcf20410001099eafd58
parent3e48b0e380319dc586a329baac640b9457feb87a (diff)
downloadrust-0f8519c341a53a4697f839041bc0a14dd6c6e773.tar.gz
rust-0f8519c341a53a4697f839041bc0a14dd6c6e773.zip
Fix various bugs around empty structs and patterns
-rw-r--r--src/librustc_mir/hair/cx/expr.rs2
-rw-r--r--src/librustc_typeck/check/_match.rs75
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/test/compile-fail/empty-struct-braces-gate-2.rs17
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-1.rs10
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-2.rs12
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-3.rs29
-rw-r--r--src/test/compile-fail/empty-struct-unit-pat.rs21
-rw-r--r--src/test/compile-fail/issue-19086.rs2
-rw-r--r--src/test/compile-fail/issue-27831.rs2
-rw-r--r--src/test/compile-fail/issue-28992-empty.rs26
-rw-r--r--src/test/compile-fail/match-pattern-field-mismatch-2.rs2
-rw-r--r--src/test/compile-fail/pattern-error-continue.rs2
-rw-r--r--src/test/run-pass/empty-struct-braces.rs20
14 files changed, 143 insertions, 79 deletions
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index c546a264be1..3380b3a6c14 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -178,7 +178,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                     }
                     ty::TyEnum(adt, substs) => {
                         match cx.tcx.def_map.borrow()[&self.id].full_def() {
-                            def::DefVariant(enum_id, variant_id, true) => {
+                            def::DefVariant(enum_id, variant_id, _) => {
                                 debug_assert!(adt.did == enum_id);
                                 let index = adt.variant_index_with_id(variant_id);
                                 let field_refs = field_refs(&adt.variants[index], fields);
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index aaaca486006..21958387056 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -21,6 +21,7 @@ use check::{check_expr_with_lvalue_pref};
 use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
 use require_same_types;
 use util::nodemap::FnvHashMap;
+use session::Session;
 
 use std::cmp;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -136,6 +137,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         }
         hir::PatEnum(..) | hir::PatIdent(..)
                 if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
+            if let hir::PatEnum(ref path, ref subpats) = pat.node {
+                if !(subpats.is_some() && subpats.as_ref().unwrap().is_empty()) {
+                    bad_struct_kind_err(tcx.sess, pat.span, path);
+                    return;
+                }
+            }
             let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
             let const_scheme = tcx.lookup_item_type(const_did);
             assert!(const_scheme.generics.is_empty());
@@ -192,11 +199,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         }
         hir::PatIdent(_, ref path, _) => {
             let path = hir_util::ident_to_path(path.span, path.node);
-            check_pat_enum(pcx, pat, &path, Some(&[]), expected);
+            check_pat_enum(pcx, pat, &path, Some(&[]), expected, false);
         }
         hir::PatEnum(ref path, ref subpats) => {
             let subpats = subpats.as_ref().map(|v| &v[..]);
-            check_pat_enum(pcx, pat, path, subpats, expected);
+            let is_tuple_struct_pat = !(subpats.is_some() && subpats.unwrap().is_empty());
+            check_pat_enum(pcx, pat, path, subpats, expected, is_tuple_struct_pat);
         }
         hir::PatQPath(ref qself, ref path) => {
             let self_ty = fcx.to_ty(&qself.ty);
@@ -572,11 +580,19 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat,
     fcx.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() });
 }
 
+// This function exists due to the warning "diagnostic code E0164 already used"
+fn bad_struct_kind_err(sess: &Session, span: Span, path: &hir::Path) {
+    let name = pprust::path_to_string(path);
+    span_err!(sess, span, E0164,
+        "`{}` does not name a tuple variant or a tuple struct", name);
+}
+
 pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                                 pat: &hir::Pat,
                                 path: &hir::Path,
                                 subpats: Option<&'tcx [P<hir::Pat>]>,
-                                expected: Ty<'tcx>)
+                                expected: Ty<'tcx>,
+                                is_tuple_struct_pat: bool)
 {
     // Typecheck the path.
     let fcx = pcx.fcx;
@@ -618,25 +634,43 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
                      path_scheme, &ctor_predicates,
                      opt_ty, def, pat.span, pat.id);
 
+    let report_bad_struct_kind = || {
+        bad_struct_kind_err(tcx.sess, pat.span, path);
+        fcx.write_error(pat.id);
+
+        if let Some(subpats) = subpats {
+            for pat in subpats {
+                check_pat(pcx, &**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 {
-        let pat_ty = fcx.node_ty(pat.id);
-        demand::suptype(fcx, pat.span, expected, pat_ty);
+        if is_tuple_struct_pat {
+            report_bad_struct_kind();
+        } else {
+            let pat_ty = fcx.node_ty(pat.id);
+            demand::suptype(fcx, pat.span, expected, pat_ty);
+        }
         return;
     }
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
 
-
     let real_path_ty = fcx.node_ty(pat.id);
     let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
         ty::TyEnum(enum_def, expected_substs)
             if def == def::DefVariant(enum_def.did, def.def_id(), false) =>
         {
             let variant = enum_def.variant_of_def(def);
+            if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
+                report_bad_struct_kind();
+                return;
+            }
             (variant.fields
                     .iter()
                     .map(|f| fcx.instantiate_type_scheme(pat.span,
@@ -646,26 +680,21 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
              "variant")
         }
         ty::TyStruct(struct_def, expected_substs) => {
-            (struct_def.struct_variant()
-                       .fields
-                       .iter()
-                       .map(|f| fcx.instantiate_type_scheme(pat.span,
-                                                            expected_substs,
-                                                            &f.unsubst_ty()))
-                       .collect(),
+            let variant = struct_def.struct_variant();
+            if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
+                report_bad_struct_kind();
+                return;
+            }
+            (variant.fields
+                    .iter()
+                    .map(|f| fcx.instantiate_type_scheme(pat.span,
+                                                         expected_substs,
+                                                         &f.unsubst_ty()))
+                    .collect(),
              "struct")
         }
         _ => {
-            let name = pprust::path_to_string(path);
-            span_err!(tcx.sess, pat.span, E0164,
-                "`{}` does not name a non-struct variant or a tuple struct", name);
-            fcx.write_error(pat.id);
-
-            if let Some(subpats) = subpats {
-                for pat in subpats {
-                    check_pat(pcx, &**pat, tcx.types.err);
-                }
-            }
+            report_bad_struct_kind();
             return;
         }
     };
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a635c1b047d..bed22aa1e93 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1446,7 +1446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                               -> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
     {
         let (adt, variant) = match def {
-            def::DefVariant(enum_id, variant_id, true) => {
+            def::DefVariant(enum_id, variant_id, _) => {
                 let adt = self.tcx().lookup_adt_def(enum_id);
                 (adt, adt.variant_with_id(variant_id))
             }
diff --git a/src/test/compile-fail/empty-struct-braces-gate-2.rs b/src/test/compile-fail/empty-struct-braces-gate-2.rs
index c1b73bdc96a..b2d44301eed 100644
--- a/src/test/compile-fail/empty-struct-braces-gate-2.rs
+++ b/src/test/compile-fail/empty-struct-braces-gate-2.rs
@@ -20,8 +20,7 @@ enum E {
 fn main() {
     let e2: Empty2 = Empty2 {}; //~ ERROR empty structs and enum variants with braces are unstable
     let e2: Empty2 = Empty2;
-    // Issue #28692
-    // let e5: E = E::Empty5 {}; // ERROR empty structs and enum variants with braces are unstable
+    let e5: E = E::Empty5 {}; //~ ERROR empty structs and enum variants with braces are unstable
     let e5: E = E::Empty5;
 
     match e2 {
@@ -33,17 +32,15 @@ fn main() {
     match e2 {
         Empty2 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable
     }
-    // Issue #28692
-    // match e5 {
-    //     E::Empty5 {} => {} // ERROR empty structs and enum variants with braces are unstable
-    // }
+    match e5 {
+        E::Empty5 {} => {} //~ ERROR empty structs and enum variants with braces are unstable
+    }
     match e5 {
         E::Empty5 => {}
     }
-    // Issue #28692
-    // match e5 {
-    //     E::Empty5 { .. } => {} // ERROR empty structs and enum variants with braces are unstable
-    // }
+    match e5 {
+        E::Empty5 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable
+    }
 
     let e22 = Empty2 { ..e2 }; //~ ERROR empty structs and enum variants with braces are unstable
 }
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 e095f69ed7d..6a6c3f16c04 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-1.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs
@@ -10,7 +10,6 @@
 
 // Can't use empty braced struct as constant pattern
 
-#![deny(warnings)]
 #![feature(braced_empty_structs)]
 
 struct Empty1 {}
@@ -23,11 +22,10 @@ fn main() {
     let e1 = Empty1 {};
     let e2 = E::Empty2 {};
 
-    // Issue #28692
-    // match e1 {
-    //     Empty1 => () // ERROR incorrect error
-    // }
+    match e1 {
+        Empty1 => () // Not an error, `Empty1` is interpreted as a new binding
+    }
     match e2 {
-        E::Empty2 => () //~ ERROR `E::Empty2` does not name a non-struct variant or a tuple struct
+        E::Empty2 => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
     }
 }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs
index 0e7152ec89a..d98d64b712a 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-2.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs
@@ -14,13 +14,8 @@
 
 struct Empty1 {}
 
-enum E {
-    Empty2 {}
-}
-
 fn main() {
     let e1 = Empty1 {};
-    let e2 = E::Empty2 {};
 
     // Rejected by parser as yet
     // match e1 {
@@ -29,11 +24,4 @@ fn main() {
     match e1 {
         Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
     }
-    // Issue #28692
-    // match e2 {
-    //     E::Empty2() => () // ERROR unresolved enum variant, struct or const `Empty2`
-    // }
-    // match e2 {
-    //     E::Empty2(..) => () // ERROR unresolved enum variant, struct or const `Empty2`
-    // }
 }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs
new file mode 100644
index 00000000000..9fae203f389
--- /dev/null
+++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs
@@ -0,0 +1,29 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use empty braced struct as enum pattern
+
+#![feature(braced_empty_structs)]
+
+enum E {
+    Empty2 {}
+}
+
+fn main() {
+    let e2 = E::Empty2 {};
+
+    // Rejected by parser as yet
+    // match e2 {
+    //     E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct
+    // }
+    match e2 {
+        E::Empty2(..) => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
+    }
+}
diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs
index 966a2780f9f..f9af71527a1 100644
--- a/src/test/compile-fail/empty-struct-unit-pat.rs
+++ b/src/test/compile-fail/empty-struct-unit-pat.rs
@@ -12,8 +12,6 @@
 
 #![feature(braced_empty_structs)]
 
-FIXME //~ ERROR expected item, found `FIXME`
-
 struct Empty1;
 
 enum E {
@@ -24,17 +22,18 @@ fn main() {
     let e1 = Empty1;
     let e2 = E::Empty2;
 
-    // Issue #28692
-    // match e1 {
-    //     Empty1() => () // ERROR variable `Empty1` should have a snake case name
-    // }
+    // Rejected by parser as yet
     // match e1 {
-    //     Empty1(..) => () // ERROR variable `Empty1` should have a snake case name
-    // }
-    // match e2 {
-    //     E::Empty2() => () // ERROR variable `Empty2` should have a snake case name
+    //     Empty1() => () // ERROR `Empty1` does not name a tuple variant or a tuple struct
     // }
+    match e1 {
+        Empty1(..) => () //~ ERROR `Empty1` does not name a tuple variant or a tuple struct
+    }
+    // Rejected by parser as yet
     // match e2 {
-    //     E::Empty2(..) => () // ERROR variable `Empty2` should have a snake case name
+    //     E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct
     // }
+    match e2 {
+        E::Empty2(..) => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
+    }
 }
diff --git a/src/test/compile-fail/issue-19086.rs b/src/test/compile-fail/issue-19086.rs
index 69201859457..56452449d4e 100644
--- a/src/test/compile-fail/issue-19086.rs
+++ b/src/test/compile-fail/issue-19086.rs
@@ -18,6 +18,6 @@ fn main() {
     let f = FooB { x: 3, y: 4 };
     match f {
         FooB(a, b) => println!("{} {}", a, b),
-//~^ ERROR `FooB` does not name a non-struct variant or a tuple struct
+//~^ ERROR `FooB` does not name a tuple variant or a tuple struct
     }
 }
diff --git a/src/test/compile-fail/issue-27831.rs b/src/test/compile-fail/issue-27831.rs
index 3cdb370f0e9..ff2846dc705 100644
--- a/src/test/compile-fail/issue-27831.rs
+++ b/src/test/compile-fail/issue-27831.rs
@@ -26,7 +26,7 @@ fn main() {
     let Bar { .. } = x; //~ ERROR empty structs and enum variants with braces are unstable
 
     match Enum::Bar {
-        Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct
+        Enum::Bar { .. } //~ ERROR empty structs and enum variants with braces are unstable
            => {}
         Enum::Foo { .. } //~ ERROR `Enum::Foo` does not name a struct
            => {}
diff --git a/src/test/compile-fail/issue-28992-empty.rs b/src/test/compile-fail/issue-28992-empty.rs
new file mode 100644
index 00000000000..f7d53ba23da
--- /dev/null
+++ b/src/test/compile-fail/issue-28992-empty.rs
@@ -0,0 +1,26 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use constants as tuple struct patterns
+
+#![feature(associated_consts)]
+
+const C1: i32 = 0;
+
+struct S;
+
+impl S {
+    const C2: i32 = 0;
+}
+
+fn main() {
+    if let C1(..) = 0 {} //~ ERROR `C1` does not name a tuple variant or a tuple struct
+    if let S::C2(..) = 0 {} //~ ERROR `S::C2` does not name a tuple variant or a tuple struct
+}
diff --git a/src/test/compile-fail/match-pattern-field-mismatch-2.rs b/src/test/compile-fail/match-pattern-field-mismatch-2.rs
index e63ddf6c7fd..a4ba93ea173 100644
--- a/src/test/compile-fail/match-pattern-field-mismatch-2.rs
+++ b/src/test/compile-fail/match-pattern-field-mismatch-2.rs
@@ -20,7 +20,7 @@ fn main() {
           color::rgb(_, _, _) => { }
           color::cmyk(_, _, _, _) => { }
           color::no_color(_) => { }
-          //~^ ERROR this pattern has 1 field, but the corresponding variant has no fields
+          //~^ ERROR `color::no_color` does not name a tuple variant or a tuple struct
         }
     }
 }
diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs
index aa7202574ab..891a586423e 100644
--- a/src/test/compile-fail/pattern-error-continue.rs
+++ b/src/test/compile-fail/pattern-error-continue.rs
@@ -25,7 +25,7 @@ fn f(_c: char) {}
 fn main() {
     match A::B(1, 2) {
         A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but
-        A::D(_) => (),       //~ ERROR this pattern has 1 field, but
+        A::D(_) => (),       //~ ERROR `A::D` does not name a tuple variant or a tuple struct
         _ => ()
     }
     match 'c' {
diff --git a/src/test/run-pass/empty-struct-braces.rs b/src/test/run-pass/empty-struct-braces.rs
index f2fbf2dd337..80ea1bc3a0e 100644
--- a/src/test/run-pass/empty-struct-braces.rs
+++ b/src/test/run-pass/empty-struct-braces.rs
@@ -30,7 +30,7 @@ fn main() {
     let e3: Empty3 = Empty3 {};
     let e3: Empty3 = Empty3;
     let e4: E = E::Empty4 {};
-    // let e5: E = E::Empty5 {}; // Issue #28692
+    let e5: E = E::Empty5 {};
     let e5: E = E::Empty5;
 
     match e1 {
@@ -46,11 +46,10 @@ fn main() {
         E::Empty4 {} => {}
         _ => {}
     }
-    // Issue #28692
-    // match e5 {
-    //     E::Empty5 {} => {}
-    //     _ => {}
-    // }
+    match e5 {
+        E::Empty5 {} => {}
+        _ => {}
+    }
 
     match e1 {
         Empty1 { .. } => {}
@@ -65,11 +64,10 @@ fn main() {
         E::Empty4 { .. } => {}
         _ => {}
     }
-    // Issue #28692
-    // match e5 {
-    //     E::Empty5 { .. } => {}
-    //     _ => {}
-    // }
+    match e5 {
+        E::Empty5 { .. } => {}
+        _ => {}
+    }
 
     match e2 {
         Empty2 => {}