correct universally_quantify to use structure_of, and introduce a test for this

This commit is contained in:
Niko Matsakis 2012-04-17 16:03:23 -07:00
parent bbfb83c2c5
commit f3f34bf09b
2 changed files with 60 additions and 51 deletions

View File

@ -1975,13 +1975,17 @@ fn universally_quantify_from_sty(fcx: @fn_ctxt,
bound_tys: [ty::t],
sty: ty::sty) -> ty::t {
let tcx = fcx.tcx();
let isr = collect_named_regions_in_tys(tcx, @nil, bound_tys) { |_id|
fcx.next_region_var()
};
let anon_r = fcx.next_region_var();
ty::fold_sty_to_ty(fcx.ccx.tcx, sty) {|t|
replace_bound_regions(tcx, span, anon_r, isr, t)
#debug["universally_quantify_from_sty(bound_tys=%?)",
bound_tys.map {|x| fcx.ty_to_str(x) }];
indent {||
let tcx = fcx.tcx();
let isr = collect_named_regions_in_tys(tcx, @nil, bound_tys) { |_id|
fcx.next_region_var()
};
let anon_r = fcx.next_region_var();
ty::fold_sty_to_ty(fcx.ccx.tcx, sty) { |t|
replace_bound_regions(tcx, span, anon_r, isr, t)
}
}
}
@ -2000,7 +2004,9 @@ fn universally_quantify_regions(fcx: @fn_ctxt,
fn universally_quantify_before_call(fcx: @fn_ctxt,
span: span,
ty: ty::t) -> ty::t {
if !ty::type_has_regions(ty) { ret ty; }
#debug["universally_quantify_before_call(ty=%s)",
fcx.ty_to_str(ty)];
// This is subtle: we expect `ty` to be a function type, which normally
// introduce a level of binding. In this case, we want to process the
@ -2018,12 +2024,14 @@ fn universally_quantify_before_call(fcx: @fn_ctxt,
// - Finally, we can use fold_sty_to_ty() and replace_bound_regions()
// to replace the bound regions as well as the bound anonymous region.
// We have to use fold_sty_to_ty() to ignore the outer fn().
alt ty::get(ty).struct {
alt structure_of(fcx, span, ty) {
sty @ ty::ty_fn(fty) {
let all_tys = fty.inputs.map({|a| a.ty}) + [fty.output];
universally_quantify_from_sty(fcx, span, all_tys, sty)
}
_ {
sty {
#debug["not a fn ty: %?", sty];
// if not a function type, we're gonna' report an error
// at some point, since the user is trying to call this thing
ty
@ -2719,45 +2727,44 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let fty = universally_quantify_before_call(fcx, sp, fty);
#debug["check_call_or_bind: after universal quant., fty=%s",
fcx.ty_to_str(fty)];
let sty = structure_of(fcx, sp, fty);
let supplied_arg_count = vec::len(args);
// Grab the argument types
let mut arg_tys = alt sty {
ty::ty_fn({inputs: arg_tys, _}) { arg_tys }
let arg_tys = alt structure_of(fcx, sp, fty) {
ty::ty_fn({inputs: arg_tys, output: ret_ty, _}) {
let expected_arg_count = vec::len(arg_tys);
if expected_arg_count == supplied_arg_count {
arg_tys.map { |a| a.ty }
} else {
fcx.ccx.tcx.sess.span_err(
sp, #fmt["this function takes %u parameter%s but %u \
parameter%s supplied", expected_arg_count,
if expected_arg_count == 1u {
""
} else {
"s"
},
supplied_arg_count,
if supplied_arg_count == 1u {
" was"
} else {
"s were"
}]);
fcx.next_ty_vars(supplied_arg_count)
}
}
_ {
// I would like to make this span_err, but it's really hard due to
// the way that expr_bind() is written.
fcx.ccx.tcx.sess.span_fatal(sp, "mismatched types: \
expected function or native \
function but found "
+ fcx.ty_to_str(fty))
+ fcx.ty_to_str(fty));
}
};
// Check that the correct number of arguments were supplied.
let expected_arg_count = vec::len(arg_tys);
let supplied_arg_count = vec::len(args);
if expected_arg_count != supplied_arg_count {
fcx.ccx.tcx.sess.span_err(
sp, #fmt["this function takes %u parameter%s but %u \
parameter%s supplied", expected_arg_count,
if expected_arg_count == 1u {
""
} else {
"s"
},
supplied_arg_count,
if supplied_arg_count == 1u {
" was"
} else {
"s were"
}]);
// Just use fresh type variables for the types,
// since we don't know them.
arg_tys = vec::from_fn(supplied_arg_count) {|_i|
{mode: ast::expl(ast::by_ref),
ty: fcx.next_ty_var()}
};
}
// Check the arguments.
// We do this in a pretty awful way: first we typecheck any arguments
// that are not anonymous functions, then we typecheck the anonymous
@ -2775,7 +2782,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
_ { false }
};
if is_block == check_blocks {
let arg_ty = arg_tys[i].ty;
let arg_ty = arg_tys[i];
bot |= check_expr_with_unifier(fcx, a, arg_ty) {||
demand::assign(fcx, a.span, arg_ty, a);
};

View File

@ -1,5 +1,3 @@
// xfail-test
fn with<T>(t: T, f: fn(T)) { f(t) }
fn nested(x: &x.int) { // (1)
@ -26,15 +24,19 @@ fn nested(x: &x.int) { // (1)
//!^ ERROR mismatched types: expected `&x.int` but found `&y.int`
fail;
}
) {|f|
) {|foo|
let a: &x.int = f(x, x) { |_x, _y, z| z };
let b: &x.int = f(x, a) { |_x, _y, z| z };
let c: &x.int = f(a, a) { |_x, _y, z| z };
let a: &x.int = foo(x, x) { |_x, _y, z| z };
let b: &x.int = foo(x, a) { |_x, _y, z| z };
let c: &x.int = foo(a, a) { |_x, _y, z| z };
let d: &x.int = f(x, x) { |_x, _y, z| z };
let e: &x.int = f(x, &a) { |_x, _y, z| z };
let f: &x.int = f(&a, &a) { |_x, _y, z| z };
let z = 3;
let d: &x.int = foo(x, x) { |_x, _y, z| z };
let e: &x.int = foo(x, &z) { |_x, _y, z| z };
let f: &x.int = foo(&z, &z) { |_x, _y, z| z }; //! ERROR mismatched types: expected `&x.int` but found
foo(x, &z) { |x, _y, _z| x }; //! ERROR mismatched types: expected `&z.int` but found `&x.int`
foo(x, &z) { |_x, y, _z| y }; //! ERROR mismatched types: expected `&z.int` but found `&<block at
}
}