Skip to content

Commit 7e70412

Browse files
committed
Some refactoring and WIP on issue rust-lang#2263.
1 parent ef33c5c commit 7e70412

File tree

5 files changed

+120
-58
lines changed

5 files changed

+120
-58
lines changed

src/rustc/middle/ty.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export ty_opaque_box, mk_opaque_box;
8181
export ty_constr_arg;
8282
export ty_float, mk_float, mk_mach_float, type_is_fp;
8383
export ty_fn, fn_ty, mk_fn;
84-
export ty_fn_proto, ty_fn_ret, ty_fn_ret_style;
84+
export ty_fn_proto, ty_fn_ret, ty_fn_ret_style, tys_in_fn_ty;
8585
export ty_int, mk_int, mk_mach_int, mk_char;
8686
export ty_str, mk_str, type_is_str;
8787
export ty_vec, mk_vec, type_is_vec;
@@ -2090,6 +2090,11 @@ fn is_fn_ty(fty: t) -> bool {
20902090
}
20912091
}
20922092

2093+
// Returns a vec of all the input and output types of fty.
2094+
fn tys_in_fn_ty(fty: fn_ty) -> [t] {
2095+
fty.inputs.map({|a| a.ty}) + [fty.output]
2096+
}
2097+
20932098
// Just checks whether it's a fn that returns bool,
20942099
// not its purity.
20952100
fn is_pred_ty(fty: t) -> bool {

src/rustc/middle/typeck/check.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ type parameter).
6969
import astconv::{ast_conv, ast_ty_to_ty};
7070
import collect::{methods}; // ccx.to_ty()
7171
import method::{methods}; // methods for method::lookup
72-
import regionmanip::{universally_quantify_regions_before_call,
72+
import middle::ty::tys_in_fn_ty;
73+
import regionmanip::{universally_quantify_from_sty,
7374
region_of, replace_bound_regions,
7475
collect_bound_regions_in_tys};
7576
import rscope::*;
@@ -718,7 +719,31 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
718719

719720
let mut bot = false;
720721

721-
let fty = universally_quantify_regions_before_call(fcx, sp, fty);
722+
// Replace all region parameters in the arguments and return
723+
// type with fresh region variables.
724+
725+
#debug["check_call_or_bind: before universal quant., fty=%s",
726+
fcx.ty_to_str(fty)];
727+
728+
// This is subtle: we expect `fty` to be a function type, which
729+
// normally introduce a level of binding. In this case, we want to
730+
// process the types bound by the function but not by any nested
731+
// functions. Therefore, we match one level of structure.
732+
let fty =
733+
alt structure_of(fcx, sp, fty) {
734+
sty @ ty::ty_fn(inner_fty) {
735+
let all_tys = tys_in_fn_ty(inner_fty);
736+
universally_quantify_from_sty(fcx, sp, all_tys, sty)
737+
}
738+
sty {
739+
#debug["not a fn ty: %?", sty];
740+
741+
// if not a function type, we're gonna' report an error at
742+
// some point, since the user is trying to call this thing
743+
fty
744+
}
745+
};
746+
722747
#debug["check_call_or_bind: after universal quant., fty=%s",
723748
fcx.ty_to_str(fty)];
724749

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

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* Code to handle method lookups (which can be quite complex) */
22

33
import syntax::ast_map;
4-
import regionmanip::universally_quantify_regions;
4+
import regionmanip::universally_quantify_from_sty;
55
import middle::typeck::infer::{ty_and_region_var_methods};
66

