diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 883e3659720a..9eb372a6c590 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -526,41 +526,41 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, etc: bool, expected: Ty<'tcx>) { let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; + let report_nonstruct = || { + let name = pprust::path_to_string(path); + span_err!(tcx.sess, pat.span, E0163, + "`{}` does not name a struct or a struct variant", name); + fcx.write_error(pat.id); + + for field in fields { + check_pat(pcx, &field.node.pat, tcx.types.err); + } + }; let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); let (adt_def, variant) = match def { - def::DefTrait(_) => { - let name = pprust::path_to_string(path); - span_err!(tcx.sess, pat.span, E0168, - "use of trait `{}` in a struct pattern", name); - fcx.write_error(pat.id); - - for field in fields { - check_pat(pcx, &*field.node.pat, tcx.types.err); - } - return; - }, - _ => { - let def_type = tcx.lookup_item_type(def.def_id()); - match def_type.ty.sty { + def::DefTy(did, _) | def::DefStruct(did) => { + match tcx.lookup_item_type(did).ty.sty { ty::TyStruct(struct_def, _) => (struct_def, struct_def.struct_variant()), - ty::TyEnum(enum_def, _) - if def == def::DefVariant(enum_def.did, def.def_id(), true) => - (enum_def, enum_def.variant_of_def(def)), _ => { - let name = pprust::path_to_string(path); - span_err!(tcx.sess, pat.span, E0163, - "`{}` does not name a struct or a struct variant", name); - fcx.write_error(pat.id); - - for field in fields { - check_pat(pcx, &*field.node.pat, tcx.types.err); - } + report_nonstruct(); return; } } } + def::DefVariant(eid, vid, true) => { + match tcx.lookup_item_type(vid).ty.sty { + ty::TyEnum(enum_def, _) if enum_def.did == eid => { + (enum_def, enum_def.variant_with_id(vid)) + } + _ => tcx.sess.span_bug(pat.span, "variant's type is not its enum") + } + } + _ => { + report_nonstruct(); + return; + } }; instantiate_path(pcx.fcx, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6221134afd38..92f39d972ee1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1421,14 +1421,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// This is used when checking the constructor in struct literals. fn instantiate_struct_literal_ty(&self, - did: ast::DefId, + struct_ty: ty::TypeScheme<'tcx>, path: &ast::Path) -> TypeAndSubsts<'tcx> { - let tcx = self.tcx(); - - let ty::TypeScheme { generics, ty: decl_ty } = - tcx.lookup_item_type(did); + let ty::TypeScheme { generics, ty: decl_ty } = struct_ty; let substs = astconv::ast_path_substs_for_ty(self, self, path.span, @@ -3168,6 +3165,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } + fn report_exprstruct_on_nondict<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>, + id: ast::NodeId, + fields: &'tcx [ast::Field], + base_expr: &'tcx Option>, + path: &ast::Path) + { + span_err!(fcx.tcx().sess, path.span, E0071, + "`{}` does not name a structure", + pprust::path_to_string(path)); + check_struct_fields_on_error(fcx, id, fields, base_expr) + } + type ExprCheckerWithTy = fn(&FnCtxt, &ast::Expr, Ty); let tcx = fcx.ccx.tcx; @@ -3618,7 +3627,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast::ExprStruct(ref path, ref fields, ref base_expr) => { // Resolve the path. let def = lookup_full_def(tcx, path.span, id); - let struct_id = match def { + + let struct_ty = match def { def::DefVariant(enum_id, variant_id, true) => { if let &Some(ref base_expr) = base_expr { span_err!(tcx.sess, base_expr.span, E0436, @@ -3627,54 +3637,38 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } check_struct_enum_variant(fcx, id, expr.span, enum_id, variant_id, &fields[..]); - enum_id + Some(tcx.lookup_item_type(enum_id)) } - def::DefTrait(def_id) => { - span_err!(tcx.sess, path.span, E0159, - "use of trait `{}` as a struct constructor", - pprust::path_to_string(path)); - check_struct_fields_on_error(fcx, - id, - &fields[..], - base_expr); - def_id - }, - def => { + def::DefTy(did, _) | def::DefStruct(did) => { // Verify that this was actually a struct. - let typ = fcx.ccx.tcx.lookup_item_type(def.def_id()); - match typ.ty.sty { - ty::TyStruct(struct_def, _) => { - check_struct_constructor(fcx, - id, - expr.span, - struct_def, - &fields[..], - base_expr.as_ref().map(|e| &**e)); - } - _ => { - span_err!(tcx.sess, path.span, E0071, - "`{}` does not name a structure", - pprust::path_to_string(path)); - check_struct_fields_on_error(fcx, - id, - &fields[..], - base_expr); - } + let typ = tcx.lookup_item_type(did); + if let ty::TyStruct(struct_def, _) = typ.ty.sty { + check_struct_constructor(fcx, + id, + expr.span, + struct_def, + &fields, + base_expr.as_ref().map(|e| &**e)); + } else { + report_exprstruct_on_nondict(fcx, id, &fields, base_expr, path); } - - def.def_id() + Some(typ) + } + _ => { + report_exprstruct_on_nondict(fcx, id, &fields, base_expr, path); + None } }; // Turn the path into a type and verify that that type unifies with // the resulting structure type. This is needed to handle type // parameters correctly. - let actual_structure_type = fcx.expr_ty(&*expr); - if !actual_structure_type.references_error() { - let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path); + if let Some(struct_ty) = struct_ty { + let expr_ty = fcx.expr_ty(&expr); + let type_and_substs = fcx.instantiate_struct_literal_ty(struct_ty, path); match fcx.mk_subty(false, infer::Misc(path.span), - actual_structure_type, + expr_ty, type_and_substs.ty) { Ok(()) => {} Err(type_error) => { @@ -3685,8 +3679,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.infcx() .ty_to_string(type_and_substs.ty), fcx.infcx() - .ty_to_string( - actual_structure_type), + .ty_to_string(expr_ty), type_error); tcx.note_and_explain_type_err(&type_error, path.span); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index fd1a5595e8f1..c49f05fa7a2e 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -735,39 +735,33 @@ fn some_func(x: &mut i32) { "##, E0071: r##" -You tried to use a structure initialization with a non-structure type. +You tried to use structure-literal syntax to create an item that is +not a struct-style structure or enum variant. + Example of erroneous code: ``` -enum Foo { FirstValue }; +enum Foo { FirstValue(i32) }; let u = Foo::FirstValue { value: 0i32 }; // error: Foo::FirstValue // isn't a structure! -// or even simpler, if the structure wasn't defined at all: -let u = RandomName { random_field: 0i32 }; // error: RandomName - // isn't a structure! -``` +// or even simpler, if the name doesn't refer to a structure at all. +let t = u32 { value: 4 }; // error: `u32` does not name a structure.``` -To fix this, please check: - * Did you spell it right? - * Did you accidentaly used an enum as a struct? - * Did you accidentaly make an enum when you intended to use a struct? +To fix this, ensure that the name was correctly spelled, and that +the correct form of initializer was used. -Here is the previous code with all missing information: +For example, the code above can be fixed to: ``` -struct Inner { - value: i32 -} - enum Foo { - FirstValue(Inner) + FirstValue(i32) } fn main() { - let u = Foo::FirstValue(Inner { value: 0i32 }); + let u = Foo::FirstValue(0i32); - let t = Inner { value: 0i32 }; + let t = 4; } ``` "##, @@ -1636,30 +1630,6 @@ fn(isize, *const *const u8) -> isize ``` "##, -E0159: r##" -You tried to use a trait as a struct constructor. Erroneous code example: - -``` -trait TraitNotAStruct {} - -TraitNotAStruct{ value: 0 }; // error: use of trait `TraitNotAStruct` as a - // struct constructor -``` - -Please verify you used the correct type name or please implement the trait -on a struct and use this struct constructor. Example: - -``` -trait TraitNotAStruct {} - -struct Foo { - value: i32 -} - -Foo{ value: 0 }; // ok! -``` -"##, - E0166: r##" This error means that the compiler found a return expression in a function marked as diverging. A function diverges if it has `!` in the place of the @@ -2673,10 +2643,11 @@ register_diagnostics! { E0127, E0129, E0141, +// E0159, // use of trait `{}` as struct constructor E0163, E0164, E0167, - E0168, +// E0168, E0173, // manual implementations of unboxed closure traits are experimental E0174, // explicit use of unboxed closure methods are experimental E0182, diff --git a/src/test/compile-fail-fulldeps/issue-18986.rs b/src/test/compile-fail-fulldeps/issue-18986.rs index 06fc3db58c15..5f7752bb203c 100644 --- a/src/test/compile-fail-fulldeps/issue-18986.rs +++ b/src/test/compile-fail-fulldeps/issue-18986.rs @@ -15,6 +15,6 @@ pub use use_from_trait_xc::Trait; fn main() { match () { - Trait { x: 42 } => () //~ ERROR use of trait `Trait` in a struct pattern + Trait { x: 42 } => () //~ ERROR `Trait` does not name a struct } } diff --git a/src/test/compile-fail/issue-27815.rs b/src/test/compile-fail/issue-27815.rs new file mode 100644 index 000000000000..b1ac2dfd1c41 --- /dev/null +++ b/src/test/compile-fail/issue-27815.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod A {} + +fn main() { + let u = A { x: 1 }; //~ ERROR `A` does not name a structure + let v = u32 { x: 1 }; //~ ERROR `u32` does not name a structure + match () { + A { x: 1 } => {} //~ ERROR `A` does not name a struct + u32 { x: 1 } => {} //~ ERROR `u32` does not name a struct + } +} diff --git a/src/test/compile-fail/trait-as-struct-constructor.rs b/src/test/compile-fail/trait-as-struct-constructor.rs index b864e6ca9578..67ccd6b7cd05 100644 --- a/src/test/compile-fail/trait-as-struct-constructor.rs +++ b/src/test/compile-fail/trait-as-struct-constructor.rs @@ -12,5 +12,5 @@ trait TraitNotAStruct {} fn main() { TraitNotAStruct{ value: 0 }; - //~^ ERROR: use of trait `TraitNotAStruct` as a struct constructor [E0159] + //~^ ERROR: `TraitNotAStruct` does not name a structure [E0071] }