@@ -68,9 +68,11 @@ 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+ } ;
7274use rustc_error_codes:: * ;
73- use rustc_span:: { Pos , Span } ;
75+ use rustc_span:: { DesugaringKind , Pos , Span } ;
7476use rustc_target:: spec:: abi;
7577use std:: { cmp, fmt} ;
7678
@@ -1289,6 +1291,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12891291 mut values : Option < ValuePairs < ' tcx > > ,
12901292 terr : & TypeError < ' tcx > ,
12911293 ) {
1294+ let span = cause. span ( self . tcx ) ;
1295+
12921296 // For some types of errors, expected-found does not make
12931297 // sense, so just ignore the values we were given.
12941298 match terr {
@@ -1298,6 +1302,85 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12981302 _ => { }
12991303 }
13001304
1305+ struct OpaqueTypesVisitor < ' tcx > {
1306+ types : FxHashMap < & ' static str , FxHashSet < Span > > ,
1307+ expected : FxHashMap < & ' static str , FxHashSet < Span > > ,
1308+ found : FxHashMap < & ' static str , FxHashSet < Span > > ,
1309+ ignore_span : Span ,
1310+ tcx : TyCtxt < ' tcx > ,
1311+ }
1312+
1313+ impl < ' tcx > OpaqueTypesVisitor < ' tcx > {
1314+ fn visit_expected_found (
1315+ tcx : TyCtxt < ' tcx > ,
1316+ expected : Ty < ' tcx > ,
1317+ found : Ty < ' tcx > ,
1318+ ignore_span : Span ,
1319+ ) -> Self {
1320+ let mut types_visitor = OpaqueTypesVisitor {
1321+ types : Default :: default ( ) ,
1322+ expected : Default :: default ( ) ,
1323+ found : Default :: default ( ) ,
1324+ ignore_span,
1325+ tcx,
1326+ } ;
1327+ expected. visit_with ( & mut types_visitor) ;
1328+ std:: mem:: swap ( & mut types_visitor. expected , & mut types_visitor. types ) ;
1329+ found. visit_with ( & mut types_visitor) ;
1330+ std:: mem:: swap ( & mut types_visitor. found , & mut types_visitor. types ) ;
1331+ types_visitor
1332+ }
1333+
1334+ fn report ( & self , err : & mut DiagnosticBuilder < ' _ > ) {
1335+ for ( target, types) in & [ ( "expected" , & self . expected ) , ( "found" , & self . found ) ] {
1336+ for ( key, values) in types. iter ( ) {
1337+ let count = values. len ( ) ;
1338+ for sp in values {
1339+ err. span_label (
1340+ * sp,
1341+ format ! (
1342+ "{}this is {}the {} {}{}" ,
1343+ if sp. is_desugaring( DesugaringKind :: Async ) {
1344+ "in the desugared `async fn`, "
1345+ } else {
1346+ ""
1347+ } ,
1348+ if count > 1 { "one of" } else { "" } ,
1349+ target,
1350+ key,
1351+ pluralize!( count) ,
1352+ ) ,
1353+ ) ;
1354+ }
1355+ }
1356+ }
1357+ }
1358+ }
1359+
1360+ impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for OpaqueTypesVisitor < ' tcx > {
1361+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> bool {
1362+ let kind = match t. kind {
1363+ ty:: Closure ( ..) => "closure" ,
1364+ ty:: Opaque ( ..) => "opaque type" ,
1365+ _ => "" ,
1366+ } ;
1367+ match t. kind {
1368+ ty:: Closure ( def_id, _) | ty:: Opaque ( def_id, _) => {
1369+ let span = self . tcx . def_span ( def_id) ;
1370+ debug ! ( "note_type_err visit_ty {:?}" , span. macro_backtrace( ) ) ;
1371+ if !self . ignore_span . overlaps ( span)
1372+ && !self . expected . values ( ) . any ( |exp| exp. iter ( ) . any ( |sp| * sp == span) )
1373+ {
1374+ let entry = self . types . entry ( kind) . or_default ( ) ;
1375+ entry. insert ( span) ;
1376+ }
1377+ }
1378+ _ => { }
1379+ }
1380+ t. super_visit_with ( self )
1381+ }
1382+ }
1383+
13011384 debug ! ( "note_type_err(diag={:?})" , diag) ;
13021385 let ( expected_found, exp_found, is_simple_error) = match values {
13031386 None => ( None , None , false ) ,
@@ -1306,6 +1389,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13061389 ValuePairs :: Types ( exp_found) => {
13071390 let is_simple_err =
13081391 exp_found. expected . is_simple_text ( ) && exp_found. found . is_simple_text ( ) ;
1392+ OpaqueTypesVisitor :: visit_expected_found (
1393+ self . tcx ,
1394+ exp_found. expected ,
1395+ exp_found. found ,
1396+ span,
1397+ )
1398+ . report ( diag) ;
13091399
13101400 ( is_simple_err, Some ( exp_found) )
13111401 }
@@ -1323,8 +1413,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13231413 }
13241414 } ;
13251415
1326- let span = cause. span ( self . tcx ) ;
1327-
13281416 // Ignore msg for object safe coercion
13291417 // since E0038 message will be printed
13301418 match terr {
@@ -1336,7 +1424,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13361424 }
13371425 }
13381426 } ;
1339-
13401427 if let Some ( ( expected, found) ) = expected_found {
13411428 let expected_label = exp_found. map_or ( "type" . into ( ) , |ef| ef. expected . prefix_string ( ) ) ;
13421429 let found_label = exp_found. map_or ( "type" . into ( ) , |ef| ef. found . prefix_string ( ) ) ;
0 commit comments