Skip to content

Commit 3f92a77

Browse files
authored
Restrict subtyping (#1970)
I realised that we allow quantifier bounds to vary under subtyping, which is undecidable, see Pierce's POPL '92 paper. This change enforces equivalence.
1 parent fe2e33a commit 3f92a77

File tree

9 files changed

+208
-31
lines changed

9 files changed

+208
-31
lines changed

src/mo_types/type.ml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ let stable t = serializable true t
680680
TODO: haul string_of_typ before the lub/glb business, if possible *)
681681
let str = ref (fun _ -> failwith "")
682682

683+
683684
(* Equivalence & Subtyping *)
684685

685686
module SS = Set.Make (struct type t = typ * typ let compare = compare end)
@@ -748,7 +749,7 @@ let rec rel_typ rel eq t1 t2 =
748749
rel_list rel_typ rel eq ts1 ts2
749750
| Func (s1, c1, tbs1, t11, t12), Func (s2, c2, tbs2, t21, t22) ->
750751
s1 = s2 && c1 = c2 &&
751-
(match rel_binds rel eq tbs1 tbs2 with
752+
(match rel_binds eq eq tbs1 tbs2 with
752753
| Some ts ->
753754
rel_list rel_typ rel eq (List.map (open_ ts) t21) (List.map (open_ ts) t11) &&
754755
rel_list rel_typ rel eq (List.map (open_ ts) t12) (List.map (open_ ts) t22)
@@ -818,6 +819,9 @@ and eq t1 t2 : bool =
818819
and sub t1 t2 : bool =
819820
rel_typ (ref SS.empty) (ref SS.empty) t1 t2
820821

822+
and eq_binds tbs1 tbs2 =
823+
let eq = ref SS.empty in rel_binds eq eq tbs1 tbs2 <> None
824+
821825
and eq_kind' eq k1 k2 : bool =
822826
match k1, k2 with
823827
| Def (tbs1, t1), Def (tbs2, t2)
@@ -843,6 +847,7 @@ and eq_con eq c1 c2 =
843847

844848
let eq_kind k1 k2 : bool = eq_kind' (ref SS.empty) k1 k2
845849

850+
846851
(* Compatibility *)
847852

848853
let compatible_list p co xs1 xs2 =
@@ -997,8 +1002,7 @@ let rec lub' lubs glbs t1 t2 =
9971002
| Obj (s1, tf1), Obj (s2, tf2) when s1 = s2 ->
9981003
Obj (s1, lub_fields lubs glbs tf1 tf2)
9991004
| Func (s1, c1, bs1, args1, res1), Func (s2, c2, bs2, args2, res2) when
1000-
s1 = s2 && c1 = c2 && List.(length bs1 = length bs2) &&
1001-
List.for_all2 (fun b1 b2 -> b1.sort = b2.sort) bs1 bs2 &&
1005+
s1 = s2 && c1 = c2 && eq_binds bs1 bs2 &&
10021006
List.(length args1 = length args2 && length res1 = length res2) ->
10031007
combine_func_parts s1 c1 bs1 args1 res1 bs2 args2 res2 lubs glbs glb' lub'
10041008
| Async (t11, t12), Async (t21, t22) when eq t11 t21 ->
@@ -1071,8 +1075,7 @@ and glb' lubs glbs t1 t2 =
10711075
| Some fs -> Obj (s1, fs)
10721076
)
10731077
| Func (s1, c1, bs1, args1, res1), Func (s2, c2, bs2, args2, res2) when
1074-
s1 = s2 && c1 = c2 && List.(length bs1 = length bs2) &&
1075-
List.for_all2 (fun b1 b2 -> b1.sort = b2.sort) bs1 bs2 &&
1078+
s1 = s2 && c1 = c2 && eq_binds bs1 bs2 &&
10761079
List.(length args1 = length args2 && length res1 = length res2) ->
10771080
combine_func_parts s1 c1 bs1 args1 res1 bs2 args2 res2 lubs glbs lub' glb'
10781081
| Async (t11, t12), Async (t21, t22) when eq t11 t21 ->
@@ -1129,10 +1132,8 @@ and combine_func_parts s c bs1 args1 res1 bs2 args2 res2 lubs glbs contra co =
11291132
let get_con = function | Con (c, []) -> c | _ -> assert false in
11301133
let cs = map get_con ts1 in
11311134
let cl = map (close cs) in
1132-
let combine_binds =
1133-
map2 (fun b1 b2 -> {b1 with bound = contra lubs glbs b1.bound b2.bound}) in
11341135
Func (
1135-
s, c, combine_binds bs1 bs2,
1136+
s, c, bs1,
11361137
cl (map2 (contra lubs glbs) (op args1) (op args2)),
11371138
cl (map2 (co lubs glbs) (op res1) (op res2))
11381139
)

test/fail/bounds-mismatch.mo

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
{
2+
func f(g : <A>() -> ()) {};
3+
f(func<A>() {}); // okay
4+
};
5+
6+
{
7+
func f(g : <A <: Nat>() -> ()) {};
8+
f(func<A <: Nat>() {}); // okay
9+
};
10+
11+
{
12+
func f(g : <A>() -> ()) {};
13+
f(func() {}); // error
14+
};
15+
16+
{
17+
func f(g : () -> ()) {};
18+
f(func<A>() {}); // error
19+
};
20+
21+
{
22+
func f(g : <A>() -> ()) {};
23+
f(func<A <: Nat>() {}); // error
24+
};
25+
26+
{
27+
func f(g : <A <: Nat>() -> ()) {};
28+
f(func<A>() {}); // error
29+
};
30+
31+
{
32+
func f(g : <A <: Int>() -> ()) {};
33+
f(func<A <: Nat>() {}); // error
34+
};
35+
36+
{
37+
func f(g : <A <: Nat>() -> ()) {};
38+
f(func<A <: Int>() {}); // error
39+
};
40+
41+
{
42+
let _ = [func<A>() {}, func<A>() {}]; // okay
43+
};
44+
45+
{
46+
let _ = [func<A <: Nat>() {}, func<A <: Nat>() {}]; // okay
47+
};
48+
49+
{
50+
let _ = [func() {}, func<A>() {}]; // warn
51+
};
52+
53+
{
54+
let _ = [func<A>() {}, func<A <: Nat>() {}]; // warn
55+
};
56+
57+
{
58+
let _ = [func<A <: Int>() {}, func<A <: Nat>() {}]; // warn
59+
};
60+
61+
{
62+
// okay
63+
let _ = [func(_ : <A <: Nat>() -> ()) {}, func(_ : <A <: Nat>() -> ()) {}];
64+
};
65+
66+
{
67+
// no warning
68+
let _ : [None -> ()] = [func(_ : <A <: Nat>() -> ()) {}, func(_ : <A <: Int>() -> ()) {}];
69+
};
70+
71+
72+
{
73+
type A = <X> X -> X;
74+
type B = <Y <: Nat> Y -> Y;
75+
func f(x : A) : B = x;
76+
};
77+
78+
{
79+
type A = <X <: Int, Y <: {}> X -> Y;
80+
type B = <X <: Int, Y <: {x : Nat}> X -> Y;
81+
func f(x : A) : B = x;
82+
};
83+
84+
{
85+
type A = <X <: Nat, Y> X -> Y;
86+
type B = <Y <: Nat, X <: Y> Y -> X;
87+
func f(x : A) : B = x;
88+
};
89+
90+
{
91+
type A = <X, Y> X -> X;
92+
type B = <X <: Y, Y> X -> X;
93+
func f(x : A) : B = x;
94+
};
95+
96+
{
97+
type A = <X, Y, Z <: X> X -> X;
98+
type B = <X, Y <: X, Z <: Y> X -> X;
99+
func f(x : A) : B = x;
100+
};
101+
102+
{
103+
class C() { public let x = 0 };
104+
type A = <X <: {x : Int}> X -> X;
105+
type B = <X <: C> X -> X;
106+
func f(x : A) : B = x;
107+
};
108+
109+
{
110+
class C<X <: Int>() {public func f() : X { f() }};
111+
type A = <X, Y <: {f : () -> X}> X -> X;
112+
type B = <X <: Nat, Y <: C<X>> X -> X;
113+
func f(x : A) : B = x;
114+
};
115+
116+
{
117+
class C<X <: Int>() {public func f() : X { f() }};
118+
type A = <X, Y <: {f : () -> Nat}> X -> X;
119+
type B = <X <: Nat, Y <: C<X>> X -> X;
120+
func f(x : A) : B = x;
121+
};
122+
123+
124+
{
125+
let poly_funcs4 = [
126+
func<A <: Int, B <: Nat> (as : [A], b : B) : A = as[0],
127+
func<B <: Nat, A <: Int> (bs : [B], a : A) : B = bs[0]
128+
];
129+
};

test/fail/ok/bounds-mismatch.tc.ok

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
bounds-mismatch.mo:13.5-13.14: type error, expression of type
2+
() -> ()
3+
cannot produce expected type
4+
<A>() -> ()
5+
bounds-mismatch.mo:18.5-18.17: type error, expression of type
6+
<A>() -> ()
7+
cannot produce expected type
8+
() -> ()
9+
bounds-mismatch.mo:23.5-23.24: type error, expression of type
10+
<A <: Nat>() -> ()
11+
cannot produce expected type
12+
<A>() -> ()
13+
bounds-mismatch.mo:28.5-28.17: type error, expression of type
14+
<A>() -> ()
15+
cannot produce expected type
16+
<A <: Nat>() -> ()
17+
bounds-mismatch.mo:33.5-33.24: type error, expression of type
18+
<A <: Nat>() -> ()
19+
cannot produce expected type
20+
<A <: Int>() -> ()
21+
bounds-mismatch.mo:38.5-38.24: type error, expression of type
22+
<A <: Int>() -> ()
23+
cannot produce expected type
24+
<A <: Nat>() -> ()
25+
bounds-mismatch.mo:50.11-50.36: warning, this array has type [Any] because elements have inconsistent types
26+
bounds-mismatch.mo:54.11-54.46: warning, this array has type [Any] because elements have inconsistent types
27+
bounds-mismatch.mo:58.11-58.53: warning, this array has type [Any] because elements have inconsistent types
28+
bounds-mismatch.mo:75.21-75.22: type error, expression of type
29+
<X>X -> X
30+
cannot produce expected type
31+
<Y <: Nat>Y -> Y
32+
bounds-mismatch.mo:81.21-81.22: type error, expression of type
33+
<X <: Int, Y <: {}>X -> Y
34+
cannot produce expected type
35+
<X <: Int, Y <: {x : Nat}>X -> Y
36+
bounds-mismatch.mo:87.21-87.22: type error, expression of type
37+
<X <: Nat, Y>X -> Y
38+
cannot produce expected type
39+
<Y <: Nat, X <: Y>Y -> X
40+
bounds-mismatch.mo:93.21-93.22: type error, expression of type
41+
<X, Y>X -> X
42+
cannot produce expected type
43+
<X <: Y, Y>X -> X
44+
bounds-mismatch.mo:99.21-99.22: type error, expression of type
45+
<X, Y, Z <: X>X -> X
46+
cannot produce expected type
47+
<X, Y <: X, Z <: Y>X -> X
48+
bounds-mismatch.mo:106.21-106.22: type error, expression of type
49+
<X <: {x : Int}>X -> X
50+
cannot produce expected type
51+
<X <: C>X -> X
52+
bounds-mismatch.mo:113.21-113.22: type error, expression of type
53+
<X, Y <: {f : () -> X}>X -> X
54+
cannot produce expected type
55+
<X <: Nat, Y <: C/1<X>>X -> X
56+
bounds-mismatch.mo:120.21-120.22: type error, expression of type
57+
<X, Y <: {f : () -> Nat}>X -> X
58+
cannot produce expected type
59+
<X <: Nat, Y <: C/2<X>>X -> X
60+
bounds-mismatch.mo:125.21-128.4: warning, this array has type [Any] because elements have inconsistent types
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Return code 1

test/repl/lib/type-lub.mo

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ let poly_funcs3 = [ func<A, B> (as : [A], b : B) : A = as[0]
2525
, func<B, A> (bs : [B], a : A) : B = bs[0]
2626
];
2727

28-
let poly_funcs4 = [ func<A <: Int, B <: Nat> (as : [A], b : B) : A = as[0]
29-
, func<B <: Nat, A <: Int> (bs : [B], a : A) : B = bs[0]
30-
];
31-
3228
let funcs = [ func (a : [Int]) : Nat = a.size()
3329
, func (a : [Nat]) : Int = -42
3430
];

test/repl/ok/type-lub-repl.stdout.ok

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ Motoko compiler (revision XXX)
1717
> 3 : Int
1818
> -42 : Int
1919
> [func, func] : [(<A, B>([A], B) -> A)]
20-
> [func, func] : [(<A <: Nat, B <: Nat>([A], B) -> A)]
21-
> 1 : Nat
22-
> 11 : Nat
2320
> [func, func] : [({#bar} -> ())]
2421
> > > [[42], [25], [77]] : [[Any]]
2522
> [42, 77, [1, 2, 3]] : [Any]

test/repl/type-lub-repl.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ poly_funcs2;
1919
poly_funcs2[0]<Int>([1, 2, 3]);
2020
poly_funcs2[1]<Char>([1, 2, 3]);
2121
poly_funcs3;
22-
poly_funcs4;
23-
poly_funcs4[0]<Nat, Nat>([1, 2, 3], 42);
24-
poly_funcs4[1]<Nat, Nat>([11, 22, 33], 25);
2522
2623
variant_funcs;
2724
variant_funcs[0](#bar);

test/run-drun/type-lub.mo

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ actor a {
2727
, func<B, A> (bs : [B], a : A) : B = bs[0]
2828
];
2929

30-
let poly_funcs4 = [ func<A <: Int, B <: Nat> (as : [A], b : B) : A = as[0]
31-
, func<B <: Nat, A <: Int> (bs : [B], a : A) : B = bs[0]
32-
];
33-
3430
let funcs = [ func (a : [Int]) : Nat = a.size()
3531
, func (a : [Nat]) : Int = -42
3632
];

test/run/type-inclusion.mo

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,52 +108,52 @@ func f(x : A) : B<Nat> = x;
108108

109109
{
110110
type A = <X> X -> X;
111-
type B = <Y <: Nat> Y -> Y;
111+
type B = <Y> Y -> Y;
112112
func f(x : A) : B = x;
113113
};
114114

115115
{
116116
type A = <X <: Int, Y <: {}> X -> Y;
117-
type B = <X <: Int, Y <: {x : Nat}> X -> Y;
117+
type B = <X <: Int, Y <: {}> X -> Y;
118118
func f(x : A) : B = x;
119119
};
120120

121121
{
122122
type A = <X <: Nat, Y> X -> Y;
123-
type B = <Y <: Nat, X <: Y> Y -> X;
123+
type B = <Y <: Nat, X> Y -> X;
124124
func f(x : A) : B = x;
125125
};
126126

127127
{
128128
type A = <X, Y> X -> X;
129-
type B = <X <: Y, Y> X -> X;
129+
type B = <X, Y> X -> X;
130130
func f(x : A) : B = x;
131131
};
132132

133133
{
134134
type A = <X, Y, Z <: X> X -> X;
135-
type B = <X, Y <: X, Z <: Y> X -> X;
135+
type B = <X, Y, Z <: X> X -> X;
136136
func f(x : A) : B = x;
137137
};
138138

139139
{
140140
class C() { public let x = 0 };
141-
type A = <X <: {x : Int}> X -> X;
141+
type A = <X <: C> X -> X;
142142
type B = <X <: C> X -> X;
143143
func f(x : A) : B = x;
144144
};
145145

146146
{
147147
class C<X <: Int>() {public func f() : X { f() }};
148-
type A = <X, Y <: {f : () -> X}> X -> X;
149-
type B = <X <: Nat, Y <: C<X>> X -> X;
148+
type A = <X <: Int, Y <: {f : () -> X}> X -> X;
149+
type B = <X <: Int, Y <: C<X>> X -> X;
150150
func f(x : A) : B = x;
151151
};
152152

153153
{
154154
class C<X <: Int>() {public func f() : X { f() }};
155155
type A = <X, Y <: {f : () -> Nat}> X -> X;
156-
type B = <X <: Nat, Y <: C<X>> X -> X;
156+
type B = <X, Y <: C<Nat>> X -> X;
157157
func f(x : A) : B = x;
158158
};
159159

0 commit comments

Comments
 (0)