@@ -22,7 +22,7 @@ use rustc_errors::{DiagnosticBuilder, EmissionGuarantee};
22
22
use rustc_hir:: def:: DefKind ;
23
23
use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
24
24
use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , TyCtxtInferExt } ;
25
- use rustc_infer:: traits:: { util, TraitEngine , TraitEngineExt } ;
25
+ use rustc_infer:: traits:: { util, FulfillmentErrorCode , TraitEngine , TraitEngineExt } ;
26
26
use rustc_middle:: traits:: query:: NoSolution ;
27
27
use rustc_middle:: traits:: solve:: { CandidateSource , Certainty , Goal } ;
28
28
use rustc_middle:: traits:: specialization_graph:: OverlapMode ;
@@ -35,6 +35,8 @@ use rustc_span::DUMMY_SP;
35
35
use std:: fmt:: Debug ;
36
36
use std:: ops:: ControlFlow ;
37
37
38
+ use super :: error_reporting:: suggest_new_overflow_limit;
39
+
38
40
/// Whether we do the orphan check relative to this crate or
39
41
/// to some remote crate.
40
42
#[ derive( Copy , Clone , Debug ) ]
@@ -56,6 +58,9 @@ pub struct OverlapResult<'tcx> {
56
58
/// `true` if the overlap might've been permitted before the shift
57
59
/// to universes.
58
60
pub involves_placeholder : bool ,
61
+
62
+ /// Used in the new solver to suggest increasing the recursion limit.
63
+ pub overflowing_predicates : Vec < ty:: Predicate < ' tcx > > ,
59
64
}
60
65
61
66
pub fn add_placeholder_note < G : EmissionGuarantee > ( err : & mut DiagnosticBuilder < ' _ , G > ) {
@@ -65,6 +70,18 @@ pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut DiagnosticBuilder<'_
65
70
) ;
66
71
}
67
72
73
+ pub fn suggest_increasing_recursion_limit < ' tcx , G : EmissionGuarantee > (
74
+ tcx : TyCtxt < ' tcx > ,
75
+ err : & mut DiagnosticBuilder < ' _ , G > ,
76
+ overflowing_predicates : & [ ty:: Predicate < ' tcx > ] ,
77
+ ) {
78
+ for pred in overflowing_predicates {
79
+ err. note ( format ! ( "overflow evaluating the requirement `{}`" , pred) ) ;
80
+ }
81
+
82
+ suggest_new_overflow_limit ( tcx, err) ;
83
+ }
84
+
68
85
#[ derive( Debug , Clone , Copy ) ]
69
86
enum TrackAmbiguityCauses {
70
87
Yes ,
@@ -221,11 +238,11 @@ fn overlap<'tcx>(
221
238
) ,
222
239
) ;
223
240
241
+ let mut overflowing_predicates = Vec :: new ( ) ;
224
242
if overlap_mode. use_implicit_negative ( ) {
225
- if let Some ( _failing_obligation) =
226
- impl_intersection_has_impossible_obligation ( selcx, & obligations)
227
- {
228
- return None ;
243
+ match impl_intersection_has_impossible_obligation ( selcx, & obligations) {
244
+ Ok ( ( ) ) => return None ,
245
+ Err ( p) => overflowing_predicates = p,
229
246
}
230
247
}
231
248
@@ -261,7 +278,12 @@ fn overlap<'tcx>(
261
278
impl_header = deeply_normalize_for_diagnostics ( & infcx, param_env, impl_header) ;
262
279
}
263
280
264
- Some ( OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder } )
281
+ Some ( OverlapResult {
282
+ impl_header,
283
+ intercrate_ambiguity_causes,
284
+ involves_placeholder,
285
+ overflowing_predicates,
286
+ } )
265
287
}
266
288
267
289
#[ instrument( level = "debug" , skip( infcx) , ret) ]
@@ -305,10 +327,14 @@ fn equate_impl_headers<'tcx>(
305
327
/// of the two impls above to be empty.
306
328
///
307
329
/// Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
330
+ ///
331
+ /// If there is no impossible obligation, this returns a list of obligations which
332
+ /// overflowed by hitting the `recursion_limit` in the new solver. This is used
333
+ /// to improve the error message.
308
334
fn impl_intersection_has_impossible_obligation < ' a , ' cx , ' tcx > (
309
335
selcx : & mut SelectionContext < ' cx , ' tcx > ,
310
336
obligations : & ' a [ PredicateObligation < ' tcx > ] ,
311
- ) -> Option < PredicateObligation < ' tcx > > {
337
+ ) -> Result < ( ) , Vec < ty :: Predicate < ' tcx > > > {
312
338
let infcx = selcx. infcx ;
313
339
314
340
if infcx. next_trait_solver ( ) {
@@ -317,28 +343,42 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
317
343
318
344
// We only care about the obligations that are *definitely* true errors.
319
345
// Ambiguities do not prove the disjointness of two impls.
320
- let mut errors = fulfill_cx. select_where_possible ( infcx) ;
321
- errors. pop ( ) . map ( |err| err. obligation )
346
+ let errors = fulfill_cx. select_where_possible ( infcx) ;
347
+ if errors. is_empty ( ) {
348
+ let overflow_errors = fulfill_cx. collect_remaining_errors ( infcx) ;
349
+ let overflowing_predicates = overflow_errors
350
+ . into_iter ( )
351
+ . filter ( |e| match e. code {
352
+ FulfillmentErrorCode :: Ambiguity { overflow : Some ( true ) } => true ,
353
+ _ => false ,
354
+ } )
355
+ . map ( |e| infcx. resolve_vars_if_possible ( e. obligation . predicate ) )
356
+ . collect ( ) ;
357
+ Err ( overflowing_predicates)
358
+ } else {
359
+ Ok ( ( ) )
360
+ }
322
361
} else {
323
- obligations
324
- . iter ( )
325
- . find ( |obligation| {
326
- // We use `evaluate_root_obligation` to correctly track intercrate
327
- // ambiguity clauses. We cannot use this in the new solver.
328
- let evaluation_result = selcx. evaluate_root_obligation ( obligation) ;
329
-
330
- match evaluation_result {
331
- Ok ( result) => !result. may_apply ( ) ,
332
- // If overflow occurs, we need to conservatively treat the goal as possibly holding,
333
- // since there can be instantiations of this goal that don't overflow and result in
334
- // success. This isn't much of a problem in the old solver, since we treat overflow
335
- // fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
336
- // but in the new solver, this is very important for correctness, since overflow
337
- // *must* be treated as ambiguity for completeness.
338
- Err ( _overflow) => false ,
362
+ for obligation in obligations {
363
+ // We use `evaluate_root_obligation` to correctly track intercrate
364
+ // ambiguity clauses.
365
+ let evaluation_result = selcx. evaluate_root_obligation ( obligation) ;
366
+
367
+ match evaluation_result {
368
+ Ok ( result) => {
369
+ if !result. may_apply ( ) {
370
+ return Ok ( ( ) ) ;
371
+ }
339
372
}
340
- } )
341
- . cloned ( )
373
+ // If overflow occurs, we need to conservatively treat the goal as possibly holding,
374
+ // since there can be instantiations of this goal that don't overflow and result in
375
+ // success. While this isn't much of a problem in the old solver, since we treat overflow
376
+ // fatally, this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>.
377
+ Err ( _overflow) => { }
378
+ }
379
+ }
380
+
381
+ Err ( Vec :: new ( ) )
342
382
}
343
383
}
344
384
0 commit comments