Fix various bugs around empty structs and patterns
This commit is contained in:
parent
3e48b0e380
commit
0f8519c341
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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`
|
||||
// }
|
||||
}
|
||||
|
29
src/test/compile-fail/empty-struct-braces-pat-3.rs
Normal file
29
src/test/compile-fail/empty-struct-braces-pat-3.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
// Rejected by parser as yet
|
||||
// match e1 {
|
||||
// Empty1() => () // ERROR variable `Empty1` should have a snake case name
|
||||
// }
|
||||
// match e1 {
|
||||
// Empty1(..) => () // ERROR variable `Empty1` 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
|
||||
// }
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
=> {}
|
||||
|
26
src/test/compile-fail/issue-28992-empty.rs
Normal file
26
src/test/compile-fail/issue-28992-empty.rs
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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' {
|
||||
|
@ -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 => {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user