77
enum lookup = {
@@ -188,13 +188,12 @@ impl methods for lookup {
188188

189189
// Here "self" refers to the callee side...
190190
let self_ty =
191-
universally_quantify_regions(
192-
self.fcx, self.expr.span, self_ty);
191+
universally_quantify_from_sty(
192+
self.fcx, self.expr.span, [self_ty],
193+
ty::get(self_ty).struct);
193194

194195
// ... and "ty" refers to the caller side.
195-
let ty =
196-
universally_quantify_regions(
197-
self.fcx, self.expr.span, self.self_ty);
196+
let ty = self.self_ty;
198197

199198
// if we can assign the caller to the callee, that's a
200199
// potential match. Collect those in the vector.

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

+4-42
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import middle::typeck::infer::{ty_and_region_var_methods};
21
import syntax::print::pprust::{expr_to_str};
32

43
// Helper functions related to manipulating region types.
54

6-
// Helper for the other universally_quantify_*() routines. Extracts the bound
7-
// regions from bound_tys and then replaces those same regions with fresh
8-
// variables in `sty`, returning the resulting type.
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. See also universally_quantify_before_call().
99
fn universally_quantify_from_sty(fcx: @fn_ctxt,
1010
span: span,
1111
bound_tys: [ty::t],
@@ -30,44 +30,6 @@ fn universally_quantify_from_sty(fcx: @fn_ctxt,
3030
}
3131
}
3232

33-
// Replaces all region parameters in the given type with region variables.
34-
// Does not descend into fn types. This is used when deciding whether an impl
35-
// applies at a given call site. See also universally_quantify_before_call().
36-
fn universally_quantify_regions(fcx: @fn_ctxt,
37-
span: span,
38-
ty: ty::t) -> ty::t {
39-
universally_quantify_from_sty(fcx, span, [ty], ty::get(ty).struct)
40-
}
41-
42-
// Expects a function type. Replaces all region parameters in the arguments
43-
// and return type with fresh region variables. This is used when typechecking
44-
// function calls, bind expressions, and method calls.
45-
fn universally_quantify_regions_before_call(fcx: @fn_ctxt,
46-
span: span,
47-
ty: ty::t) -> ty::t {
48-
49-
#debug["universally_quantify_before_call(ty=%s)",
50-
fcx.ty_to_str(ty)];
51-
52-
// This is subtle: we expect `ty` to be a function type, which normally
53-
// introduce a level of binding. In this case, we want to process the
54-
// types bound by the function but not by any nested functions.
55-
// Therefore, we match one level of structure.
56-
alt structure_of(fcx, span, ty) {
57-
sty @ ty::ty_fn(fty) {
58-
let all_tys = fty.inputs.map({|a| a.ty}) + [fty.output];
59-
universally_quantify_from_sty(fcx, span, all_tys, sty)
60-
}
61-
sty {
62-
#debug["not a fn ty: %?", sty];
63-
64-
// if not a function type, we're gonna' report an error
65-
// at some point, since the user is trying to call this thing
66-
ty
67-
}
68-
}
69-
}
70-
7133
fn replace_bound_regions(
7234
tcx: ty::ctxt,
7335
span: span,

src/rustc/middle/typeck/infer.rs

+78-7
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,14 @@ import std::smallintmap::smallintmap;
147147
import std::smallintmap::map;
148148
import std::map::hashmap;
149149
import middle::ty;
150-
import middle::ty::{ty_vid, region_vid, vid};
151-
import syntax::ast;
150+
import middle::ty::{ty_vid, tys_in_fn_ty, region_vid, vid};
151+
import syntax::{ast, ast_util};
152152
import syntax::ast::{ret_style};
153153
import util::ppaux::{ty_to_str, mt_to_str};
154154
import result::{result, extensions, ok, err, map, map2, iter2};
155-
import ty::type_is_bot;
155+
import ty::{mk_fn, type_is_bot};
156+
import check::regionmanip::{collect_bound_regions_in_tys,
157+
replace_bound_regions};
156158
import driver::session::session;
157159
import util::common::{indent, indenter};
158160

@@ -453,6 +455,18 @@ impl ty_and_region_var_methods for infer_ctxt {
453455
fn next_region_var() -> ty::region {
454456
ret ty::re_var(self.next_region_var_id());
455457
}
458+
459+
fn ty_to_str(t: ty::t) -> str {
460+
ty_to_str(self.tcx,
461+
self.resolve_type_vars_if_possible(t))
462+
}
463+
464+
fn resolve_type_vars_if_possible(typ: ty::t) -> ty::t {
465+
alt infer::resolve_deep(self, typ, false) {
466+
result::ok(new_type) { ret new_type; }
467+
result::err(_) { ret typ; }
468+
}
469+
}
456470
}
457471

458472
impl unify_methods for infer_ctxt {
@@ -1579,6 +1593,67 @@ impl of combine for sub {
15791593
}
15801594
}
15811595

1596+
fn fns(a: ty::fn_ty, b: ty::fn_ty) -> cres<ty::fn_ty> {
1597+
// Rather than checking the subtype relationship between `a` and `b`
1598+
// as-is, we need to do some extra work here in order to make sure
1599+
// that function subtyping works correctly with respect to regions
1600+
// (issue #2263).
1601+
1602+
// First, we instantiate each bound region in the subtype with a fresh
1603+
// region variable.
1604+
let a_isr =
1605+
collect_bound_regions_in_tys(self.tcx,
1606+
@nil,
1607+
tys_in_fn_ty(a)) {
1608+
|br|
1609+
let rvar = self.infcx().next_region_var();
1610+
#debug["Bound region %s maps to %s",
1611+
bound_region_to_str(self.tcx, br),
1612+
region_to_str(self.tcx, rvar)];
1613+
rvar
1614+
};
1615+
1616+
let a_ty = replace_bound_regions(self.tcx,
1617+
ast_util::dummy_sp(),
1618+
a_isr,
1619+
mk_fn(self.tcx, a));
1620+
#debug["a_ty: %s", self.infcx().ty_to_str(a_ty)];
1621+
1622+
// Second, we instantiate each bound region in the supertype with a
1623+
// fresh concrete region.
1624+
let b_isr =
1625+
collect_bound_regions_in_tys(self.tcx,
1626+
@nil,
1627+
tys_in_fn_ty(b)) {
1628+
|br| ty::re_bound(br) };
1629+
// FIXME: or maybe re_skolemized? What would that look like?
1630+
// (issue #2263)
1631+
1632+
let b_ty = replace_bound_regions(self.tcx,
1633+
ast_util::dummy_sp(),
1634+
b_isr,
1635+
mk_fn(self.tcx, b));
1636+
#debug["b_ty: %s", self.infcx().ty_to_str(b_ty)];
1637+
1638+
// Turn back into ty::fn_ty.
1639+
alt (ty::get(a_ty).struct, ty::get(b_ty).struct) {
1640+
(ty::ty_fn(a_fn_ty), ty::ty_fn(b_fn_ty)) {
1641+
// Try to compare the supertype and subtype now that they've been
1642+
// instantiated.
1643+
super_fns(self, a_fn_ty, b_fn_ty)
1644+
1645+
}
1646+
_ {
1647+
// Shouldn't happen.
1648+
self.infcx().tcx.sess.bug(
1649+
#fmt["%s: at least one of %s and %s isn't a fn_ty",
1650+
self.tag(),
1651+
self.infcx().ty_to_str(a_ty),
1652+
self.infcx().ty_to_str(b_ty)]);
1653+
}
1654+
}
1655+
}
1656+
15821657
// Traits please:
15831658

15841659
fn flds(a: ty::field, b: ty::field) -> cres<ty::field> {
@@ -1598,10 +1673,6 @@ impl of combine for sub {
15981673
super_args(self, a, b)
15991674
}
16001675

1601-
fn fns(a: ty::fn_ty, b: ty::fn_ty) -> cres<ty::fn_ty> {
1602-
super_fns(self, a, b)
1603-
}
1604-
16051676
fn substs(as: ty::substs, bs: ty::substs) -> cres<ty::substs> {
16061677
super_substs(self, as, bs)
16071678
}

0 commit comments

Comments
 (0)