@@ -97,9 +97,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
9797 & self ,
9898 body : & Body < ' tcx > ,
9999 from_region : RegionVid ,
100+ from_region_origin : NLLRegionVariableOrigin ,
100101 target_test : impl Fn ( RegionVid ) -> bool ,
101102 ) -> ( ConstraintCategory , bool , Span ) {
102- debug ! ( "best_blame_constraint(from_region={:?})" , from_region) ;
103+ debug ! ( "best_blame_constraint(from_region={:?}, from_region_origin={:?})" ,
104+ from_region, from_region_origin) ;
103105
104106 // Find all paths
105107 let ( path, target_region) =
@@ -152,19 +154,85 @@ impl<'tcx> RegionInferenceContext<'tcx> {
152154 // we still want to screen for an "interesting" point to
153155 // highlight (e.g., a call site or something).
154156 let target_scc = self . constraint_sccs . scc ( target_region) ;
155- let best_choice = ( 0 ..path. len ( ) ) . rev ( ) . find ( |& i| {
156- let constraint = path[ i] ;
157+ let mut range = 0 ..path. len ( ) ;
158+
159+ // As noted above, when reporting an error, there is typically a chain of constraints
160+ // leading from some "source" region which must outlive some "target" region.
161+ // In most cases, we prefer to "blame" the constraints closer to the target --
162+ // but there is one exception. When constraints arise from higher-ranked subtyping,
163+ // we generally prefer to blame the source value,
164+ // as the "target" in this case tends to be some type annotation that the user gave.
165+ // Therefore, if we find that the region origin is some instantiation
166+ // of a higher-ranked region, we start our search from the "source" point
167+ // rather than the "target", and we also tweak a few other things.
168+ //
169+ // An example might be this bit of Rust code:
170+ //
171+ // ```rust
172+ // let x: fn(&'static ()) = |_| {};
173+ // let y: for<'a> fn(&'a ()) = x;
174+ // ```
175+ //
176+ // In MIR, this will be converted into a combination of assignments and type ascriptions.
177+ // In particular, the 'static is imposed through a type ascription:
178+ //
179+ // ```rust
180+ // x = ...;
181+ // AscribeUserType(x, fn(&'static ())
182+ // y = x;
183+ // ```
184+ //
185+ // We wind up ultimately with constraints like
186+ //
187+ // ```rust
188+ // !a: 'temp1 // from the `y = x` statement
189+ // 'temp1: 'temp2
190+ // 'temp2: 'static // from the AscribeUserType
191+ // ```
192+ //
193+ // and here we prefer to blame the source (the y = x statement).
194+ let blame_source = match from_region_origin {
195+ NLLRegionVariableOrigin :: FreeRegion
196+ | NLLRegionVariableOrigin :: Existential { from_forall : false } => {
197+ true
198+ }
199+ NLLRegionVariableOrigin :: Placeholder ( _)
200+ | NLLRegionVariableOrigin :: Existential { from_forall : true } => {
201+ false
202+ }
203+ } ;
204+
205+ let find_region = |i : & usize | {
206+ let constraint = path[ * i] ;
157207
158208 let constraint_sup_scc = self . constraint_sccs . scc ( constraint. sup ) ;
159209
160- match categorized_path[ i] . 0 {
161- ConstraintCategory :: OpaqueType | ConstraintCategory :: Boring |
162- ConstraintCategory :: BoringNoLocation | ConstraintCategory :: Internal => false ,
163- ConstraintCategory :: TypeAnnotation | ConstraintCategory :: Return |
164- ConstraintCategory :: Yield => true ,
165- _ => constraint_sup_scc != target_scc,
210+ if blame_source {
211+ match categorized_path[ * i] . 0 {
212+ ConstraintCategory :: OpaqueType | ConstraintCategory :: Boring |
213+ ConstraintCategory :: BoringNoLocation | ConstraintCategory :: Internal => false ,
214+ ConstraintCategory :: TypeAnnotation | ConstraintCategory :: Return |
215+ ConstraintCategory :: Yield => true ,
216+ _ => constraint_sup_scc != target_scc,
217+ }
218+ } else {
219+ match categorized_path[ * i] . 0 {
220+ ConstraintCategory :: OpaqueType | ConstraintCategory :: Boring |
221+ ConstraintCategory :: BoringNoLocation | ConstraintCategory :: Internal => false ,
222+ _ => true
223+ }
166224 }
167- } ) ;
225+ } ;
226+
227+ let best_choice = if blame_source {
228+ range. rev ( ) . find ( find_region)
229+ } else {
230+ range. find ( find_region)
231+ } ;
232+
233+ debug ! ( "best_blame_constraint: best_choice={:?} blame_source={}" ,
234+ best_choice, blame_source) ;
235+
168236 if let Some ( i) = best_choice {
169237 if let Some ( next) = categorized_path. get ( i + 1 ) {
170238 if categorized_path[ i] . 0 == ConstraintCategory :: Return
@@ -300,12 +368,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
300368 infcx : & ' a InferCtxt < ' a , ' tcx > ,
301369 mir_def_id : DefId ,
302370 fr : RegionVid ,
371+ fr_origin : NLLRegionVariableOrigin ,
303372 outlived_fr : RegionVid ,
304373 renctx : & mut RegionErrorNamingCtx ,
305374 ) -> DiagnosticBuilder < ' a > {
306375 debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
307376
308- let ( category, _, span) = self . best_blame_constraint ( body, fr, |r| {
377+ let ( category, _, span) = self . best_blame_constraint ( body, fr, fr_origin , |r| {
309378 self . provides_universal_region ( r, fr, outlived_fr)
310379 } ) ;
311380
@@ -712,6 +781,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
712781 let ( category, from_closure, span) = self . best_blame_constraint (
713782 body,
714783 borrow_region,
784+ NLLRegionVariableOrigin :: FreeRegion ,
715785 |r| self . provides_universal_region ( r, borrow_region, outlived_region)
716786 ) ;
717787
@@ -771,11 +841,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
771841 & self ,
772842 body : & Body < ' tcx > ,
773843 fr1 : RegionVid ,
844+ fr1_origin : NLLRegionVariableOrigin ,
774845 fr2 : RegionVid ,
775846 ) -> ( ConstraintCategory , Span ) {
776847 let ( category, _, span) = self . best_blame_constraint (
777848 body,
778849 fr1,
850+ fr1_origin,
779851 |r| self . provides_universal_region ( r, fr1, fr2) ,
780852 ) ;
781853 ( category, span)
@@ -828,7 +900,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
828900 universe1. cannot_name ( placeholder. universe )
829901 }
830902
831- NLLRegionVariableOrigin :: FreeRegion | NLLRegionVariableOrigin :: Existential => false ,
903+ NLLRegionVariableOrigin :: FreeRegion | NLLRegionVariableOrigin :: Existential { .. } => {
904+ false
905+ }
832906 }
833907 }
834908}
0 commit comments