1
Fork 0

Move pattern resolution checks from typeck to resolve

Make error messages more precise
This commit is contained in:
Vadim Petrochenkov 2016-09-15 00:51:46 +03:00
parent e8ea38e42a
commit c95b280d72
33 changed files with 125 additions and 113 deletions

View file

@ -140,12 +140,16 @@ impl Def {
Def::Mod(..) => "module",
Def::Static(..) => "static",
Def::Variant(..) => "variant",
Def::VariantCtor(..) => "variant",
Def::VariantCtor(.., CtorKind::Fn) => "tuple variant",
Def::VariantCtor(.., CtorKind::Const) => "unit variant",
Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
Def::Enum(..) => "enum",
Def::TyAlias(..) => "type",
Def::TyAlias(..) => "type alias",
Def::AssociatedTy(..) => "associated type",
Def::Struct(..) => "struct",
Def::StructCtor(..) => "struct",
Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
Def::StructCtor(.., CtorKind::Const) => "unit struct",
Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
Def::Union(..) => "union",
Def::Trait(..) => "trait",
Def::Method(..) => "method",

View file

@ -485,7 +485,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
E0531,
"unresolved {} `{}`",
expected_what,
path.segments.last().unwrap().identifier)
path)
}
ResolutionError::PatPathUnexpected(expected_what, found_what, path) => {
struct_span_err!(resolver.session,
@ -494,7 +494,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
"expected {}, found {} `{}`",
expected_what,
found_what,
path.segments.last().unwrap().identifier)
path)
}
}
}
@ -2376,15 +2376,16 @@ impl<'a> Resolver<'a> {
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
bmode != BindingMode::ByValue(Mutability::Immutable);
match def {
Def::StructCtor(..) | Def::VariantCtor(..) |
Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
// A constant, unit variant, etc pattern.
Def::StructCtor(_, CtorKind::Const) |
Def::VariantCtor(_, CtorKind::Const) |
Def::Const(..) if !always_binding => {
// A unit struct/variant or constant pattern.
let name = ident.node.name;
self.record_use(name, ValueNS, binding.unwrap(), ident.span);
Some(PathResolution::new(def))
}
Def::StructCtor(..) | Def::VariantCtor(..) |
Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => {
Def::Const(..) | Def::Static(..) => {
// A fresh binding that shadows something unacceptable.
resolve_error(
self,
@ -2401,7 +2402,7 @@ impl<'a> Resolver<'a> {
}
def => {
span_bug!(ident.span, "unexpected definition for an \
identifier in pattern {:?}", def);
identifier in pattern: {:?}", def);
}
}
}).unwrap_or_else(|| {
@ -2411,23 +2412,29 @@ impl<'a> Resolver<'a> {
self.record_def(pat.id, resolution);
}
PatKind::TupleStruct(ref path, ..) => {
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
match def {
Def::StructCtor(..) | Def::VariantCtor(..) => true,
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => true,
// `UnitVariant(..)` is accepted for backward compatibility.
Def::StructCtor(_, CtorKind::Const) |
Def::VariantCtor(_, CtorKind::Const)
if pats.is_empty() && ddpos.is_some() => true,
_ => false,
}
}, "variant or struct");
}, "tuple struct/variant");
}
PatKind::Path(ref qself, ref path) => {
self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| {
match def {
Def::StructCtor(..) | Def::VariantCtor(..) |
Def::StructCtor(_, CtorKind::Const) |
Def::VariantCtor(_, CtorKind::Const) |
Def::Const(..) | Def::AssociatedConst(..) => true,
_ => false,
}
}, "variant, struct or constant");
}, "unit struct/variant or constant");
}
PatKind::Struct(ref path, ..) => {

View file

@ -8,10 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hir::def::Def;
use rustc::hir::{self, PatKind};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::infer::{self, InferOk, TypeOrigin};
use hir::pat_util::EnumerateAndAdjustIterator;
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
use check::{FnCtxt, Expectation};
use lint;
use util::nodemap::FnvHashMap;
@ -23,9 +24,6 @@ use syntax::codemap::Spanned;
use syntax::ptr::P;
use syntax_pos::Span;
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
let tcx = self.tcx;
@ -516,10 +514,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
expected: Ty<'tcx>) -> Ty<'tcx>
{
let tcx = self.tcx;
let report_unexpected_def = || {
let report_unexpected_def = |def: Def| {
span_err!(tcx.sess, pat.span, E0533,
"`{}` does not name a unit variant, unit struct or a constant",
pprust::path_to_string(path));
"expected unit struct/variant or constant, found {} `{}`",
def.kind_name(), path);
};
// Resolve the path and check the definition for errors.
@ -531,18 +529,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
return tcx.types.err;
}
Def::Method(..) => {
report_unexpected_def();
report_unexpected_def(def);
return tcx.types.err;
}
Def::VariantCtor(..) | Def::StructCtor(..) => {
let variant = tcx.expect_variant_def(def);
if variant.kind != VariantKind::Unit {
report_unexpected_def();
return tcx.types.err;
}
}
Def::VariantCtor(_, CtorKind::Const) |
Def::StructCtor(_, CtorKind::Const) |
Def::Const(..) | Def::AssociatedConst(..) => {} // OK
_ => bug!("unexpected pattern definition {:?}", def)
_ => bug!("unexpected pattern definition: {:?}", def)
}
// Type check the path.
@ -564,9 +557,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.check_pat(&pat, tcx.types.err);
}
};
let report_unexpected_def = |is_lint| {
let msg = format!("`{}` does not name a tuple variant or a tuple struct",
pprust::path_to_string(path));
let report_unexpected_def = |def: Def, is_lint| {
let msg = format!("expected tuple struct/variant, found {} `{}`",
def.kind_name(), path);
if is_lint {
tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
pat.id, pat.span, msg);
@ -585,23 +578,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
on_error();
return tcx.types.err;
}
Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
report_unexpected_def(false);
Def::AssociatedConst(..) | Def::Method(..) => {
report_unexpected_def(def, false);
return tcx.types.err;
}
Def::VariantCtor(..) | Def::StructCtor(..) => {
Def::VariantCtor(_, ctor_kind) | Def::StructCtor(_, ctor_kind) => {
if ctor_kind == CtorKind::Const {
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
// is allowed for backward compatibility.
report_unexpected_def(def, true);
}
tcx.expect_variant_def(def)
}
_ => bug!("unexpected pattern definition {:?}", def)
_ => bug!("unexpected pattern definition: {:?}", 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 tcx.types.err;
}
// Type check the path.
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> {
self.check_pat(&subpat, field_ty);
}
} else {
let subpats_ending = if subpats.len() == 1 {
""
} else {
"s"
};
let fields_ending = if variant.fields.len() == 1 {
""
} else {
"s"
};
let subpats_ending = if subpats.len() == 1 { "" } else { "s" };
let fields_ending = if variant.fields.len() == 1 { "" } else { "s" };
struct_span_err!(tcx.sess, pat.span, E0023,
"this pattern has {} field{}, but the corresponding {} has {} field{}",
subpats.len(), subpats_ending, def.kind_name(),

View file

@ -8,7 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
enum Foo { B { i: u32 } }
#![feature(associated_consts)]
enum Foo {}
impl Foo {
const B: u8 = 0;
}
fn bar(foo: Foo) -> u32 {
match foo {

View file

@ -12,6 +12,6 @@ mod foo { pub struct bar; }
fn main() {
let bar = 5;
//~^ ERROR let bindings cannot shadow structs
//~^ ERROR let bindings cannot shadow unit structs
use foo::bar;
}

View file

@ -32,13 +32,13 @@ fn main() {
}
match e3 {
E::Empty3 => ()
//~^ ERROR `E::Empty3` does not name a unit variant, unit struct or a constant
//~^ ERROR expected unit struct/variant or constant, found struct variant `E::Empty3`
}
match xe1 {
XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
}
match xe3 {
XE::XEmpty3 => ()
//~^ ERROR `XE::XEmpty3` does not name a unit variant, unit struct or a constant
//~^ ERROR expected unit struct/variant or constant, found struct variant `XE::XEmpty3`
}
}

View file

@ -24,15 +24,15 @@ fn main() {
let xe1 = XEmpty1 {};
match e1 {
Empty1() => () //~ ERROR unresolved variant or struct `Empty1`
Empty1() => () //~ ERROR unresolved tuple struct/variant `Empty1`
}
match xe1 {
XEmpty1() => () //~ ERROR unresolved variant or struct `XEmpty1`
XEmpty1() => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
}
match e1 {
Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1`
Empty1(..) => () //~ ERROR unresolved tuple struct/variant `Empty1`
}
match xe1 {
XEmpty1(..) => () //~ ERROR unresolved variant or struct `XEmpty1`
XEmpty1(..) => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
}
}

View file

@ -26,15 +26,19 @@ fn main() {
let xe3 = XE::XEmpty3 {};
match e3 {
E::Empty3() => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
E::Empty3() => ()
//~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3`
}
match xe3 {
XE::XEmpty3() => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
XE::XEmpty3() => ()
//~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3`
}
match e3 {
E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
E::Empty3(..) => ()
//~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3`
}
match xe3 {
XE::XEmpty3(..) => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple
XE::XEmpty3(..) => ()
//~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3
}
}

View file

@ -31,17 +31,19 @@ fn main() {
let xe5 = XE::XEmpty5();
match e2 {
Empty2 => () //~ ERROR `Empty2` does not name a unit variant, unit struct or a constant
Empty2 => () //~ ERROR match bindings cannot shadow tuple structs
}
match xe6 {
XEmpty6 => () //~ ERROR `XEmpty6` does not name a unit variant, unit struct or a constant
XEmpty6 => () //~ ERROR match bindings cannot shadow tuple structs
}
match e4 {
E::Empty4 => () //~ ERROR `E::Empty4` does not name a unit variant, unit struct or a
E::Empty4 => ()
//~^ ERROR expected unit struct/variant or constant, found tuple variant `E::Empty4`
}
match xe5 {
XE::XEmpty5 => (), //~ ERROR `XE::XEmpty5` does not name a unit variant, unit struct or a
XE::XEmpty5 => (),
//~^ ERROR expected unit struct/variant or constant, found tuple variant `XE::XEmpty5`
_ => {},
}
}

View file

@ -31,21 +31,22 @@ fn main() {
let xe4 = XE::XEmpty4;
match e2 {
Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
Empty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2`
//~^ WARNING hard error
}
match xe2 {
XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
XEmpty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
//~^ WARNING hard error
}
match e4 {
E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
E::Empty4(..) => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
//~^ WARNING hard error
}
match xe4 {
XE::XEmpty4(..) => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
//~^ WARNING hard error
XE::XEmpty4(..) => (),
//~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
//~| WARNING hard error
_ => {},
}
}

View file

@ -23,7 +23,6 @@ enum E {
Empty4
}
// remove attribute after warning cycle and promoting warnings to errors
fn main() {
let e2 = Empty2;
let e4 = E::Empty4;
@ -31,17 +30,21 @@ fn main() {
let xe4 = XE::XEmpty4;
match e2 {
Empty2() => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct
Empty2() => ()
//~^ ERROR expected tuple struct/variant, found unit struct `Empty2`
}
match xe2 {
XEmpty2() => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct
XEmpty2() => ()
//~^ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
}
match e4 {
E::Empty4() => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct
E::Empty4() => ()
//~^ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
}
match xe4 {
XE::XEmpty4() => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
XE::XEmpty4() => (),
//~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
_ => {},
}
}

View file

@ -11,5 +11,5 @@
struct hello(isize);
fn main() {
let hello = 0; //~ERROR let bindings cannot shadow structs
let hello = 0; //~ERROR let bindings cannot shadow tuple structs
}

View file

@ -9,5 +9,5 @@
// except according to those terms.
fn main() {
let a(1) = 13; //~ ERROR unresolved variant or struct `a`
let a(1) = 13; //~ ERROR unresolved tuple struct/variant `a`
}

View file

@ -13,7 +13,7 @@ fn foo(_: usize) -> Foo { Foo(false) }
fn main() {
match Foo(true) {
foo(x) //~ ERROR expected variant or struct, found function `foo`
foo(x) //~ ERROR expected tuple struct/variant, found function `foo`
=> ()
}
}

View file

@ -12,6 +12,6 @@ mod foo { pub fn bar() {} }
fn main() {
match () {
foo::bar => {} //~ ERROR expected variant, struct or constant, found function `bar`
foo::bar => {} //~ ERROR expected unit struct/variant or constant, found function `foo::bar`
}
}

View file

@ -13,7 +13,7 @@ pub static X: usize = 1;
fn main() {
match 1 {
self::X => { },
//~^ ERROR expected variant, struct or constant, found static `X`
//~^ ERROR expected unit struct/variant or constant, found static `self::X`
_ => { },
}
}

View file

@ -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 tuple variant or a tuple struct
//~^ ERROR expected tuple struct/variant, found struct variant `FooB`
}
}

View file

@ -10,7 +10,7 @@
fn main() {
match Some(1) {
None @ _ => {} //~ ERROR match bindings cannot shadow variants
None @ _ => {} //~ ERROR match bindings cannot shadow unit variants
};
const C: u8 = 1;
match 1 {

View file

@ -14,7 +14,9 @@ fn main() {
let u = A { x: 1 }; //~ ERROR `A` does not name a struct or a struct variant
let v = u32 { x: 1 }; //~ ERROR `u32` does not name a struct or a struct variant
match () {
A { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found module `A`
u32 { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found builtin type `u32
A { x: 1 } => {}
//~^ ERROR expected variant, struct or type alias, found module `A`
u32 { x: 1 } => {}
//~^ ERROR expected variant, struct or type alias, found builtin type `u32`
}
}

View file

@ -21,6 +21,7 @@ impl S {
}
fn main() {
if let C1(..) = 0 {} //~ ERROR expected variant or struct, found constant `C1`
if let S::C2(..) = 0 {} //~ ERROR `S::C2` does not name a tuple variant or a tuple struct
if let C1(..) = 0 {} //~ ERROR expected tuple struct/variant, found constant `C1`
if let S::C2(..) = 0 {}
//~^ ERROR expected tuple struct/variant, found associated constant `S::C2`
}

View file

@ -18,12 +18,12 @@ struct S;
fn main() {
match Foo::Baz {
Foo::Bar => {}
//~^ ERROR `Foo::Bar` does not name a unit variant, unit struct or a constant
//~^ ERROR expected unit struct/variant or constant, found tuple variant `Foo::Bar`
_ => {}
}
match S {
S(()) => {}
//~^ ERROR `S` does not name a tuple variant or a tuple struct
//~^ ERROR expected tuple struct/variant, found unit struct `S`
}
}

View file

@ -12,6 +12,6 @@ struct S(u8);
const C: S = S(10);
fn main() {
let C(a) = S(11); //~ ERROR expected variant or struct, found constant `C`
let C(..) = S(11); //~ ERROR expected variant or struct, found constant `C`
let C(a) = S(11); //~ ERROR expected tuple struct/variant, found constant `C`
let C(..) = S(11); //~ ERROR expected tuple struct/variant, found constant `C`
}

View file

@ -11,7 +11,7 @@
fn main() {
let z = match 3 {
x(1) => x(1) //~ ERROR unresolved variant or struct `x`
x(1) => x(1) //~ ERROR unresolved tuple struct/variant `x`
//~^ ERROR unresolved name `x`
};
assert!(z == 3);

View file

@ -20,7 +20,7 @@ fn main() {
color::rgb(_, _, _) => { }
color::cmyk(_, _, _, _) => { }
color::no_color(_) => { }
//~^ ERROR `color::no_color` does not name a tuple variant or a tuple struct
//~^ ERROR expected tuple struct/variant, found unit variant `color::no_color`
}
}
}

View file

@ -18,7 +18,7 @@ fn main() {
fn foo(c: color) {
match c {
color::rgb(_, _) => { }
//~^ ERROR this pattern has 2 fields, but the corresponding variant has 3 fields
//~^ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields
color::cmyk(_, _, _, _) => { }
color::no_color => { }
}

View file

@ -22,13 +22,13 @@ impl MyTrait for Foo {}
fn main() {
match 0u32 {
Foo::bar => {} //~ ERROR `Foo::bar` does not name a unit variant, unit struct or a constant
Foo::bar => {} //~ ERROR expected unit struct/variant or constant, found method `Foo::bar`
}
match 0u32 {
<Foo>::bar => {} //~ ERROR `bar` does not name a unit variant, unit struct or a constant
<Foo>::bar => {} //~ ERROR expected unit struct/variant or constant, found method `bar`
}
match 0u32 {
<Foo>::trait_bar => {}
//~^ ERROR `trait_bar` does not name a unit variant, unit struct or a constant
//~^ ERROR expected unit struct/variant or constant, found method `trait_bar`
}
}

View file

@ -19,6 +19,6 @@ impl MyTrait for Foo {}
fn main() {
match 0u32 {
<Foo as MyTrait>::trait_bar => {}
//~^ ERROR expected variant, struct or constant, found method `trait_bar`
//~^ ERROR expected unit struct/variant or constant, found method `MyTrait::trait_bar`
}
}

View file

@ -11,7 +11,7 @@
use std::option::*;
fn main() {
let None: isize = 42; //~ ERROR let bindings cannot shadow variants
let None: isize = 42; //~ ERROR let bindings cannot shadow unit variants
log(debug, None);
//~^ ERROR unresolved name `debug`
//~| ERROR unresolved name `log`

View file

@ -11,5 +11,5 @@
struct foo(usize);
fn main() {
let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow structs
let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow tuple structs
}

View file

@ -20,9 +20,9 @@ fn main() {
}
match S(1, 2, 3) {
S(1, 2, 3, 4) => {}
//~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields
//~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields
S(1, 2, .., 3, 4) => {}
//~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields
//~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields
_ => {}
}
}

View file

@ -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 `A::D` does not name a tuple variant or a tuple struct
A::D(_) => (), //~ ERROR expected tuple struct/variant, found unit variant `A::D`
_ => ()
}
match 'c' {

View file

@ -28,7 +28,7 @@ impl S {
fn main() {
match 10 {
<S as Tr>::A::f::<u8> => {}
//~^ ERROR `Tr::A::f<u8>` does not name a unit variant, unit struct or a constant
//~^ ERROR expected unit struct/variant or constant, found method `Tr::A::f<u8>`
0 ... <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
}
}

View file

@ -39,7 +39,7 @@ fn main() {
foo::<static_priv_by_default::m>();
//~^ ERROR: enum `m` is private
foo::<static_priv_by_default::n>();
//~^ ERROR: type `n` is private
//~^ ERROR: type alias `n` is private
// public items in a private mod should be inaccessible
static_priv_by_default::foo::a;