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