@@ -22,7 +22,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
2222use rustc_hir:: def:: DefKind ;
2323use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
2424use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , TyCtxtInferExt } ;
25- use rustc_infer:: traits:: { util, TraitEngine , TraitEngineExt } ;
25+ use rustc_infer:: traits:: { util, FulfillmentErrorCode , TraitEngine , TraitEngineExt } ;
2626use rustc_middle:: traits:: query:: NoSolution ;
2727use rustc_middle:: traits:: solve:: { CandidateSource , Certainty , Goal } ;
2828use rustc_middle:: traits:: specialization_graph:: OverlapMode ;
@@ -35,6 +35,8 @@ use rustc_span::DUMMY_SP;
3535use std:: fmt:: Debug ;
3636use std:: ops:: ControlFlow ;
3737
38+ use super :: error_reporting:: suggest_new_overflow_limit;
39+
3840/// Whether we do the orphan check relative to this crate or
3941/// to some remote crate.
4042#[ derive( Copy , Clone , Debug ) ]
@@ -56,6 +58,9 @@ pub struct OverlapResult<'tcx> {
5658 /// `true` if the overlap might've been permitted before the shift
5759 /// to universes.
5860 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 > > ,
5964}
6065
6166pub 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>) {
6570 ) ;
6671}
6772
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+
6885#[ derive( Debug , Clone , Copy ) ]
6986enum TrackAmbiguityCauses {
7087 Yes ,
@@ -221,11 +238,13 @@ fn overlap<'tcx>(
221238 ) ,
222239 ) ;
223240
241+ let mut overflowing_predicates = Vec :: new ( ) ;
224242 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+ }
229248 }
230249 }
231250
@@ -261,7 +280,12 @@ fn overlap<'tcx>(
261280 impl_header = deeply_normalize_for_diagnostics ( & infcx, param_env, impl_header) ;
262281 }
263282
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+ } )
265289}
266290
267291#[ instrument( level = "debug" , skip( infcx) , ret) ]
@@ -287,6 +311,19 @@ fn equate_impl_headers<'tcx>(
287311 result. map ( |infer_ok| infer_ok. obligations ) . ok ( )
288312}
289313
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+
290327/// Check if both impls can be satisfied by a common type by considering whether
291328/// any of either impl's obligations is not known to hold.
292329///
@@ -308,7 +345,7 @@ fn equate_impl_headers<'tcx>(
308345fn impl_intersection_has_impossible_obligation < ' a , ' cx , ' tcx > (
309346 selcx : & mut SelectionContext < ' cx , ' tcx > ,
310347 obligations : & ' a [ PredicateObligation < ' tcx > ] ,
311- ) -> Option < PredicateObligation < ' tcx > > {
348+ ) -> IntersectionHasImpossibleObligations < ' tcx > {
312349 let infcx = selcx. infcx ;
313350
314351 if infcx. next_trait_solver ( ) {
@@ -317,28 +354,42 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
317354
318355 // We only care about the obligations that are *definitely* true errors.
319356 // 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+ }
322372 } 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+ }
339383 }
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 ( ) }
342393 }
343394}
344395
0 commit comments