Skip to content

Commit 0f8519c

Browse files
committed
Fix various bugs around empty structs and patterns
1 parent 3e48b0e commit 0f8519c

14 files changed

+143
-79
lines changed

src/librustc_mir/hair/cx/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
178178
}
179179
ty::TyEnum(adt, substs) => {
180180
match cx.tcx.def_map.borrow()[&self.id].full_def() {
181-
def::DefVariant(enum_id, variant_id, true) => {
181+
def::DefVariant(enum_id, variant_id, _) => {
182182
debug_assert!(adt.did == enum_id);
183183
let index = adt.variant_index_with_id(variant_id);
184184
let field_refs = field_refs(&adt.variants[index], fields);

src/librustc_typeck/check/_match.rs

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use check::{check_expr_with_lvalue_pref};
2121
use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
2222
use require_same_types;
2323
use util::nodemap::FnvHashMap;
24+
use session::Session;
2425

2526
use std::cmp;
2627
use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -136,6 +137,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
136137
}
137138
hir::PatEnum(..) | hir::PatIdent(..)
138139
if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
140+
if let hir::PatEnum(ref path, ref subpats) = pat.node {
141+
if !(subpats.is_some() && subpats.as_ref().unwrap().is_empty()) {
142+
bad_struct_kind_err(tcx.sess, pat.span, path);
143+
return;
144+
}
145+
}
139146
let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
140147
let const_scheme = tcx.lookup_item_type(const_did);
141148
assert!(const_scheme.generics.is_empty());
@@ -192,11 +199,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
192199
}
193200
hir::PatIdent(_, ref path, _) => {
194201
let path = hir_util::ident_to_path(path.span, path.node);
195-
check_pat_enum(pcx, pat, &path, Some(&[]), expected);
202+
check_pat_enum(pcx, pat, &path, Some(&[]), expected, false);
196203
}
197204
hir::PatEnum(ref path, ref subpats) => {
198205
let subpats = subpats.as_ref().map(|v| &v[..]);
199-
check_pat_enum(pcx, pat, path, subpats, expected);
206+
let is_tuple_struct_pat = !(subpats.is_some() && subpats.unwrap().is_empty());
207+
check_pat_enum(pcx, pat, path, subpats, expected, is_tuple_struct_pat);
200208
}
201209
hir::PatQPath(ref qself, ref path) => {
202210
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,
572580
fcx.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() });
573581
}
574582

583+
// This function exists due to the warning "diagnostic code E0164 already used"
584+
fn bad_struct_kind_err(sess: &Session, span: Span, path: &hir::Path) {
585+
let name = pprust::path_to_string(path);
586+
span_err!(sess, span, E0164,
587+
"`{}` does not name a tuple variant or a tuple struct", name);
588+
}
589+
575590
pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
576591
pat: &hir::Pat,
577592
path: &hir::Path,
578593
subpats: Option<&'tcx [P<hir::Pat>]>,
579-
expected: Ty<'tcx>)
594+
expected: Ty<'tcx>,
595+
is_tuple_struct_pat: bool)
580596
{
581597
// Typecheck the path.
582598
let fcx = pcx.fcx;
@@ -618,25 +634,43 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
618634
path_scheme, &ctor_predicates,
619635
opt_ty, def, pat.span, pat.id);
620636

637+
let report_bad_struct_kind = || {
638+
bad_struct_kind_err(tcx.sess, pat.span, path);
639+
fcx.write_error(pat.id);
640+
641+
if let Some(subpats) = subpats {
642+
for pat in subpats {
643+
check_pat(pcx, &**pat, tcx.types.err);
644+
}
645+
}
646+
};
647+
621648
// If we didn't have a fully resolved path to start with, we had an
622649
// associated const, and we should quit now, since the rest of this
623650
// function uses checks specific to structs and enums.
624651
if path_res.depth != 0 {
625-
let pat_ty = fcx.node_ty(pat.id);
626-
demand::suptype(fcx, pat.span, expected, pat_ty);
652+
if is_tuple_struct_pat {
653+
report_bad_struct_kind();
654+
} else {
655+
let pat_ty = fcx.node_ty(pat.id);
656+
demand::suptype(fcx, pat.span, expected, pat_ty);
657+
}
627658
return;
628659
}
629660

