@@ -195,6 +195,261 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
195195 Ok ( HrMatchResult { value : a_value } )
196196 } ) ;
197197 }
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+ }
198453}
199454
200455fn fold_regions_in < ' a , ' gcx , ' tcx , T , F > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
0 commit comments