Skip to content

Commit e6b9db0

Browse files
committed
refactor region manipulation routines to eliminate duplication
fn subtyping is starting to work, but it's exposing bugs in the code which checks for iface conformance, which doesn't properly skolemize the self region
1 parent b744f52 commit e6b9db0

File tree

4 files changed

+119
-186
lines changed

4 files changed

+119
-186
lines changed

src/rustc/middle/typeck/check.rs

Lines changed: 62 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ import astconv::{ast_conv, ast_ty_to_ty};
7070
import collect::{methods}; // ccx.to_ty()
7171
import method::{methods}; // methods for method::lookup
7272
import middle::ty::tys_in_fn_ty;
73-
import regionmanip::{universally_quantify_from_sty,
73+
import regionmanip::{replace_bound_regions_in_fn_ty,
7474
region_of, replace_bound_regions,
7575
collect_bound_regions_in_tys};
7676
import rscope::*;
@@ -84,7 +84,6 @@ type fn_ctxt =
8484
// Used by loop bodies that return from the outer function
8585
indirect_ret_ty: option<ty::t>,
8686
purity: ast::purity,
87-
proto: ast::proto,
8887
infcx: infer::infer_ctxt,
8988
locals: hashmap<ast::node_id, ty_vid>,
9089

@@ -128,55 +127,41 @@ fn check_bare_fn(ccx: @crate_ctxt,
128127
id: ast::node_id,
129128
self_ty: option<ty::t>) {
130129
let fty = ty::node_id_to_type(ccx.tcx, id);
131-
let ret_ty = ty::ty_fn_ret(fty);
132-
let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
133-
check_fn(ccx, ast::proto_bare, decl, body,
134-
ret_ty, arg_tys, false, none, self_ty);
130+
let fn_ty = alt check ty::get(fty).struct { ty::ty_fn(f) {f} };
131+
check_fn(ccx, self_ty, fn_ty, decl, body, false, none);
135132
}
136133

137134
fn check_fn(ccx: @crate_ctxt,
138-
proto: ast::proto,
135+
self_ty: option<ty::t>,
136+
fn_ty: ty::fn_ty,
139137
decl: ast::fn_decl,
140138
body: ast::blk,
141-
ret_ty: ty::t,
142-
arg_tys: [ty::t],
143139
indirect_ret: bool,
144-
old_fcx: option<@fn_ctxt>,
145-
self_ty: option<ty::t>) {
140+
old_fcx: option<@fn_ctxt>) {
146141

147142
let tcx = ccx.tcx;
148143

149-
let isr = {
150-
// Find the list of in-scope regions. These are derived from the
151-
// various regions that are bound in the argument, return, and self
152-
// types. For each of those bound regions, we will create a mapping
153-
// to a free region tied to the node_id of this function. For an
154-
// in-depth discussion of why we must distinguish bound/free regions,
155-
// see the big comment in region.rs.
156-
let all_tys = arg_tys + [ret_ty] + self_ty.to_vec();
157-
let old_isr = option::map_default(old_fcx, @nil) {
158-
|fcx| fcx.in_scope_regions };
159-
collect_bound_regions_in_tys(tcx, old_isr, all_tys) {
160-
|br| ty::re_free(body.node.id, br) }
161-
};
144+
// ______________________________________________________________________
145+
// First, we have to replace any bound regions in the fn and self
146+
// types with free ones. The free region references will be bound
147+
// the node_id of the body block.
162148

163-
// Replace the bound regions that appear in the arg tys, ret ty, etc with
164-
// the free versions we just collected.
165-
let arg_tys = arg_tys.map {
166-
|arg_ty| replace_bound_regions(tcx, body.span, isr, arg_ty)
167-
};
168-
let ret_ty = {
169-
replace_bound_regions(tcx, body.span, isr, ret_ty)
170-
};
171-
let self_ty = option::map(self_ty) {
172-
|self_ty| replace_bound_regions(tcx, body.span, isr, self_ty)
149+
let {isr, self_ty, fn_ty} = {
150+
let old_isr = option::map_default(old_fcx, @nil,
151+
{ |fcx| fcx.in_scope_regions });
152+
replace_bound_regions_in_fn_ty(tcx, old_isr, self_ty, fn_ty,
153+
{ |br| ty::re_free(body.node.id, br) })
173154
};
174155

156+
let arg_tys = fn_ty.inputs.map { |a| a.ty };
157+
let ret_ty = fn_ty.output;
158+
175159
#debug["check_fn(arg_tys=%?, ret_ty=%?, self_ty=%?)",
176160
arg_tys.map {|a| ty_to_str(tcx, a) },
177161
ty_to_str(tcx, ret_ty),
178162
option::map(self_ty) {|st| ty_to_str(tcx, st) }];
179163

164+
// ______________________________________________________________________
180165
// Create the function context. This is either derived from scratch or,
181166
// in the case of function expressions, based on the outer context.
182167
let fcx: @fn_ctxt = {
@@ -211,7 +196,6 @@ fn check_fn(ccx: @crate_ctxt,
211196
ret_ty: ret_ty,
212197
indirect_ret_ty: indirect_ret_ty,
213198
purity: purity,
214-
proto: proto,
215199
infcx: infcx,
216200
locals: locals,
217201
mut blocks: [],
@@ -708,74 +692,66 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
708692
// A generic function to factor out common logic from call and bind
709693
// expressions.
710694
fn check_call_or_bind(
711-
fcx: @fn_ctxt, sp: span, call_expr_id: ast::node_id, fty: ty::t,
695+
fcx: @fn_ctxt, sp: span, call_expr_id: ast::node_id, in_fty: ty::t,
712696
args: [option<@ast::expr>]) -> {fty: ty::t, bot: bool} {
713697

714698
let mut bot = false;
715699

716700
// Replace all region parameters in the arguments and return
717701
// type with fresh region variables.
718702

719-
#debug["check_call_or_bind: before universal quant., fty=%s",
720-
fcx.infcx.ty_to_str(fty)];
703+
#debug["check_call_or_bind: before universal quant., in_fty=%s",
704+
fcx.infcx.ty_to_str(in_fty)];
721705

722706
// This is subtle: we expect `fty` to be a function type, which
723707
// normally introduce a level of binding. In this case, we want to
724708
// process the types bound by the function but not by any nested
725709
// functions. Therefore, we match one level of structure.
726-
let fty =
727-
alt structure_of(fcx, sp, fty) {
728-
sty @ ty::ty_fn(inner_fty) {
729-
let all_tys = tys_in_fn_ty(inner_fty);
730-
universally_quantify_from_sty(fcx, sp, all_tys, sty)
710+
let fn_ty =
711+
alt structure_of(fcx, sp, in_fty) {
712+
sty @ ty::ty_fn(fn_ty) {
713+
replace_bound_regions_in_fn_ty(
714+
fcx.ccx.tcx, @nil, none, fn_ty,
715+
{ |_br| fcx.infcx.next_region_var() }).fn_ty
731716
}
732717
sty {
733-
#debug["not a fn ty: %?", sty];
734-
735-
// if not a function type, we're gonna' report an error at
736-
// some point, since the user is trying to call this thing
737-
fty
718+
// I would like to make this span_err, but it's
719+
// really hard due to the way that expr_bind() is
720+
// written.
721+
fcx.ccx.tcx.sess.span_fatal(sp, "mismatched types: \
722+
expected function or native \
723+
function but found "
724+
+ fcx.infcx.ty_to_str(in_fty));
738725
}
739726
};
740727

728+
let fty = ty::mk_fn(fcx.tcx(), fn_ty);
741729
#debug["check_call_or_bind: after universal quant., fty=%s",
742730
fcx.infcx.ty_to_str(fty)];
743731

744732
let supplied_arg_count = vec::len(args);
745733

746-
// Grab the argument types
747-
let arg_tys = alt structure_of(fcx, sp, fty) {
748-
ty::ty_fn({inputs: arg_tys, output: ret_ty, _}) {
749-
let expected_arg_count = vec::len(arg_tys);
750-
if expected_arg_count == supplied_arg_count {
751-
arg_tys.map { |a| a.ty }
752-
} else {
753-
fcx.ccx.tcx.sess.span_err(
754-
sp, #fmt["this function takes %u parameter%s but %u \
755-
parameter%s supplied", expected_arg_count,
756-
if expected_arg_count == 1u {
757-
""
758-
} else {
759-
"s"
760-
},
761-
supplied_arg_count,
762-
if supplied_arg_count == 1u {
763-
" was"
764-
} else {
765-
"s were"
766-
}]);
767-
fcx.infcx.next_ty_vars(supplied_arg_count)
768-
}
769-
}
770-
771-
_ {
772-
// I would like to make this span_err, but it's really hard due to
773-
// the way that expr_bind() is written.
774-
fcx.ccx.tcx.sess.span_fatal(sp, "mismatched types: \
775-
expected function or native \
776-
function but found "
777-
+ fcx.infcx.ty_to_str(fty));
778-
}
734+
// Grab the argument types, supplying fresh type variables
735+
// if the wrong number of arguments were supplied
736+
let expected_arg_count = vec::len(fn_ty.inputs);
737+
let arg_tys = if expected_arg_count == supplied_arg_count {
738+
fn_ty.inputs.map { |a| a.ty }
739+
} else {
740+
fcx.ccx.tcx.sess.span_err(
741+
sp, #fmt["this function takes %u parameter%s but %u \
742+
parameter%s supplied", expected_arg_count,
743+
if expected_arg_count == 1u {
744+
""
745+
} else {
746+
"s"
747+
},
748+
supplied_arg_count,
749+
if supplied_arg_count == 1u {
750+
" was"
751+
} else {
752+
"s were"
753+
}]);
754+
fcx.infcx.next_ty_vars(supplied_arg_count)
779755
};
780756

781757
// Check the arguments.
@@ -1049,21 +1025,17 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
10491025
};
10501026

10511027
// construct the function type
1052-
let fty = ty::mk_fn(tcx,
1053-
astconv::ty_of_fn_decl(fcx, fcx, proto, decl,
1054-
expected_tys));
1028+
let fn_ty = astconv::ty_of_fn_decl(fcx, fcx, proto,
1029+
decl, expected_tys);
1030+
let fty = ty::mk_fn(tcx, fn_ty);
10551031

10561032
#debug("check_expr_fn_with_unifier %s fty=%s",
10571033
expr_to_str(expr), fcx.infcx.ty_to_str(fty));
10581034

10591035
fcx.write_ty(expr.id, fty);
10601036

1061-
let ret_ty = ty::ty_fn_ret(fty);
1062-
let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
1063-
1064-
check_fn(fcx.ccx, proto, decl, body,
1065-
ret_ty, arg_tys, is_loop_body, some(fcx),
1066-
fcx.self_ty);
1037+
check_fn(fcx.ccx, fcx.self_ty, fn_ty, decl, body,
1038+
is_loop_body, some(fcx));
10671039
}
10681040

