@@ -62,22 +62,79 @@ to pump constraints along and reach a fixed point, but it does impose
62
62
some heuristics in the case where the user is relating two type
63
63
variables A <: B.
64
64
65
- The key point when relating type variables is that we do not know what
66
- type the variable represents, but we must make some change that will
67
- ensure that, whatever types A and B are resolved to, they are resolved
68
- to types which have a subtype relation.
69
-
70
- There are basically two options here:
71
-
72
- - we can merge A and B. Basically we make them the same variable.
73
- The lower bound of this new variable is LUB(LB(A), LB(B)) and
74
- the upper bound is GLB(UB(A), UB(B)).
75
-
76
- - we can adjust the bounds of A and B. Because we do not allow
77
- type variables to appear in each other's bounds, this only works if A
78
- and B have appropriate bounds. But if we can ensure that UB(A) <: LB(B),
79
- then we know that whatever happens A and B will be resolved to types with
80
- the appropriate relation.
65
+ Combining two variables such that variable A will forever be a subtype
66
+ of variable B is the trickiest part of the algorithm because there is
67
+ often no right choice---that is, the right choice will depend on
68
+ future constraints which we do not yet know. The problem comes about
69
+ because both A and B have bounds that can be adjusted in the future.
70
+ Let's look at some of the cases that can come up.
71
+
72
+ Imagine, to start, the best case, where both A and B have an upper and
73
+ lower bound (that is, the bounds are not top nor bot respectively). In
74
+ that case, if we're lucky, A.ub <: B.lb, and so we know that whatever
75
+ A and B should become, they will forever have the desired subtyping
76
+ relation. We can just leave things as they are.
77
+
78
+ ### Option 1: Unify
79
+
80
+ However, suppose that A.ub is *not* a subtype of B.lb. In
81
+ that case, we must make a decision. One option is to unify A
82
+ and B so that they are one variable whose bounds are:
83
+
84
+ UB = GLB(A.ub, B.ub)
85
+ LB = LUB(A.lb, B.lb)
86
+
87
+ (Note that we will have to verify that LB <: UB; if it does not, the
88
+ types are not intersecting and there is an error) In that case, A <: B
89
+ holds trivially because A==B. However, we have now lost some
90
+ flexibility, because perhaps the user intended for A and B to end up
91
+ as different types and not the same type.
92
+
93
+ Pictorally, what this does is to take two distinct variables with
94
+ (hopefully not completely) distinct type ranges and produce one with
95
+ the intersection.
96
+
97
+ B.ub B.ub
98
+ /\ /
99
+ A.ub / \ A.ub /
100
+ / \ / \ \ /
101
+ / X \ UB
102
+ / / \ \ / \
103
+ / / / \ / /
104
+ \ \ / / \ /
105
+ \ X / LB
106
+ \ / \ / / \
107
+ \ / \ / / \
108
+ A.lb B.lb A.lb B.lb
109
+
110
+
111
+ ### Option 2: Relate UB/LB
112
+
113
+ Another option is to keep A and B as distinct variables but set their
114
+ bounds in such a way that, whatever happens, we know that A <: B will hold.
115
+ This can be achieved by ensuring that A.ub <: B.lb. In practice there
116
+ are two ways to do that, depicted pictorally here:
117
+
118
+ Before Option #1 Option #2
119
+
120
+ B.ub B.ub B.ub
121
+ /\ / \ / \
122
+ A.ub / \ A.ub /(B')\ A.ub /(B')\
123
+ / \ / \ \ / / \ / /
124
+ / X \ __UB____/ UB /
125
+ / / \ \ / | | /
126
+ / / / \ / | | /
127
+ \ \ / / /(A')| | /
128
+ \ X / / LB ______LB/
129
+ \ / \ / / / \ / (A')/ \
130
+ \ / \ / \ / \ \ / \
131
+ A.lb B.lb A.lb B.lb A.lb B.lb
132
+
133
+ In these diagrams, UB and LB are defined as before. As you can see,
134
+ the new ranges `A'` and `B'` are quite different from the range that
135
+ would be produced by unifying the variables.
136
+
137
+ ### What we do now
81
138
82
139
Our current technique is to *try* (transactionally) to relate the
83
140
existing bounds of A and B, if there are any (i.e., if `UB(A) != top
@@ -105,6 +162,17 @@ because the type variable `T` is merged with the type variable for
105
162
`X`, and thus inherits its UB/LB of `@mut int`. This leaves no
106
163
flexibility for `T` to later adjust to accommodate `@int`.
107
164
165
+ ### What to do when not all bounds are present
166
+
167
+ In the prior discussion we assumed that A.ub was not top and B.lb was
168
+ not bot. Unfortunately this is rarely the case. Often type variables
169
+ have "lopsided" bounds. For example, if a variable in the program has
170
+ been initialized but has not been used, then its corresponding type
171
+ variable will have a lower bound but no upper bound. When that
172
+ variable is then used, we would like to know its upper bound---but we
173
+ don't have one! In this case we'll do different things depending on
174
+ how the variable is being used.
175
+
108
176
## Transactional support
109
177
110
178
Whenever we adjust merge variables or adjust their bounds, we always
@@ -156,6 +224,17 @@ We have a notion of assignability which differs somewhat from
156
224
subtyping; in particular it may cause region borrowing to occur. See
157
225
the big comment later in this file on Type Assignment for specifics.
158
226
227
+ ### In conclusion
228
+
229
+ I showed you three ways to relate `A` and `B`. There are also more,
230
+ of course, though I'm not sure if there are any more sensible options.
231
+ The main point is that there are various options, each of which
232
+ produce a distinct range of types for `A` and `B`. Depending on what
233
+ the correct values for A and B are, one of these options will be the
234
+ right choice: but of course we don't know the right values for A and B
235
+ yet, that's what we're trying to find! In our code, we opt to unify
236
+ (Option #1).
237
+
159
238
# Implementation details
160
239
161
240
We make use of a trait-like impementation strategy to consolidate
@@ -842,7 +921,10 @@ impl infer_ctxt {
842
921
} } } } }
843
922
}
844
923
845
- fn vars < V : copy vid, T : copy to_str st> (
924
+ /// Ensure that variable A is a subtype of variable B. This is a
925
+ /// subtle and tricky process, as described in detail at the top
926
+ /// of this file.
927
+ fn var_sub_var < V : copy vid, T : copy to_str st> (
846
928
vb : & vals_and_bindings < V , bounds < T > > ,
847
929
a_id : V , b_id : V ) -> ures {
848
930
@@ -955,23 +1037,23 @@ impl infer_ctxt {
955
1037
}
956
1038
957
1039
/// make variable a subtype of T
958
- fn vart < V : copy vid, T : copy to_str st> (
1040
+ fn var_sub_t < V : copy vid, T : copy to_str st> (
959
1041
vb : & vals_and_bindings < V , bounds < T > > ,
960
1042
a_id : V , b : T ) -> ures {
961
1043
962
1044
let nde_a = self . get ( vb, a_id) ;
963
1045
let a_id = nde_a. root ;
964
1046
let a_bounds = nde_a. possible_types ;
965
1047
966
- debug ! { "vart (%s=%s <: %s)" ,
1048
+ debug ! { "var_sub_t (%s=%s <: %s)" ,
967
1049
a_id. to_str( ) , a_bounds. to_str( self ) ,
968
1050
b. to_str( self ) } ;
969
1051
let b_bounds = { lb: none, ub: some ( b) } ;
970
1052
self . set_var_to_merged_bounds ( vb, a_id, a_bounds, b_bounds,
971
1053
nde_a. rank )
972
1054
}
973
1055
974
- fn vart_integral < V : copy vid> (
1056
+ fn var_sub_t_integral < V : copy vid> (
975
1057
vb : & vals_and_bindings < V , int_ty_set > ,
976
1058
a_id : V , b : ty:: t ) -> ures {
977
1059
@@ -992,7 +1074,7 @@ impl infer_ctxt {
992
1074
}
993
1075
994
1076
/// make T a subtype of variable
995
- fn tvar < V : copy vid, T : copy to_str st> (
1077
+ fn t_sub_var < V : copy vid, T : copy to_str st> (
996
1078
vb : & vals_and_bindings < V , bounds < T > > ,
997
1079
a : T , b_id : V ) -> ures {
998
1080
@@ -1001,14 +1083,14 @@ impl infer_ctxt {
1001
1083
let b_id = nde_b. root ;
1002
1084
let b_bounds = nde_b. possible_types ;
1003
1085
1004
- debug ! { "tvar (%s <: %s=%s)" ,
1086
+ debug ! { "t_sub_var (%s <: %s=%s)" ,
1005
1087
a. to_str( self ) ,
1006
1088
b_id. to_str( ) , b_bounds. to_str( self ) } ;
1007
1089
self . set_var_to_merged_bounds ( vb, b_id, a_bounds, b_bounds,
1008
1090
nde_b. rank )
1009
1091
}
1010
1092
1011
- fn tvar_integral < V : copy vid> (
1093
+ fn t_sub_var_integral < V : copy vid> (
1012
1094
vb : & vals_and_bindings < V , int_ty_set > ,
1013
1095
a : ty:: t , b_id : V ) -> ures {
1014
1096
@@ -1771,8 +1853,8 @@ fn super_tys<C:combine>(
1771
1853
}
1772
1854
( ty:: ty_int( _) , ty:: ty_var_integral( b_id) ) |
1773
1855
( ty:: ty_uint( _) , ty:: ty_var_integral( b_id) ) => {
1774
- self . infcx ( ) . tvar_integral ( & self . infcx ( ) . ty_var_integral_bindings ,
1775
- a, b_id)
1856
+ self . infcx ( ) . t_sub_var_integral ( & self . infcx ( ) . ty_var_integral_bindings ,
1857
+ a, b_id)
1776
1858
. then ( || ok ( a) )
1777
1859
}
1778
1860
@@ -1914,20 +1996,20 @@ impl sub: combine {
1914
1996
do indent {
1915
1997
match ( a, b) {
1916
1998
( ty:: re_var ( a_id) , ty:: re_var ( b_id) ) => {
1917
- do self . infcx ( ) . vars ( & self . region_var_bindings ,
1918
- a_id, b_id) . then {
1999
+ do self . infcx ( ) . var_sub_var ( & self . region_var_bindings ,
2000
+ a_id, b_id) . then {
1919
2001
ok ( a)
1920
2002
}
1921
2003
}
1922
2004
( ty:: re_var ( a_id) , _) => {
1923
- do self . infcx ( ) . vart ( & self . region_var_bindings ,
1924
- a_id, b) . then {
2005
+ do self . infcx ( ) . var_sub_t ( & self . region_var_bindings ,
2006
+ a_id, b) . then {
1925
2007
ok ( a)
1926
2008
}
1927
2009
}
1928
2010
( _, ty:: re_var ( b_id) ) => {
1929
- do self . infcx ( ) . tvar ( & self . region_var_bindings ,
1930
- a, b_id) . then {
2011
+ do self . infcx ( ) . t_sub_var ( & self . region_var_bindings ,
2012
+ a, b_id) . then {
1931
2013
ok ( a)
1932
2014
}
1933
2015
}
@@ -1988,16 +2070,16 @@ impl sub: combine {
1988
2070
ok ( a)
1989
2071
}
1990
2072
( ty:: ty_var ( a_id) , ty:: ty_var ( b_id) ) => {
1991
- self . infcx ( ) . vars ( & self . ty_var_bindings ,
1992
- a_id, b_id) . then ( || ok ( a) )
2073
+ self . infcx ( ) . var_sub_var ( & self . ty_var_bindings ,
2074
+ a_id, b_id) . then ( || ok ( a) )
1993
2075
}
1994
2076
( ty:: ty_var ( a_id) , _) => {
1995
- self . infcx ( ) . vart ( & self . ty_var_bindings ,
1996
- a_id, b) . then ( || ok ( a) )
2077
+ self . infcx ( ) . var_sub_t ( & self . ty_var_bindings ,
2078
+ a_id, b) . then ( || ok ( a) )
1997
2079
}
1998
2080
( _, ty:: ty_var ( b_id) ) => {
1999
- self . infcx ( ) . tvar ( & self . ty_var_bindings ,
2000
- a, b_id) . then ( || ok ( a) )
2081
+ self . infcx ( ) . t_sub_var ( & self . ty_var_bindings ,
2082
+ a, b_id) . then ( || ok ( a) )
2001
2083
}
2002
2084
( _, ty:: ty_bot) => {
2003
2085
err ( ty:: terr_sorts ( b, a) )
@@ -2591,10 +2673,10 @@ fn lattice_vars<V:copy vid, T:copy to_str st, L:lattice_ops combine>(
2591
2673
2592
2674
// Otherwise, we need to merge A and B into one variable. We can
2593
2675
// then use either variable as an upper bound:
2594
- self . infcx ( ) . vars ( vb, a_vid, b_vid) . then ( || ok ( a_t) )
2676
+ self . infcx ( ) . var_sub_var ( vb, a_vid, b_vid) . then ( || ok ( a_t) )
2595
2677
}
2596
2678
2597
- fn lattice_var_t < V : copy vid, T : copy to_str st, L : lattice_ops combine> (
2679
+ fn lattice_var_and_t < V : copy vid, T : copy to_str st, L : lattice_ops combine> (
2598
2680
self : & L , vb : & vals_and_bindings < V , bounds < T > > ,
2599
2681
+a_id : V , +b : T ,
2600
2682
c_ts : fn ( T , T ) -> cres < T > ) -> cres < T > {
@@ -2606,7 +2688,7 @@ fn lattice_var_t<V:copy vid, T:copy to_str st, L:lattice_ops combine>(
2606
2688
// The comments in this function are written for LUB, but they
2607
2689
// apply equally well to GLB if you inverse upper/lower/sub/super/etc.
2608
2690
2609
- debug ! { "%s.lattice_vart (%s=%s <: %s)" ,
2691
+ debug ! { "%s.lattice_var_and_t (%s=%s <: %s)" ,
2610
2692
self . tag( ) ,
2611
2693
a_id. to_str( ) , a_bounds. to_str( self . infcx( ) ) ,
2612
2694
b. to_str( self . infcx( ) ) } ;
0 commit comments