Skip to content

Commit c95b280

Browse files
committed
Move pattern resolution checks from typeck to resolve
Make error messages more precise
1 parent e8ea38e commit c95b280

33 files changed

+125
-113
lines changed

src/librustc/hir/def.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,16 @@ impl Def {
140140
Def::Mod(..) => "module",
141141
Def::Static(..) => "static",
142142
Def::Variant(..) => "variant",
143-
Def::VariantCtor(..) => "variant",
143+
Def::VariantCtor(.., CtorKind::Fn) => "tuple variant",
144+
Def::VariantCtor(.., CtorKind::Const) => "unit variant",
145+
Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
144146
Def::Enum(..) => "enum",
145-
Def::TyAlias(..) => "type",
147+
Def::TyAlias(..) => "type alias",
146148
Def::AssociatedTy(..) => "associated type",
147149
Def::Struct(..) => "struct",
148-
Def::StructCtor(..) => "struct",
150+
Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
151+
Def::StructCtor(.., CtorKind::Const) => "unit struct",
152+
Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
149153
Def::Union(..) => "union",
150154
Def::Trait(..) => "trait",
151155
Def::Method(..) => "method",

src/librustc_resolve/lib.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
485485
E0531,
486486
"unresolved {} `{}`",
487487
expected_what,
488-
path.segments.last().unwrap().identifier)
488+
path)
489489
}
490490
ResolutionError::PatPathUnexpected(expected_what, found_what, path) => {
491491
struct_span_err!(resolver.session,
@@ -494,7 +494,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
494494
"expected {}, found {} `{}`",
495495
expected_what,
496496
found_what,
497-
path.segments.last().unwrap().identifier)
497+
path)
498498
}
499499
}
500500
}
@@ -2376,15 +2376,16 @@ impl<'a> Resolver<'a> {
23762376
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
23772377
bmode != BindingMode::ByValue(Mutability::Immutable);
23782378
match def {
2379-
Def::StructCtor(..) | Def::VariantCtor(..) |
2380-
Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
2381-
// A constant, unit variant, etc pattern.
2379+
Def::StructCtor(_, CtorKind::Const) |
2380+
Def::VariantCtor(_, CtorKind::Const) |
2381+
Def::Const(..) if !always_binding => {
2382+
// A unit struct/variant or constant pattern.
23822383
let name = ident.node.name;
23832384
self.record_use(name, ValueNS, binding.unwrap(), ident.span);
23842385
Some(PathResolution::new(def))
23852386
}
23862387
Def::StructCtor(..) | Def::VariantCtor(..) |
2387-
Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => {
2388+
Def::Const(..) | Def::Static(..) => {
23882389
// A fresh binding that shadows something unacceptable.
23892390
resolve_error(
23902391
self,
@@ -2401,7 +2402,7 @@ impl<'a> Resolver<'a> {
24012402
}
24022403
def => {
24032404
span_bug!(ident.span, "unexpected definition for an \
2404-
identifier in pattern {:?}", def);
2405+
identifier in pattern: {:?}", def);
24052406
}
24062407
}
24072408
}).unwrap_or_else(|| {
@@ -2411,23 +2412,29 @@ impl<'a> Resolver<'a> {
24112412
self.record_def(pat.id, resolution);
24122413
}
24132414

2414-
PatKind::TupleStruct(ref path, ..) => {
2415+
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
24152416
self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
24162417
match def {
2417-
Def::StructCtor(..) | Def::VariantCtor(..) => true,
2418+
Def::StructCtor(_, CtorKind::Fn) |
2419+
Def::VariantCtor(_, CtorKind::Fn) => true,
2420+
// `UnitVariant(..)` is accepted for backward compatibility.
2421+
Def::StructCtor(_, CtorKind::Const) |
2422+
Def::VariantCtor(_, CtorKind::Const)
2423+
if pats.is_empty() && ddpos.is_some() => true,
24182424
_ => false,
24192425
}
2420-
}, "variant or struct");
2426+
}, "tuple struct/variant");
24212427
}
24222428

24232429
PatKind::Path(ref qself, ref path) => {
24242430
self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| {
24252431
match def {
2426-
Def::StructCtor(..) | Def::VariantCtor(..) |
2432+
Def::StructCtor(_, CtorKind::Const) |
2433+
Def::VariantCtor(_, CtorKind::Const) |
24272434
Def::Const(..) | Def::AssociatedConst(..) => true,
24282435
_ => false,
24292436
}
2430-
}, "variant, struct or constant");
2437+
}, "unit struct/variant or constant");
24312438
}
24322439

