1+ use rustc_errors:: DiagnosticBuilder ;
12use 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 } ;
37use rustc_middle:: ty:: error:: TypeError ;
4- use rustc_middle:: ty:: { self , Ty , TypeFoldable } ;
8+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
59use rustc_span:: Span ;
610use rustc_trait_selection:: traits:: query:: type_op;
11+ use rustc_trait_selection:: traits:: { SelectionContext , TraitEngineExt as _} ;
712
813use std:: fmt;
914use std:: rc:: Rc ;
@@ -37,11 +42,10 @@ impl UniverseInfo<'tcx> {
3742 crate fn report_error (
3843 & self ,
3944 mbcx : & mut MirBorrowckCtxt < ' _ , ' tcx > ,
40- _placeholder : ty:: PlaceholderRegion ,
41- _error_element : RegionElement ,
45+ placeholder : ty:: PlaceholderRegion ,
46+ error_element : RegionElement ,
4247 span : Span ,
4348 ) {
44- // FIXME: improve this error message
4549 match self . 0 {
4650 UniverseInfoInner :: RelateTys { expected, found } => {
4751 let body_id = mbcx. infcx . tcx . hir ( ) . local_def_id_to_hir_id ( mbcx. mir_def_id ( ) ) ;
@@ -53,7 +57,13 @@ impl UniverseInfo<'tcx> {
5357 ) ;
5458 err. buffer ( & mut mbcx. errors_buffer ) ;
5559 }
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.
5767 mbcx. infcx
5868 . tcx
5969 . sess
@@ -73,8 +83,8 @@ impl<'tcx> ToUniverseInfo<'tcx>
7383{
7484 fn to_universe_info ( self , base_universe : ty:: UniverseIndex ) -> UniverseInfo < ' tcx > {
7585 UniverseInfo ( UniverseInfoInner :: TypeOp ( Rc :: new ( PredicateQuery {
76- _canonical_query : self ,
77- _base_universe : base_universe,
86+ canonical_query : self ,
87+ base_universe,
7888 } ) ) )
7989 }
8090}
@@ -84,8 +94,8 @@ impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'t
8494{
8595 fn to_universe_info ( self , base_universe : ty:: UniverseIndex ) -> UniverseInfo < ' tcx > {
8696 UniverseInfo ( UniverseInfoInner :: TypeOp ( Rc :: new ( NormalizeQuery {
87- _canonical_query : self ,
88- _base_universe : base_universe,
97+ canonical_query : self ,
98+ base_universe,
8999 } ) ) )
90100 }
91101}
@@ -109,23 +119,229 @@ impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::Custo
109119
110120#[ allow( unused_lifetimes) ]
111121trait 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+ }
113184}
114185
115186struct PredicateQuery < ' tcx > {
116- _canonical_query :
187+ canonical_query :
117188 Canonical < ' tcx , ty:: ParamEnvAnd < ' tcx , type_op:: prove_predicate:: ProvePredicate < ' tcx > > > ,
118- _base_universe : ty:: UniverseIndex ,
189+ base_universe : ty:: UniverseIndex ,
119190}
120191
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+ }
122227
123228struct 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 ,
126231}
127232
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 ,
130236{
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+ } )
131347}
0 commit comments