提交 a6a5c48c 编写于 作者: N Niko Matsakis

make `ref x` bindings produce region ptrs and fix various minor bugs

we now detect inconsistent modes, binding names, and various other errors.
typeck/trans integration is mostly done.

borrowck not so much.

more tests needed.
上级 ecaf9e39
...@@ -148,7 +148,8 @@ enum meta_item_ { ...@@ -148,7 +148,8 @@ enum meta_item_ {
#[auto_serialize] #[auto_serialize]
enum binding_mode { enum binding_mode {
bind_by_value, bind_by_value,
bind_by_ref bind_by_ref(ast::mutability),
bind_by_implicit_ref
} }
#[auto_serialize] #[auto_serialize]
......
...@@ -228,7 +228,9 @@ fn binder_pat(span: span, nm: ast::ident) -> @ast::pat { ...@@ -228,7 +228,9 @@ fn binder_pat(span: span, nm: ast::ident) -> @ast::pat {
let path = @{span: span, global: false, idents: ~[nm], let path = @{span: span, global: false, idents: ~[nm],
rp: none, types: ~[]}; rp: none, types: ~[]};
@{id: self.next_id(), @{id: self.next_id(),
node: ast::pat_ident(ast::bind_by_ref, path, none), node: ast::pat_ident(ast::bind_by_implicit_ref,
path,
none),
span: span} span: span}
} }
...@@ -834,7 +836,7 @@ fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: ast::ident, ...@@ -834,7 +836,7 @@ fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: ast::ident,
// Generate pattern var(v1, v2, v3) // Generate pattern var(v1, v2, v3)
|pats| { |pats| {
if vec::is_empty(pats) { if vec::is_empty(pats) {
ast::pat_ident(ast::bind_by_ref, ast::pat_ident(ast::bind_by_implicit_ref,
cx.path(v_span, ~[v_name]), cx.path(v_span, ~[v_name]),
none) none)
} else { } else {
......
...@@ -116,7 +116,7 @@ fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt { ...@@ -116,7 +116,7 @@ fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt {
@{node: {is_mutbl: false, @{node: {is_mutbl: false,
ty: self.ty_infer(), ty: self.ty_infer(),
pat: @{id: self.next_id(), pat: @{id: self.next_id(),
node: ast::pat_ident(ast::bind_by_ref, node: ast::pat_ident(ast::bind_by_implicit_ref,
path(ident, path(ident,
self.empty_span()), self.empty_span()),
none), none),
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
import dvec::{dvec, extensions}; import dvec::{dvec, extensions};
import vec::{push}; import vec::{push};
import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute, import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
bind_by_ref, bind_by_value, bitand, bitor, bitxor, blk, bind_by_ref, bind_by_implicit_ref, bind_by_value,
bitand, bitor, bitxor, blk,
blk_check_mode, bound_const, bound_copy, bound_send, bound_trait, blk_check_mode, bound_const, bound_copy, bound_send, bound_trait,
bound_owned, box, by_copy, by_move, by_mutbl_ref, by_ref, by_val, bound_owned, box, by_copy, by_move, by_mutbl_ref, by_ref, by_val,
capture_clause, capture_item, cdir_dir_mod, cdir_src_mod, capture_clause, capture_item, cdir_dir_mod, cdir_src_mod,
...@@ -1718,7 +1719,9 @@ fn parse_pat(refutable: bool) -> @pat { ...@@ -1718,7 +1719,9 @@ fn parse_pat(refutable: bool) -> @pat {
} else { } else {
subpat = @{ subpat = @{
id: self.get_id(), id: self.get_id(),
node: pat_ident(bind_by_ref, fieldpath, none), node: pat_ident(bind_by_implicit_ref,
fieldpath,
none),
span: mk_sp(lo, hi) span: mk_sp(lo, hi)
}; };
} }
...@@ -1749,87 +1752,100 @@ fn parse_pat(refutable: bool) -> @pat { ...@@ -1749,87 +1752,100 @@ fn parse_pat(refutable: bool) -> @pat {
} }
} }
tok => { tok => {
if !is_ident_or_path(tok) || if !is_ident_or_path(tok)
self.is_keyword(~"true") || self.is_keyword(~"false") { || self.is_keyword(~"true")
|| self.is_keyword(~"false")
{
let val = self.parse_expr_res(RESTRICT_NO_BAR_OP); let val = self.parse_expr_res(RESTRICT_NO_BAR_OP);
if self.eat_keyword(~"to") { if self.eat_keyword(~"to") {
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP); let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
hi = end.span.hi;
pat = pat_range(val, end); pat = pat_range(val, end);
} else { } else {
hi = val.span.hi;
pat = pat_lit(val); pat = pat_lit(val);
} }
} else { } else if self.eat_keyword(~"ref") {
let binding_mode; let mutbl = self.parse_mutability();
if self.eat_keyword(~"ref") { pat = self.parse_pat_ident(refutable, bind_by_ref(mutbl));
binding_mode = bind_by_ref;
} else if self.eat_keyword(~"copy") { } else if self.eat_keyword(~"copy") {
binding_mode = bind_by_value; pat = self.parse_pat_ident(refutable, bind_by_value);
} else if refutable { } else if !is_plain_ident(self.token) {
// XXX: Should be bind_by_value, but that's not pat = self.parse_enum_variant(refutable);
// backward compatible.
binding_mode = bind_by_ref;
} else { } else {
binding_mode = bind_by_value; // this is a plain identifier, like `x` or `x(...)`
}
if is_plain_ident(self.token) &&
match self.look_ahead(1) { match self.look_ahead(1) {
token::LPAREN | token::LBRACKET | token::LT => { token::LPAREN | token::LBRACKET | token::LT => {
false pat = self.parse_enum_variant(refutable);
} }
_ => { _ => {
true let binding_mode = if refutable {
// XXX: Should be bind_by_value, but that's not
// backward compatible.
bind_by_implicit_ref
} else {
bind_by_value
};
pat = self.parse_pat_ident(refutable, binding_mode);
}
}
}
hi = self.span.hi;
}
}
return @{id: self.get_id(), node: pat, span: mk_sp(lo, hi)};
}
fn parse_pat_ident(refutable: bool,
binding_mode: ast::binding_mode) -> ast::pat_ {
if !is_plain_ident(self.token) {
self.span_fatal(
copy self.last_span,
~"expected identifier, found path");
} }
} {
let name = self.parse_value_path(); let name = self.parse_value_path();
let sub = if self.eat(token::AT) { let sub = if self.eat(token::AT) {
some(self.parse_pat(refutable)) some(self.parse_pat(refutable))
} else { none };
// just to be friendly, if they write something like
// ref some(i)
// we end up here with ( as the current token. This shortly
// leads to a parse error. Note that if there is no explicit
// binding mode then we do not end up here, because the lookahead
// will direct us over to parse_enum_variant()
if self.token == token::LPAREN {
self.span_fatal(
copy self.last_span,
~"expected identifier, found enum pattern");
} }
else { none };
pat = pat_ident(binding_mode, name, sub); pat_ident(binding_mode, name, sub)
} else { }
fn parse_enum_variant(refutable: bool) -> ast::pat_ {
let enum_path = self.parse_path_with_tps(true); let enum_path = self.parse_path_with_tps(true);
hi = enum_path.span.hi;
let mut args: ~[@pat] = ~[];
let mut star_pat = false;
match self.token { match self.token {
token::LPAREN => match self.look_ahead(1u) { token::LPAREN => {
token::BINOP(token::STAR) => { match self.look_ahead(1u) {
// This is a "top constructor only" pat token::BINOP(token::STAR) => { // foo(*)
self.bump(); self.bump(); self.expect(token::LPAREN);
star_pat = true; self.expect(token::BINOP(token::STAR));
self.expect(token::RPAREN); self.expect(token::RPAREN);
pat_enum(enum_path, none)
} }
_ => { _ => { // foo(a, ..., z)
args = self.parse_unspanned_seq( let args = self.parse_unspanned_seq(
token::LPAREN, token::RPAREN, token::LPAREN, token::RPAREN,
seq_sep_trailing_disallowed(token::COMMA), seq_sep_trailing_disallowed(token::COMMA),
|p| p.parse_pat(refutable)); |p| p.parse_pat(refutable));
hi = self.span.hi; pat_enum(enum_path, some(args))
}
}
_ => ()
} }
// at this point, we're not sure whether it's a enum or a
// bind
if star_pat {
pat = pat_enum(enum_path, none);
}
else if vec::is_empty(args) &&
vec::len(enum_path.idents) == 1u {
pat = pat_ident(binding_mode, enum_path, none);
}
else {
pat = pat_enum(enum_path, some(args));
} }
} }
_ => { // option::none
pat_enum(enum_path, some(~[]))
} }
} }
} }
return @{id: self.get_id(), node: pat, span: mk_sp(lo, hi)};
}
fn parse_local(is_mutbl: bool, fn parse_local(is_mutbl: bool,
allow_init: bool) -> @local { allow_init: bool) -> @local {
......
...@@ -1332,8 +1332,12 @@ fn print_pat(s: ps, &&pat: @ast::pat) { ...@@ -1332,8 +1332,12 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
ast::pat_wild => word(s.s, ~"_"), ast::pat_wild => word(s.s, ~"_"),
ast::pat_ident(binding_mode, path, sub) => { ast::pat_ident(binding_mode, path, sub) => {
match binding_mode { match binding_mode {
ast::bind_by_ref => word_space(s, ~"ref"), ast::bind_by_ref(mutbl) => {
ast::bind_by_value => () word_nbsp(s, ~"ref");
print_mutability(s, mutbl);
}
ast::bind_by_implicit_ref |
ast::bind_by_value => {}
} }
print_path(s, path, true); print_path(s, path, true);
match sub { match sub {
......
...@@ -264,15 +264,17 @@ fn cat_def(id: ast::node_id, ...@@ -264,15 +264,17 @@ fn cat_def(id: ast::node_id,
mutbl:m, ty:expr_ty} mutbl:m, ty:expr_ty}
} }
ast::def_binding(vid, ast::bind_by_value) => { ast::def_binding(vid, ast::bind_by_value) |
// by-value bindings are basically local variables ast::def_binding(vid, ast::bind_by_ref(_)) => {
// by-value/by-ref bindings are local variables
@{id:id, span:span, @{id:id, span:span,
cat:cat_local(vid), lp:some(@lp_local(vid)), cat:cat_local(vid), lp:some(@lp_local(vid)),
mutbl:m_imm, ty:expr_ty} mutbl:m_imm, ty:expr_ty}
} }
ast::def_binding(pid, ast::bind_by_ref) => { ast::def_binding(pid, ast::bind_by_implicit_ref) => {
// bindings are "special" since they are implicit pointers. // implicit-by-ref bindings are "special" since they are
// implicit pointers.
// lookup the mutability for this binding that we found in // lookup the mutability for this binding that we found in
// gather_loans when we categorized it // gather_loans when we categorized it
......
...@@ -404,7 +404,7 @@ fn add_class_fields(self: @ir_maps, did: def_id) { ...@@ -404,7 +404,7 @@ fn add_class_fields(self: @ir_maps, did: def_id) {
fn visit_local(local: @local, &&self: @ir_maps, vt: vt<@ir_maps>) { fn visit_local(local: @local, &&self: @ir_maps, vt: vt<@ir_maps>) {
let def_map = self.tcx.def_map; let def_map = self.tcx.def_map;
do pat_util::pat_bindings(def_map, local.node.pat) |p_id, sp, path| { do pat_util::pat_bindings(def_map, local.node.pat) |_bm, p_id, sp, path| {
debug!{"adding local variable %d", p_id}; debug!{"adding local variable %d", p_id};
let name = ast_util::path_to_ident(path); let name = ast_util::path_to_ident(path);
(*self).add_live_node_for_node(p_id, lnk_vdef(sp)); (*self).add_live_node_for_node(p_id, lnk_vdef(sp));
...@@ -587,7 +587,7 @@ fn variable_from_def_map(node_id: node_id, ...@@ -587,7 +587,7 @@ fn variable_from_def_map(node_id: node_id,
fn pat_bindings(pat: @pat, f: fn(live_node, variable, span)) { fn pat_bindings(pat: @pat, f: fn(live_node, variable, span)) {
let def_map = self.tcx.def_map; let def_map = self.tcx.def_map;
do pat_util::pat_bindings(def_map, pat) |p_id, sp, _n| { do pat_util::pat_bindings(def_map, pat) |_bm, p_id, sp, _n| {
let ln = self.live_node(p_id, sp); let ln = self.live_node(p_id, sp);
let var = self.variable(p_id, sp); let var = self.variable(p_id, sp);
f(ln, var, sp); f(ln, var, sp);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
// use the node_id of their namesake in the first pattern. // use the node_id of their namesake in the first pattern.
fn pat_id_map(dm: resolve3::DefMap, pat: @pat) -> pat_id_map { fn pat_id_map(dm: resolve3::DefMap, pat: @pat) -> pat_id_map {
let map = std::map::box_str_hash(); let map = std::map::box_str_hash();
do pat_bindings(dm, pat) |p_id, _s, n| { do pat_bindings(dm, pat) |_bm, p_id, _s, n| {
map.insert(path_to_ident(n), p_id); map.insert(path_to_ident(n), p_id);
}; };
return map; return map;
...@@ -33,11 +33,11 @@ fn pat_is_variant(dm: resolve3::DefMap, pat: @pat) -> bool { ...@@ -33,11 +33,11 @@ fn pat_is_variant(dm: resolve3::DefMap, pat: @pat) -> bool {
} }
fn pat_bindings(dm: resolve3::DefMap, pat: @pat, fn pat_bindings(dm: resolve3::DefMap, pat: @pat,
it: fn(node_id, span, @path)) { it: fn(binding_mode, node_id, span, @path)) {
do walk_pat(pat) |p| { do walk_pat(pat) |p| {
match p.node { match p.node {
pat_ident(_, pth, _) if !pat_is_variant(dm, p) => { pat_ident(binding_mode, pth, _) if !pat_is_variant(dm, p) => {
it(p.id, p.span, pth); it(binding_mode, p.id, p.span, pth);
} }
_ => {} _ => {}
} }
...@@ -46,6 +46,6 @@ fn pat_bindings(dm: resolve3::DefMap, pat: @pat, ...@@ -46,6 +46,6 @@ fn pat_bindings(dm: resolve3::DefMap, pat: @pat,
fn pat_binding_ids(dm: resolve3::DefMap, pat: @pat) -> ~[node_id] { fn pat_binding_ids(dm: resolve3::DefMap, pat: @pat) -> ~[node_id] {
let mut found = ~[]; let mut found = ~[];
pat_bindings(dm, pat, |b_id, _sp, _pt| vec::push(found, b_id) ); pat_bindings(dm, pat, |_bm, b_id, _sp, _pt| vec::push(found, b_id) );
return found; return found;
} }
...@@ -5,9 +5,13 @@ ...@@ -5,9 +5,13 @@
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
import middle::lang_items::LanguageItems; import middle::lang_items::LanguageItems;
import middle::lint::{deny, allow, forbid, level, unused_imports, warn}; import middle::lint::{deny, allow, forbid, level, unused_imports, warn};
import syntax::ast::{_mod, add, arm, bind_by_value, bitand, bitor, bitxor}; import middle::pat_util::{pat_bindings};
import syntax::ast::{_mod, add, arm};
import syntax::ast::{bind_by_ref, bind_by_implicit_ref, bind_by_value};
import syntax::ast::{bitand, bitor, bitxor};
import syntax::ast::{blk, bound_const, bound_copy, bound_owned, bound_send}; import syntax::ast::{blk, bound_const, bound_copy, bound_owned, bound_send};
import syntax::ast::{bound_trait, capture_clause, class_ctor, class_dtor}; import syntax::ast::{bound_trait, binding_mode,
capture_clause, class_ctor, class_dtor};
import syntax::ast::{class_member, class_method, crate, crate_num, decl_item}; import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn}; import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn};
import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod}; import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod};
...@@ -36,7 +40,7 @@ ...@@ -36,7 +40,7 @@
import syntax::ast::{view_item_import, view_item_use, view_path_glob}; import syntax::ast::{view_item_import, view_item_use, view_path_glob};
import syntax::ast::{view_path_list, view_path_simple}; import syntax::ast::{view_path_list, view_path_simple};
import syntax::ast_util::{def_id_of_def, dummy_sp, local_def, new_def_hash}; import syntax::ast_util::{def_id_of_def, dummy_sp, local_def, new_def_hash};
import syntax::ast_util::{walk_pat}; import syntax::ast_util::{walk_pat, path_to_ident};
import syntax::attr::{attr_metas, contains_name}; import syntax::attr::{attr_metas, contains_name};
import syntax::print::pprust::{pat_to_str, path_to_str}; import syntax::print::pprust::{pat_to_str, path_to_str};
import syntax::codemap::span; import syntax::codemap::span;
...@@ -52,12 +56,20 @@ ...@@ -52,12 +56,20 @@
import vec::pop; import vec::pop;
import std::list::{cons, list, nil}; import std::list::{cons, list, nil};
import std::map::{hashmap, int_hash, str_hash}; import std::map::{hashmap, int_hash, box_str_hash};
import str_eq = str::eq; import str_eq = str::eq;
// Definition mapping // Definition mapping
type DefMap = hashmap<node_id,def>; type DefMap = hashmap<node_id,def>;
struct binding_info {
span: span;
binding_mode: binding_mode;
}
// Map from the name in a pattern to its binding mode.
type BindingMap = hashmap<ident,binding_info>;
// Implementation resolution // Implementation resolution
// XXX: This kind of duplicates information kept in ty::method. Maybe it // XXX: This kind of duplicates information kept in ty::method. Maybe it
...@@ -3584,38 +3596,54 @@ fn resolve_local(local: @local, visitor: ResolveVisitor) { ...@@ -3584,38 +3596,54 @@ fn resolve_local(local: @local, visitor: ResolveVisitor) {
none, visitor); none, visitor);
} }
fn num_bindings(pat: @pat) -> uint { fn binding_mode_map(pat: @pat) -> BindingMap {
pat_util::pat_binding_ids(self.def_map, pat).len() let result = box_str_hash();
do pat_bindings(self.def_map, pat) |binding_mode, _id, sp, path| {
let ident = path_to_ident(path);
result.insert(ident,
binding_info {span: sp,
binding_mode: binding_mode});
} }
return result;
fn warn_var_patterns(arm: arm) {
/*
The idea here is that an arm like:
alpha | beta
where alpha is a variant and beta is an identifier that
might refer to a variant that's not in scope will result
in a confusing error message. Showing that beta actually binds a
new variable might help.
*/
for arm.pats.each |p| {
do pat_util::pat_bindings(self.def_map, p) |_id, sp, pth| {
self.session.span_note(sp, fmt!{"Treating %s as a variable \
binding, because it does not denote any variant in scope",
path_to_str(pth)});
}
};
} }
fn check_consistent_bindings(arm: arm) { fn check_consistent_bindings(arm: arm) {
if arm.pats.len() == 0 { return; } if arm.pats.len() == 0 { return; }
let good = self.num_bindings(arm.pats[0]); let map_0 = self.binding_mode_map(arm.pats[0]);
for arm.pats.each() |p: @pat| { for arm.pats.eachi() |i, p: @pat| {
if self.num_bindings(p) != good { let map_i = self.binding_mode_map(p);
self.session.span_err(p.span,
~"inconsistent number of bindings"); for map_0.each |key, binding_0| {
self.warn_var_patterns(arm); match map_i.find(key) {
break; none => {
}; self.session.span_err(
}; p.span,
fmt!{"variable `%s` from pattern #1 is \
not bound in pattern #%u",
*key, i + 1});
}
some(binding_i) => {
if binding_0.binding_mode != binding_i.binding_mode {
self.session.span_err(
binding_i.span,
fmt!{"variable `%s` is bound with different \
mode in pattern #%u than in pattern #1",
*key, i + 1});
}
}
}
}
for map_i.each |key, binding| {
if !map_0.contains_key(key) {
self.session.span_err(
binding.span,
fmt!{"variable `%s` from pattern #%u is \
not bound in pattern #1",
*key, i + 1});
}
}
}
} }
fn resolve_arm(arm: arm, visitor: ResolveVisitor) { fn resolve_arm(arm: arm, visitor: ResolveVisitor) {
......
...@@ -662,77 +662,86 @@ enum branch_kind { no_branch, single, switch, compare, } ...@@ -662,77 +662,86 @@ enum branch_kind { no_branch, single, switch, compare, }
} }
} }
struct phi_binding {
pat_id: ast::node_id;
phi_val: ValueRef;
mode: ast::binding_mode;
ty: ty::t;
}
type phi_bindings_list = ~[phi_binding];
// Returns false for unreachable blocks // Returns false for unreachable blocks
fn make_phi_bindings(bcx: block, map: ~[exit_node], fn make_phi_bindings(bcx: block,
ids: pat_util::pat_id_map) -> bool { map: ~[exit_node],
ids: pat_util::pat_id_map)
-> option<phi_bindings_list> {
let _icx = bcx.insn_ctxt(~"alt::make_phi_bindings"); let _icx = bcx.insn_ctxt(~"alt::make_phi_bindings");
let our_block = bcx.llbb as uint; let our_block = bcx.llbb as uint;
let mut success = true, bcx = bcx; let mut phi_bindings = ~[];
for ids.each |name, node_id| { for ids.each |name, node_id| {
let mut llbbs = ~[]; let mut llbbs = ~[];
let mut vals = ~[]; let mut vals = ~[];
let mut binding = none;
for vec::each(map) |ex| { for vec::each(map) |ex| {
if ex.to as uint == our_block { if ex.to as uint == our_block {
match assoc(name, ex.bound) { match assoc(name, ex.bound) {
some(binding) => { some(b) => {
vec::push(llbbs, ex.from); vec::push(llbbs, ex.from);
vec::push(vals, binding.val); vec::push(vals, b.val);
binding = some(b);
} }
none => () none => ()
} }
} }
} }
if vals.len() > 0u {
let local = Phi(bcx, val_ty(vals[0]), vals, llbbs); let binding = match binding {
bcx.fcx.lllocals.insert(node_id, local_mem(local)); some(binding) => binding,
} else { success = false; } none => {
};
if !success {
Unreachable(bcx); Unreachable(bcx);
return none;
}
};
let phi_val = Phi(bcx, val_ty(vals[0]), vals, llbbs);
vec::push(phi_bindings, phi_binding {
pat_id: node_id,
phi_val: phi_val,
mode: binding.mode,
ty: binding.ty
});
} }
return success; return some(move phi_bindings);
} }
// Copies by-value bindings into their homes. // Copies by-value bindings into their homes.
fn copy_by_value_bindings(bcx: block, fn make_pattern_bindings(bcx: block, phi_bindings: phi_bindings_list)
exit_node_map: &[exit_node],
pat_ids: pat_util::pat_id_map)
-> block { -> block {
let mut bcx = bcx; let mut bcx = bcx;
let our_block = bcx.llbb as uint;
for pat_ids.each |name, node_id| {
let bindings = dvec::dvec();
for exit_node_map.each |exit_node| {
if exit_node.to as uint == our_block {
match assoc(name, exit_node.bound) {
none => {}
some(binding) => bindings.push(binding)
}
}
}
if bindings.len() == 0 {
again;
}
let binding = bindings[0]; for phi_bindings.each |binding| {
let phi_val = binding.phi_val;
match binding.mode { match binding.mode {
ast::bind_by_ref => {} ast::bind_by_implicit_ref => {
ast::bind_by_value => { // use local: phi is a ptr to the value
let llvalue; bcx.fcx.lllocals.insert(binding.pat_id,
match bcx.fcx.lllocals.get(node_id) { local_mem(phi_val));
local_mem(llval) =>
llvalue = llval,
local_imm(_) =>
bcx.sess().bug(~"local_imm unexpected here")
} }
ast::bind_by_ref(_) => {
// use local_imm: ptr is the value
bcx.fcx.lllocals.insert(binding.pat_id,
local_imm(phi_val));
}
ast::bind_by_value => {
// by value: make a new temporary and copy the value out
let lltype = type_of::type_of(bcx.fcx.ccx, binding.ty); let lltype = type_of::type_of(bcx.fcx.ccx, binding.ty);
let allocation = alloca(bcx, lltype); let allocation = alloca(bcx, lltype);
let ty = binding.ty; let ty = binding.ty;
bcx = copy_val(bcx, INIT, allocation, bcx = copy_val(bcx, INIT, allocation,
load_if_immediate(bcx, llvalue, ty), ty); load_if_immediate(bcx, phi_val, ty), ty);
bcx.fcx.lllocals.insert(node_id, local_mem(allocation)); bcx.fcx.lllocals.insert(binding.pat_id,
local_mem(allocation));
add_clean(bcx, allocation, ty); add_clean(bcx, allocation, ty);
} }
} }
...@@ -810,14 +819,17 @@ fn mk_fail(bcx: block, sp: span, msg: ~str, ...@@ -810,14 +819,17 @@ fn mk_fail(bcx: block, sp: span, msg: ~str,
for vec::each(arms) |a| { for vec::each(arms) |a| {
let body_cx = bodies[i]; let body_cx = bodies[i];
let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]); let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]);
if make_phi_bindings(body_cx, exit_map, id_map) { match make_phi_bindings(body_cx, exit_map, id_map) {
let body_cx = copy_by_value_bindings(body_cx, exit_map, id_map); none => {}
some(phi_bindings) => {
let body_cx = make_pattern_bindings(body_cx, phi_bindings);
let arm_dest = dup_for_join(dest); let arm_dest = dup_for_join(dest);
vec::push(arm_dests, arm_dest); vec::push(arm_dests, arm_dest);
let mut arm_cx = trans_block(body_cx, a.body, arm_dest); let mut arm_cx = trans_block(body_cx, a.body, arm_dest);
arm_cx = trans_block_cleanups(arm_cx, body_cx); arm_cx = trans_block_cleanups(arm_cx, body_cx);
vec::push(arm_cxs, arm_cx); vec::push(arm_cxs, arm_cx);
} }
}
i += 1u; i += 1u;
} }
join_returns(scope_cx, arm_cxs, arm_dests, dest) join_returns(scope_cx, arm_cxs, arm_dests, dest)
......
...@@ -930,7 +930,7 @@ fn ast_constr_to_sp_constr(tcx: ty::ctxt, args: ~[arg], c: @constr) -> ...@@ -930,7 +930,7 @@ fn ast_constr_to_sp_constr(tcx: ty::ctxt, args: ~[arg], c: @constr) ->
fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding { fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding {
let mut lhs = ~[]; let mut lhs = ~[];
do pat_bindings(tcx.def_map, loc.node.pat) |p_id, _s, name| { do pat_bindings(tcx.def_map, loc.node.pat) |_bm, p_id, _s, name| {
vec::push(lhs, local_dest({ident: path_to_ident(name), node: p_id})); vec::push(lhs, local_dest({ident: path_to_ident(name), node: p_id}));
}; };
{lhs: lhs, rhs: loc.node.init} {lhs: lhs, rhs: loc.node.init}
......
...@@ -156,15 +156,32 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { ...@@ -156,15 +156,32 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
} }
fcx.write_ty(pat.id, b_ty); fcx.write_ty(pat.id, b_ty);
} }
ast::pat_ident(_, name, sub) if !pat_is_variant(tcx.def_map, pat) => { ast::pat_ident(bm, name, sub) if !pat_is_variant(tcx.def_map, pat) => {
let vid = lookup_local(fcx, pat.span, pat.id); let vid = lookup_local(fcx, pat.span, pat.id);
let mut typ = ty::mk_var(tcx, vid); let mut typ = ty::mk_var(tcx, vid);
demand::suptype(fcx, pat.span, expected, typ);
match bm {
ast::bind_by_ref(mutbl) => {
// if the binding is like
// ref x | ref const x | ref mut x
// then the type of x is &M T where M is the mutability
// and T is the expected type
let region_var = fcx.infcx.next_region_var_nb();
let mt = {ty: expected, mutbl: mutbl};
let region_ty = ty::mk_rptr(tcx, region_var, mt);
demand::eqtype(fcx, pat.span, region_ty, typ);
}
ast::bind_by_value | ast::bind_by_implicit_ref => {
// otherwise the type of x is the expected type T
demand::eqtype(fcx, pat.span, expected, typ);
}
}
let canon_id = pcx.map.get(ast_util::path_to_ident(name)); let canon_id = pcx.map.get(ast_util::path_to_ident(name));
if canon_id != pat.id { if canon_id != pat.id {
let tv_id = lookup_local(fcx, pat.span, canon_id); let tv_id = lookup_local(fcx, pat.span, canon_id);
let ct = ty::mk_var(tcx, tv_id); let ct = ty::mk_var(tcx, tv_id);
demand::suptype(fcx, pat.span, ct, typ); demand::eqtype(fcx, pat.span, ct, typ);
} }
fcx.write_ty(pat.id, typ); fcx.write_ty(pat.id, typ);
match sub { match sub {
......
...@@ -9,7 +9,7 @@ enum foo { ...@@ -9,7 +9,7 @@ enum foo {
fn main() { fn main() {
import bar::{alpha, charlie}; import bar::{alpha, charlie};
match alpha { match alpha {
alpha | beta => {} //~ ERROR: inconsistent number of bindings alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1
charlie => {} charlie => {}
} }
} }
...@@ -2,6 +2,6 @@ enum foo { alpha, beta(int) } ...@@ -2,6 +2,6 @@ enum foo { alpha, beta(int) }
fn main() { fn main() {
match alpha { match alpha {
alpha | beta(i) => {} //~ ERROR inconsistent number of bindings alpha | beta(i) => {} //~ ERROR variable `i` from pattern #2 is not bound in pattern #1
} }
} }
fn matcher(x: option<int>) {
alt x {
ref some(i) => {} //~ ERROR expected identifier, found enum pattern
none => {}
}
}
fn main() {}
enum opts {
a(int), b(int), c(int)
}
fn matcher1(x: opts) {
alt x {
a(ref i) | b(copy i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
c(_) => {}
}
}
fn matcher2(x: opts) {
alt x {
a(ref i) | b(i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
c(_) => {}
}
}
fn matcher3(x: opts) {
alt x {
a(ref mut i) | b(ref const i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
c(_) => {}
}
}
fn matcher4(x: opts) {
alt x {
a(ref mut i) | b(ref i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1
c(_) => {}
}
}
fn matcher5(x: opts) {
alt x {
a(ref i) | b(ref i) => {}
c(_) => {}
}
}
fn main() {}
\ No newline at end of file
fn main() {
let y = 1;
alt y {
a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2
//~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
}
}
type rec = {
f: int
};
fn destructure(x: &mut rec) {
alt *x {
{f: ref mut f} => *f += 1
}
}
fn main() {
let mut v = {f: 22};
destructure(&mut v);
assert v.f == 23;
}
\ No newline at end of file
fn destructure(x: option<int>) -> int {
alt x {
none => 0,
some(ref v) => *v
}
}
fn main() {
assert destructure(some(22)) == 22;
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册