1
+ use rustc_errors:: DiagnosticBuilder ;
1
2
use rustc_infer:: infer:: canonical:: Canonical ;
2
- use rustc_infer:: traits:: ObligationCause ;
3
+ use rustc_infer:: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
4
+ use rustc_infer:: infer:: region_constraints:: Constraint ;
5
+ use rustc_infer:: infer:: { InferCtxt , RegionResolutionError , SubregionOrigin , TyCtxtInferExt as _} ;
6
+ use rustc_infer:: traits:: { Normalized , Obligation , ObligationCause , TraitEngine , TraitEngineExt } ;
3
7
use rustc_middle:: ty:: error:: TypeError ;
4
- use rustc_middle:: ty:: { self , Ty , TypeFoldable } ;
8
+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
5
9
use rustc_span:: Span ;
6
10
use rustc_trait_selection:: traits:: query:: type_op;
11
+ use rustc_trait_selection:: traits:: { SelectionContext , TraitEngineExt as _} ;
7
12
8
13
use std:: fmt;
9
14
use std:: rc:: Rc ;
@@ -37,11 +42,10 @@ impl UniverseInfo<'tcx> {
37
42
crate fn report_error (
38
43
& self ,
39
44
mbcx : & mut MirBorrowckCtxt < ' _ , ' tcx > ,
40
- _placeholder : ty:: PlaceholderRegion ,
41
- _error_element : RegionElement ,
45
+ placeholder : ty:: PlaceholderRegion ,
46
+ error_element : RegionElement ,
42
47
span : Span ,
43
48
) {
44
- // FIXME: improve this error message
45
49
match self . 0 {
46
50
UniverseInfoInner :: RelateTys { expected, found } => {
47
51
let body_id = mbcx. infcx . tcx . hir ( ) . local_def_id_to_hir_id ( mbcx. mir_def_id ( ) ) ;
@@ -53,7 +57,13 @@ impl UniverseInfo<'tcx> {
53
57
) ;
54
58
err. buffer ( & mut mbcx. errors_buffer ) ;
55
59
}
56
- UniverseInfoInner :: TypeOp ( _) | UniverseInfoInner :: Other => {
60
+ UniverseInfoInner :: TypeOp ( ref type_op_info) => {
61
+ type_op_info. report_error ( mbcx, placeholder, error_element, span) ;
62
+ }
63
+ UniverseInfoInner :: Other => {
64
+ // FIXME: This error message isn't great, but it doesn't show
65
+ // up in the existing UI tests. Consider investigating this
66
+ // some more.
57
67
mbcx. infcx
58
68
. tcx
59
69
. sess
@@ -73,8 +83,8 @@ impl<'tcx> ToUniverseInfo<'tcx>
73
83
{
74
84
fn to_universe_info ( self , base_universe : ty:: UniverseIndex ) -> UniverseInfo < ' tcx > {
75
85
UniverseInfo ( UniverseInfoInner :: TypeOp ( Rc :: new ( PredicateQuery {
76
- _canonical_query : self ,
77
- _base_universe : base_universe,
86
+ canonical_query : self ,
87
+ base_universe,
78
88
} ) ) )
79
89
}
80
90
}
@@ -84,8 +94,8 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'t
84
94
{
85
95
fn to_universe_info ( self , base_universe : ty:: UniverseIndex ) -> UniverseInfo < ' tcx > {
86
96
UniverseInfo ( UniverseInfoInner :: TypeOp ( Rc :: new ( NormalizeQuery {
87
- _canonical_query : self ,
88
- _base_universe : base_universe,
97
+ canonical_query : self ,
98
+ base_universe,
89
99
} ) ) )
90
100
}
91
101
}
@@ -109,23 +119,229 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo
109
119
110
120
#[ allow( unused_lifetimes) ]
111
121
trait TypeOpInfo < ' tcx > {
112
- // TODO: Methods for rerunning type op and reporting an error
122
+ /// Returns an rrror to be reported if rerunning the type op fails to
123
+ /// recover the error's cause.
124
+ fn fallback_error ( & self , tcx : TyCtxt < ' tcx > , span : Span ) -> DiagnosticBuilder < ' tcx > ;
125
+
126
+ fn base_universe ( & self ) -> ty:: UniverseIndex ;
127
+
128
+ fn nice_error (
129
+ & self ,
130
+ tcx : TyCtxt < ' tcx > ,
131
+ span : Span ,
132
+ placeholder_region : ty:: Region < ' tcx > ,
133
+ error_region : Option < ty:: Region < ' tcx > > ,
134
+ ) -> Option < DiagnosticBuilder < ' tcx > > ;
135
+
136
+ fn report_error (
137
+ & self ,
138
+ mbcx : & mut MirBorrowckCtxt < ' _ , ' tcx > ,
139
+ placeholder : ty:: PlaceholderRegion ,
140
+ error_element : RegionElement ,
141
+ span : Span ,
142
+ ) {
143
+ let tcx = mbcx. infcx . tcx ;
144
+ let base_universe = self . base_universe ( ) ;
145
+
146
+ let adjusted_universe = if let Some ( adjusted) =
147
+ placeholder. universe . as_u32 ( ) . checked_sub ( base_universe. as_u32 ( ) )
148
+ {
149
+ adjusted
150
+ } else {
151
+ self . fallback_error ( tcx, span) . buffer ( & mut mbcx. errors_buffer ) ;
152
+ return ;
153
+ } ;
154
+
155
+ let placeholder_region = tcx. mk_region ( ty:: RePlaceholder ( ty:: Placeholder {
156
+ name : placeholder. name ,
157
+ universe : adjusted_universe. into ( ) ,
158
+ } ) ) ;
159
+
160
+ let error_region =
161
+ if let RegionElement :: PlaceholderRegion ( error_placeholder) = error_element {
162
+ let adjusted_universe =
163
+ error_placeholder. universe . as_u32 ( ) . checked_sub ( base_universe. as_u32 ( ) ) ;
164
+ adjusted_universe. map ( |adjusted| {
165
+ tcx. mk_region ( ty:: RePlaceholder ( ty:: Placeholder {
166
+ name : error_placeholder. name ,
167
+ universe : adjusted. into ( ) ,
168
+ } ) )
169
+ } )
170
+ } else {
171
+ None
172
+ } ;
173
+
174
+ debug ! ( ?placeholder_region) ;
175
+
176
+ let nice_error = self . nice_error ( tcx, span, placeholder_region, error_region) ;
177
+
178
+ if let Some ( nice_error) = nice_error {
179
+ nice_error. buffer ( & mut mbcx. errors_buffer ) ;
180
+ } else {
181
+ self . fallback_error ( tcx, span) . buffer ( & mut mbcx. errors_buffer ) ;
182
+ }
183
+ }
113
184
}
114
185
115
186
struct PredicateQuery < ' tcx > {
116
- _canonical_query :
187
+ canonical_query :
117
188
Canonical < ' tcx , ty:: ParamEnvAnd < ' tcx , type_op:: prove_predicate:: ProvePredicate < ' tcx > > > ,
118
- _base_universe : ty:: UniverseIndex ,
189
+ base_universe : ty:: UniverseIndex ,
119
190
}
120
191
121
- impl TypeOpInfo < ' tcx > for PredicateQuery < ' tcx > { }
192
+ impl TypeOpInfo < ' tcx > for PredicateQuery < ' tcx > {
193
+ fn fallback_error ( & self , tcx : TyCtxt < ' tcx > , span : Span ) -> DiagnosticBuilder < ' tcx > {
194
+ let mut err = tcx. sess . struct_span_err ( span, "higher-ranked lifetime error" ) ;
195
+ err. note ( & format ! ( "could not prove {}" , self . canonical_query. value. value. predicate) ) ;
196
+ err
197
+ }
198
+
199
+ fn base_universe ( & self ) -> ty:: UniverseIndex {
200
+ self . base_universe
201
+ }
202
+
203
+ fn nice_error (
204
+ & self ,
205
+ tcx : TyCtxt < ' tcx > ,
206
+ span : Span ,
207
+ placeholder_region : ty:: Region < ' tcx > ,
208
+ error_region : Option < ty:: Region < ' tcx > > ,
209
+ ) -> Option < DiagnosticBuilder < ' tcx > > {
210
+ tcx. infer_ctxt ( ) . enter_with_canonical ( span, & self . canonical_query , |ref infcx, key, _| {
211
+ let mut fulfill_cx = TraitEngine :: new ( tcx) ;
212
+
213
+ let ( param_env, prove_predicate) = key. into_parts ( ) ;
214
+ fulfill_cx. register_predicate_obligation (
215
+ infcx,
216
+ Obligation :: new (
217
+ ObligationCause :: dummy_with_span ( span) ,
218
+ param_env,
219
+ prove_predicate. predicate ,
220
+ ) ,
221
+ ) ;
222
+
223
+ try_extract_error_from_fulfill_cx ( fulfill_cx, infcx, placeholder_region, error_region)
224
+ } )
225
+ }
226
+ }
122
227
123
228
struct NormalizeQuery < ' tcx , T > {
124
- _canonical_query : Canonical < ' tcx , ty:: ParamEnvAnd < ' tcx , type_op:: Normalize < T > > > ,
125
- _base_universe : ty:: UniverseIndex ,
229
+ canonical_query : Canonical < ' tcx , ty:: ParamEnvAnd < ' tcx , type_op:: Normalize < T > > > ,
230
+ base_universe : ty:: UniverseIndex ,
126
231
}
127
232
128
- impl < T > TypeOpInfo < ' tcx > for NormalizeQuery < ' tcx , T > where
129
- T : Copy + fmt:: Display + TypeFoldable < ' tcx > + ' tcx
233
+ impl < T > TypeOpInfo < ' tcx > for NormalizeQuery < ' tcx , T >
234
+ where
235
+ T : Copy + fmt:: Display + TypeFoldable < ' tcx > + ' tcx ,
130
236
{
237
+ fn fallback_error ( & self , tcx : TyCtxt < ' tcx > , span : Span ) -> DiagnosticBuilder < ' tcx > {
238
+ let mut err = tcx. sess . struct_span_err ( span, "higher-ranked lifetime error" ) ;
239
+ err. note ( & format ! ( "could not normalize `{}`" , self . canonical_query. value. value. value) ) ;
240
+ err
241
+ }
242
+
243
+ fn base_universe ( & self ) -> ty:: UniverseIndex {
244
+ self . base_universe
245
+ }
246
+
247
+ fn nice_error (
248
+ & self ,
249
+ tcx : TyCtxt < ' tcx > ,
250
+ span : Span ,
251
+ placeholder_region : ty:: Region < ' tcx > ,
252
+ error_region : Option < ty:: Region < ' tcx > > ,
253
+ ) -> Option < DiagnosticBuilder < ' tcx > > {
254
+ tcx. infer_ctxt ( ) . enter_with_canonical ( span, & self . canonical_query , |ref infcx, key, _| {
255
+ let mut fulfill_cx = TraitEngine :: new ( tcx) ;
256
+
257
+ let mut selcx = SelectionContext :: new ( infcx) ;
258
+ let ( param_env, value) = key. into_parts ( ) ;
259
+
260
+ let Normalized { value : _, obligations } = rustc_trait_selection:: traits:: normalize (
261
+ & mut selcx,
262
+ param_env,
263
+ ObligationCause :: dummy_with_span ( span) ,
264
+ value. value ,
265
+ ) ;
266
+ fulfill_cx. register_predicate_obligations ( infcx, obligations) ;
267
+
268
+ try_extract_error_from_fulfill_cx ( fulfill_cx, infcx, placeholder_region, error_region)
269
+ } )
270
+ }
271
+ }
272
+
273
+ fn try_extract_error_from_fulfill_cx < ' tcx > (
274
+ mut fulfill_cx : Box < dyn TraitEngine < ' tcx > + ' tcx > ,
275
+ infcx : & InferCtxt < ' _ , ' tcx > ,
276
+ placeholder_region : ty:: Region < ' tcx > ,
277
+ error_region : Option < ty:: Region < ' tcx > > ,
278
+ ) -> Option < DiagnosticBuilder < ' tcx > > {
279
+ let tcx = infcx. tcx ;
280
+
281
+ // We generally shouldn't have here because the query was
282
+ // already run, but there's no point using `delay_span_bug`
283
+ // when we're going to emit an error here anyway.
284
+ let _errors = fulfill_cx. select_all_or_error ( infcx) . err ( ) . unwrap_or_else ( Vec :: new) ;
285
+
286
+ let region_obligations = infcx. take_registered_region_obligations ( ) ;
287
+ debug ! ( ?region_obligations) ;
288
+
289
+ let ( sub_region, cause) = infcx. with_region_constraints ( |region_constraints| {
290
+ debug ! ( ?region_constraints) ;
291
+ region_constraints. constraints . iter ( ) . find_map ( |( constraint, cause) | {
292
+ match * constraint {
293
+ Constraint :: RegSubReg ( sub, sup) if sup == placeholder_region && sup != sub => {
294
+ Some ( ( sub, cause. clone ( ) ) )
295
+ }
296
+ // FIXME: Should this check the universe of the var?
297
+ Constraint :: VarSubReg ( vid, sup) if sup == placeholder_region => {
298
+ Some ( ( tcx. mk_region ( ty:: ReVar ( vid) ) , cause. clone ( ) ) )
299
+ }
300
+ _ => None ,
301
+ }
302
+ } )
303
+ } ) ?;
304
+
305
+ debug ! ( ?sub_region, ?cause) ;
306
+ let nice_error = match ( error_region, sub_region) {
307
+ ( Some ( error_region) , & ty:: ReVar ( vid) ) => NiceRegionError :: new (
308
+ infcx,
309
+ RegionResolutionError :: SubSupConflict (
310
+ vid,
311
+ infcx. region_var_origin ( vid) ,
312
+ cause. clone ( ) ,
313
+ error_region,
314
+ cause. clone ( ) ,
315
+ placeholder_region,
316
+ ) ,
317
+ ) ,
318
+ ( Some ( error_region) , _) => NiceRegionError :: new (
319
+ infcx,
320
+ RegionResolutionError :: ConcreteFailure ( cause. clone ( ) , error_region, placeholder_region) ,
321
+ ) ,
322
+ // Note universe here is wrong...
323
+ ( None , & ty:: ReVar ( vid) ) => NiceRegionError :: new (
324
+ infcx,
325
+ RegionResolutionError :: UpperBoundUniverseConflict (
326
+ vid,
327
+ infcx. region_var_origin ( vid) ,
328
+ infcx. universe_of_region ( sub_region) ,
329
+ cause. clone ( ) ,
330
+ placeholder_region,
331
+ ) ,
332
+ ) ,
333
+ ( None , _) => NiceRegionError :: new (
334
+ infcx,
335
+ RegionResolutionError :: ConcreteFailure ( cause. clone ( ) , sub_region, placeholder_region) ,
336
+ ) ,
337
+ } ;
338
+ nice_error. try_report_from_nll ( ) . or_else ( || {
339
+ if let SubregionOrigin :: Subtype ( trace) = cause {
340
+ Some (
341
+ infcx. report_and_explain_type_error ( * trace, & TypeError :: RegionsPlaceholderMismatch ) ,
342
+ )
343
+ } else {
344
+ None
345
+ }
346
+ } )
131
347
}
0 commit comments