@@ -20,8 +20,8 @@ use tracing::{debug, instrument};
2020use crate :: error_reporting:: TypeErrCtxt ;
2121use crate :: error_reporting:: infer:: need_type_info:: TypeAnnotationNeeded ;
2222use crate :: error_reporting:: traits:: { FindExprBySpan , to_pretty_impl_header} ;
23- use crate :: traits:: ObligationCtxt ;
2423use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt ;
24+ use crate :: traits:: { FulfillmentError , ObligationCtxt } ;
2525
2626#[ derive( Debug ) ]
2727pub enum CandidateSource {
@@ -174,10 +174,43 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>(
174174}
175175
176176impl < ' a , ' tcx > TypeErrCtxt < ' a , ' tcx > {
177+ /// The term of an ambiguous obligation's predicate that gets blamed for the
178+ /// missing type annotation: the first one still containing inference variables.
179+ ///
180+ /// Besides `maybe_report_ambiguity` pointing its diagnostics at this term,
181+ /// `report_fulfillment_errors` merges the ambiguity errors whose blamed terms
182+ /// share an inference variable into a single diagnostic.
183+ pub ( super ) fn ambiguity_term ( & self , predicate : ty:: Predicate < ' tcx > ) -> Option < ty:: Term < ' tcx > > {
184+ match predicate. kind ( ) . skip_binder ( ) {
185+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) ) => data
186+ . trait_ref
187+ . args
188+ . iter ( )
189+ . filter_map ( ty:: GenericArg :: as_term)
190+ . find ( |term| term. has_non_region_infer ( ) ) ,
191+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( data) ) => data
192+ . projection_term
193+ . args
194+ . iter ( )
195+ . filter_map ( ty:: GenericArg :: as_term)
196+ . chain ( [ data. term ] )
197+ . find ( |term| term. has_non_region_infer ( ) ) ,
198+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: WellFormed ( term) ) => Some ( term) ,
199+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstEvaluatable ( data) ) => {
200+ data. walk ( ) . filter_map ( ty:: GenericArg :: as_term) . find ( |term| term. is_infer ( ) )
201+ }
202+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ct, _) ) => Some ( ct. into ( ) ) ,
203+ ty:: PredicateKind :: Subtype ( data) => Some ( data. a . into ( ) ) ,
204+ ty:: PredicateKind :: NormalizesTo ( data) if data. term . is_infer ( ) => Some ( data. term ) ,
205+ _ => None ,
206+ }
207+ }
208+
177209 #[ instrument( skip( self ) , level = "debug" ) ]
178210 pub ( super ) fn maybe_report_ambiguity (
179211 & self ,
180212 obligation : & PredicateObligation < ' tcx > ,
213+ related : & [ & FulfillmentError < ' tcx > ] ,
181214 ) -> ErrorGuaranteed {
182215 // Unable to successfully determine, probably means
183216 // insufficient type information, but could mean
@@ -255,12 +288,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
255288 // Pick the first generic parameter that still contains inference variables as the one
256289 // we're going to emit an error for. If there are none (see above), fall back to
257290 // a more general error.
258- let term = data
259- . trait_ref
260- . args
261- . iter ( )
262- . filter_map ( ty:: GenericArg :: as_term)
263- . find ( |s| s. has_non_region_infer ( ) ) ;
291+ let term = self . ambiguity_term ( predicate) ;
264292
265293 let mut err = if let Some ( term) = term {
266294 let candidates: Vec < _ > = self
@@ -306,34 +334,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
306334 . with_long_ty_path ( long_ty_path)
307335 } ;
308336
309- let mut ambiguities = compute_applicable_impls_for_diagnostics (
310- self . infcx ,
311- & obligation. with ( self . tcx , trait_pred) ,
312- false ,
313- ) ;
314- let has_non_region_infer = trait_pred
315- . skip_binder ( )
316- . trait_ref
317- . args
318- . types ( )
319- . any ( |t| !t. is_ty_or_numeric_infer ( ) ) ;
320- // It doesn't make sense to talk about applicable impls if there are more than a
321- // handful of them. If there are a lot of them, but only a few of them have no type
322- // params, we only show those, as they are more likely to be useful/intended.
323- if ambiguities. len ( ) > 5 {
324- let infcx = self . infcx ;
325- if !ambiguities. iter ( ) . all ( |option| match option {
326- CandidateSource :: DefId ( did) => infcx. tcx . generics_of ( * did) . count ( ) == 0 ,
327- CandidateSource :: ParamEnv ( _) => true ,
328- } ) {
329- // If not all are blanket impls, we filter blanked impls out.
330- ambiguities. retain ( |option| match option {
331- CandidateSource :: DefId ( did) => infcx. tcx . generics_of ( * did) . count ( ) == 0 ,
332- CandidateSource :: ParamEnv ( _) => true ,
333- } ) ;
334- }
335- }
336- if ambiguities. len ( ) > 1 && ambiguities. len ( ) < 10 && has_non_region_infer {
337+ if let Some ( ambiguities) = self . applicable_impls_to_mention ( obligation, trait_pred)
338+ {
337339 if let Some ( e) = self . tainted_by_errors ( )
338340 && term. is_none ( )
339341 {
@@ -590,13 +592,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
590592 // other `Foo` impls are incoherent.
591593 return guar;
592594 }
593- let term = data
594- . projection_term
595- . args
596- . iter ( )
597- . filter_map ( ty:: GenericArg :: as_term)
598- . chain ( [ data. term ] )
599- . find ( |g| g. has_non_region_infer ( ) ) ;
595+ let term = self . ambiguity_term ( predicate) ;
600596 let predicate = self . tcx . short_string ( predicate, & mut long_ty_path) ;
601597 if let Some ( term) = term {
602598 self . emit_inference_failure_err (
@@ -621,16 +617,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
621617 }
622618 }
623619
624- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstEvaluatable ( data ) ) => {
620+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstEvaluatable ( _ ) ) => {
625621 if let Err ( e) = predicate. error_reported ( ) {
626622 return e;
627623 }
628624 if let Some ( e) = self . tainted_by_errors ( ) {
629625 return e;
630626 }
631- let term =
632- data. walk ( ) . filter_map ( ty:: GenericArg :: as_term) . find ( |term| term. is_infer ( ) ) ;
633- if let Some ( term) = term {
627+ if let Some ( term) = self . ambiguity_term ( predicate) {
634628 self . emit_inference_failure_err (
635629 obligation. cause . body_def_id ,
636630 span,
@@ -713,10 +707,119 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
713707 . with_long_ty_path ( long_ty_path)
714708 }
715709 } ;
710+
711+ // The related obligations are ambiguous because of the same inference variable,
712+ // so they belong to this diagnostic: annotating the variable has to satisfy all
713+ // of them at once. Mention their requirements, except for bookkeeping predicates
714+ // (`WellFormed`, sizedness, ...) whose mention wouldn't be actionable.
715+ let mut mentioned = vec ! [ predicate] ;
716+ let mut mentioned_strs: Vec < String > = vec ! [ ] ;
717+ for & error in related {
718+ let related_pred = self . resolve_vars_if_possible ( error. obligation . predicate ) ;
719+ if mentioned. contains ( & related_pred) {
720+ continue ;
721+ }
722+ let note = match related_pred. kind ( ) . skip_binder ( ) {
723+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) )
724+ if !matches ! (
725+ self . tcx. as_lang_item( data. def_id( ) ) ,
726+ Some ( LangItem :: Sized | LangItem :: MetaSized | LangItem :: PointeeSized )
727+ ) =>
728+ {
729+ let clause = related_pred. kind ( ) . rebind ( data) ;
730+ if let ty:: Infer ( _) = clause. self_ty ( ) . skip_binder ( ) . kind ( ) {
731+ let tr = self . tcx . short_string (
732+ clause. print_modifiers_and_trait_path ( ) ,
733+ & mut err. long_ty_path ( ) ,
734+ ) ;
735+ format ! ( "the type must also implement `{tr}`" )
736+ } else {
737+ let pred = self . tcx . short_string ( related_pred, & mut err. long_ty_path ( ) ) ;
738+ let note = format ! ( "cannot satisfy `{pred}`" ) ;
739+ // The self type is known, so the `impl`s that could have applied to it are
740+ // few and worth pointing at, like the blamed bound does. When it is still
741+ // an inference variable the list is every `impl` of the trait, which is
742+ // why the branch above only names the trait.
743+ //
744+ // `tainted_by_errors` is checked because `annotate_source_of_ambiguity`
745+ // downgrades the whole diagnostic once an error was already emitted.
746+ if !mentioned_strs. contains ( & note)
747+ && self . tainted_by_errors ( ) . is_none ( )
748+ && let Some ( ambiguities) =
749+ self . applicable_impls_to_mention ( & error. obligation , clause)
750+ {
751+ self . annotate_source_of_ambiguity ( & mut err, & ambiguities, related_pred) ;
752+ mentioned_strs. push ( note) ;
753+ mentioned. push ( related_pred) ;
754+ continue ;
755+ }
756+ note
757+ }
758+ }
759+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( _) ) => {
760+ let pred = self . tcx . short_string ( related_pred, & mut err. long_ty_path ( ) ) ;
761+ format ! ( "cannot satisfy `{pred}`" )
762+ }
763+ _ => {
764+ mentioned. push ( related_pred) ;
765+ continue ;
766+ }
767+ } ;
768+ // Two predicates can print identically (e.g. `From<?0>` and `From<?1>` both show as
769+ // `From<_>`); only emit each unique note string once.
770+ if !mentioned_strs. contains ( & note) {
771+ err. note ( note. clone ( ) ) ;
772+ mentioned_strs. push ( note) ;
773+ }
774+ mentioned. push ( related_pred) ;
775+ }
776+
716777 self . note_obligation_cause ( & mut err, obligation) ;
778+ // The merged errors are not reported on their own anymore, so the bounds they came from
779+ // have to be explained here too. Causes shared with the blamed obligation are already
780+ // described by the call above.
781+ for & error in related {
782+ if error. obligation . cause . code ( ) != obligation. cause . code ( ) {
783+ self . note_obligation_cause ( & mut err, & error. obligation ) ;
784+ }
785+ }
717786 err. emit ( )
718787 }
719788
789+ /// The `impl`s and `where` clauses that could have satisfied `trait_pred`, when listing them
790+ /// is likely to help. `None` means the caller should describe the bound some other way.
791+ fn applicable_impls_to_mention (
792+ & self ,
793+ obligation : & PredicateObligation < ' tcx > ,
794+ trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
795+ ) -> Option < Vec < CandidateSource > > {
796+ let mut ambiguities = compute_applicable_impls_for_diagnostics (
797+ self . infcx ,
798+ & obligation. with ( self . tcx , trait_pred) ,
799+ false ,
800+ ) ;
801+ let has_non_region_infer =
802+ trait_pred. skip_binder ( ) . trait_ref . args . types ( ) . any ( |t| !t. is_ty_or_numeric_infer ( ) ) ;
803+ // It doesn't make sense to talk about applicable impls if there are more than a
804+ // handful of them. If there are a lot of them, but only a few of them have no type
805+ // params, we only show those, as they are more likely to be useful/intended.
806+ if ambiguities. len ( ) > 5 {
807+ let infcx = self . infcx ;
808+ if !ambiguities. iter ( ) . all ( |option| match option {
809+ CandidateSource :: DefId ( did) => infcx. tcx . generics_of ( * did) . count ( ) == 0 ,
810+ CandidateSource :: ParamEnv ( _) => true ,
811+ } ) {
812+ // If not all are blanket impls, we filter blanked impls out.
813+ ambiguities. retain ( |option| match option {
814+ CandidateSource :: DefId ( did) => infcx. tcx . generics_of ( * did) . count ( ) == 0 ,
815+ CandidateSource :: ParamEnv ( _) => true ,
816+ } ) ;
817+ }
818+ }
819+ ( ambiguities. len ( ) > 1 && ambiguities. len ( ) < 10 && has_non_region_infer)
820+ . then_some ( ambiguities)
821+ }
822+
720823 fn annotate_source_of_ambiguity (
721824 & self ,
722825 err : & mut Diag < ' _ > ,
0 commit comments