Check the declaration type in a for loop against the sequence type
Changed the typechecker to correctly typecheck the declared variable type in a for or for-each loop against the vector element type (for a for loop) or the iterator type (for a for-each loop). Added a test case.
This commit is contained in:
parent
0c5a55f275
commit
b6e0c5829f
2 changed files with 62 additions and 15 deletions
|
@ -1872,6 +1872,22 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
check_call_or_bind(scx, f, args_opt_0);
|
check_call_or_bind(scx, f, args_opt_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A generic function for checking for or for-each loops
|
||||||
|
fn check_for_or_for_each(&@stmt_ctxt scx, &@ast::decl decl,
|
||||||
|
&ty::t element_ty, &ast::block body,
|
||||||
|
uint node_id) {
|
||||||
|
check_decl_local(scx.fcx, decl);
|
||||||
|
check_block(scx, body);
|
||||||
|
|
||||||
|
// Unify type of decl with element type of the seq
|
||||||
|
demand::simple(scx, decl.span, ty::decl_local_ty(scx.fcx.ccx.tcx,
|
||||||
|
decl),
|
||||||
|
element_ty);
|
||||||
|
|
||||||
|
auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
|
||||||
|
write::ty_only_fixup(scx, node_id, typ);
|
||||||
|
}
|
||||||
|
|
||||||
alt (expr.node) {
|
alt (expr.node) {
|
||||||
case (ast::expr_lit(?lit, ?a)) {
|
case (ast::expr_lit(?lit, ?a)) {
|
||||||
auto typ = check_lit(scx.fcx.ccx, lit);
|
auto typ = check_lit(scx.fcx.ccx, lit);
|
||||||
|
@ -2000,8 +2016,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
case (none[@ast::expr]) {
|
case (none[@ast::expr]) {
|
||||||
auto nil = ty::mk_nil(scx.fcx.ccx.tcx);
|
auto nil = ty::mk_nil(scx.fcx.ccx.tcx);
|
||||||
if (!are_compatible(scx, scx.fcx.ret_ty, nil)) {
|
if (!are_compatible(scx, scx.fcx.ret_ty, nil)) {
|
||||||
// TODO: span_err
|
scx.fcx.ccx.tcx.sess.span_err(expr.span,
|
||||||
scx.fcx.ccx.tcx.sess.span_err(expr.span,
|
|
||||||
"put; in iterator yielding non-nil");
|
"put; in iterator yielding non-nil");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2159,24 +2174,33 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast::expr_for(?decl, ?seq, ?body, ?a)) {
|
case (ast::expr_for(?decl, ?seq, ?body, ?a)) {
|
||||||
check_decl_local(scx.fcx, decl);
|
|
||||||
check_expr(scx, seq);
|
check_expr(scx, seq);
|
||||||
check_block(scx, body);
|
alt (struct (scx.fcx.ccx.tcx,
|
||||||
|
expr_ty(scx.fcx.ccx.tcx, seq))) {
|
||||||
// FIXME: enforce that the type of the decl is the element type
|
// FIXME: I include the check_for_or_each call in
|
||||||
// of the seq.
|
// each case because of a bug in typestate;
|
||||||
|
// once that bug is fixed, the call can be moved
|
||||||
auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
|
// out of the alt expression
|
||||||
write::ty_only_fixup(scx, a.id, typ);
|
case (ty::ty_vec(?vec_elt_ty)) {
|
||||||
|
auto elt_ty = vec_elt_ty.ty;
|
||||||
|
check_for_or_for_each(scx, decl, elt_ty, body, a.id);
|
||||||
|
}
|
||||||
|
case (ty::ty_str) {
|
||||||
|
auto elt_ty = ty::mk_mach(scx.fcx.ccx.tcx,
|
||||||
|
util::common::ty_u8);
|
||||||
|
check_for_or_for_each(scx, decl, elt_ty, body, a.id);
|
||||||
|
}
|
||||||
|
case (_) {
|
||||||
|
scx.fcx.ccx.tcx.sess.span_err(expr.span,
|
||||||
|
"type of for loop iterator is not a vector or string");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast::expr_for_each(?decl, ?seq, ?body, ?a)) {
|
case (ast::expr_for_each(?decl, ?seq, ?body, ?a)) {
|
||||||
check_decl_local(scx.fcx, decl);
|
|
||||||
check_expr(scx, seq);
|
check_expr(scx, seq);
|
||||||
check_block(scx, body);
|
check_for_or_for_each(scx, decl, expr_ty(scx.fcx.ccx.tcx, seq),
|
||||||
|
body, a.id);
|
||||||
auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
|
|
||||||
write::ty_only_fixup(scx, a.id, typ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case (ast::expr_while(?cond, ?body, ?a)) {
|
case (ast::expr_while(?cond, ?body, ?a)) {
|
||||||
|
|
23
src/test/compile-fail/for-loop-decl.rs
Normal file
23
src/test/compile-fail/for-loop-decl.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// error-pattern: mismatched types
|
||||||
|
use std;
|
||||||
|
import std::map::hashmap;
|
||||||
|
import std::bitv;
|
||||||
|
|
||||||
|
type fn_info = rec(hashmap[uint, var_info] vars);
|
||||||
|
type var_info = rec(uint a, uint b);
|
||||||
|
|
||||||
|
fn bitv_to_str(fn_info enclosing, bitv::t v) -> str {
|
||||||
|
auto s = "";
|
||||||
|
|
||||||
|
// error is that the value type in the hash map is var_info, not a tuple
|
||||||
|
for each (@tup(uint, tup(uint, uint)) p in enclosing.vars.items()) {
|
||||||
|
if (bitv::get(v, p._1._0)) {
|
||||||
|
s += "foo"; // " " + p._1._1 + " " + "[" + p._0 + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret s;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
log "OK";
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue