librustc: Accept type aliases for structures in structure literals and

structure patterns.

Closes #4508.
This commit is contained in:
Patrick Walton 2014-07-04 16:45:47 -07:00
parent 9897160523
commit aaaf7e00ec
11 changed files with 173 additions and 68 deletions

View File

@ -677,8 +677,17 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
} 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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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
}
})

View File

@ -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;
}

View File

@ -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")
}
}
}

View File

@ -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};

View File

@ -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 <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.
pub struct S {
pub x: int,
pub y: int,
}
pub type S2 = S;

View File

@ -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() { }
fn main() { }

View File

@ -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 <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.
// 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);
}
}
}

View File

@ -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 <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.
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);
}
}
}