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.
This commit is contained in:
parent
ecaf9e39c9
commit
a6a5c48c64
@ -148,7 +148,8 @@ type field_pat = {ident: ident, pat: @pat};
|
||||
#[auto_serialize]
|
||||
enum binding_mode {
|
||||
bind_by_value,
|
||||
bind_by_ref
|
||||
bind_by_ref(ast::mutability),
|
||||
bind_by_implicit_ref
|
||||
}
|
||||
|
||||
#[auto_serialize]
|
||||
|
@ -228,7 +228,9 @@ impl helpers of ext_ctxt_helpers for ext_ctxt {
|
||||
let path = @{span: span, global: false, idents: ~[nm],
|
||||
rp: none, types: ~[]};
|
||||
@{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}
|
||||
}
|
||||
|
||||
@ -834,7 +836,7 @@ fn ser_enum(cx: ext_ctxt, tps: ser_tps_map, e_name: ast::ident,
|
||||
// Generate pattern var(v1, v2, v3)
|
||||
|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]),
|
||||
none)
|
||||
} else {
|
||||
|
@ -116,7 +116,7 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
|
||||
@{node: {is_mutbl: false,
|
||||
ty: self.ty_infer(),
|
||||
pat: @{id: self.next_id(),
|
||||
node: ast::pat_ident(ast::bind_by_ref,
|
||||
node: ast::pat_ident(ast::bind_by_implicit_ref,
|
||||
path(ident,
|
||||
self.empty_span()),
|
||||
none),
|
||||
|
@ -16,7 +16,8 @@ import common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed,
|
||||
import dvec::{dvec, extensions};
|
||||
import vec::{push};
|
||||
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,
|
||||
bound_owned, box, by_copy, by_move, by_mutbl_ref, by_ref, by_val,
|
||||
capture_clause, capture_item, cdir_dir_mod, cdir_src_mod,
|
||||
@ -1718,7 +1719,9 @@ class parser {
|
||||
} else {
|
||||
subpat = @{
|
||||
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)
|
||||
};
|
||||
}
|
||||
@ -1749,88 +1752,101 @@ class parser {
|
||||
}
|
||||
}
|
||||
tok => {
|
||||
if !is_ident_or_path(tok) ||
|
||||
self.is_keyword(~"true") || self.is_keyword(~"false") {
|
||||
if !is_ident_or_path(tok)
|
||||
|| self.is_keyword(~"true")
|
||||
|| self.is_keyword(~"false")
|
||||
{
|
||||
let val = self.parse_expr_res(RESTRICT_NO_BAR_OP);
|
||||
if self.eat_keyword(~"to") {
|
||||
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
|
||||
hi = end.span.hi;
|
||||
pat = pat_range(val, end);
|
||||
} else {
|
||||
hi = val.span.hi;
|
||||
pat = pat_lit(val);
|
||||
}
|
||||
} else if self.eat_keyword(~"ref") {
|
||||
let mutbl = self.parse_mutability();
|
||||
pat = self.parse_pat_ident(refutable, bind_by_ref(mutbl));
|
||||
} else if self.eat_keyword(~"copy") {
|
||||
pat = self.parse_pat_ident(refutable, bind_by_value);
|
||||
} else if !is_plain_ident(self.token) {
|
||||
pat = self.parse_enum_variant(refutable);
|
||||
} else {
|
||||
let binding_mode;
|
||||
if self.eat_keyword(~"ref") {
|
||||
binding_mode = bind_by_ref;
|
||||
} else if self.eat_keyword(~"copy") {
|
||||
binding_mode = bind_by_value;
|
||||
} else if refutable {
|
||||
// XXX: Should be bind_by_value, but that's not
|
||||
// backward compatible.
|
||||
binding_mode = bind_by_ref;
|
||||
} else {
|
||||
binding_mode = bind_by_value;
|
||||
}
|
||||
|
||||
if is_plain_ident(self.token) &&
|
||||
match self.look_ahead(1) {
|
||||
token::LPAREN | token::LBRACKET | token::LT => {
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
true
|
||||
}
|
||||
} {
|
||||
let name = self.parse_value_path();
|
||||
let sub = if self.eat(token::AT) {
|
||||
some(self.parse_pat(refutable))
|
||||
}
|
||||
else { none };
|
||||
pat = pat_ident(binding_mode, name, sub);
|
||||
} else {
|
||||
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 {
|
||||
token::LPAREN => match self.look_ahead(1u) {
|
||||
token::BINOP(token::STAR) => {
|
||||
// This is a "top constructor only" pat
|
||||
self.bump(); self.bump();
|
||||
star_pat = true;
|
||||
self.expect(token::RPAREN);
|
||||
}
|
||||
_ => {
|
||||
args = self.parse_unspanned_seq(
|
||||
token::LPAREN, token::RPAREN,
|
||||
seq_sep_trailing_disallowed(token::COMMA),
|
||||
|p| p.parse_pat(refutable));
|
||||
hi = self.span.hi;
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
// this is a plain identifier, like `x` or `x(...)`
|
||||
match self.look_ahead(1) {
|
||||
token::LPAREN | token::LBRACKET | token::LT => {
|
||||
pat = self.parse_enum_variant(refutable);
|
||||
}
|
||||
_ => {
|
||||
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 sub = if self.eat(token::AT) {
|
||||
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");
|
||||
}
|
||||
|
||||
pat_ident(binding_mode, name, sub)
|
||||
}
|
||||
|
||||
fn parse_enum_variant(refutable: bool) -> ast::pat_ {
|
||||
let enum_path = self.parse_path_with_tps(true);
|
||||
match self.token {
|
||||
token::LPAREN => {
|
||||
match self.look_ahead(1u) {
|
||||
token::BINOP(token::STAR) => { // foo(*)
|
||||
self.expect(token::LPAREN);
|
||||
self.expect(token::BINOP(token::STAR));
|
||||
self.expect(token::RPAREN);
|
||||
pat_enum(enum_path, none)
|
||||
}
|
||||
_ => { // foo(a, ..., z)
|
||||
let args = self.parse_unspanned_seq(
|
||||
token::LPAREN, token::RPAREN,
|
||||
seq_sep_trailing_disallowed(token::COMMA),
|
||||
|p| p.parse_pat(refutable));
|
||||
pat_enum(enum_path, some(args))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => { // option::none
|
||||
pat_enum(enum_path, some(~[]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_local(is_mutbl: bool,
|
||||
allow_init: bool) -> @local {
|
||||
let lo = self.span.lo;
|
||||
|
@ -1332,8 +1332,12 @@ fn print_pat(s: ps, &&pat: @ast::pat) {
|
||||
ast::pat_wild => word(s.s, ~"_"),
|
||||
ast::pat_ident(binding_mode, path, sub) => {
|
||||
match binding_mode {
|
||||
ast::bind_by_ref => word_space(s, ~"ref"),
|
||||
ast::bind_by_value => ()
|
||||
ast::bind_by_ref(mutbl) => {
|
||||
word_nbsp(s, ~"ref");
|
||||
print_mutability(s, mutbl);
|
||||
}
|
||||
ast::bind_by_implicit_ref |
|
||||
ast::bind_by_value => {}
|
||||
}
|
||||
print_path(s, path, true);
|
||||
match sub {
|
||||
|
@ -264,15 +264,17 @@ impl public_methods for borrowck_ctxt {
|
||||
mutbl:m, ty:expr_ty}
|
||||
}
|
||||
|
||||
ast::def_binding(vid, ast::bind_by_value) => {
|
||||
// by-value bindings are basically local variables
|
||||
ast::def_binding(vid, ast::bind_by_value) |
|
||||
ast::def_binding(vid, ast::bind_by_ref(_)) => {
|
||||
// by-value/by-ref bindings are local variables
|
||||
@{id:id, span:span,
|
||||
cat:cat_local(vid), lp:some(@lp_local(vid)),
|
||||
mutbl:m_imm, ty:expr_ty}
|
||||
}
|
||||
|
||||
ast::def_binding(pid, ast::bind_by_ref) => {
|
||||
// bindings are "special" since they are implicit pointers.
|
||||
ast::def_binding(pid, ast::bind_by_implicit_ref) => {
|
||||
// implicit-by-ref bindings are "special" since they are
|
||||
// implicit pointers.
|
||||
|
||||
// lookup the mutability for this binding that we found in
|
||||
// gather_loans when we categorized it
|
||||
|
@ -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>) {
|
||||
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};
|
||||
let name = ast_util::path_to_ident(path);
|
||||
(*self).add_live_node_for_node(p_id, lnk_vdef(sp));
|
||||
@ -587,7 +587,7 @@ class liveness {
|
||||
|
||||
fn pat_bindings(pat: @pat, f: fn(live_node, variable, span)) {
|
||||
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 var = self.variable(p_id, sp);
|
||||
f(ln, var, sp);
|
||||
|
@ -15,7 +15,7 @@ type pat_id_map = std::map::hashmap<ident, node_id>;
|
||||
// use the node_id of their namesake in the first pattern.
|
||||
fn pat_id_map(dm: resolve3::DefMap, pat: @pat) -> pat_id_map {
|
||||
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);
|
||||
};
|
||||
return map;
|
||||
@ -33,11 +33,11 @@ fn pat_is_variant(dm: resolve3::DefMap, pat: @pat) -> bool {
|
||||
}
|
||||
|
||||
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| {
|
||||
match p.node {
|
||||
pat_ident(_, pth, _) if !pat_is_variant(dm, p) => {
|
||||
it(p.id, p.span, pth);
|
||||
pat_ident(binding_mode, pth, _) if !pat_is_variant(dm, p) => {
|
||||
it(binding_mode, p.id, p.span, pth);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -46,6 +46,6 @@ fn pat_bindings(dm: resolve3::DefMap, pat: @pat,
|
||||
|
||||
fn pat_binding_ids(dm: resolve3::DefMap, pat: @pat) -> ~[node_id] {
|
||||
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;
|
||||
}
|
||||
|
@ -5,9 +5,13 @@ import metadata::cstore::find_use_stmt_cnum;
|
||||
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
|
||||
import middle::lang_items::LanguageItems;
|
||||
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::{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::{def, def_arg, def_binding, def_class, def_const, def_fn};
|
||||
import syntax::ast::{def_foreign_mod, def_id, def_local, def_mod};
|
||||
@ -36,7 +40,7 @@ import syntax::ast::{ty_uint, variant, view_item, view_item_export};
|
||||
import syntax::ast::{view_item_import, view_item_use, view_path_glob};
|
||||
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::{walk_pat};
|
||||
import syntax::ast_util::{walk_pat, path_to_ident};
|
||||
import syntax::attr::{attr_metas, contains_name};
|
||||
import syntax::print::pprust::{pat_to_str, path_to_str};
|
||||
import syntax::codemap::span;
|
||||
@ -52,12 +56,20 @@ import str::{connect, split_str};
|
||||
import vec::pop;
|
||||
|
||||
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;
|
||||
|
||||
// Definition mapping
|
||||
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
|
||||
|
||||
// XXX: This kind of duplicates information kept in ty::method. Maybe it
|
||||
@ -3584,38 +3596,54 @@ class Resolver {
|
||||
none, visitor);
|
||||
}
|
||||
|
||||
fn num_bindings(pat: @pat) -> uint {
|
||||
pat_util::pat_binding_ids(self.def_map, pat).len()
|
||||
fn binding_mode_map(pat: @pat) -> BindingMap {
|
||||
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) {
|
||||
if arm.pats.len() == 0 { return; }
|
||||
let good = self.num_bindings(arm.pats[0]);
|
||||
for arm.pats.each() |p: @pat| {
|
||||
if self.num_bindings(p) != good {
|
||||
self.session.span_err(p.span,
|
||||
~"inconsistent number of bindings");
|
||||
self.warn_var_patterns(arm);
|
||||
break;
|
||||
};
|
||||
};
|
||||
if arm.pats.len() == 0 { return; }
|
||||
let map_0 = self.binding_mode_map(arm.pats[0]);
|
||||
for arm.pats.eachi() |i, p: @pat| {
|
||||
let map_i = self.binding_mode_map(p);
|
||||
|
||||
for map_0.each |key, binding_0| {
|
||||
match map_i.find(key) {
|
||||
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) {
|
||||
|
@ -662,77 +662,86 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
fn make_phi_bindings(bcx: block, map: ~[exit_node],
|
||||
ids: pat_util::pat_id_map) -> bool {
|
||||
fn make_phi_bindings(bcx: block,
|
||||
map: ~[exit_node],
|
||||
ids: pat_util::pat_id_map)
|
||||
-> option<phi_bindings_list> {
|
||||
let _icx = bcx.insn_ctxt(~"alt::make_phi_bindings");
|
||||
let our_block = bcx.llbb as uint;
|
||||
let mut success = true, bcx = bcx;
|
||||
let mut phi_bindings = ~[];
|
||||
for ids.each |name, node_id| {
|
||||
let mut llbbs = ~[];
|
||||
let mut vals = ~[];
|
||||
let mut binding = none;
|
||||
for vec::each(map) |ex| {
|
||||
if ex.to as uint == our_block {
|
||||
match assoc(name, ex.bound) {
|
||||
some(binding) => {
|
||||
some(b) => {
|
||||
vec::push(llbbs, ex.from);
|
||||
vec::push(vals, binding.val);
|
||||
vec::push(vals, b.val);
|
||||
binding = some(b);
|
||||
}
|
||||
none => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
if vals.len() > 0u {
|
||||
let local = Phi(bcx, val_ty(vals[0]), vals, llbbs);
|
||||
bcx.fcx.lllocals.insert(node_id, local_mem(local));
|
||||
} else { success = false; }
|
||||
};
|
||||
if !success {
|
||||
Unreachable(bcx);
|
||||
|
||||
let binding = match binding {
|
||||
some(binding) => binding,
|
||||
none => {
|
||||
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.
|
||||
fn copy_by_value_bindings(bcx: block,
|
||||
exit_node_map: &[exit_node],
|
||||
pat_ids: pat_util::pat_id_map)
|
||||
-> block {
|
||||
fn make_pattern_bindings(bcx: block, phi_bindings: phi_bindings_list)
|
||||
-> block {
|
||||
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 {
|
||||
ast::bind_by_ref => {}
|
||||
ast::bind_by_implicit_ref => {
|
||||
// use local: phi is a ptr to the value
|
||||
bcx.fcx.lllocals.insert(binding.pat_id,
|
||||
local_mem(phi_val));
|
||||
}
|
||||
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 => {
|
||||
let llvalue;
|
||||
match bcx.fcx.lllocals.get(node_id) {
|
||||
local_mem(llval) =>
|
||||
llvalue = llval,
|
||||
local_imm(_) =>
|
||||
bcx.sess().bug(~"local_imm unexpected here")
|
||||
}
|
||||
|
||||
// by value: make a new temporary and copy the value out
|
||||
let lltype = type_of::type_of(bcx.fcx.ccx, binding.ty);
|
||||
let allocation = alloca(bcx, lltype);
|
||||
let ty = binding.ty;
|
||||
bcx = copy_val(bcx, INIT, allocation,
|
||||
load_if_immediate(bcx, llvalue, ty), ty);
|
||||
bcx.fcx.lllocals.insert(node_id, local_mem(allocation));
|
||||
load_if_immediate(bcx, phi_val, ty), ty);
|
||||
bcx.fcx.lllocals.insert(binding.pat_id,
|
||||
local_mem(allocation));
|
||||
add_clean(bcx, allocation, ty);
|
||||
}
|
||||
}
|
||||
@ -810,13 +819,16 @@ fn trans_alt_inner(scope_cx: block, expr: @ast::expr, arms: ~[ast::arm],
|
||||
for vec::each(arms) |a| {
|
||||
let body_cx = bodies[i];
|
||||
let id_map = pat_util::pat_id_map(tcx.def_map, a.pats[0]);
|
||||
if make_phi_bindings(body_cx, exit_map, id_map) {
|
||||
let body_cx = copy_by_value_bindings(body_cx, exit_map, id_map);
|
||||
let arm_dest = dup_for_join(dest);
|
||||
vec::push(arm_dests, arm_dest);
|
||||
let mut arm_cx = trans_block(body_cx, a.body, arm_dest);
|
||||
arm_cx = trans_block_cleanups(arm_cx, body_cx);
|
||||
vec::push(arm_cxs, arm_cx);
|
||||
match make_phi_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);
|
||||
vec::push(arm_dests, arm_dest);
|
||||
let mut arm_cx = trans_block(body_cx, a.body, arm_dest);
|
||||
arm_cx = trans_block_cleanups(arm_cx, body_cx);
|
||||
vec::push(arm_cxs, arm_cx);
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
|
@ -930,7 +930,7 @@ type binding = {lhs: ~[dest], rhs: option<initializer>};
|
||||
|
||||
fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding {
|
||||
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}));
|
||||
};
|
||||
{lhs: lhs, rhs: loc.node.init}
|
||||
|
@ -156,15 +156,32 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
|
||||
}
|
||||
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 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));
|
||||
if canon_id != pat.id {
|
||||
let tv_id = lookup_local(fcx, pat.span, canon_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);
|
||||
match sub {
|
||||
|
@ -9,7 +9,7 @@ mod bar {
|
||||
fn main() {
|
||||
import bar::{alpha, charlie};
|
||||
match alpha {
|
||||
alpha | beta => {} //~ ERROR: inconsistent number of bindings
|
||||
alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1
|
||||
charlie => {}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ enum foo { alpha, beta(int) }
|
||||
|
||||
fn main() {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
8
src/test/compile-fail/pat-ref-enum.rs
Normal file
8
src/test/compile-fail/pat-ref-enum.rs
Normal file
@ -0,0 +1,8 @@
|
||||
fn matcher(x: option<int>) {
|
||||
alt x {
|
||||
ref some(i) => {} //~ ERROR expected identifier, found enum pattern
|
||||
none => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
41
src/test/compile-fail/resolve-inconsistent-binding-mode.rs
Normal file
41
src/test/compile-fail/resolve-inconsistent-binding-mode.rs
Normal file
@ -0,0 +1,41 @@
|
||||
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() {}
|
7
src/test/compile-fail/resolve-inconsistent-names.rs
Normal file
7
src/test/compile-fail/resolve-inconsistent-names.rs
Normal file
@ -0,0 +1,7 @@
|
||||
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
|
||||
}
|
||||
}
|
15
src/test/run-pass/alt-ref-binding-mut.rs
Normal file
15
src/test/run-pass/alt-ref-binding-mut.rs
Normal file
@ -0,0 +1,15 @@
|
||||
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;
|
||||
}
|
10
src/test/run-pass/alt-ref-binding.rs
Normal file
10
src/test/run-pass/alt-ref-binding.rs
Normal file
@ -0,0 +1,10 @@
|
||||
fn destructure(x: option<int>) -> int {
|
||||
alt x {
|
||||
none => 0,
|
||||
some(ref v) => *v
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert destructure(some(22)) == 22;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user