@@ -195,6 +195,261 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
195
195
Ok ( HrMatchResult { value : a_value } )
196
196
} ) ;
197
197
}
198
+
199
+ pub fn higher_ranked_lub < T > ( & mut self , a : & Binder < T > , b : & Binder < T > , a_is_expected : bool )
200
+ -> RelateResult < ' tcx , Binder < T > >
201
+ where T : Relate < ' tcx >
202
+ {
203
+ // Start a snapshot so we can examine "all bindings that were
204
+ // created as part of this type comparison".
205
+ return self . infcx . commit_if_ok ( |snapshot| {
206
+ // Instantiate each bound region with a fresh region variable.
207
+ let span = self . trace . cause . span ;
208
+ let ( a_with_fresh, a_map) =
209
+ self . infcx . replace_late_bound_regions_with_fresh_var (
210
+ span, HigherRankedType , a) ;
211
+ let ( b_with_fresh, _) =
212
+ self . infcx . replace_late_bound_regions_with_fresh_var (
213
+ span, HigherRankedType , b) ;
214
+
215
+ // Collect constraints.
216
+ let result0 =
217
+ self . lub ( a_is_expected) . relate ( & a_with_fresh, & b_with_fresh) ?;
218
+ let result0 =
219
+ self . infcx . resolve_type_vars_if_possible ( & result0) ;
220
+ debug ! ( "lub result0 = {:?}" , result0) ;
221
+
222
+ // Generalize the regions appearing in result0 if possible
223
+ let new_vars = self . infcx . region_vars_confined_to_snapshot ( snapshot) ;
224
+ let span = self . trace . cause . span ;
225
+ let result1 =
226
+ fold_regions_in (
227
+ self . tcx ( ) ,
228
+ & result0,
229
+ |r, debruijn| generalize_region ( self . infcx , span, snapshot, debruijn,
230
+ & new_vars, & a_map, r) ) ;
231
+
232
+ debug ! ( "lub({:?},{:?}) = {:?}" ,
233
+ a,
234
+ b,
235
+ result1) ;
236
+
237
+ Ok ( ty:: Binder ( result1) )
238
+ } ) ;
239
+
240
+ fn generalize_region < ' a , ' gcx , ' tcx > ( infcx : & InferCtxt < ' a , ' gcx , ' tcx > ,
241
+ span : Span ,
242
+ snapshot : & CombinedSnapshot ,
243
+ debruijn : ty:: DebruijnIndex ,
244
+ new_vars : & [ ty:: RegionVid ] ,
245
+ a_map : & FxHashMap < ty:: BoundRegion , ty:: Region < ' tcx > > ,
246
+ r0 : ty:: Region < ' tcx > )
247
+ -> ty:: Region < ' tcx > {
248
+ // Regions that pre-dated the LUB computation stay as they are.
249
+ if !is_var_in_set ( new_vars, r0) {
250
+ assert ! ( !r0. is_late_bound( ) ) ;
251
+ debug ! ( "generalize_region(r0={:?}): not new variable" , r0) ;
252
+ return r0;
253
+ }
254
+
255
+ let tainted = infcx. tainted_regions ( snapshot, r0, TaintDirections :: both ( ) ) ;
256
+
257
+ // Variables created during LUB computation which are
258
+ // *related* to regions that pre-date the LUB computation
259
+ // stay as they are.
260
+ if !tainted. iter ( ) . all ( |& r| is_var_in_set ( new_vars, r) ) {
261
+ debug ! ( "generalize_region(r0={:?}): \
262
+ non-new-variables found in {:?}",
263
+ r0, tainted) ;
264
+ assert ! ( !r0. is_late_bound( ) ) ;
265
+ return r0;
266
+ }
267
+
268
+ // Otherwise, the variable must be associated with at
269
+ // least one of the variables representing bound regions
270
+ // in both A and B. Replace the variable with the "first"
271
+ // bound region from A that we find it to be associated
272
+ // with.
273
+ for ( a_br, a_r) in a_map {
274
+ if tainted. iter ( ) . any ( |x| x == a_r) {
275
+ debug ! ( "generalize_region(r0={:?}): \
276
+ replacing with {:?}, tainted={:?}",
277
+ r0, * a_br, tainted) ;
278
+ return infcx. tcx . mk_region ( ty:: ReLateBound ( debruijn, * a_br) ) ;
279
+ }
280
+ }
281
+
282
+ span_bug ! (
283
+ span,
284
+ "region {:?} is not associated with any bound region from A!" ,
285
+ r0)
286
+ }
287
+ }
288
+
289
+ pub fn higher_ranked_glb < T > ( & mut self , a : & Binder < T > , b : & Binder < T > , a_is_expected : bool )
290
+ -> RelateResult < ' tcx , Binder < T > >
291
+ where T : Relate < ' tcx >
292
+ {
293
+ debug ! ( "higher_ranked_glb({:?}, {:?})" ,
294
+ a, b) ;
295
+
296
+ // Make a snapshot so we can examine "all bindings that were
297
+ // created as part of this type comparison".
298
+ return self . infcx . commit_if_ok ( |snapshot| {
299
+ // Instantiate each bound region with a fresh region variable.
300
+ let ( a_with_fresh, a_map) =
301
+ self . infcx . replace_late_bound_regions_with_fresh_var (
302
+ self . trace . cause . span , HigherRankedType , a) ;
303
+ let ( b_with_fresh, b_map) =
304
+ self . infcx . replace_late_bound_regions_with_fresh_var (
305
+ self . trace . cause . span , HigherRankedType , b) ;
306
+ let a_vars = var_ids ( self , & a_map) ;
307
+ let b_vars = var_ids ( self , & b_map) ;
308
+
309
+ // Collect constraints.
310
+ let result0 =
311
+ self . glb ( a_is_expected) . relate ( & a_with_fresh, & b_with_fresh) ?;
312
+ let result0 =
313
+ self . infcx . resolve_type_vars_if_possible ( & result0) ;
314
+ debug ! ( "glb result0 = {:?}" , result0) ;
315
+
316
+ // Generalize the regions appearing in result0 if possible
317
+ let new_vars = self . infcx . region_vars_confined_to_snapshot ( snapshot) ;
318
+ let span = self . trace . cause . span ;
319
+ let result1 =
320
+ fold_regions_in (
321
+ self . tcx ( ) ,
322
+ & result0,
323
+ |r, debruijn| generalize_region ( self . infcx , span, snapshot, debruijn,
324
+ & new_vars,
325
+ & a_map, & a_vars, & b_vars,
326
+ r) ) ;
327
+
328
+ debug ! ( "glb({:?},{:?}) = {:?}" ,
329
+ a,
330
+ b,
331
+ result1) ;
332
+
333
+ Ok ( ty:: Binder ( result1) )
334
+ } ) ;
335
+
336
+ fn generalize_region < ' a , ' gcx , ' tcx > ( infcx : & InferCtxt < ' a , ' gcx , ' tcx > ,
337
+ span : Span ,
338
+ snapshot : & CombinedSnapshot ,
339
+ debruijn : ty:: DebruijnIndex ,
340
+ new_vars : & [ ty:: RegionVid ] ,
341
+ a_map : & FxHashMap < ty:: BoundRegion , ty:: Region < ' tcx > > ,
342
+ a_vars : & [ ty:: RegionVid ] ,
343
+ b_vars : & [ ty:: RegionVid ] ,
344
+ r0 : ty:: Region < ' tcx > )
345
+ -> ty:: Region < ' tcx > {
346
+ if !is_var_in_set ( new_vars, r0) {
347
+ assert ! ( !r0. is_late_bound( ) ) ;
348
+ return r0;
349
+ }
350
+
351
+ let tainted = infcx. tainted_regions ( snapshot, r0, TaintDirections :: both ( ) ) ;
352
+
353
+ let mut a_r = None ;
354
+ let mut b_r = None ;
355
+ let mut only_new_vars = true ;
356
+ for r in & tainted {
357
+ if is_var_in_set ( a_vars, * r) {
358
+ if a_r. is_some ( ) {
359
+ return fresh_bound_variable ( infcx, debruijn) ;
360
+ } else {
361
+ a_r = Some ( * r) ;
362
+ }
363
+ } else if is_var_in_set ( b_vars, * r) {
364
+ if b_r. is_some ( ) {
365
+ return fresh_bound_variable ( infcx, debruijn) ;
366
+ } else {
367
+ b_r = Some ( * r) ;
368
+ }
369
+ } else if !is_var_in_set ( new_vars, * r) {
370
+ only_new_vars = false ;
371
+ }
372
+ }
373
+
374
+ // NB---I do not believe this algorithm computes
375
+ // (necessarily) the GLB. As written it can
376
+ // spuriously fail. In particular, if there is a case
377
+ // like: |fn(&a)| and fn(fn(&b)), where a and b are
378
+ // free, it will return fn(&c) where c = GLB(a,b). If
379
+ // however this GLB is not defined, then the result is
380
+ // an error, even though something like
381
+ // "fn<X>(fn(&X))" where X is bound would be a
382
+ // subtype of both of those.
383
+ //
384
+ // The problem is that if we were to return a bound
385
+ // variable, we'd be computing a lower-bound, but not
386
+ // necessarily the *greatest* lower-bound.
387
+ //
388
+ // Unfortunately, this problem is non-trivial to solve,
389
+ // because we do not know at the time of computing the GLB
390
+ // whether a GLB(a,b) exists or not, because we haven't
391
+ // run region inference (or indeed, even fully computed
392
+ // the region hierarchy!). The current algorithm seems to
393
+ // works ok in practice.
394
+
395
+ if a_r. is_some ( ) && b_r. is_some ( ) && only_new_vars {
396
+ // Related to exactly one bound variable from each fn:
397
+ return rev_lookup ( infcx, span, a_map, a_r. unwrap ( ) ) ;
398
+ } else if a_r. is_none ( ) && b_r. is_none ( ) {
399
+ // Not related to bound variables from either fn:
400
+ assert ! ( !r0. is_late_bound( ) ) ;
401
+ return r0;
402
+ } else {
403
+ // Other:
404
+ return fresh_bound_variable ( infcx, debruijn) ;
405
+ }
406
+ }
407
+
408
+ fn rev_lookup < ' a , ' gcx , ' tcx > ( infcx : & InferCtxt < ' a , ' gcx , ' tcx > ,
409
+ span : Span ,
410
+ a_map : & FxHashMap < ty:: BoundRegion , ty:: Region < ' tcx > > ,
411
+ r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx >
412
+ {
413
+ for ( a_br, a_r) in a_map {
414
+ if * a_r == r {
415
+ return infcx. tcx . mk_region ( ty:: ReLateBound ( ty:: DebruijnIndex :: new ( 1 ) , * a_br) ) ;
416
+ }
417
+ }
418
+ span_bug ! (
419
+ span,
420
+ "could not find original bound region for {:?}" ,
421
+ r) ;
422
+ }
423
+
424
+ fn fresh_bound_variable < ' a , ' gcx , ' tcx > ( infcx : & InferCtxt < ' a , ' gcx , ' tcx > ,
425
+ debruijn : ty:: DebruijnIndex )
426
+ -> ty:: Region < ' tcx > {
427
+ infcx. region_vars . new_bound ( debruijn)
428
+ }
429
+ }
430
+ }
431
+
432
+ fn var_ids < ' a , ' gcx , ' tcx > ( fields : & CombineFields < ' a , ' gcx , ' tcx > ,
433
+ map : & FxHashMap < ty:: BoundRegion , ty:: Region < ' tcx > > )
434
+ -> Vec < ty:: RegionVid > {
435
+ map. iter ( )
436
+ . map ( |( _, & r) | match * r {
437
+ ty:: ReVar ( r) => { r }
438
+ _ => {
439
+ span_bug ! (
440
+ fields. trace. cause. span,
441
+ "found non-region-vid: {:?}" ,
442
+ r) ;
443
+ }
444
+ } )
445
+ . collect ( )
446
+ }
447
+
448
+ fn is_var_in_set ( new_vars : & [ ty:: RegionVid ] , r : ty:: Region ) -> bool {
449
+ match * r {
450
+ ty:: ReVar ( ref v) => new_vars. iter ( ) . any ( |x| x == v) ,
451
+ _ => false
452
+ }
198
453
}
199
454
200
455
fn fold_regions_in < ' a , ' gcx , ' tcx , T , F > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
0 commit comments