24332440
PatKind::Struct(ref path, ..) => {

src/librustc_typeck/check/_match.rs

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use hir::def::Def;
11+
use rustc::hir::{self, PatKind};
12+
use rustc::hir::def::{Def, CtorKind};
13+
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
1214
use rustc::infer::{self, InferOk, TypeOrigin};
13-
use hir::pat_util::EnumerateAndAdjustIterator;
14-
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
15+
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
1516
use check::{FnCtxt, Expectation};
1617
use lint;
1718
use util::nodemap::FnvHashMap;
@@ -23,9 +24,6 @@ use syntax::codemap::Spanned;
2324
use syntax::ptr::P;
2425
use syntax_pos::Span;
2526

26-
use rustc::hir::{self, PatKind};
27-
use rustc::hir::print as pprust;
28-
2927
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
3028
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
3129
let tcx = self.tcx;
@@ -516,10 +514,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
516514
expected: Ty<'tcx>) -> Ty<'tcx>
517515
{
518516
let tcx = self.tcx;
519-
let report_unexpected_def = || {
517+
let report_unexpected_def = |def: Def| {
520518
span_err!(tcx.sess, pat.span, E0533,
521-
"`{}` does not name a unit variant, unit struct or a constant",
522-
pprust::path_to_string(path));
519+
"expected unit struct/variant or constant, found {} `{}`",
520+
def.kind_name(), path);
523521
};
524522

525523
// Resolve the path and check the definition for errors.
@@ -531,18 +529,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
531529
return tcx.types.err;
532530
}
533531
Def::Method(..) => {
534-
report_unexpected_def();
532+
report_unexpected_def(def);
535533
return tcx.types.err;
536534
}
537-
Def::VariantCtor(..) | Def::StructCtor(..) => {
538-
let variant = tcx.expect_variant_def(def);
539-
if variant.kind != VariantKind::Unit {
540-
report_unexpected_def();
541-
return tcx.types.err;
542-
}
543-
}
535+
Def::VariantCtor(_, CtorKind::Const) |
536+
Def::StructCtor(_, CtorKind::Const) |
544537
Def::Const(..) | Def::AssociatedConst(..) => {} // OK
545-
_ => bug!("unexpected pattern definition {:?}", def)
538+
_ => bug!("unexpected pattern definition: {:?}", def)
546539
}
547540

