@@ -22,7 +22,7 @@ use rustc_errors::{Diag, 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 Diag < ' _ , G > ) {
@@ -65,6 +70,18 @@ pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
65
70
) ;
66
71
}
67
72
73
+ pub fn suggest_increasing_recursion_limit < ' tcx , G : EmissionGuarantee > (
74
+ tcx : TyCtxt < ' tcx > ,
75
+ err : & mut Diag < ' _ , 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,13 @@ 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
+ IntersectionHasImpossibleObligations :: Yes => return None ,
245
+ IntersectionHasImpossibleObligations :: No { overflowing_predicates : p } => {
246
+ overflowing_predicates = p
247
+ }
229
248
}
230
249
}
231
250
@@ -261,7 +280,12 @@ fn overlap<'tcx>(
261
280
impl_header = deeply_normalize_for_diagnostics ( & infcx, param_env, impl_header) ;
262
281
}
263
282
264
- Some ( OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder } )
283
+ Some ( OverlapResult {
284
+ impl_header,
285
+ intercrate_ambiguity_causes,
286
+ involves_placeholder,
287
+ overflowing_predicates,
288
+ } )
265
289
}
266
290
267
291
#[ instrument( level = "debug" , skip( infcx) , ret) ]
@@ -287,6 +311,19 @@ fn equate_impl_headers<'tcx>(
287
311
result. map ( |infer_ok| infer_ok. obligations ) . ok ( )
288
312
}
289
313
314
+ /// The result of [fn impl_intersection_has_impossible_obligation].
315
+ enum IntersectionHasImpossibleObligations < ' tcx > {
316
+ Yes ,
317
+ No {
318
+ /// With `-Znext-solver=coherence`, some obligations may
319
+ /// fail if only the user increased the recursion limit.
320
+ ///
321
+ /// We return those obligations here and mention them in the
322
+ /// error message.
323
+ overflowing_predicates : Vec < ty:: Predicate < ' tcx > > ,
324
+ } ,
325
+ }
326
+
290
327
/// Check if both impls can be satisfied by a common type by considering whether
291
328
/// any of either impl's obligations is not known to hold.
292
329
///
@@ -308,7 +345,7 @@ fn equate_impl_headers<'tcx>(
308
345
fn impl_intersection_has_impossible_obligation < ' a , ' cx , ' tcx > (
309
346
selcx : & mut SelectionContext < ' cx , ' tcx > ,
310
347
obligations : & ' a [ PredicateObligation < ' tcx > ] ,
311
- ) -> Option < PredicateObligation < ' tcx > > {
348
+ ) -> IntersectionHasImpossibleObligations < ' tcx > {
312
349
let infcx = selcx. infcx ;
313
350
314
351
if infcx. next_trait_solver ( ) {
@@ -317,28 +354,42 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
317
354
318
355
// We only care about the obligations that are *definitely* true errors.
319
356
// 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 )
357
+ let errors = fulfill_cx. select_where_possible ( infcx) ;
358
+ if errors. is_empty ( ) {
359
+ let overflow_errors = fulfill_cx. collect_remaining_errors ( infcx) ;
360
+ let overflowing_predicates = overflow_errors
361
+ . into_iter ( )
362
+ . filter ( |e| match e. code {
363
+ FulfillmentErrorCode :: Ambiguity { overflow : Some ( true ) } => true ,
364
+ _ => false ,
365
+ } )
366
+ . map ( |e| infcx. resolve_vars_if_possible ( e. obligation . predicate ) )
367
+ . collect ( ) ;
368
+ IntersectionHasImpossibleObligations :: No { overflowing_predicates }
369
+ } else {
370
+ IntersectionHasImpossibleObligations :: Yes
371
+ }
322
372
} 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 ,
373
+ for obligation in obligations {
374
+ // We use `evaluate_root_obligation` to correctly track intercrate
375
+ // ambiguity clauses.
376
+ let evaluation_result = selcx. evaluate_root_obligation ( obligation) ;
377
+
378
+ match evaluation_result {
379
+ Ok ( result) => {
380
+ if !result. may_apply ( ) {
381
+ return IntersectionHasImpossibleObligations :: Yes ;
382
+ }
339
383
}
340
- } )
341
- . cloned ( )
384
+ // If overflow occurs, we need to conservatively treat the goal as possibly holding,
385
+ // since there can be instantiations of this goal that don't overflow and result in
386
+ // success. While this isn't much of a problem in the old solver, since we treat overflow
387
+ // fatally, this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>.
388
+ Err ( _overflow) => { }
389
+ }
390
+ }
391
+
392
+ IntersectionHasImpossibleObligations :: No { overflowing_predicates : Vec :: new ( ) }
342
393
}
343
394
}
344
395
0 commit comments