@@ -90,6 +90,45 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
90
90
intercrate : bool ,
91
91
92
92
inferred_obligations : SnapshotVec < InferredObligationsSnapshotVecDelegate < ' tcx > > ,
93
+
94
+ intercrate_ambiguity_causes : Vec < IntercrateAmbiguityCause > ,
95
+ }
96
+
97
+ #[ derive( Clone ) ]
98
+ pub enum IntercrateAmbiguityCause {
99
+ DownstreamCrate {
100
+ trait_desc : String ,
101
+ self_desc : Option < String > ,
102
+ } ,
103
+ UpstreamCrateUpdate {
104
+ trait_desc : String ,
105
+ self_desc : Option < String > ,
106
+ } ,
107
+ }
108
+
109
+ impl IntercrateAmbiguityCause {
110
+ /// Emits notes when the overlap is caused by complex intercrate ambiguities.
111
+ /// See #23980 for details.
112
+ pub fn add_intercrate_ambiguity_hint < ' a , ' tcx > ( & self ,
113
+ err : & mut :: errors:: DiagnosticBuilder ) {
114
+ match self {
115
+ & IntercrateAmbiguityCause :: DownstreamCrate { ref trait_desc, ref self_desc } => {
116
+ let self_desc = if let & Some ( ref ty) = self_desc {
117
+ format ! ( " for type `{}`" , ty)
118
+ } else { "" . to_string ( ) } ;
119
+ err. note ( & format ! ( "downstream crates may implement trait `{}`{}" ,
120
+ trait_desc, self_desc) ) ;
121
+ }
122
+ & IntercrateAmbiguityCause :: UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
123
+ let self_desc = if let & Some ( ref ty) = self_desc {
124
+ format ! ( " for type `{}`" , ty)
125
+ } else { "" . to_string ( ) } ;
126
+ err. note ( & format ! ( "upstream crates may add new impl of trait `{}`{} \
127
+ in future versions",
128
+ trait_desc, self_desc) ) ;
129
+ }
130
+ }
131
+ }
93
132
}
94
133
95
134
// A stack that walks back up the stack frame.
@@ -380,6 +419,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
380
419
freshener : infcx. freshener ( ) ,
381
420
intercrate : false ,
382
421
inferred_obligations : SnapshotVec :: new ( ) ,
422
+ intercrate_ambiguity_causes : Vec :: new ( ) ,
383
423
}
384
424
}
385
425
@@ -389,6 +429,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
389
429
freshener : infcx. freshener ( ) ,
390
430
intercrate : true ,
391
431
inferred_obligations : SnapshotVec :: new ( ) ,
432
+ intercrate_ambiguity_causes : Vec :: new ( ) ,
392
433
}
393
434
}
394
435
@@ -404,6 +445,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
404
445
self . infcx
405
446
}
406
447
448
+ pub fn intercrate_ambiguity_causes ( & self ) -> & [ IntercrateAmbiguityCause ] {
449
+ & self . intercrate_ambiguity_causes
450
+ }
451
+
407
452
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
408
453
/// context's self.
409
454
fn in_snapshot < R , F > ( & mut self , f : F ) -> R
@@ -757,6 +802,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
757
802
if unbound_input_types && self . intercrate {
758
803
debug ! ( "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous" ,
759
804
stack. fresh_trait_ref) ;
805
+ // Heuristics: show the diagnostics when there are no candidates in crate.
806
+ if let Ok ( candidate_set) = self . assemble_candidates ( stack) {
807
+ if !candidate_set. ambiguous && candidate_set. vec . is_empty ( ) {
808
+ let trait_ref = stack. obligation . predicate . skip_binder ( ) . trait_ref ;
809
+ let self_ty = trait_ref. self_ty ( ) ;
810
+ let cause = IntercrateAmbiguityCause :: DownstreamCrate {
811
+ trait_desc : trait_ref. to_string ( ) ,
812
+ self_desc : if self_ty. has_concrete_skeleton ( ) {
813
+ Some ( self_ty. to_string ( ) )
814
+ } else {
815
+ None
816
+ } ,
817
+ } ;
818
+ self . intercrate_ambiguity_causes . push ( cause) ;
819
+ }
820
+ }
760
821
return EvaluatedToAmbig ;
761
822
}
762
823
if unbound_input_types &&
@@ -1003,6 +1064,25 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1003
1064
1004
1065
if !self . is_knowable ( stack) {
1005
1066
debug ! ( "coherence stage: not knowable" ) ;
1067
+ // Heuristics: show the diagnostics when there are no candidates in crate.
1068
+ let candidate_set = self . assemble_candidates ( stack) ?;
1069
+ if !candidate_set. ambiguous && candidate_set. vec . is_empty ( ) {
1070
+ let trait_ref = stack. obligation . predicate . skip_binder ( ) . trait_ref ;
1071
+ let self_ty = trait_ref. self_ty ( ) ;
1072
+ let trait_desc = trait_ref. to_string ( ) ;
1073
+ let self_desc = if self_ty. has_concrete_skeleton ( ) {
1074
+ Some ( self_ty. to_string ( ) )
1075
+ } else {
1076
+ None
1077
+ } ;
1078
+ let cause = if !coherence:: trait_ref_is_local_or_fundamental ( self . tcx ( ) ,
1079
+ trait_ref) {
1080
+ IntercrateAmbiguityCause :: UpstreamCrateUpdate { trait_desc, self_desc }
1081
+ } else {
1082
+ IntercrateAmbiguityCause :: DownstreamCrate { trait_desc, self_desc }
1083
+ } ;
1084
+ self . intercrate_ambiguity_causes . push ( cause) ;
1085
+ }
1006
1086
return Ok ( None ) ;
1007
1087
}
1008
1088
@@ -1124,7 +1204,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
1124
1204
// ok to skip binder because of the nature of the
1125
1205
// trait-ref-is-knowable check, which does not care about
1126
1206
// bound regions
1127
- let trait_ref = & predicate. skip_binder ( ) . trait_ref ;
1207
+ let trait_ref = predicate. skip_binder ( ) . trait_ref ;
1128
1208
1129
1209
coherence:: trait_ref_is_knowable ( self . tcx ( ) , trait_ref)
1130
1210
}
0 commit comments