Skip to content

Commit d661338

Browse files
committed
Introduce covariance, contravariance and invariance to the type unifier
This will be used to resolve some problems with mutable? covariance and also to implement function subtyping
1 parent b61578e commit d661338

File tree

1 file changed

+47
-22
lines changed

1 file changed

+47
-22
lines changed

src/comp/middle/ty.rs

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,8 @@ mod unify {
18071807
}
18081808

18091809
// Unifies two sets.
1810-
fn union(cx: @ctxt, set_a: uint, set_b: uint) -> union_result {
1810+
fn union(cx: @ctxt, set_a: uint, set_b: uint,
1811+
variance: variance) -> union_result {
18111812
ufind::grow(cx.vb.sets, uint::max(set_a, set_b) + 1u);
18121813
let root_a = ufind::find(cx.vb.sets, set_a);
18131814
let root_b = ufind::find(cx.vb.sets, set_b);
@@ -1831,7 +1832,7 @@ mod unify {
18311832
alt smallintmap::find(cx.vb.types, root_b) {
18321833
none. { replace_type(cx, t_a); ret unres_ok; }
18331834
some(t_b) {
1834-
alt unify_step(cx, t_a, t_b) {
1835+
alt unify_step(cx, t_a, t_b, variance) {
18351836
ures_ok(t_c) { replace_type(cx, t_c); ret unres_ok; }
18361837
ures_err(terr) { ret unres_err(terr); }
18371838
}
@@ -1842,20 +1843,20 @@ mod unify {
18421843
}
18431844

18441845
fn record_var_binding_for_expected(
1845-
cx: @ctxt, key: int, typ: t) -> result {
1846+
cx: @ctxt, key: int, typ: t, variance: variance) -> result {
18461847
record_var_binding(
18471848
cx, key, typ,
18481849
fn (cx: @ctxt, old_type: t, new_type: t) -> result {
1849-
unify_step(cx, old_type, new_type)
1850+
unify_step(cx, old_type, new_type, variance)
18501851
})
18511852
}
18521853

18531854
fn record_var_binding_for_actual(
1854-
cx: @ctxt, key: int, typ: t) -> result {
1855+
cx: @ctxt, key: int, typ: t, variance: variance) -> result {
18551856
record_var_binding(
18561857
cx, key, typ,
18571858
fn (cx: @ctxt, old_type: t, new_type: t) -> result {
1858-
unify_step(cx, new_type, old_type)
1859+
unify_step(cx, new_type, old_type, variance)
18591860
})
18601861
}
18611862

@@ -1960,7 +1961,8 @@ mod unify {
19601961
}
19611962
fn unify_fn_common(cx: @ctxt, _expected: t, _actual: t,
19621963
expected_inputs: [arg], expected_output: t,
1963-
actual_inputs: [arg], actual_output: t) ->
1964+
actual_inputs: [arg], actual_output: t,
1965+
variance: variance) ->
19641966
fn_common_res {
19651967
let expected_len = vec::len::<arg>(expected_inputs);
19661968
let actual_len = vec::len::<arg>(actual_inputs);
@@ -1985,7 +1987,8 @@ mod unify {
19851987
(ures_err(terr_mode_mismatch(expected_input.mode,
19861988
actual_input.mode)));
19871989
} else { expected_input.mode };
1988-
let result = unify_step(cx, expected_input.ty, actual_input.ty);
1990+
let result = unify_step(
1991+
cx, expected_input.ty, actual_input.ty, variance);
19891992
alt result {
19901993
ures_ok(rty) { result_ins += [{mode: result_mode, ty: rty}]; }
19911994
_ { ret fn_common_res_err(result); }
@@ -1994,7 +1997,7 @@ mod unify {
19941997
}
19951998
// Check the output.
19961999

1997-
let result = unify_step(cx, expected_output, actual_output);
2000+
let result = unify_step(cx, expected_output, actual_output, variance);
19982001
alt result {
19992002
ures_ok(rty) { ret fn_common_res_ok(result_ins, rty); }
20002003
_ { ret fn_common_res_err(result); }
@@ -2095,7 +2098,19 @@ mod unify {
20952098
_ { ret fix_ok(typ); }
20962099
}
20972100
}
2098-
fn unify_step(cx: @ctxt, expected: t, actual: t) -> result {
2101+
2102+
// Specifies the allowable subtyping between expected and actual types
2103+
tag variance {
2104+
// Actual may be a subtype of expected
2105+
covariant;
2106+
// Actual may be a supertype of expected
2107+
contravariant;
2108+
// Actual must be the same type as expected
2109+
invariant;
2110+
}
2111+
2112+
fn unify_step(cx: @ctxt, expected: t, actual: t,
2113+
variance: variance) -> result {
20992114
// TODO: rewrite this using tuple pattern matching when available, to
21002115
// avoid all this rightward drift and spikiness.
21012116

@@ -2187,7 +2202,8 @@ mod unify {
21872202
while i < expected_len {
21882203
let expected_tp = expected_tps[i];
21892204
let actual_tp = actual_tps[i];
2190-
let result = unify_step(cx, expected_tp, actual_tp);
2205+
let result = unify_step(
2206+
cx, expected_tp, actual_tp, variance);
21912207
alt result {
21922208
ures_ok(rty) { result_tps += [rty]; }
21932209
_ { ret result; }
@@ -2208,7 +2224,8 @@ mod unify {
22082224
none. { ret ures_err(terr_box_mutability); }
22092225
some(m) { mut = m; }
22102226
}
2211-
let result = unify_step(cx, expected_mt.ty, actual_mt.ty);
2227+
let result = unify_step(
2228+
cx, expected_mt.ty, actual_mt.ty, variance);
22122229
alt result {
22132230
ures_ok(result_sub) {
22142231
let mt = {ty: result_sub, mut: mut};
@@ -2228,7 +2245,8 @@ mod unify {
22282245
none. { ret ures_err(terr_box_mutability); }
22292246
some(m) { mut = m; }
22302247
}
2231-
let result = unify_step(cx, expected_mt.ty, actual_mt.ty);
2248+
let result = unify_step(
2249+
cx, expected_mt.ty, actual_mt.ty, variance);
22322250
alt result {
22332251
ures_ok(result_mt) {
22342252
let mt = {ty: result_mt, mut: mut};
@@ -2248,7 +2266,8 @@ mod unify {
22482266
none. { ret ures_err(terr_vec_mutability); }
22492267
some(m) { mut = m; }
22502268
}
2251-
let result = unify_step(cx, expected_mt.ty, actual_mt.ty);
2269+
let result = unify_step(
2270+
cx, expected_mt.ty, actual_mt.ty, variance);
22522271
alt result {
22532272
ures_ok(result_sub) {
22542273
let mt = {ty: result_sub, mut: mut};
@@ -2268,7 +2287,8 @@ mod unify {
22682287
none. { ret ures_err(terr_vec_mutability); }
22692288
some(m) { mut = m; }
22702289
}
2271-
let result = unify_step(cx, expected_mt.ty, actual_mt.ty);
2290+
let result = unify_step(
2291+
cx, expected_mt.ty, actual_mt.ty, variance);
22722292
alt result {
22732293
ures_ok(result_sub) {
22742294
let mt = {ty: result_sub, mut: mut};
@@ -2286,13 +2306,15 @@ mod unify {
22862306
if ex_id.crate != act_id.crate || ex_id.node != act_id.node {
22872307
ret ures_err(terr_mismatch);
22882308
}
2289-
let result = unify_step(cx, ex_inner, act_inner);
2309+
let result = unify_step(
2310+
cx, ex_inner, act_inner, variance);
22902311
alt result {
22912312
ures_ok(res_inner) {
22922313
let i = 0u;
22932314
let res_tps = [];
22942315
for ex_tp: t in ex_tps {
2295-
let result = unify_step(cx, ex_tp, act_tps[i]);
2316+
let result = unify_step(
2317+
cx, ex_tp, act_tps[i], variance);
22962318
alt result {
22972319
ures_ok(rty) { res_tps += [rty]; }
22982320
_ { ret result; }
@@ -2338,7 +2360,7 @@ mod unify {
23382360
}
23392361
let result =
23402362
unify_step(cx, expected_field.mt.ty,
2341-
actual_field.mt.ty);
2363+
actual_field.mt.ty, variance);
23422364
alt result {
23432365
ures_ok(rty) {
23442366
let mt = {ty: rty, mut: mut};
@@ -2370,7 +2392,8 @@ mod unify {
23702392
while i < expected_len {
23712393
let expected_elem = expected_elems[i];
23722394
let actual_elem = actual_elems[i];
2373-
let result = unify_step(cx, expected_elem, actual_elem);
2395+
let result = unify_step(
2396+
cx, expected_elem, actual_elem, variance);
23742397
alt result {
23752398
ures_ok(rty) { result_elems += [rty]; }
23762399
_ { ret result; }
@@ -2419,7 +2442,8 @@ mod unify {
24192442
// unify the base types...
24202443
alt struct(cx.tcx, actual) {
24212444
ty::ty_constr(actual_t, actual_constrs) {
2422-
let rslt = unify_step(cx, expected_t, actual_t);
2445+
let rslt = unify_step(
2446+
cx, expected_t, actual_t, variance);
24232447
alt rslt {
24242448
ures_ok(rty) {
24252449
// FIXME: probably too restrictive --
@@ -2435,7 +2459,8 @@ mod unify {
24352459
// If the actual type is *not* a constrained type,
24362460
// then we go ahead and just ignore the constraints on
24372461
// the expected type. typestate handles the rest.
2438-
ret unify_step(cx, expected_t, actual);
2462+
ret unify_step(
2463+
cx, expected_t, actual, variance);
24392464
}
24402465
}
24412466
}
@@ -2444,7 +2469,7 @@ mod unify {
24442469
fn unify(expected: t, actual: t, vb: @var_bindings, tcx: ty_ctxt) ->
24452470
result {
24462471
let cx = @{vb: vb, tcx: tcx};
2447-
ret unify_step(cx, expected, actual);
2472+
ret unify_step(cx, expected, actual, covariant);
24482473
}
24492474
fn dump_var_bindings(tcx: ty_ctxt, vb: @var_bindings) {
24502475
let i = 0u;

0 commit comments

Comments
 (0)