@@ -31,7 +31,7 @@ use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableGenerator
3131use super :: util;
3232
3333use dep_graph:: { DepNodeIndex , DepKind } ;
34- use hir:: def_id:: DefId ;
34+ use hir:: def_id:: { DefId , LOCAL_CRATE } ;
3535use infer;
3636use infer:: { InferCtxt , InferOk , TypeFreshener } ;
3737use ty:: subst:: { Kind , Subst , Substs } ;
@@ -91,6 +91,45 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
9191 intercrate : bool ,
9292
9393 inferred_obligations : SnapshotVec < InferredObligationsSnapshotVecDelegate < ' tcx > > ,
94+
95+ intercrate_ambiguity_causes : Vec < IntercrateAmbiguityCause > ,
96+ }
97+
98+ #[ derive( Clone ) ]
99+ pub enum IntercrateAmbiguityCause {
100+ DownstreamCrate {
101+ trait_desc : String ,
102+ self_desc : Option < String > ,
103+ } ,
104+ UpstreamCrateUpdate {
105+ trait_desc : String ,
106+ self_desc : Option < String > ,
107+ } ,
108+ }
109+
110+ impl IntercrateAmbiguityCause {
111+ /// Emits notes when the overlap is caused by complex intercrate ambiguities.
112+ /// See #23980 for details.
113+ pub fn add_intercrate_ambiguity_hint < ' a , ' tcx > ( & self ,
114+ err : & mut :: errors:: DiagnosticBuilder ) {
115+ match self {
116+ & IntercrateAmbiguityCause :: DownstreamCrate { ref trait_desc, ref self_desc } => {
117+ let self_desc = if let & Some ( ref ty) = self_desc {
118+ format ! ( " for type `{}`" , ty)
119+ } else { "" . to_string ( ) } ;
120+ err. note ( & format ! ( "downstream crates may implement trait `{}`{}" ,
121+ trait_desc, self_desc) ) ;
122+ }
123+ & IntercrateAmbiguityCause :: UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
124+ let self_desc = if let & Some ( ref ty) = self_desc {
125+ format ! ( " for type `{}`" , ty)
126+ } else { "" . to_string ( ) } ;
127+ err. note ( & format ! ( "upstream crates may add new impl of trait `{}`{} \
128+ in future versions",
129+ trait_desc, self_desc) ) ;
130+ }
131+ }
132+ }
94133}
95134
96135// A stack that walks back up the stack frame.
@@ -390,6 +429,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
390429 freshener : infcx. freshener ( ) ,
391430 intercrate : false ,
392431 inferred_obligations : SnapshotVec :: new ( ) ,
432+ intercrate_ambiguity_causes : Vec :: new ( ) ,
393433 }
394434 }
395435
@@ -399,6 +439,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
399439 freshener : infcx. freshener ( ) ,
400440 intercrate : true ,
401441 inferred_obligations : SnapshotVec :: new ( ) ,
442+ intercrate_ambiguity_causes : Vec :: new ( ) ,
402443 }
403444 }
404445
@@ -414,6 +455,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
414455 self . infcx
415456 }
416457
458+ pub fn intercrate_ambiguity_causes ( & self ) -> & [ IntercrateAmbiguityCause ] {
459+ & self . intercrate_ambiguity_causes
460+ }
461+
417462 /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
418463 /// context's self.
419464 fn in_snapshot < R , F > ( & mut self , f : F ) -> R
@@ -767,6 +812,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
767812 if unbound_input_types && self . intercrate {
768813 debug ! ( "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous" ,
769814 stack. fresh_trait_ref) ;
815+ // Heuristics: show the diagnostics when there are no candidates in crate.
816+ if let Ok ( candidate_set) = self . assemble_candidates ( stack) {
817+ if !candidate_set. ambiguous && candidate_set. vec . is_empty ( ) {
818+ let trait_ref = stack. obligation . predicate . skip_binder ( ) . trait_ref ;
819+ let self_ty = trait_ref. self_ty ( ) ;
820+ let cause = IntercrateAmbiguityCause :: DownstreamCrate {
821+ trait_desc : trait_ref. to_string ( ) ,
822+ self_desc : if self_ty. has_concrete_skeleton ( ) {
823+ Some ( self_ty. to_string ( ) )
824+ } else {
825+ None
826+ } ,
827+ } ;
828+ self . intercrate_ambiguity_causes . push ( cause) ;
829+ }
830+ }
770831 return EvaluatedToAmbig ;
771832 }
772833 if unbound_input_types &&
@@ -1021,6 +1082,25 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
10211082
10221083 if !self . is_knowable ( stack) {
10231084 debug ! ( "coherence stage: not knowable" ) ;
1085+ // Heuristics: show the diagnostics when there are no candidates in crate.
1086+ let candidate_set = self . assemble_candidates ( stack) ?;
1087+ if !candidate_set. ambiguous && candidate_set. vec . is_empty ( ) {
1088+ let trait_ref = stack. obligation . predicate . skip_binder ( ) . trait_ref ;
1089+ let self_ty = trait_ref. self_ty ( ) ;
1090+ let trait_desc = trait_ref. to_string ( ) ;
1091+ let self_desc = if self_ty. has_concrete_skeleton ( ) {
1092+ Some ( self_ty. to_string ( ) )
1093+ } else {
1094+ None
1095+ } ;
1096+ let cause = if !coherence:: trait_ref_is_local_or_fundamental ( self . tcx ( ) ,
1097+ trait_ref) {
1098+ IntercrateAmbiguityCause :: UpstreamCrateUpdate { trait_desc, self_desc }
1099+ } else {
1100+ IntercrateAmbiguityCause :: DownstreamCrate { trait_desc, self_desc }
1101+ } ;
1102+ self . intercrate_ambiguity_causes . push ( cause) ;
1103+ }
10241104 return Ok ( None ) ;
10251105 }
10261106
0 commit comments