@@ -198,6 +198,261 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
198198 Ok ( HrMatchResult { value : a_value } )
199199 } ) ;
200200 }
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+ }
201456}
202457
203458fn fold_regions_in < ' a , ' gcx , ' tcx , T , F > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
0 commit comments