630661
let pat_ty = fcx.node_ty(pat.id);
631662
demand::eqtype(fcx, pat.span, expected, pat_ty);
632663

633-
634664
let real_path_ty = fcx.node_ty(pat.id);
635665
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
636666
ty::TyEnum(enum_def, expected_substs)
637667
if def == def::DefVariant(enum_def.did, def.def_id(), false) =>
638668
{
639669
let variant = enum_def.variant_of_def(def);
670+
if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
671+
report_bad_struct_kind();
672+
return;
673+
}
640674
(variant.fields
641675
.iter()
642676
.map(|f| fcx.instantiate_type_scheme(pat.span,
@@ -646,26 +680,21 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
646680
"variant")
647681
}
648682
ty::TyStruct(struct_def, expected_substs) => {
649-
(struct_def.struct_variant()
650-
.fields
651-
.iter()
652-
.map(|f| fcx.instantiate_type_scheme(pat.span,
653-
expected_substs,
654-
&f.unsubst_ty()))
655-
.collect(),
683+
let variant = struct_def.struct_variant();
684+
if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
685+
report_bad_struct_kind();
686+
return;
687+
}
688+
(variant.fields
689+
.iter()
690+
.map(|f| fcx.instantiate_type_scheme(pat.span,
691+
expected_substs,
692+
&f.unsubst_ty()))
693+
.collect(),
656694
"struct")
657695
}
658696
_ => {
659-
let name = pprust::path_to_string(path);
660-
span_err!(tcx.sess, pat.span, E0164,
661-
"`{}` does not name a non-struct variant or a tuple struct", name);
662-
fcx.write_error(pat.id);
663-
664-
if let Some(subpats) = subpats {
665-
for pat in subpats {
666-
check_pat(pcx, &**pat, tcx.types.err);
667-
}
668-
}
697+
report_bad_struct_kind();
669698
return;
670699
}
671700
};

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1446,7 +1446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14461446
-> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
14471447
{
14481448
let (adt, variant) = match def {
1449-
def::DefVariant(enum_id, variant_id, true) => {
1449+
def::DefVariant(enum_id, variant_id, _) => {
14501450
let adt = self.tcx().lookup_adt_def(enum_id);
14511451
(adt, adt.variant_with_id(variant_id))
14521452
}

src/test/compile-fail/empty-struct-braces-gate-2.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ enum E {
2020
fn main() {
2121
let e2: Empty2 = Empty2 {}; //~ ERROR empty structs and enum variants with braces are unstable
2222
let e2: Empty2 = Empty2;
23-
// Issue #28692
24-
// let e5: E = E::Empty5 {}; // ERROR empty structs and enum variants with braces are unstable
23+
let e5: E = E::Empty5 {}; //~ ERROR empty structs and enum variants with braces are unstable
2524
let e5: E = E::Empty5;
2625

2726
match e2 {
@@ -33,17 +32,15 @@ fn main() {
3332
match e2 {
3433
Empty2 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable
3534
}
36-
// Issue #28692
37-
// match e5 {
38-
// E::Empty5 {} => {} // ERROR empty structs and enum variants with braces are unstable
39-
// }
35+
match e5 {
36+
E::Empty5 {} => {} //~ ERROR empty structs and enum variants with braces are unstable
37+
}
4038
match e5 {
4139
E::Empty5 => {}
4240
}
43-
// Issue #28692
44-
// match e5 {
45-
// E::Empty5 { .. } => {} // ERROR empty structs and enum variants with braces are unstable
46-
// }
41+
match e5 {
42+
E::Empty5 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable
43+
}
4744

4845
let e22 = Empty2 { ..e2 }; //~ ERROR empty structs and enum variants with braces are unstable
4946
}

src/test/compile-fail/empty-struct-braces-pat-1.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
// Can't use empty braced struct as constant pattern
1212

13-
#![deny(warnings)]
1413
#![feature(braced_empty_structs)]
1514

1615
struct Empty1 {}
@@ -23,11 +22,10 @@ fn main() {
2322
let e1 = Empty1 {};
2423
let e2 = E::Empty2 {};
2524

26-
// Issue #28692
27-
// match e1 {
28-
// Empty1 => () // ERROR incorrect error
29-
// }
25+
match e1 {
26+
Empty1 => () // Not an error, `Empty1` is interpreted as a new binding
27+
}
3028
match e2 {
31-
E::Empty2 => () //~ ERROR `E::Empty2` does not name a non-struct variant or a tuple struct
29+
E::Empty2 => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
3230
}
3331
}

src/test/compile-fail/empty-struct-braces-pat-2.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,8 @@
1414

1515
struct Empty1 {}
1616

17-
enum E {
18-
Empty2 {}
19-
}
20-
2117
fn main() {
2218
let e1 = Empty1 {};
23-
let e2 = E::Empty2 {};
2419

2520
// Rejected by parser as yet
2621
// match e1 {
@@ -29,11 +24,4 @@ fn main() {
2924
match e1 {
3025
Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
3126
}
32-
// Issue #28692
33-
// match e2 {
34-
// E::Empty2() => () // ERROR unresolved enum variant, struct or const `Empty2`
35-
// }
36-
// match e2 {
37-
// E::Empty2(..) => () // ERROR unresolved enum variant, struct or const `Empty2`
38-
// }
3927
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Can't use empty braced struct as enum pattern
12+
13+
#![feature(braced_empty_structs)]
14+
15+
enum E {
16+
Empty2 {}
17+
}
18+
19+
fn main() {
20+
let e2 = E::Empty2 {};
21+
22+
// Rejected by parser as yet
23+
// match e2 {
24+
// E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct
25+
// }
26+
match e2 {
27+
E::Empty2(..) => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
28+
}
29+
}

src/test/compile-fail/empty-struct-unit-pat.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212

1313
#![feature(braced_empty_structs)]
1414

15-
FIXME //~ ERROR expected item, found `FIXME`
16-
1715
struct Empty1;
1816

1917
enum E {
@@ -24,17 +22,18 @@ fn main() {
2422
let e1 = Empty1;
2523
let e2 = E::Empty2;
2624

27-
// Issue #28692
28-
// match e1 {
29-
// Empty1() => () // ERROR variable `Empty1` should have a snake case name
30-
// }
25+
// Rejected by parser as yet
3126
// match e1 {
32-
// Empty1(..) => () // ERROR variable `Empty1` should have a snake case name
33-
// }
34-
// match e2 {
35-
// E::Empty2() => () // ERROR variable `Empty2` should have a snake case name
27+
// Empty1() => () // ERROR `Empty1` does not name a tuple variant or a tuple struct
3628
// }
29+
match e1 {
30+
Empty1(..) => () //~ ERROR `Empty1` does not name a tuple variant or a tuple struct
31+
}
32+
// Rejected by parser as yet
3733
// match e2 {
38-
// E::Empty2(..) => () // ERROR variable `Empty2` should have a snake case name
34+
// E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct
3935
// }
36+
match e2 {
37+
E::Empty2(..) => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
38+
}
4039
}

src/test/compile-fail/issue-19086.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ fn main() {
1818
let f = FooB { x: 3, y: 4 };
1919
match f {
2020
FooB(a, b) => println!("{} {}", a, b),
21-
//~^ ERROR `FooB` does not name a non-struct variant or a tuple struct
21+
//~^ ERROR `FooB` does not name a tuple variant or a tuple struct
2222
}
2323
}

src/test/compile-fail/issue-27831.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn main() {
2626
let Bar { .. } = x; //~ ERROR empty structs and enum variants with braces are unstable
2727

2828
match Enum::Bar {
29-
Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct
29+
Enum::Bar { .. } //~ ERROR empty structs and enum variants with braces are unstable
3030
=> {}
3131
Enum::Foo { .. } //~ ERROR `Enum::Foo` does not name a struct
3232
=> {}

0 commit comments

Comments
 (0)