Skip to content

Commit 0f0fa26

Browse files
committed
Enforce variance rules for mutable types
1 parent 48d351b commit 0f0fa26

9 files changed

+140
-40
lines changed

src/comp/middle/ty.rs

+48-40
Original file line numberDiff line numberDiff line change
@@ -1845,31 +1845,25 @@ mod unify {
18451845
fn record_var_binding_for_expected(
18461846
cx: @ctxt, key: int, typ: t, variance: variance) -> result {
18471847
record_var_binding(
1848-
cx, key, typ,
1849-
lambda (cx: @ctxt, old_type: t, new_type: t) -> result {
1850-
unify_step(cx, old_type, new_type, variance)
1851-
})
1848+
cx, key, typ, variance_transform(variance, covariant))
18521849
}
18531850

18541851
fn record_var_binding_for_actual(
18551852
cx: @ctxt, key: int, typ: t, variance: variance) -> result {
1853+
// Unifying in 'the other direction' so flip the variance
18561854
record_var_binding(
1857-
cx, key, typ,
1858-
lambda (cx: @ctxt, old_type: t, new_type: t) -> result {
1859-
unify_step(cx, new_type, old_type, variance)
1860-
})
1855+
cx, key, typ, variance_transform(variance, contravariant))
18611856
}
18621857

