@@ -2,6 +2,22 @@ import check::{fn_ctxt, impl_self_ty};
2
2
import infer:: { resolve_type, resolve_all, force_all, fixup_err_to_str} ;
3
3
import ast_util:: new_def_hash;
4
4
5
+ // vtable resolution looks for places where trait bounds are
6
+ // subsituted in and figures out which vtable is used. There is some
7
+ // extra complication thrown in to support early "opportunistic"
8
+ // vtable resolution. This is a hacky mechanism that is invoked while
9
+ // typechecking function calls (after typechecking non-closure
10
+ // arguments and before typechecking closure arguments) in the hope of
11
+ // solving for the trait parameters from the impl. (For example,
12
+ // determining that if a parameter bounded by BaseIter<A> is
13
+ // instantiated with option<int>, that A = int.)
14
+ //
15
+ // In early resolution mode, no vtables are recorded, and a number of
16
+ // errors are ignored. Early resolution only works if a type is
17
+ // *fully* resolved. (We could be less restrictive than that, but it
18
+ // would require much more care, and this seems to work decently in
19
+ // practice.)
20
+
5
21
fn has_trait_bounds ( tps : ~[ ty:: param_bounds ] ) -> bool {
6
22
vec:: any ( tps, |bs| {
7
23
vec:: any ( * bs, |b| {
@@ -14,7 +30,8 @@ fn lookup_vtables(fcx: @fn_ctxt,
14
30
sp : span ,
15
31
bounds : @~[ ty:: param_bounds ] ,
16
32
substs : & ty:: substs ,
17
- allow_unsafe : bool ) -> vtable_res {
33
+ allow_unsafe : bool ,
34
+ is_early : bool ) -> vtable_res {
18
35
let tcx = fcx. ccx . tcx ;
19
36
let mut result = ~[ ] , i = 0 u;
20
37
for substs. tps. each |ty| {
@@ -23,7 +40,7 @@ fn lookup_vtables(fcx: @fn_ctxt,
23
40
ty:: bound_trait( i_ty) => {
24
41
let i_ty = ty:: subst ( tcx, substs, i_ty) ;
25
42
vec:: push ( result, lookup_vtable ( fcx, sp, ty, i_ty,
26
- allow_unsafe) ) ;
43
+ allow_unsafe, is_early ) ) ;
27
44
}
28
45
_ => ( )
29
46
}
@@ -34,13 +51,15 @@ fn lookup_vtables(fcx: @fn_ctxt,
34
51
}
35
52
36
53
fn fixup_substs ( fcx : @fn_ctxt , sp : span ,
37
- id : ast:: def_id , substs : ty:: substs ) -> ty:: substs {
54
+ id : ast:: def_id , substs : ty:: substs ,
55
+ is_early : bool ) -> option < ty:: substs > {
38
56
let tcx = fcx. ccx . tcx ;
39
57
// use a dummy type just to package up the substs that need fixing up
40
58
let t = ty:: mk_trait ( tcx, id, substs, ty:: vstore_slice ( ty:: re_static) ) ;
41
- let t_f = fixup_ty ( fcx, sp, t) ;
42
- match check ty:: get ( t_f) . struct {
43
- ty:: ty_trait( _, substs_f, _) => substs_f,
59
+ do fixup_ty( fcx, sp, t, is_early) . map |t_f| {
60
+ match check ty:: get ( t_f) . struct {
61
+ ty:: ty_trait( _, substs_f, _) => substs_f,
62
+ }
44
63
}
45
64
}
46
65
@@ -54,7 +73,7 @@ Look up the vtable to use when treating an item of type <t>
54
73
as if it has type <trait_ty>
55
74
*/
56
75
fn lookup_vtable( fcx : @fn_ctxt , sp : span , ty : ty:: t , trait_ty : ty:: t ,
57
- allow_unsafe : bool )
76
+ allow_unsafe : bool , is_early : bool )
58
77
-> vtable_origin {
59
78
60
79
debug ! { "lookup_vtable(ty=%s, trait_ty=%s)" ,
@@ -65,7 +84,18 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
65
84
let ( trait_id, trait_substs) = match check ty:: get ( trait_ty) . struct {
66
85
ty:: ty_trait( did, substs, _) => ( did, substs)
67
86
} ;
68
- let ty = fixup_ty ( fcx, sp, ty) ;
87
+ let ty = match fixup_ty ( fcx, sp, ty, is_early) {
88
+ some( ty) => ty,
89
+ none => {
90
+ // fixup_ty can only fail if this is early resolution
91
+ assert is_early;
92
+ // The type has unconstrained type variables in it, so we can't
93
+ // do early resolution on it. Return some completely bogus vtable
94
+ // information: we aren't storing it anyways.
95
+ return vtable_param ( 0 , 0 ) ;
96
+ }
97
+ } ;
98
+
69
99
match ty:: get ( ty) . struct {
70
100
ty:: ty_param( { idx: n, def_id: did} ) => {
71
101
let mut n_bound = 0 u;
@@ -97,7 +127,7 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
97
127
did} ;
98
128
99
129
relate_trait_tys ( fcx, sp, trait_ty, ty) ;
100
- if !allow_unsafe {
130
+ if !allow_unsafe && !is_early {
101
131
for vec:: each( * ty:: trait_methods( tcx, did) ) |m| {
102
132
if ty:: type_has_self ( ty:: mk_fn ( tcx, m. fty ) ) {
103
133
tcx. sess . span_err (
@@ -154,21 +184,30 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
154
184
}
155
185
156
186
// check that desired trait type unifies
157
- debug ! { "(checking vtable) @2 relating trait ty %s to \
187
+ debug ! ( "(checking vtable) @2 relating trait ty %s to \
158
188
of_ty %s",
159
189
fcx. infcx. ty_to_str( trait_ty) ,
160
- fcx. infcx. ty_to_str( of_ty) } ;
190
+ fcx. infcx. ty_to_str( of_ty) ) ;
161
191
let of_ty = ty:: subst ( tcx, & substs, of_ty) ;
162
192
relate_trait_tys ( fcx, sp, trait_ty, of_ty) ;
163
193
164
- // recursively process the bounds
194
+ // recursively process the bounds.
165
195
let trait_tps = trait_substs. tps ;
166
- let substs_f = fixup_substs ( fcx, sp, trait_id,
167
- substs) ;
196
+ // see comments around the earlier call to fixup_ty
197
+ let substs_f = match fixup_substs ( fcx, sp, trait_id,
198
+ substs, is_early) {
199
+ some( substs) => substs,
200
+ none => {
201
+ assert is_early;
202
+ // Bail out with a bogus answer
203
+ return vtable_param ( 0 , 0 ) ;
204
+ }
205
+ } ;
206
+
168
207
connect_trait_tps ( fcx, sp, substs_f. tps ,
169
208
trait_tps, im. did ) ;
170
209
let subres = lookup_vtables ( fcx, sp, im_bs, & substs_f,
171
- false ) ;
210
+ false , is_early ) ;
172
211
vec:: push ( found,
173
212
vtable_static ( im. did , substs_f. tps ,
174
213
subres) ) ;
@@ -181,8 +220,10 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
181
220
0 u => { /* fallthrough */ }
182
221
1 u => { return found[ 0 ] ; }
183
222
_ => {
184
- fcx. ccx . tcx . sess . span_err (
185
- sp, ~"multiple applicable methods in scope") ;
223
+ if !is_early {
224
+ fcx. ccx . tcx . sess . span_err (
225
+ sp, ~"multiple applicable methods in scope") ;
226
+ }
186
227
return found[ 0 ] ;
187
228
}
188
229
}
@@ -195,17 +236,21 @@ fn lookup_vtable(fcx: @fn_ctxt, sp: span, ty: ty::t, trait_ty: ty::t,
195
236
ty_to_str(tcx, ty));
196
237
}
197
238
198
- fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t {
239
+ fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t, is_early: bool)
240
+ -> option<ty::t> {
199
241
let tcx = fcx.ccx.tcx;
200
242
match resolve_type(fcx.infcx, ty, resolve_all | force_all) {
201
- result::ok(new_type) => new_type,
202
- result::err(e) => {
243
+ result::ok(new_type) => some( new_type) ,
244
+ result::err(e) if !is_early => {
203
245
tcx.sess.span_fatal(
204
246
sp,
205
247
fmt!{" cannot determine a type \
206
248
for this bounded type parameter: %s",
207
249
fixup_err_to_str( e) } )
208
250
}
251
+ result:: err( e) => {
252
+ none
253
+ }
209
254
}
210
255
}
211
256
@@ -226,7 +271,7 @@ fn connect_trait_tps(fcx: @fn_ctxt, sp: span, impl_tys: ~[ty::t],
226
271
}
227
272
}
228
273
229
- fn resolve_expr ( ex: @ast:: expr, & & fcx: @fn_ctxt, v : visit :: vt < @ fn_ctxt > ) {
274
+ fn early_resolve_expr ( ex: @ast:: expr, & & fcx: @fn_ctxt, is_early : bool ) {
230
275
let cx = fcx. ccx;
231
276
match ex. node {
232
277
ast : : expr_path( * ) => {
@@ -236,11 +281,9 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
236
281
let did = ast_util:: def_id_of_def( cx. tcx. def_map. get( ex. id) ) ;
237
282
let item_ty = ty:: lookup_item_type( cx. tcx, did) ;
238
283
if has_trait_bounds( * item_ty. bounds) {
239
- cx. vtable_map. insert( ex. id, lookup_vtables( fcx,
240
- ex. span,
241
- item_ty. bounds,
242
- substs,
243
- false ) ) ;
284
+ let vtbls = lookup_vtables( fcx, ex. span, item_ty. bounds,
285
+ substs, false , is_early) ;
286
+ if !is_early { cx. vtable_map. insert( ex. id, vtbls) ; }
244
287
}
245
288
}
246
289
_ => ( )
@@ -260,11 +303,9 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
260
303
_ => ex. callee_id
261
304
} ;
262
305
let substs = fcx. node_ty_substs( callee_id) ;
263
- cx. vtable_map. insert( callee_id, lookup_vtables( fcx,
264
- ex. span,
265
- bounds,
266
- & substs,
267
- false ) ) ;
306
+ let vtbls = lookup_vtables( fcx, ex. span, bounds,
307
+ & substs, false , is_early) ;
308
+ if !is_early { cx. vtable_map. insert( callee_id, vtbls) ; }
268
309
}
269
310
}
270
311
_ => ( )
@@ -280,18 +321,22 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
280
321
passing in the source and target type
281
322
*/
282
323
let vtable = lookup_vtable( fcx, ex. span, fcx. expr_ty( src) ,
283
- target_ty, true ) ;
324
+ target_ty, true , is_early ) ;
284
325
/*
285
326
Map this expression to that vtable (that is: "ex has
286
327
vtable <vtable>")
287
328
*/
288
- cx. vtable_map. insert( ex. id, @~[ vtable] ) ;
329
+ if !is_early { cx. vtable_map. insert( ex. id, @~[ vtable] ) ; }
289
330
}
290
331
_ => ( )
291
332
}
292
333
}
293
334
_ => ( )
294
335
}
336
+ }
337
+
338
+ fn resolve_expr( ex: @ast:: expr, & & fcx: @fn_ctxt, v: visit:: vt < @fn_ctxt > ) {
339
+ early_resolve_expr( ex, fcx, false ) ;
295
340
visit:: visit_expr( ex, fcx, v) ;
296
341
}
297
342
0 commit comments