@@ -97,9 +97,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
97
97
& self ,
98
98
body : & Body < ' tcx > ,
99
99
from_region : RegionVid ,
100
+ from_region_origin : NLLRegionVariableOrigin ,
100
101
target_test : impl Fn ( RegionVid ) -> bool ,
101
102
) -> ( 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) ;
103
105
104
106
// Find all paths
105
107
let ( path, target_region) =
@@ -152,19 +154,85 @@ impl<'tcx> RegionInferenceContext<'tcx> {
152
154
// we still want to screen for an "interesting" point to
153
155
// highlight (e.g., a call site or something).
154
156
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] ;
157
207
158
208
let constraint_sup_scc = self . constraint_sccs . scc ( constraint. sup ) ;
159
209
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
+ }
166
224
}
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
+
168
236
if let Some ( i) = best_choice {
169
237
if let Some ( next) = categorized_path. get ( i + 1 ) {
170
238
if categorized_path[ i] . 0 == ConstraintCategory :: Return
@@ -300,12 +368,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
300
368
infcx : & ' a InferCtxt < ' a , ' tcx > ,
301
369
mir_def_id : DefId ,
302
370
fr : RegionVid ,
371
+ fr_origin : NLLRegionVariableOrigin ,
303
372
outlived_fr : RegionVid ,
304
373
renctx : & mut RegionErrorNamingCtx ,
305
374
) -> DiagnosticBuilder < ' a > {
306
375
debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
307
376
308
- let ( category, _, span) = self . best_blame_constraint ( body, fr, |r| {
377
+ let ( category, _, span) = self . best_blame_constraint ( body, fr, fr_origin , |r| {
309
378
self . provides_universal_region ( r, fr, outlived_fr)
310
379
} ) ;
311
380
@@ -712,6 +781,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
712
781
let ( category, from_closure, span) = self . best_blame_constraint (
713
782
body,
714
783
borrow_region,
784
+ NLLRegionVariableOrigin :: FreeRegion ,
715
785
|r| self . provides_universal_region ( r, borrow_region, outlived_region)
716
786
) ;
717
787
@@ -771,11 +841,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
771
841
& self ,
772
842
body : & Body < ' tcx > ,
773
843
fr1 : RegionVid ,
844
+ fr1_origin : NLLRegionVariableOrigin ,
774
845
fr2 : RegionVid ,
775
846
) -> ( ConstraintCategory , Span ) {
776
847
let ( category, _, span) = self . best_blame_constraint (
777
848
body,
778
849
fr1,
850
+ fr1_origin,
779
851
|r| self . provides_universal_region ( r, fr1, fr2) ,
780
852
) ;
781
853
( category, span)
@@ -828,7 +900,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
828
900
universe1. cannot_name ( placeholder. universe )
829
901
}
830
902
831
- NLLRegionVariableOrigin :: FreeRegion | NLLRegionVariableOrigin :: Existential => false ,
903
+ NLLRegionVariableOrigin :: FreeRegion | NLLRegionVariableOrigin :: Existential { .. } => {
904
+ false
905
+ }
832
906
}
833
907
}
834
908
}
0 commit comments