@@ -68,9 +68,12 @@ use rustc_hir as hir;
6868use rustc_hir:: def_id:: DefId ;
6969use rustc_hir:: Node ;
7070
71- use errors:: { struct_span_err, Applicability , DiagnosticBuilder , DiagnosticStyledString } ;
71+ use errors:: {
72+ pluralize, struct_span_err, Applicability , DiagnosticBuilder , DiagnosticStyledString ,
73+ } ;
74+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
7275use rustc_error_codes:: * ;
73- use rustc_span:: { Pos , Span } ;
76+ use rustc_span:: { DesugaringKind , Pos , Span } ;
7477use rustc_target:: spec:: abi;
7578use std:: { cmp, fmt} ;
7679
@@ -1289,6 +1292,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12891292 mut values : Option < ValuePairs < ' tcx > > ,
12901293 terr : & TypeError < ' tcx > ,
12911294 ) {
1295+ let span = cause. span ( self . tcx ) ;
1296+
12921297 // For some types of errors, expected-found does not make
12931298 // sense, so just ignore the values we were given.
12941299 match terr {
@@ -1298,6 +1303,100 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12981303 _ => { }
12991304 }
13001305
1306+ struct OpaqueTypesVisitor < ' tcx > {
1307+ types : FxHashMap < TyCategory , FxHashSet < Span > > ,
1308+ expected : FxHashMap < TyCategory , FxHashSet < Span > > ,
1309+ found : FxHashMap < TyCategory , FxHashSet < Span > > ,
1310+ ignore_span : Span ,
1311+ tcx : TyCtxt < ' tcx > ,
1312+ }
1313+
1314+ impl < ' tcx > OpaqueTypesVisitor < ' tcx > {
1315+ fn visit_expected_found (
1316+ tcx : TyCtxt < ' tcx > ,
1317+ expected : Ty < ' tcx > ,
1318+ found : Ty < ' tcx > ,
1319+ ignore_span : Span ,
1320+ ) -> Self {
1321+ let mut types_visitor = OpaqueTypesVisitor {
1322+ types : Default :: default ( ) ,
1323+ expected : Default :: default ( ) ,
1324+ found : Default :: default ( ) ,
1325+ ignore_span,
1326+ tcx,
1327+ } ;
1328+ // The visitor puts all the relevant encountered types in `self.types`, but in
1329+ // here we want to visit two separate types with no relation to each other, so we
1330+ // move the results from `types` to `expected` or `found` as appropriate.
1331+ expected. visit_with ( & mut types_visitor) ;
1332+ std:: mem:: swap ( & mut types_visitor. expected , & mut types_visitor. types ) ;
1333+ found. visit_with ( & mut types_visitor) ;
1334+ std:: mem:: swap ( & mut types_visitor. found , & mut types_visitor. types ) ;
1335+ types_visitor
1336+ }
1337+
1338+ fn report ( & self , err : & mut DiagnosticBuilder < ' _ > ) {
1339+ self . add_labels_for_types ( err, "expected" , & self . expected ) ;
1340+ self . add_labels_for_types ( err, "found" , & self . found ) ;
1341+ }
1342+
1343+ fn add_labels_for_types (
1344+ & self ,
1345+ err : & mut DiagnosticBuilder < ' _ > ,
1346+ target : & str ,
1347+ types : & FxHashMap < TyCategory , FxHashSet < Span > > ,
1348+ ) {
1349+ for ( key, values) in types. iter ( ) {
1350+ let count = values. len ( ) ;
1351+ let kind = key. descr ( ) ;
1352+ for sp in values {
1353+ err. span_label (
1354+ * sp,
1355+ format ! (
1356+ "{}{}{} {}{}" ,
1357+ if sp. is_desugaring( DesugaringKind :: Async ) {
1358+ "the `Output` of this `async fn`'s "
1359+ } else if count == 1 {
1360+ "the "
1361+ } else {
1362+ ""
1363+ } ,
1364+ if count > 1 { "one of the " } else { "" } ,
1365+ target,
1366+ kind,
1367+ pluralize!( count) ,
1368+ ) ,
1369+ ) ;
1370+ }
1371+ }
1372+ }
1373+ }
1374+
1375+ impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for OpaqueTypesVisitor < ' tcx > {
1376+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> bool {
1377+ if let Some ( ( kind, def_id) ) = TyCategory :: from_ty ( t) {
1378+ let span = self . tcx . def_span ( def_id) ;
1379+ // Avoid cluttering the output when the "found" and error span overlap:
1380+ //
1381+ // error[E0308]: mismatched types
1382+ // --> $DIR/issue-20862.rs:2:5
1383+ // |
1384+ // LL | |y| x + y
1385+ // | ^^^^^^^^^
1386+ // | |
1387+ // | the found closure
1388+ // | expected `()`, found closure
1389+ // |
1390+ // = note: expected unit type `()`
1391+ // found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]`
1392+ if !self . ignore_span . overlaps ( span) {
1393+ self . types . entry ( kind) . or_default ( ) . insert ( span) ;
1394+ }
1395+ }
1396+ t. super_visit_with ( self )
1397+ }
1398+ }
1399+
13011400 debug ! ( "note_type_err(diag={:?})" , diag) ;
13021401 let ( expected_found, exp_found, is_simple_error) = match values {
13031402 None => ( None , None , false ) ,
@@ -1306,6 +1405,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13061405 ValuePairs :: Types ( exp_found) => {
13071406 let is_simple_err =
13081407 exp_found. expected . is_simple_text ( ) && exp_found. found . is_simple_text ( ) ;
1408+ OpaqueTypesVisitor :: visit_expected_found (
1409+ self . tcx ,
1410+ exp_found. expected ,
1411+ exp_found. found ,
1412+ span,
1413+ )
1414+ . report ( diag) ;
13091415
13101416 ( is_simple_err, Some ( exp_found) )
13111417 }
@@ -1323,8 +1429,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13231429 }
13241430 } ;
13251431
1326- let span = cause. span ( self . tcx ) ;
1327-
13281432 // Ignore msg for object safe coercion
13291433 // since E0038 message will be printed
13301434 match terr {
@@ -1336,7 +1440,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13361440 }
13371441 }
13381442 } ;
1339-
13401443 if let Some ( ( expected, found) ) = expected_found {
13411444 let expected_label = exp_found. map_or ( "type" . into ( ) , |ef| ef. expected . prefix_string ( ) ) ;
13421445 let found_label = exp_found. map_or ( "type" . into ( ) , |ef| ef. found . prefix_string ( ) ) ;
@@ -1933,3 +2036,34 @@ impl<'tcx> ObligationCause<'tcx> {
19332036 }
19342037 }
19352038}
2039+
2040+ /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
2041+ /// extra information about each type, but we only care about the category.
2042+ #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
2043+ crate enum TyCategory {
2044+ Closure ,
2045+ Opaque ,
2046+ Generator ,
2047+ Foreign ,
2048+ }
2049+
2050+ impl TyCategory {
2051+ fn descr ( & self ) -> & ' static str {
2052+ match self {
2053+ Self :: Closure => "closure" ,
2054+ Self :: Opaque => "opaque type" ,
2055+ Self :: Generator => "generator" ,
2056+ Self :: Foreign => "foreign type" ,
2057+ }
2058+ }
2059+
2060+ pub fn from_ty ( ty : Ty < ' _ > ) -> Option < ( Self , DefId ) > {
2061+ match ty. kind {
2062+ ty:: Closure ( def_id, _) => Some ( ( Self :: Closure , def_id) ) ,
2063+ ty:: Opaque ( def_id, _) => Some ( ( Self :: Opaque , def_id) ) ,
2064+ ty:: Generator ( def_id, ..) => Some ( ( Self :: Generator , def_id) ) ,
2065+ ty:: Foreign ( def_id) => Some ( ( Self :: Foreign , def_id) ) ,
2066+ _ => None ,
2067+ }
2068+ }
2069+ }
0 commit comments