12
12
use middle:: freevars:: freevar_entry;
13
13
use middle:: freevars;
14
14
use middle:: subst;
15
+ use middle:: ty:: ParameterEnvironment ;
15
16
use middle:: ty;
16
- use middle:: ty_fold;
17
17
use middle:: ty_fold:: TypeFoldable ;
18
- use middle:: typeck;
18
+ use middle:: ty_fold;
19
+ use middle:: typeck:: check:: vtable;
19
20
use middle:: typeck:: { MethodCall , NoAdjustment } ;
21
+ use middle:: typeck;
20
22
use util:: ppaux:: { Repr , ty_to_string} ;
21
23
use util:: ppaux:: UserString ;
22
24
25
+ use std:: collections:: HashSet ;
23
26
use syntax:: ast:: * ;
27
+ use syntax:: ast_util;
24
28
use syntax:: attr;
25
29
use syntax:: codemap:: Span ;
26
30
use syntax:: print:: pprust:: { expr_to_string, ident_to_string} ;
27
- use syntax:: { visit} ;
28
31
use syntax:: visit:: Visitor ;
32
+ use syntax:: visit;
29
33
30
34
// Kind analysis pass.
31
35
//
@@ -47,13 +51,13 @@ use syntax::visit::Visitor;
47
51
// primitives in the stdlib are explicitly annotated to only take sendable
48
52
// types.
49
53
50
- #[ deriving( Clone ) ]
51
54
pub struct Context < ' a > {
52
55
tcx : & ' a ty:: ctxt ,
56
+ struct_and_enum_bounds_checked : HashSet < ty:: t > ,
57
+ parameter_environments : Vec < ParameterEnvironment > ,
53
58
}
54
59
55
60
impl < ' a > Visitor < ( ) > for Context < ' a > {
56
-
57
61
fn visit_expr ( & mut self , ex : & Expr , _: ( ) ) {
58
62
check_expr ( self , ex) ;
59
63
}
@@ -74,12 +78,18 @@ impl<'a> Visitor<()> for Context<'a> {
74
78
fn visit_pat ( & mut self , p : & Pat , _: ( ) ) {
75
79
check_pat ( self , p) ;
76
80
}
81
+
82
+ fn visit_local ( & mut self , l : & Local , _: ( ) ) {
83
+ check_local ( self , l) ;
84
+ }
77
85
}
78
86
79
87
pub fn check_crate ( tcx : & ty:: ctxt ,
80
88
krate : & Crate ) {
81
89
let mut ctx = Context {
82
90
tcx : tcx,
91
+ struct_and_enum_bounds_checked : HashSet :: new ( ) ,
92
+ parameter_environments : Vec :: new ( ) ,
83
93
} ;
84
94
visit:: walk_crate ( & mut ctx, krate, ( ) ) ;
85
95
tcx. sess . abort_if_errors ( ) ;
@@ -165,12 +175,90 @@ fn check_item(cx: &mut Context, item: &Item) {
165
175
match item. node {
166
176
ItemImpl ( _, Some ( ref trait_ref) , ref self_type, _) => {
167
177
check_impl_of_trait ( cx, item, trait_ref, & * * self_type) ;
178
+
179
+ let parameter_environment =
180
+ ParameterEnvironment :: for_item ( cx. tcx , item. id ) ;
181
+ cx. parameter_environments . push ( parameter_environment) ;
182
+
183
+ // Check bounds on the `self` type.
184
+ check_bounds_on_structs_or_enums_in_type_if_possible (
185
+ cx,
186
+ item. span ,
187
+ ty:: node_id_to_type ( cx. tcx , item. id ) ) ;
188
+
189
+ // Check bounds on the trait ref.
190
+ match ty:: impl_trait_ref ( cx. tcx ,
191
+ ast_util:: local_def ( item. id ) ) {
192
+ None => { }
193
+ Some ( trait_ref) => {
194
+ check_bounds_on_structs_or_enums_in_trait_ref (
195
+ cx,
196
+ item. span ,
197
+ & * trait_ref) ;
198
+ }
199
+ }
200
+
201
+ drop ( cx. parameter_environments . pop ( ) ) ;
202
+ }
203
+ ItemEnum ( ..) => {
204
+ let parameter_environment =
205
+ ParameterEnvironment :: for_item ( cx. tcx , item. id ) ;
206
+ cx. parameter_environments . push ( parameter_environment) ;
207
+
208
+ let def_id = ast_util:: local_def ( item. id ) ;
209
+ for variant in ty:: enum_variants ( cx. tcx , def_id) . iter ( ) {
210
+ for arg in variant. args . iter ( ) {
211
+ check_bounds_on_structs_or_enums_in_type_if_possible (
212
+ cx,
213
+ item. span ,
214
+ * arg)
215
+ }
216
+ }
217
+
218
+ drop ( cx. parameter_environments . pop ( ) ) ;
219
+ }
220
+ ItemStruct ( ..) => {
221
+ let parameter_environment =
222
+ ParameterEnvironment :: for_item ( cx. tcx , item. id ) ;
223
+ cx. parameter_environments . push ( parameter_environment) ;
224
+
225
+ let def_id = ast_util:: local_def ( item. id ) ;
226
+ for field in ty:: lookup_struct_fields ( cx. tcx , def_id) . iter ( ) {
227
+ check_bounds_on_structs_or_enums_in_type_if_possible (
228
+ cx,
229
+ item. span ,
230
+ ty:: node_id_to_type ( cx. tcx , field. id . node ) )
231
+ }
232
+
233
+ drop ( cx. parameter_environments . pop ( ) ) ;
234
+
235
+ }
236
+ ItemStatic ( ..) => {
237
+ let parameter_environment =
238
+ ParameterEnvironment :: for_item ( cx. tcx , item. id ) ;
239
+ cx. parameter_environments . push ( parameter_environment) ;
240
+
241
+ check_bounds_on_structs_or_enums_in_type_if_possible (
242
+ cx,
243
+ item. span ,
244
+ ty:: node_id_to_type ( cx. tcx , item. id ) ) ;
245
+
246
+ drop ( cx. parameter_environments . pop ( ) ) ;
168
247
}
169
248
_ => { }
170
249
}
171
250
}
172
251
173
- visit:: walk_item ( cx, item, ( ) ) ;
252
+ visit:: walk_item ( cx, item, ( ) )
253
+ }
254
+
255
+ fn check_local ( cx : & mut Context , local : & Local ) {
256
+ check_bounds_on_structs_or_enums_in_type_if_possible (
257
+ cx,
258
+ local. span ,
259
+ ty:: node_id_to_type ( cx. tcx , local. id ) ) ;
260
+
261
+ visit:: walk_local ( cx, local, ( ) )
174
262
}
175
263
176
264
// Yields the appropriate function to check the kind of closed over
@@ -254,7 +342,25 @@ fn check_fn(
254
342
} ) ;
255
343
} ) ;
256
344
257
- visit:: walk_fn ( cx, fk, decl, body, sp, ( ) ) ;
345
+ match * fk {
346
+ visit:: FkFnBlock ( ..) => {
347
+ let ty = ty:: node_id_to_type ( cx. tcx , fn_id) ;
348
+ check_bounds_on_structs_or_enums_in_type_if_possible ( cx, sp, ty) ;
349
+
350
+ visit:: walk_fn ( cx, fk, decl, body, sp, ( ) )
351
+ }
352
+ visit:: FkItemFn ( ..) | visit:: FkMethod ( ..) => {
353
+ let parameter_environment = ParameterEnvironment :: for_item ( cx. tcx ,
354
+ fn_id) ;
355
+ cx. parameter_environments . push ( parameter_environment) ;
356
+
357
+ let ty = ty:: node_id_to_type ( cx. tcx , fn_id) ;
358
+ check_bounds_on_structs_or_enums_in_type_if_possible ( cx, sp, ty) ;
359
+
360
+ visit:: walk_fn ( cx, fk, decl, body, sp, ( ) ) ;
361
+ drop ( cx. parameter_environments . pop ( ) ) ;
362
+ }
363
+ }
258
364
}
259
365
260
366
pub fn check_expr ( cx : & mut Context , e : & Expr ) {
@@ -263,6 +369,13 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
263
369
// Handle any kind bounds on type parameters
264
370
check_bounds_on_type_parameters ( cx, e) ;
265
371
372
+ // Check bounds on structures or enumerations in the type of the
373
+ // expression.
374
+ let expression_type = ty:: expr_ty ( cx. tcx , e) ;
375
+ check_bounds_on_structs_or_enums_in_type_if_possible ( cx,
376
+ e. span ,
377
+ expression_type) ;
378
+
266
379
match e. node {
267
380
ExprBox ( ref loc, ref interior) => {
268
381
let def = ty:: resolve_expr ( cx. tcx , & * * loc) ;
@@ -483,6 +596,7 @@ fn check_ty(cx: &mut Context, aty: &Ty) {
483
596
}
484
597
_ => { }
485
598
}
599
+
486
600
visit:: walk_ty ( cx, aty, ( ) ) ;
487
601
}
488
602
@@ -519,6 +633,76 @@ pub fn check_typaram_bounds(cx: &Context,
519
633
} ) ;
520
634
}
521
635
636
+ fn check_bounds_on_structs_or_enums_in_type_if_possible ( cx : & mut Context ,
637
+ span : Span ,
638
+ ty : ty:: t ) {
639
+ // If we aren't in a function, structure, or enumeration context, we don't
640
+ // have enough information to ensure that bounds on structures or
641
+ // enumerations are satisfied. So we don't perform the check.
642
+ if cx. parameter_environments . len ( ) == 0 {
643
+ return
644
+ }
645
+
646
+ // If we've already checked for this type, don't do it again. This
647
+ // massively speeds up kind checking.
648
+ if cx. struct_and_enum_bounds_checked . contains ( & ty) {
649
+ return
650
+ }
651
+ cx. struct_and_enum_bounds_checked . insert ( ty) ;
652
+
653
+ ty:: walk_ty ( ty, |ty| {
654
+ match ty:: get ( ty) . sty {
655
+ ty:: ty_struct( type_id, ref substs) |
656
+ ty:: ty_enum( type_id, ref substs) => {
657
+ let polytype = ty:: lookup_item_type ( cx. tcx , type_id) ;
658
+
659
+ // Check builtin bounds.
660
+ for ( ty, type_param_def) in substs. types
661
+ . iter ( )
662
+ . zip ( polytype. generics
663
+ . types
664
+ . iter ( ) ) {
665
+ check_typaram_bounds ( cx, span, * ty, type_param_def)
666
+ }
667
+
668
+ // Check trait bounds.
669
+ let parameter_environment =
670
+ cx. parameter_environments . get ( cx. parameter_environments
671
+ . len ( ) - 1 ) ;
672
+ debug ! (
673
+ "check_bounds_on_structs_or_enums_in_type_if_possible(): \
674
+ checking {}",
675
+ ty. repr( cx. tcx) ) ;
676
+ vtable:: check_param_bounds ( cx. tcx ,
677
+ span,
678
+ parameter_environment,
679
+ & polytype. generics . types ,
680
+ substs,
681
+ |missing| {
682
+ cx. tcx
683
+ . sess
684
+ . span_err ( span,
685
+ format ! ( "instantiating a type parameter with \
686
+ an incompatible type `{}`, which \
687
+ does not fulfill `{}`",
688
+ ty_to_string( cx. tcx, ty) ,
689
+ missing. user_string(
690
+ cx. tcx) ) . as_slice ( ) ) ;
691
+ } )
692
+ }
693
+ _ => { }
694
+ }
695
+ } ) ;
696
+ }
697
+
698
+ fn check_bounds_on_structs_or_enums_in_trait_ref ( cx : & mut Context ,
699
+ span : Span ,
700
+ trait_ref : & ty:: TraitRef ) {
701
+ for ty in trait_ref. substs . types . iter ( ) {
702
+ check_bounds_on_structs_or_enums_in_type_if_possible ( cx, span, * ty)
703
+ }
704
+ }
705
+
522
706
pub fn check_freevar_bounds ( cx : & Context , sp : Span , ty : ty:: t ,
523
707
bounds : ty:: BuiltinBounds , referenced_ty : Option < ty:: t > )
524
708
{
0 commit comments