@@ -30,7 +30,9 @@ use syntax::print::pprust;
30
30
use syntax:: ptr:: P ;
31
31
32
32
pub fn check_pat < ' a , ' tcx > ( pcx : & pat_ctxt < ' a , ' tcx > ,
33
- pat : & ast:: Pat , expected : Ty < ' tcx > ) {
33
+ pat : & ast:: Pat ,
34
+ expected : Ty < ' tcx > )
35
+ {
34
36
let fcx = pcx. fcx ;
35
37
let tcx = pcx. fcx . ccx . tcx ;
36
38
@@ -46,6 +48,19 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
46
48
check_expr ( fcx, & * * lt) ;
47
49
let expr_ty = fcx. expr_ty ( & * * lt) ;
48
50
fcx. write_ty ( pat. id , expr_ty) ;
51
+
52
+ // somewhat surprising: in this case, the subtyping
53
+ // relation goes the opposite way as the other
54
+ // cases. Actually what we really want is not a subtyping
55
+ // relation at all but rather that there exists a LUB (so
56
+ // that they can be compared). However, in practice,
57
+ // constants are always scalars or strings. For scalars
58
+ // subtyping is irrelevant, and for strings `expr_ty` is
59
+ // type is `&'static str`, so if we say that
60
+ //
61
+ // &'static str <: expected
62
+ //
63
+ // that's equivalent to there existing a LUB.
49
64
demand:: suptype ( fcx, pat. span , expected, expr_ty) ;
50
65
}
51
66
ast:: PatRange ( ref begin, ref end) => {
@@ -54,10 +69,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
54
69
55
70
let lhs_ty = fcx. expr_ty ( & * * begin) ;
56
71
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) ) {
72
+
73
+ let lhs_eq_rhs =
74
+ require_same_types (
75
+ tcx, Some ( fcx. infcx ( ) ) , false , pat. span , lhs_ty, rhs_ty,
76
+ || "mismatched types in range" . to_string ( ) ) ;
77
+
78
+ let numeric_or_char =
79
+ lhs_eq_rhs && ( ty:: type_is_numeric ( lhs_ty) || ty:: type_is_char ( lhs_ty) ) ;
80
+
81
+ if numeric_or_char {
61
82
match valid_range_bounds ( fcx. ccx , & * * begin, & * * end) {
62
83
Some ( false ) => {
63
84
span_err ! ( tcx. sess, begin. span, E0030 ,
@@ -71,38 +92,59 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
71
92
}
72
93
} else {
73
94
span_err ! ( tcx. sess, begin. span, E0029 ,
74
- "only char and numeric types are allowed in range" ) ;
95
+ "only char and numeric types are allowed in range" ) ;
75
96
}
76
97
77
98
fcx. write_ty ( pat. id , lhs_ty) ;
99
+
100
+ // subtyping doens't matter here, as the value is some kind of scalar
78
101
demand:: eqtype ( fcx, pat. span , expected, lhs_ty) ;
79
102
}
80
103
ast:: PatEnum ( ..) | ast:: PatIdent ( ..) if pat_is_const ( & tcx. def_map , pat) => {
81
104
let const_did = tcx. def_map . borrow ( ) [ pat. id ] . clone ( ) . def_id ( ) ;
82
105
let const_scheme = ty:: lookup_item_type ( tcx, const_did) ;
83
- fcx. write_ty ( pat. id , const_scheme. ty ) ;
84
- demand:: suptype ( fcx, pat. span , expected, const_scheme. ty ) ;
106
+ assert ! ( const_scheme. generics. is_empty( ) ) ;
107
+ let const_ty = pcx. fcx . instantiate_type_scheme ( pat. span ,
108
+ & Substs :: empty ( ) ,
109
+ & const_scheme. ty ) ;
110
+ fcx. write_ty ( pat. id , const_ty) ;
111
+
112
+ // FIXME(#20489) -- we should limit the types here to scalars or something!
113
+
114
+ // As with PatLit, what we really want here is that there
115
+ // exist a LUB, but for the cases that can occur, subtype
116
+ // is good enough.
117
+ demand:: suptype ( fcx, pat. span , expected, const_ty) ;
85
118
}
86
119
ast:: PatIdent ( bm, ref path, ref sub) if pat_is_binding ( & tcx. def_map , pat) => {
87
120
let typ = fcx. local_ty ( pat. span , pat. id ) ;
88
121
match bm {
89
122
ast:: BindByRef ( mutbl) => {
90
123
// if the binding is like
91
124
// 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
125
+ // then `x` is assigned a value of type ` &M T` where M is the mutability
126
+ // and T is the expected type.
94
127
let region_var = fcx. infcx ( ) . next_region_var ( infer:: PatternRegion ( pat. span ) ) ;
95
128
let mt = ty:: mt { ty : expected, mutbl : mutbl } ;
96
129
let region_ty = ty:: mk_rptr ( tcx, tcx. mk_region ( region_var) , mt) ;
130
+
131
+ // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
132
+ // required. However, we use equality, which is stronger. See (*) for
133
+ // an explanation.
97
134
demand:: eqtype ( fcx, pat. span , region_ty, typ) ;
98
135
}
99
136
// otherwise the type of x is the expected type T
100
137
ast:: BindByValue ( _) => {
138
+ // As above, `T <: typeof(x)` is required but we
139
+ // use equality, see (*) below.
101
140
demand:: eqtype ( fcx, pat. span , expected, typ) ;
102
141
}
103
142
}
143
+
104
144
fcx. write_ty ( pat. id , typ) ;
105
145
146
+ // if there are multiple arms, make sure they all agree on
147
+ // what the type of the binding `x` ought to be
106
148
let canon_id = pcx. map [ path. node ] ;
107
149
if canon_id != pat. id {
108
150
let ct = fcx. local_ty ( pat. span , canon_id) ;
@@ -124,8 +166,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
124
166
check_pat_struct ( pcx, pat, path, fields. as_slice ( ) , etc, expected) ;
125
167
}
126
168
ast:: PatTup ( ref elements) => {
127
- let element_tys: Vec < _ > = range ( 0 , elements. len ( ) ) . map ( |_| fcx. infcx ( )
128
- . next_ty_var ( ) ) . collect ( ) ;
169
+ let element_tys: Vec < _ > =
170
+ range ( 0 , elements. len ( ) ) . map ( |_| fcx. infcx ( ) . next_ty_var ( ) )
171
+ . collect ( ) ;
129
172
let pat_ty = ty:: mk_tup ( tcx, element_tys. clone ( ) ) ;
130
173
fcx. write_ty ( pat. id , pat_ty) ;
131
174
demand:: eqtype ( fcx, pat. span , expected, pat_ty) ;
@@ -138,7 +181,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
138
181
let uniq_ty = ty:: mk_uniq ( tcx, inner_ty) ;
139
182
140
183
if check_dereferencable ( pcx, pat. span , expected, & * * inner) {
141
- demand:: suptype ( fcx, pat. span , expected, uniq_ty) ;
184
+ // Here, `demand::subtype` is good enough, but I don't
185
+ // think any errors can be introduced by using
186
+ // `demand::eqtype`.
187
+ demand:: eqtype ( fcx, pat. span , expected, uniq_ty) ;
142
188
fcx. write_ty ( pat. id , uniq_ty) ;
143
189
check_pat ( pcx, & * * inner, inner_ty) ;
144
190
} else {
@@ -150,15 +196,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
150
196
let inner_ty = fcx. infcx ( ) . next_ty_var ( ) ;
151
197
152
198
let mutbl =
153
- ty:: deref ( fcx. infcx ( ) . shallow_resolve ( expected) , true )
154
- . map_or ( ast:: MutImmutable , |mt| mt . mutbl ) ;
199
+ ty:: deref ( fcx. infcx ( ) . shallow_resolve ( expected) , true ) . map ( |mt| mt . mutbl )
200
+ . unwrap_or ( ast:: MutImmutable ) ;
155
201
156
202
let mt = ty:: mt { ty : inner_ty, mutbl : mutbl } ;
157
203
let region = fcx. infcx ( ) . next_region_var ( infer:: PatternRegion ( pat. span ) ) ;
158
204
let rptr_ty = ty:: mk_rptr ( tcx, tcx. mk_region ( region) , mt) ;
159
205
160
206
if check_dereferencable ( pcx, pat. span , expected, & * * inner) {
161
- demand:: suptype ( fcx, pat. span , expected, rptr_ty) ;
207
+ // `demand::subtype` would be good enough, but using
208
+ // `eqtype` turns out to be equally general. See (*)
209
+ // below for details.
210
+ demand:: eqtype ( fcx, pat. span , expected, rptr_ty) ;
162
211
fcx. write_ty ( pat. id , rptr_ty) ;
163
212
check_pat ( pcx, & * * inner, inner_ty) ;
164
213
} else {
@@ -181,14 +230,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
181
230
let region = fcx. infcx ( ) . next_region_var ( infer:: PatternRegion ( pat. span ) ) ;
182
231
ty:: mk_slice ( tcx, tcx. mk_region ( region) , ty:: mt {
183
232
ty : inner_ty,
184
- mutbl : ty:: deref ( expected_ty, true )
185
- . map_or ( ast:: MutImmutable , |mt| mt . mutbl )
233
+ mutbl : ty:: deref ( expected_ty, true ) . map ( |mt| mt . mutbl )
234
+ . unwrap_or ( ast:: MutImmutable )
186
235
} )
187
236
}
188
237
} ;
189
238
190
239
fcx. write_ty ( pat. id , pat_ty) ;
191
- demand:: suptype ( fcx, pat. span , expected, pat_ty) ;
240
+
241
+ // `demand::subtype` would be good enough, but using
242
+ // `eqtype` turns out to be equally general. See (*)
243
+ // below for details.
244
+ demand:: eqtype ( fcx, pat. span , expected, pat_ty) ;
192
245
193
246
for elt in before. iter ( ) {
194
247
check_pat ( pcx, & * * elt, inner_ty) ;
@@ -210,6 +263,56 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
210
263
}
211
264
ast:: PatMac ( _) => tcx. sess . bug ( "unexpanded macro" )
212
265
}
266
+
267
+
268
+ // (*) In most of the cases above (literals and constants being
269
+ // the exception), we relate types using strict equality, evewn
270
+ // though subtyping would be sufficient. There are a few reasons
271
+ // for this, some of which are fairly subtle and which cost me
272
+ // (nmatsakis) an hour or two debugging to remember, so I thought
273
+ // I'd write them down this time.
274
+ //
275
+ // 1. Most importantly, there is no loss of expressiveness
276
+ // here. What we are saying is that the type of `x`
277
+ // becomes *exactly* what is expected. This might seem
278
+ // like it will cause errors in a case like this:
279
+ //
280
+ // ```
281
+ // fn foo<'x>(x: &'x int) {
282
+ // let a = 1;
283
+ // let mut z = x;
284
+ // z = &a;
285
+ // }
286
+ // ```
287
+ //
288
+ // The reason we might get an error is that `z` might be
289
+ // assigned a type like `&'x int`, and then we would have
290
+ // a problem when we try to assign `&a` to `z`, because
291
+ // the lifetime of `&a` (i.e., the enclosing block) is
292
+ // shorter than `'x`.
293
+ //
294
+ // HOWEVER, this code works fine. The reason is that the
295
+ // expected type here is whatever type the user wrote, not
296
+ // the initializer's type. In this case the user wrote
297
+ // nothing, so we are going to create a type variable `Z`.
298
+ // Then we will assign the type of the initializer (`&'x
299
+ // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
300
+ // will instantiate `Z` as a type `&'0 int` where `'0` is
301
+ // a fresh region variable, with the constraint that `'x :
302
+ // '0`. So basically we're all set.
303
+ //
304
+ // Note that there are two tests to check that this remains true
305
+ // (`regions-reassign-{match,let}-bound-pointer.rs`).
306
+ //
307
+ // 2. Things go horribly wrong if we use subtype. The reason for
308
+ // THIS is a fairly subtle case involving bound regions. See the
309
+ // `givens` field in `region_inference`, as well as the test
310
+ // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
311
+ // for details. Short version is that we must sometimes detect
312
+ // relationships between specific region variables and regions
313
+ // bound in a closure signature, and that detection gets thrown
314
+ // off when we substitute fresh region variables here to enable
315
+ // subtyping.
213
316
}
214
317
215
318
pub fn check_dereferencable < ' a , ' tcx > ( pcx : & pat_ctxt < ' a , ' tcx > ,
0 commit comments