18631858
fn record_var_binding(
1864-
cx: @ctxt, key: int, typ: t,
1865-
unify_types: fn(@ctxt, t, t) -> result) -> result {
1859+
cx: @ctxt, key: int, typ: t, variance: variance) -> result {
18661860

18671861
ufind::grow(cx.vb.sets, (key as uint) + 1u);
18681862
let root = ufind::find(cx.vb.sets, key as uint);
18691863
let result_type = typ;
18701864
alt smallintmap::find::<t>(cx.vb.types, root) {
18711865
some(old_type) {
1872-
alt unify_types(cx, old_type, typ) {
1866+
alt unify_step(cx, old_type, typ, variance) {
18731867
ures_ok(unified_type) { result_type = unified_type; }
18741868
rs { ret rs; }
18751869
}
@@ -1949,10 +1943,24 @@ mod unify {
19491943
}
19501944

19511945
// Unifies two mutability flags.
1952-
fn unify_mut(expected: ast::mutability, actual: ast::mutability) ->
1953-
option::t<ast::mutability> {
1954-
if expected == actual { ret some(expected); }
1955-
if expected == ast::maybe_mut { ret some(actual); }
1946+
fn unify_mut(expected: ast::mutability, actual: ast::mutability,
1947+
variance: variance) ->
1948+
option::t<(ast::mutability, variance)> {
1949+
1950+
// If you're unifying mutability then the thing inside
1951+
// will be invariant on anything it contains
1952+
let newvariance = variance_transform(variance, invariant);
1953+
1954+
if expected == actual { ret some((expected, newvariance)); }
1955+
if variance == covariant {
1956+
if expected == ast::maybe_mut {
1957+
ret some((actual, newvariance));
1958+
}
1959+
} else if variance == contravariant {
1960+
if actual == ast::maybe_mut {
1961+
ret some((expected, newvariance));
1962+
}
1963+
}
19561964
ret none;
19571965
}
19581966
tag fn_common_res {
@@ -2258,13 +2266,13 @@ mod unify {
22582266
ty::ty_box(expected_mt) {
22592267
alt struct(cx.tcx, actual) {
22602268
ty::ty_box(actual_mt) {
2261-
let mut;
2262-
alt unify_mut(expected_mt.mut, actual_mt.mut) {
2269+
let (mut, var) = alt unify_mut(
2270+
expected_mt.mut, actual_mt.mut, variance) {
22632271
none. { ret ures_err(terr_box_mutability); }
2264-
some(m) { mut = m; }
2265-
}
2272+
some(mv) { mv }
2273+
};
22662274
let result = unify_step(
2267-
cx, expected_mt.ty, actual_mt.ty, variance);
2275+
cx, expected_mt.ty, actual_mt.ty, var);
22682276
alt result {
22692277
ures_ok(result_sub) {
22702278
let mt = {ty: result_sub, mut: mut};
@@ -2279,13 +2287,13 @@ mod unify {
22792287
ty::ty_uniq(expected_mt) {
22802288
alt struct(cx.tcx, actual) {
22812289
ty::ty_uniq(actual_mt) {
2282-
let mut = expected_mt.mut;
2283-
alt unify_mut(expected_mt.mut, actual_mt.mut) {
2290+
let (mut, var) = alt unify_mut(
2291+
expected_mt.mut, actual_mt.mut, variance) {
22842292
none. { ret ures_err(terr_box_mutability); }
2285-
some(m) { mut = m; }
2286-
}
2293+
some(mv) { mv }
2294+
};
22872295
let result = unify_step(
2288-
cx, expected_mt.ty, actual_mt.ty, variance);
2296+
cx, expected_mt.ty, actual_mt.ty, var);
22892297
alt result {
22902298
ures_ok(result_mt) {
22912299
let mt = {ty: result_mt, mut: mut};
@@ -2300,13 +2308,13 @@ mod unify {
23002308
ty::ty_vec(expected_mt) {
23012309
alt struct(cx.tcx, actual) {
23022310
ty::ty_vec(actual_mt) {
2303-
let mut;
2304-
alt unify_mut(expected_mt.mut, actual_mt.mut) {
2311+
let (mut, var) = alt unify_mut(
2312+
expected_mt.mut, actual_mt.mut, variance) {
23052313
none. { ret ures_err(terr_vec_mutability); }
2306-
some(m) { mut = m; }
2307-
}
2314+
some(mv) { mv }
2315+
};
23082316
let result = unify_step(
2309-
cx, expected_mt.ty, actual_mt.ty, variance);
2317+
cx, expected_mt.ty, actual_mt.ty, var);
23102318
alt result {
23112319
ures_ok(result_sub) {
23122320
let mt = {ty: result_sub, mut: mut};
@@ -2321,13 +2329,13 @@ mod unify {
23212329
ty::ty_ptr(expected_mt) {
23222330
alt struct(cx.tcx, actual) {
23232331
ty::ty_ptr(actual_mt) {
2324-
let mut;
2325-
alt unify_mut(expected_mt.mut, actual_mt.mut) {
2332+
let (mut, var) = alt unify_mut(
2333+
expected_mt.mut, actual_mt.mut, variance) {
23262334
none. { ret ures_err(terr_vec_mutability); }
2327-
some(m) { mut = m; }
2328-
}
2335+
some(mv) { mv }
2336+
};
23292337
let result = unify_step(
2330-
cx, expected_mt.ty, actual_mt.ty, variance);
2338+
cx, expected_mt.ty, actual_mt.ty, var);
23312339
alt result {
23322340
ures_ok(result_sub) {
23332341
let mt = {ty: result_sub, mut: mut};
@@ -2385,12 +2393,12 @@ mod unify {
23852393
while i < expected_len {
23862394
let expected_field = expected_fields[i];
23872395
let actual_field = actual_fields[i];
2388-
let mut;
2389-
alt unify_mut(expected_field.mt.mut, actual_field.mt.mut)
2396+
let (mut, var) = alt unify_mut(
2397+
expected_field.mt.mut, actual_field.mt.mut, variance)
23902398
{
23912399
none. { ret ures_err(terr_record_mutability); }
2392-
some(m) { mut = m; }
2393-
}
2400+
some(mv) { mv }
2401+
};
23942402
if !str::eq(expected_field.ident, actual_field.ident) {
23952403
let err =
23962404
terr_record_fields(expected_field.ident,
@@ -2399,7 +2407,7 @@ mod unify {
23992407
}
24002408
let result =
24012409
unify_step(cx, expected_field.mt.ty,
2402-
actual_field.mt.ty, variance);
2410+
actual_field.mt.ty, var);
24032411
alt result {
24042412
ures_ok(rty) {
24052413
let mt = {ty: rty, mut: mut};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// error-pattern: mismatched types
2+
3+
fn main() {
4+
let v = @mutable [0];
5+
6+
fn f(&&v: @mutable [mutable? int]) {
7+
*v = [mutable 3]
8+
}
9+
10+
f(v);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// error-pattern: mismatched types
2+
3+
fn main() {
4+
let v = [mutable @mutable ~mutable [0]];
5+
6+
fn f(&&v: [mutable @mutable ~mutable [mutable? int]]) {
7+
}
8+
9+
f(v);
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// error-pattern: mismatched types
2+
3+
use std;
4+
5+
fn main() {
6+
let a = [0];
7+
let v: *mutable [int] = std::ptr::addr_of(a);
8+
9+
fn f(&&v: *mutable [mutable? int]) {
10+
unsafe {
11+
*v = [mutable 3]
12+
}
13+
}
14+
15+
f(v);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// error-pattern: mismatched types
2+
3+
fn main() {
4+
let v = {mutable g: [0]};
5+
6+
fn f(&&v: {mutable g: [mutable? int]}) {
7+
v.g = [mutable 3]
8+
}
9+
10+
f(v);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// error-pattern: mismatched types
2+
3+
fn main() {
4+
let v = ~mutable [0];
5+
6+
fn f(&&v: ~mutable [mutable? int]) {
7+
*v = [mutable 3]
8+
}
9+
10+
f(v);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// error-pattern: mismatched types
2+
3+
fn main() {
4+
let v = [mutable [0]];
5+
6+
fn f(&&v: [mutable [mutable? int]]) {
7+
v[0] = [mutable 3]
8+
}
9+
10+
f(v);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// error-pattern: mismatched types
2+
3+
fn main() {
4+
let v = [mutable [mutable 0]];
5+
6+
fn f(&&v: [mutable [mutable? int]]) {
7+
v[0] = [3]
8+
}
9+
10+
f(v);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// error-pattern: mismatched types
2+
3+
fn main() {
4+
let v = [mutable [mutable [0]]];
5+
6+
fn f(&&v: [mutable [mutable [mutable? int]]]) {
7+
v[0][1] = [mutable 3]
8+
}
9+
10+
f(v);
11+
}

0 commit comments

Comments
 (0)