10691041

@@ -1825,7 +1797,6 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
18251797
ret_ty: rty,
18261798
indirect_ret_ty: none,
18271799
purity: ast::pure_fn,
1828-
proto: ast::proto_box,
18291800
infcx: infer::new_infer_ctxt(ccx.tcx),
18301801
locals: int_hash(),
18311802
mut blocks: [],
@@ -1865,7 +1836,6 @@ fn check_enum_variants(ccx: @crate_ctxt,
18651836
ret_ty: rty,
18661837
indirect_ret_ty: none,
18671838
purity: ast::pure_fn,
1868-
proto: ast::proto_box,
18691839
infcx: infer::new_infer_ctxt(ccx.tcx),
18701840
locals: int_hash(),
18711841
mut blocks: [],

src/rustc/middle/typeck/check/method.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/* Code to handle method lookups (which can be quite complex) */
22

33
import syntax::ast_map;
4-
import regionmanip::universally_quantify_from_sty;
54
import middle::typeck::infer::methods; // next_ty_vars
65

76
enum lookup = {

src/rustc/middle/typeck/check/regionmanip.rs

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,40 @@ import syntax::print::pprust::{expr_to_str};
22

33
// Helper functions related to manipulating region types.
44

5-
// Extracts the bound regions from bound_tys and then replaces those same
6-
// regions in `sty` with fresh region variables, returning the resulting type.
7-
// Does not descend into fn types. This is used when deciding whether an impl
8-
// applies at a given call site.
9-
fn universally_quantify_from_sty(fcx: @fn_ctxt,
10-
span: span,
11-
bound_tys: [ty::t],
12-
sty: ty::sty) -> ty::t {
13-
14-
#debug["universally_quantify_from_sty(bound_tys=%?)",
15-
bound_tys.map {|x| fcx.infcx.ty_to_str(x) }];
16-
indent {||
17-
let tcx = fcx.tcx();
18-
let isr = collect_bound_regions_in_tys(tcx, @nil, bound_tys) { |br|
19-
let rvar = fcx.infcx.next_region_var();
20-
#debug["Bound region %s maps to %s",
21-
bound_region_to_str(fcx.ccx.tcx, br),
22-
region_to_str(fcx.ccx.tcx, rvar)];
23-
rvar
24-
};
25-
let t_res = ty::fold_sty_to_ty(fcx.ccx.tcx, sty) { |t|
26-
replace_bound_regions(tcx, span, isr, t)
27-
};
28-
#debug["Result of universal quant. is %s",
29-
fcx.infcx.ty_to_str(t_res)];
30-
t_res
31-
}
5+
fn replace_bound_regions_in_fn_ty(
6+
tcx: ty::ctxt,
7+
isr: isr_alist,
8+
self_ty: option<ty::t>,
9+
fn_ty: ty::fn_ty,
10+
mapf: fn(ty::bound_region) -> ty::region) -> {isr: isr_alist,
11+
self_ty: option<ty::t>,
12+
fn_ty: ty::fn_ty} {
13+
14+
let mut all_tys = ty::tys_in_fn_ty(fn_ty);
15+
for self_ty.each { |t| all_tys += [t] }
16+
17+
#debug["replace_bound_regions_in_fn_ty(self_ty=%?, fn_ty=%s, all_tys=%?)",
18+
self_ty.map { |t| ty_to_str(tcx, t) },
19+
ty_to_str(tcx, ty::mk_fn(tcx, fn_ty)),
20+
all_tys.map { |t| ty_to_str(tcx, t) }];
21+
let _i = indenter();
22+
23+
let isr = collect_bound_regions_in_tys(tcx, isr, all_tys) { |br|
24+
#debug["br=%?", br];
25+
mapf(br)
26+
};
27+
let t_fn = ty::fold_sty_to_ty(tcx, ty::ty_fn(fn_ty)) { |t|
28+
replace_bound_regions(tcx, isr, t)
29+
};
30+
let t_self = self_ty.map { |t| replace_bound_regions(tcx, isr, t) };
31+
32+
#debug["result of replace_bound_regions_in_fn_ty: self_ty=%?, fn_ty=%s",
33+
t_self.map { |t| ty_to_str(tcx, t) },
34+
ty_to_str(tcx, t_fn)];
35+
36+
ret {isr: isr,
37+
self_ty: t_self,
38+
fn_ty: alt check ty::get(t_fn).struct { ty::ty_fn(o) {o} }};
3239
}
3340

3441
// Takes `isr`, a mapping from in-scope region names ("isr"s) to their
@@ -38,7 +45,6 @@ fn universally_quantify_from_sty(fcx: @fn_ctxt,
3845
// with the corresponding bindings in `isr`.
3946
fn replace_bound_regions(
4047
tcx: ty::ctxt,
41-
span: span,
4248
isr: isr_alist,
4349
ty: ty::t) -> ty::t {
4450

@@ -58,8 +64,7 @@ fn replace_bound_regions(
5864
// within that remain bound:
5965
none if in_fn { r }
6066
none {
61-
tcx.sess.span_bug(
62-
span,
67+
tcx.sess.bug(
6368
#fmt["Bound region not found in \
6469
in_scope_regions list: %s",
6570
region_to_str(tcx, r)]);

0 commit comments

Comments
 (0)