548541
// Type check the path.
@@ -564,9 +557,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
564557
self.check_pat(&pat, tcx.types.err);
565558
}
566559
};
567-
let report_unexpected_def = |is_lint| {
568-
let msg = format!("`{}` does not name a tuple variant or a tuple struct",
569-
pprust::path_to_string(path));
560+
let report_unexpected_def = |def: Def, is_lint| {
561+
let msg = format!("expected tuple struct/variant, found {} `{}`",
562+
def.kind_name(), path);
570563
if is_lint {
571564
tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
572565
pat.id, pat.span, msg);
@@ -585,23 +578,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
585578
on_error();
586579
return tcx.types.err;
587580
}
588-
Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
589-
report_unexpected_def(false);
581+
Def::AssociatedConst(..) | Def::Method(..) => {
582+
report_unexpected_def(def, false);
590583
return tcx.types.err;
591584
}
592-
Def::VariantCtor(..) | Def::StructCtor(..) => {
585+
Def::VariantCtor(_, ctor_kind) | Def::StructCtor(_, ctor_kind) => {
586+
if ctor_kind == CtorKind::Const {
587+
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
588+
// is allowed for backward compatibility.
589+
report_unexpected_def(def, true);
590+
}
593591
tcx.expect_variant_def(def)
594592
}
595-
_ => bug!("unexpected pattern definition {:?}", def)
593+
_ => bug!("unexpected pattern definition: {:?}", def)
596594
};
597-
if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() {
598-
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
599-
// is allowed for backward compatibility.
600-
report_unexpected_def(true);
601-
} else if variant.kind != VariantKind::Tuple {
602-
report_unexpected_def(false);
603-
return tcx.types.err;
604-
}
605595

606596
// Type check the path.
607597
let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
@@ -626,16 +616,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
626616
self.check_pat(&subpat, field_ty);
627617
}
628618
} else {
629-
let subpats_ending = if subpats.len() == 1 {
630-
""
631-
} else {
632-
"s"
633-
};
634-
let fields_ending = if variant.fields.len() == 1 {
635-
""
636-
} else {
637-
"s"
638-
};
619+
let subpats_ending = if subpats.len() == 1 { "" } else { "s" };
620+
let fields_ending = if variant.fields.len() == 1 { "" } else { "s" };
639621
struct_span_err!(tcx.sess, pat.span, E0023,
640622
"this pattern has {} field{}, but the corresponding {} has {} field{}",
641623
subpats.len(), subpats_ending, def.kind_name(),

src/test/compile-fail/E0164.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
enum Foo { B { i: u32 } }
11+
#![feature(associated_consts)]
12+
13+
enum Foo {}
14+
15+
impl Foo {
16+
const B: u8 = 0;
17+
}
1218

1319
fn bar(foo: Foo) -> u32 {
1420
match foo {

src/test/compile-fail/blind-item-block-middle.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ mod foo { pub struct bar; }
1212

1313
fn main() {
1414
let bar = 5;
15-
//~^ ERROR let bindings cannot shadow structs
15+
//~^ ERROR let bindings cannot shadow unit structs
1616
use foo::bar;
1717
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ fn main() {
3232
}
3333
match e3 {
3434
E::Empty3 => ()
35-
//~^ ERROR `E::Empty3` does not name a unit variant, unit struct or a constant
35+
//~^ ERROR expected unit struct/variant or constant, found struct variant `E::Empty3`
3636
}
3737
match xe1 {
3838
XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
3939
}
4040
match xe3 {
4141
XE::XEmpty3 => ()
42-
//~^ ERROR `XE::XEmpty3` does not name a unit variant, unit struct or a constant
42+
//~^ ERROR expected unit struct/variant or constant, found struct variant `XE::XEmpty3`
4343
}
4444
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ fn main() {
2424
let xe1 = XEmpty1 {};
2525

2626
match e1 {
27-
Empty1() => () //~ ERROR unresolved variant or struct `Empty1`
27+
Empty1() => () //~ ERROR unresolved tuple struct/variant `Empty1`
2828
}
2929
match xe1 {
30-
XEmpty1() => () //~ ERROR unresolved variant or struct `XEmpty1`
30+
XEmpty1() => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
3131
}
3232
match e1 {
33-
Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1`
33+
Empty1(..) => () //~ ERROR unresolved tuple struct/variant `Empty1`
3434
}
3535
match xe1 {
36-
XEmpty1(..) => () //~ ERROR unresolved variant or struct `XEmpty1`
36+
XEmpty1(..) => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
3737
}
3838
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ fn main() {
2626
let xe3 = XE::XEmpty3 {};
2727

2828
match e3 {
29-
E::Empty3() => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
29+
E::Empty3() => ()
30+
//~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3`
3031
}
3132
match xe3 {
32-
XE::XEmpty3() => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
33+
XE::XEmpty3() => ()
34+
//~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3`
3335
}
3436
match e3 {
35-
E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
37+
E::Empty3(..) => ()
38+
//~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3`
3639
}
3740
match xe3 {
38-
XE::XEmpty3(..) => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple
41+
XE::XEmpty3(..) => ()
42+
//~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3
3943
}
4044
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,19 @@ fn main() {
3131
let xe5 = XE::XEmpty5();
3232

3333
match e2 {
34-
Empty2 => () //~ ERROR `Empty2` does not name a unit variant, unit struct or a constant
34+
Empty2 => () //~ ERROR match bindings cannot shadow tuple structs
3535
}
3636
match xe6 {
37-
XEmpty6 => () //~ ERROR `XEmpty6` does not name a unit variant, unit struct or a constant
37+
XEmpty6 => () //~ ERROR match bindings cannot shadow tuple structs
3838
}
3939

4040
match e4 {
41-
E::Empty4 => () //~ ERROR `E::Empty4` does not name a unit variant, unit struct or a
41+
E::Empty4 => ()
42+
//~^ ERROR expected unit struct/variant or constant, found tuple variant `E::Empty4`
4243
}
4344
match xe5 {
44-
XE::XEmpty5 => (), //~ ERROR `XE::XEmpty5` does not name a unit variant, unit struct or a
45+
XE::XEmpty5 => (),
46+
//~^ ERROR expected unit struct/variant or constant, found tuple variant `XE::XEmpty5`
4547
_ => {},
4648
}
4749
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,22 @@ fn main() {
3131
let xe4 = XE::XEmpty4;
3232

3333
match e2 {
34-
Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
34+
Empty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2`
3535
//~^ WARNING hard error
3636
}
3737
match xe2 {
38-
XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
38+
XEmpty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
3939
//~^ WARNING hard error
4040
}
4141

4242
match e4 {
43-
E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
43+
E::Empty4(..) => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
4444
//~^ WARNING hard error
4545
}
4646
match xe4 {
47-
XE::XEmpty4(..) => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
48-
//~^ WARNING hard error
47+
XE::XEmpty4(..) => (),
48+
//~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
49+
//~| WARNING hard error
4950
_ => {},
5051
}
5152
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,28 @@ enum E {
2323
Empty4
2424
}
2525

26-
// remove attribute after warning cycle and promoting warnings to errors
2726
fn main() {
2827
let e2 = Empty2;
2928
let e4 = E::Empty4;
3029
let xe2 = XEmpty2;
3130
let xe4 = XE::XEmpty4;
3231

3332
match e2 {
34-
Empty2() => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
33+
Empty2() => ()
34+
//~^ ERROR expected tuple struct/variant, found unit struct `Empty2`
3535
}
3636
match xe2 {
37-
XEmpty2() => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
37+
XEmpty2() => ()
38+
//~^ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
3839
}
3940

4041
match e4 {
41-
E::Empty4() => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
42+
E::Empty4() => ()
43+
//~^ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
4244
}
4345
match xe4 {
44-
XE::XEmpty4() => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
46+
XE::XEmpty4() => (),
47+
//~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
4548
_ => {},
4649
}
4750
}

0 commit comments

Comments
 (0)