@@ -46,6 +46,19 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
46
46
check_expr ( fcx, & * * lt) ;
47
47
let expr_ty = fcx. expr_ty ( & * * lt) ;
48
48
fcx. write_ty ( pat. id , expr_ty) ;
49
+
50
+ // somewhat surprising: in this case, the subtyping
51
+ // relation goes the opposite way as the other
52
+ // cases. Actually what we really want is not a subtyping
53
+ // relation at all but rather that there exists a LUB (so
54
+ // that they can be compared). However, in practice,
55
+ // constants are always scalars or strings. For scalars
56
+ // subtyping is irrelevant, and for strings `expr_ty` is
57
+ // type is `&'static str`, so if we say that
58
+ //
59
+ // &'static str <: expected
60
+ //
61
+ // that's equivalent to there existing a LUB.
49
62
demand:: suptype ( fcx, pat. span , expected, expr_ty) ;
50
63
}
51
64
ast:: PatRange ( ref begin, ref end) => {
@@ -54,10 +67,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
54
67
55
68
let lhs_ty = fcx. expr_ty ( & * * begin) ;
56
69
let rhs_ty = fcx. expr_ty ( & * * end) ;
57
- if require_same_types (
58
- tcx, Some ( fcx. infcx ( ) ) , false , pat. span , lhs_ty, rhs_ty,
59
- || "mismatched types in range" . to_string ( ) )
60
- && ( ty:: type_is_numeric ( lhs_ty) || ty:: type_is_char ( rhs_ty) ) {
70
+
71
+ let lhs_eq_rhs =
72
+ require_same_types (
73
+ tcx, Some ( fcx. infcx ( ) ) , false , pat. span , lhs_ty, rhs_ty,
74
+ || "mismatched types in range" . to_string ( ) ) ;
75
+
76
+ let numeric_or_char =
77
+ lhs_eq_rhs && ( ty:: type_is_numeric ( lhs_ty) || ty:: type_is_char ( lhs_ty) ) ;
78
+
79
+ if numeric_or_char {
61
80
match valid_range_bounds ( fcx. ccx , & * * begin, & * * end) {
62
81
Some ( false ) => {
63
82
span_err ! ( tcx. sess, begin. span, E0030 ,
@@ -75,6 +94,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
75
94
}
76
95
77
96
fcx. write_ty ( pat. id , lhs_ty) ;
97
+
98
+ // subtyping doens't matter here, as the value is some kind of scalar
78
99
demand:: eqtype ( fcx, pat. span , expected, lhs_ty) ;
79
100
}
80
101
ast:: PatEnum ( ..) | ast:: PatIdent ( ..) if pat_is_const ( & tcx. def_map , pat) => {
@@ -89,20 +110,29 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
89
110
ast:: BindByRef ( mutbl) => {
90
111
// if the binding is like
91
112
// ref x | ref const x | ref mut x
92
- // then the type of x is &M T where M is the mutability
93
- // and T is the expected type
113
+ // then `x` is assigned a value of type ` &M T` where M is the mutability
114
+ // and T is the expected type.
94
115
let region_var = fcx. infcx ( ) . next_region_var ( infer:: PatternRegion ( pat. span ) ) ;
95
116
let mt = ty:: mt { ty : expected, mutbl : mutbl } ;
96
117
let region_ty = ty:: mk_rptr ( tcx, tcx. mk_region ( region_var) , mt) ;
118
+
119
+ // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
120
+ // required. However, we use equality, which is stronger. See (*) for
121
+ // an explanation.
97
122
demand:: eqtype ( fcx, pat. span , region_ty, typ) ;
98
123
}
99
124
// otherwise the type of x is the expected type T
100
125
ast:: BindByValue ( _) => {
126
+ // As above, `T <: typeof(x)` is required but we
127
+ // use equality, see (*) below.
101
128
demand:: eqtype ( fcx, pat. span , expected, typ) ;
102
129
}
103
130
}
131
+
104
132
fcx. write_ty ( pat. id , typ) ;
105
133
134
+ // if there are multiple arms, make sure they all agree on
135
+ // what the type of the binding `x` ought to be
106
136
let canon_id = pcx. map [ path. node ] ;
107
137
if canon_id != pat. id {
108
138
let ct = fcx. local_ty ( pat. span , canon_id) ;
@@ -138,7 +168,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
138
168
let uniq_ty = ty:: mk_uniq ( tcx, inner_ty) ;
139
169
140
170
if check_dereferencable ( pcx, pat. span , expected, & * * inner) {
141
- demand:: suptype ( fcx, pat. span , expected, uniq_ty) ;
171
+ // Here, `demand::subtype` is good enough, but I don't
172
+ // think any errors can be introduced by using
173
+ // `demand::eqtype`.
174
+ demand:: eqtype ( fcx, pat. span , expected, uniq_ty) ;
142
175
fcx. write_ty ( pat. id , uniq_ty) ;
143
176
check_pat ( pcx, & * * inner, inner_ty) ;
144
177
} else {
@@ -158,7 +191,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
158
191
let rptr_ty = ty:: mk_rptr ( tcx, tcx. mk_region ( region) , mt) ;
159
192
160
193
if check_dereferencable ( pcx, pat. span , expected, & * * inner) {
161
- demand:: suptype ( fcx, pat. span , expected, rptr_ty) ;
194
+ // `demand::subtype` would be good enough, but using
195
+ // `eqtype` turns out to be equally general. See (*)
196
+ // below for details.
197
+ demand:: eqtype ( fcx, pat. span , expected, rptr_ty) ;
162
198
fcx. write_ty ( pat. id , rptr_ty) ;
163
199
check_pat ( pcx, & * * inner, inner_ty) ;
164
200
} else {
@@ -188,7 +224,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
188
224
} ;
189
225
190
226
fcx. write_ty ( pat. id , pat_ty) ;
191
- demand:: suptype ( fcx, pat. span , expected, pat_ty) ;
227
+
228
+ // `demand::subtype` would be good enough, but using
229
+ // `eqtype` turns out to be equally general. See (*)
230
+ // below for details.
231
+ demand:: eqtype ( fcx, pat. span , expected, pat_ty) ;
192
232
193
233
for elt in before. iter ( ) {
194
234
check_pat ( pcx, & * * elt, inner_ty) ;
@@ -210,6 +250,56 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
210
250
}
211
251
ast:: PatMac ( _) => tcx. sess . bug ( "unexpanded macro" )
212
252
}
253
+
254
+
255
+ // (*) In most of the cases above (literals and constants being
256
+ // the exception), we relate types using strict equality, evewn
257
+ // though subtyping would be sufficient. There are a few reasons
258
+ // for this, some of which are fairly subtle and which cost me
259
+ // (nmatsakis) an hour or two debugging to remember, so I thought
260
+ // I'd write them down this time.
261
+ //
262
+ // 1. Most importantly, there is no loss of expressiveness
263
+ // here. What we are saying is that the type of `x`
264
+ // becomes *exactly* what is expected. This might seem
265
+ // like it will cause errors in a case like this:
266
+ //
267
+ // ```
268
+ // fn foo<'x>(x: &'x int) {
269
+ // let a = 1;
270
+ // let mut z = x;
271
+ // z = &a;
272
+ // }
273
+ // ```
274
+ //
275
+ // The reason we might get an error is that `z` might be
276
+ // assigned a type like `&'x int`, and then we would have
277
+ // a problem when we try to assign `&a` to `z`, because
278
+ // the lifetime of `&a` (i.e., the enclosing block) is
279
+ // shorter than `'x`.
280
+ //
281
+ // HOWEVER, this code works fine. The reason is that the
282
+ // expected type here is whatever type the user wrote, not
283
+ // the initializer's type. In this case the user wrote
284
+ // nothing, so we are going to create a type variable `Z`.
285
+ // Then we will assign the type of the initializer (`&'x
286
+ // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
287
+ // will instantiate `Z` as a type `&'0 int` where `'0` is
288
+ // a fresh region variable, with the constraint that `'x :
289
+ // '0`. So basically we're all set.
290
+ //
291
+ // Note that there are two tests to check that this remains true
292
+ // (`regions-reassign-{match,let}-bound-pointer.rs`).
293
+ //
294
+ // 2. Things go horribly wrong if we use subtype. The reason for
295
+ // THIS is a fairly subtle case involving bound regions. See the
296
+ // `givens` field in `region_inference`, as well as the test
297
+ // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
298
+ // for details. Short version is that we must sometimes detect
299
+ // relationships between specific region variables and regions
300
+ // bound in a closure signature, and that detection gets thrown
301
+ // off when we substitute fresh region variables here to enable
302
+ // subtyping.
213
303
}
214
304
215
305
pub fn check_dereferencable < ' a , ' tcx > ( pcx : & pat_ctxt < ' a , ' tcx > ,
0 commit comments