Skip to content

Commit 0475406

Browse files
committed
infer: better names, docs
1 parent a9979c0 commit 0475406

File tree

1 file changed

+122
-40
lines changed

1 file changed

+122
-40
lines changed

src/rustc/middle/typeck/infer.rs

Lines changed: 122 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,79 @@ to pump constraints along and reach a fixed point, but it does impose
6262
some heuristics in the case where the user is relating two type
6363
variables A <: B.
6464
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
81138
82139
Our current technique is to *try* (transactionally) to relate the
83140
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
105162
`X`, and thus inherits its UB/LB of `@mut int`. This leaves no
106163
flexibility for `T` to later adjust to accommodate `@int`.
107164
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+
108176
## Transactional support
109177
110178
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
156224
subtyping; in particular it may cause region borrowing to occur. See
157225
the big comment later in this file on Type Assignment for specifics.
158226
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+
159238
# Implementation details
160239
161240
We make use of a trait-like impementation strategy to consolidate
@@ -842,7 +921,10 @@ impl infer_ctxt {
842921
}}}}}
843922
}
844923

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>(
846928
vb: &vals_and_bindings<V, bounds<T>>,
847929
a_id: V, b_id: V) -> ures {
848930

@@ -955,23 +1037,23 @@ impl infer_ctxt {
9551037
}
9561038

9571039
/// 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>(
9591041
vb: &vals_and_bindings<V, bounds<T>>,
9601042
a_id: V, b: T) -> ures {
9611043

9621044
let nde_a = self.get(vb, a_id);
9631045
let a_id = nde_a.root;
9641046
let a_bounds = nde_a.possible_types;
9651047

966-
debug!{"vart(%s=%s <: %s)",
1048+
debug!{"var_sub_t(%s=%s <: %s)",
9671049
a_id.to_str(), a_bounds.to_str(self),
9681050
b.to_str(self)};
9691051
let b_bounds = {lb: none, ub: some(b)};
9701052
self.set_var_to_merged_bounds(vb, a_id, a_bounds, b_bounds,
9711053
nde_a.rank)
9721054
}
9731055

974-
fn vart_integral<V: copy vid>(
1056+
fn var_sub_t_integral<V: copy vid>(
9751057
vb: &vals_and_bindings<V, int_ty_set>,
9761058
a_id: V, b: ty::t) -> ures {
9771059

@@ -992,7 +1074,7 @@ impl infer_ctxt {
9921074
}
9931075

9941076
/// 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>(
9961078
vb: &vals_and_bindings<V, bounds<T>>,
9971079
a: T, b_id: V) -> ures {
9981080

@@ -1001,14 +1083,14 @@ impl infer_ctxt {
10011083
let b_id = nde_b.root;
10021084
let b_bounds = nde_b.possible_types;
10031085

1004-
debug!{"tvar(%s <: %s=%s)",
1086+
debug!{"t_sub_var(%s <: %s=%s)",
10051087
a.to_str(self),
10061088
b_id.to_str(), b_bounds.to_str(self)};
10071089
self.set_var_to_merged_bounds(vb, b_id, a_bounds, b_bounds,
10081090
nde_b.rank)
10091091
}
10101092

1011-
fn tvar_integral<V: copy vid>(
1093+
fn t_sub_var_integral<V: copy vid>(
10121094
vb: &vals_and_bindings<V, int_ty_set>,
10131095
a: ty::t, b_id: V) -> ures {
10141096

@@ -1771,8 +1853,8 @@ fn super_tys<C:combine>(
17711853
}
17721854
(ty::ty_int(_), ty::ty_var_integral(b_id)) |
17731855
(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)
17761858
.then(|| ok(a) )
17771859
}
17781860

@@ -1914,20 +1996,20 @@ impl sub: combine {
19141996
do indent {
19151997
match (a, b) {
19161998
(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 {
19192001
ok(a)
19202002
}
19212003
}
19222004
(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 {
19252007
ok(a)
19262008
}
19272009
}
19282010
(_, 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 {
19312013
ok(a)
19322014
}
19332015
}
@@ -1988,16 +2070,16 @@ impl sub: combine {
19882070
ok(a)
19892071
}
19902072
(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) )
19932075
}
19942076
(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) )
19972079
}
19982080
(_, 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) )
20012083
}
20022084
(_, ty::ty_bot) => {
20032085
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>(
25912673

25922674
// Otherwise, we need to merge A and B into one variable. We can
25932675
// 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) )
25952677
}
25962678

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>(
25982680
self: &L, vb: &vals_and_bindings<V, bounds<T>>,
25992681
+a_id: V, +b: T,
26002682
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>(
26062688
// The comments in this function are written for LUB, but they
26072689
// apply equally well to GLB if you inverse upper/lower/sub/super/etc.
26082690

2609-
debug!{"%s.lattice_vart(%s=%s <: %s)",
2691+
debug!{"%s.lattice_var_and_t(%s=%s <: %s)",
26102692
self.tag(),
26112693
a_id.to_str(), a_bounds.to_str(self.infcx()),
26122694
b.to_str(self.infcx())};

0 commit comments

Comments
 (0)