diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 8b5c7061a149f..6062ea0de2227 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -677,8 +677,17 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc], } else { None }, - DefStruct(struct_id) => Some(struct_id), - _ => None + _ => { + // Assume this is a struct. + match ty::ty_to_def_id(node_id_to_type(cx.tcx, pat_id)) { + None => { + cx.tcx.sess.span_bug(pat_span, + "struct pattern wasn't of a \ + type with a def ID?!") + } + Some(def_id) => Some(def_id), + } + } }; class_id.map(|variant_id| { let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 70db3e964abb3..9ec167ee8263e 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -141,16 +141,25 @@ impl<'a> MarkSymbolVisitor<'a> { } fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[ast::FieldPat]) { - match self.tcx.def_map.borrow().get(&lhs.id) { - &def::DefStruct(id) | &def::DefVariant(_, id, _) => { - let fields = ty::lookup_struct_fields(self.tcx, id); - for pat in pats.iter() { - let field_id = fields.iter() - .find(|field| field.name == pat.ident.name).unwrap().id; - self.live_symbols.insert(field_id.node); + let id = match self.tcx.def_map.borrow().get(&lhs.id) { + &def::DefVariant(_, id, _) => id, + _ => { + match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, + lhs.id)) { + None => { + self.tcx.sess.span_bug(lhs.span, + "struct pattern wasn't of a \ + type with a def ID?!") + } + Some(def_id) => def_id, } } - _ => () + }; + let fields = ty::lookup_struct_fields(self.tcx, id); + for pat in pats.iter() { + let field_id = fields.iter() + .find(|field| field.name == pat.ident.name).unwrap().id; + self.live_symbols.insert(field_id.node); } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index b7b4618a79046..6ec1f23cdbd08 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4470,17 +4470,7 @@ impl<'a> Resolver<'a> { PatStruct(ref path, _, _) => { match self.resolve_path(pat_id, path, TypeNS, false) { - Some((DefTy(class_id), lp)) - if self.structs.contains_key(&class_id) => { - let class_def = DefStruct(class_id); - self.record_def(pattern.id, (class_def, lp)); - } - Some(definition @ (DefStruct(class_id), _)) => { - assert!(self.structs.contains_key(&class_id)); - self.record_def(pattern.id, definition); - } - Some(definition @ (DefVariant(_, variant_id, _), _)) - if self.structs.contains_key(&variant_id) => { + Some(definition) => { self.record_def(pattern.id, definition); } result => { @@ -5200,17 +5190,11 @@ impl<'a> Resolver<'a> { } ExprStruct(ref path, _, _) => { - // Resolve the path to the structure it goes to. + // Resolve the path to the structure it goes to. We don't + // check to ensure that the path is actually a structure; that + // is checked later during typeck. match self.resolve_path(expr.id, path, TypeNS, false) { - Some((DefTy(class_id), lp)) | Some((DefStruct(class_id), lp)) - if self.structs.contains_key(&class_id) => { - let class_def = DefStruct(class_id); - self.record_def(expr.id, (class_def, lp)); - } - Some(definition @ (DefVariant(_, class_id, _), _)) - if self.structs.contains_key(&class_id) => { - self.record_def(expr.id, definition); - } + Some(definition) => self.record_def(expr.id, definition), result => { debug!("(resolving expression) didn't find struct \ def: {:?}", result); diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 2f8918acb30bc..9245032289ec9 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -804,12 +804,19 @@ fn any_irrefutable_adt_pat(bcx: &Block, m: &[Match], col: uint) -> bool { let pat = *br.pats.get(col); match pat.node { ast::PatTup(_) => true, - ast::PatEnum(..) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => + ast::PatStruct(..) => { + match bcx.tcx().def_map.borrow().find(&pat.id) { + Some(&def::DefVariant(..)) => false, + _ => true, + } + } + ast::PatEnum(..) | ast::PatIdent(_, _, None) => { match bcx.tcx().def_map.borrow().find(&pat.id) { Some(&def::DefFn(..)) | Some(&def::DefStruct(..)) => true, _ => false - }, + } + } _ => false } }) diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 697c5d367ee5a..a5e7db1d6fdab 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -362,36 +362,16 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt, } } -pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: Span, - expected: ty::t, path: &ast::Path, +pub fn check_struct_pat(pcx: &pat_ctxt, _pat_id: ast::NodeId, span: Span, + _expected: ty::t, _path: &ast::Path, fields: &[ast::FieldPat], etc: bool, struct_id: ast::DefId, substitutions: &subst::Substs) { - let fcx = pcx.fcx; + let _fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; let class_fields = ty::lookup_struct_fields(tcx, struct_id); - // Check to ensure that the struct is the one specified. - match tcx.def_map.borrow().find(&pat_id) { - Some(&def::DefStruct(supplied_def_id)) - if supplied_def_id == struct_id => { - // OK. - } - Some(&def::DefStruct(..)) | Some(&def::DefVariant(..)) => { - let name = pprust::path_to_str(path); - tcx.sess - .span_err(span, - format!("mismatched types: expected `{}` but found \ - `{}`", - fcx.infcx().ty_to_str(expected), - name).as_slice()); - } - _ => { - tcx.sess.span_bug(span, "resolve didn't write in struct ID"); - } - } - check_struct_pat_fields(pcx, span, fields, class_fields, struct_id, substitutions, etc); } @@ -535,6 +515,21 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { let mut error_happened = false; match *structure { ty::ty_struct(cid, ref substs) => { + // Verify that the pattern named the right structure. + let item_did = tcx.def_map.borrow().get(&pat.id).def_id(); + let struct_did = + ty::ty_to_def_id( + ty::lookup_item_type(tcx, item_did).ty).unwrap(); + if struct_did != cid { + tcx.sess + .span_err(path.span, + format!("`{}` does not name the \ + structure `{}`", + pprust::path_to_str(path), + fcx.infcx() + .ty_to_str(expected)).as_slice()) + } + check_struct_pat(pcx, pat.id, pat.span, expected, path, fields.as_slice(), etc, cid, substs); } @@ -562,7 +557,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { "a structure pattern".to_string(), None); match tcx.def_map.borrow().find(&pat.id) { - Some(&def::DefStruct(supplied_def_id)) => { + Some(def) => { check_struct_pat(pcx, pat.id, pat.span, @@ -570,10 +565,14 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { path, fields.as_slice(), etc, - supplied_def_id, + def.def_id(), &subst::Substs::empty()); } - _ => () // Error, but we're already in an error case + None => { + tcx.sess.span_bug(pat.span, + "whoops, looks like resolve didn't \ + write a def in here") + } } error_happened = true; } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b68991aed7096..a6159e13f3f6f 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3296,17 +3296,34 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // Resolve the path. let def = tcx.def_map.borrow().find(&id).map(|i| *i); match def { - Some(def::DefStruct(type_def_id)) => { - check_struct_constructor(fcx, id, expr.span, type_def_id, - fields.as_slice(), base_expr); - } Some(def::DefVariant(enum_id, variant_id, _)) => { check_struct_enum_variant(fcx, id, expr.span, enum_id, variant_id, fields.as_slice()); } + Some(def) => { + // Verify that this was actually a struct. + let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id()); + match ty::get(typ.ty).sty { + ty::ty_struct(struct_did, _) => { + check_struct_constructor(fcx, + id, + expr.span, + struct_did, + fields.as_slice(), + base_expr); + } + _ => { + tcx.sess + .span_err(path.span, + format!("`{}` does not name a structure", + pprust::path_to_str( + path)).as_slice()) + } + } + } _ => { tcx.sess.span_bug(path.span, - "structure constructor does not name a structure type"); + "structure constructor wasn't resolved") } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index fa353652fe1ec..30c0aa41d1440 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -16,8 +16,7 @@ use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{BoundRegion, BrAnon, BrNamed}; use middle::ty::{BrFresh, ctxt}; use middle::ty::{mt, t, ParamTy}; -use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, - ReEmpty}; +use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup}; diff --git a/src/test/auxiliary/xcrate_struct_aliases.rs b/src/test/auxiliary/xcrate_struct_aliases.rs new file mode 100644 index 0000000000000..a0ec7272720dc --- /dev/null +++ b/src/test/auxiliary/xcrate_struct_aliases.rs @@ -0,0 +1,17 @@ +// Copyright 2012 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. + +pub struct S { + pub x: int, + pub y: int, +} + +pub type S2 = S; + diff --git a/src/test/compile-fail/issue-14541.rs b/src/test/compile-fail/issue-14541.rs index 2dcfeac513c32..921e331e960dc 100644 --- a/src/test/compile-fail/issue-14541.rs +++ b/src/test/compile-fail/issue-14541.rs @@ -13,8 +13,8 @@ struct vec3 { y: f32, z: f32 } fn make(v: vec2) { let vec3 { y: _, z: _ } = v; - //~^ ERROR mismatched types: expected `vec2` but found `vec3` + //~^ ERROR `vec3` does not name the structure `vec2` //~^^ ERROR struct `vec2` does not have a field named `z` } -fn main() { } \ No newline at end of file +fn main() { } diff --git a/src/test/run-pass/struct-aliases-xcrate.rs b/src/test/run-pass/struct-aliases-xcrate.rs new file mode 100644 index 0000000000000..9046cafe7579a --- /dev/null +++ b/src/test/run-pass/struct-aliases-xcrate.rs @@ -0,0 +1,31 @@ +// Copyright 2012 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. + +// aux-build:xcrate_struct_aliases.rs +extern crate xcrate_struct_aliases; + +use xcrate_struct_aliases::{S, S2}; + +fn main() { + let s = S2 { + x: 1, + y: 2, + }; + match s { + S2 { + x: x, + y: y + } => { + assert_eq!(x, 1); + assert_eq!(y, 2); + } + } +} + diff --git a/src/test/run-pass/struct-aliases.rs b/src/test/run-pass/struct-aliases.rs new file mode 100644 index 0000000000000..2cf961a5c0c94 --- /dev/null +++ b/src/test/run-pass/struct-aliases.rs @@ -0,0 +1,33 @@ +// Copyright 2012 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. + +struct S { + x: int, + y: int, +} + +type S2 = S; + +fn main() { + let s = S2 { + x: 1, + y: 2, + }; + match s { + S2 { + x: x, + y: y + } => { + assert_eq!(x, 1); + assert_eq!(y, 2); + } + } +} +