@@ -27,7 +27,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2727use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
2828use rustc_hir as hir;
2929use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
30- use rustc_span:: source_map:: SourceMap ;
3130use rustc_span:: { ExpnKind , Span , DUMMY_SP } ;
3231use std:: fmt;
3332use syntax:: ast;
@@ -1034,6 +1033,10 @@ pub fn report_object_safety_error(
10341033 violations : Vec < ObjectSafetyViolation > ,
10351034) -> DiagnosticBuilder < ' tcx > {
10361035 let trait_str = tcx. def_path_str ( trait_def_id) ;
1036+ let trait_span = tcx. hir ( ) . get_if_local ( trait_def_id) . and_then ( |node| match node {
1037+ hir:: Node :: Item ( item) => Some ( item. ident . span ) ,
1038+ _ => None ,
1039+ } ) ;
10371040 let span = tcx. sess . source_map ( ) . def_span ( span) ;
10381041 let mut err = struct_span_err ! (
10391042 tcx. sess,
@@ -1045,14 +1048,45 @@ pub fn report_object_safety_error(
10451048 err. span_label ( span, format ! ( "the trait `{}` cannot be made into an object" , trait_str) ) ;
10461049
10471050 let mut reported_violations = FxHashSet :: default ( ) ;
1051+ let mut had_span_label = false ;
10481052 for violation in violations {
1053+ if let ObjectSafetyViolation :: SizedSelf ( sp) = & violation {
1054+ if !sp. is_empty ( ) {
1055+ // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
1056+ // with a `Span`.
1057+ reported_violations. insert ( ObjectSafetyViolation :: SizedSelf ( vec ! [ ] . into ( ) ) ) ;
1058+ }
1059+ }
10491060 if reported_violations. insert ( violation. clone ( ) ) {
1050- match violation. span ( ) {
1051- Some ( span) => err. span_label ( span, violation. error_msg ( ) ) ,
1052- None => err. note ( & violation. error_msg ( ) ) ,
1061+ let spans = violation. spans ( ) ;
1062+ let msg = if trait_span. is_none ( ) || spans. is_empty ( ) {
1063+ format ! ( "the trait cannot be made into an object because {}" , violation. error_msg( ) )
1064+ } else {
1065+ had_span_label = true ;
1066+ format ! ( "...because {}" , violation. error_msg( ) )
10531067 } ;
1068+ if spans. is_empty ( ) {
1069+ err. note ( & msg) ;
1070+ } else {
1071+ for span in spans {
1072+ err. span_label ( span, & msg) ;
1073+ }
1074+ }
1075+ match ( trait_span, violation. solution ( ) ) {
1076+ ( Some ( _) , Some ( ( note, None ) ) ) => {
1077+ err. help ( & note) ;
1078+ }
1079+ ( Some ( _) , Some ( ( note, Some ( ( sugg, span) ) ) ) ) => {
1080+ err. span_suggestion ( span, & note, sugg, Applicability :: MachineApplicable ) ;
1081+ }
1082+ // Only provide the help if its a local trait, otherwise it's not actionable.
1083+ _ => { }
1084+ }
10541085 }
10551086 }
1087+ if let ( Some ( trait_span) , true ) = ( trait_span, had_span_label) {
1088+ err. span_label ( trait_span, "this trait cannot be made into an object..." ) ;
1089+ }
10561090
10571091 if tcx. sess . trait_methods_not_found . borrow ( ) . contains ( & span) {
10581092 // Avoid emitting error caused by non-existing method (#58734)
@@ -1305,6 +1339,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
13051339 & obligation. cause . code ,
13061340 & mut vec ! [ ] ,
13071341 ) ;
1342+ self . suggest_unsized_bound_if_applicable ( err, obligation) ;
1343+ }
1344+ }
1345+
1346+ fn suggest_unsized_bound_if_applicable (
1347+ & self ,
1348+ err : & mut DiagnosticBuilder < ' _ > ,
1349+ obligation : & PredicateObligation < ' tcx > ,
1350+ ) {
1351+ if let (
1352+ ty:: Predicate :: Trait ( pred, _) ,
1353+ ObligationCauseCode :: BindingObligation ( item_def_id, span) ,
1354+ ) = ( & obligation. predicate , & obligation. cause . code )
1355+ {
1356+ if let ( Some ( generics) , true ) = (
1357+ self . tcx . hir ( ) . get_if_local ( * item_def_id) . as_ref ( ) . and_then ( |n| n. generics ( ) ) ,
1358+ Some ( pred. def_id ( ) ) == self . tcx . lang_items ( ) . sized_trait ( ) ,
1359+ ) {
1360+ for param in generics. params {
1361+ if param. span == * span
1362+ && !param. bounds . iter ( ) . any ( |bound| {
1363+ bound. trait_def_id ( ) == self . tcx . lang_items ( ) . sized_trait ( )
1364+ } )
1365+ {
1366+ let ( span, separator) = match param. bounds {
1367+ [ ] => ( span. shrink_to_hi ( ) , ":" ) ,
1368+ [ .., bound] => ( bound. span ( ) . shrink_to_hi ( ) , " + " ) ,
1369+ } ;
1370+ err. span_suggestion (
1371+ span,
1372+ "consider relaxing the implicit `Sized` restriction" ,
1373+ format ! ( "{} ?Sized" , separator) ,
1374+ Applicability :: MachineApplicable ,
1375+ ) ;
1376+ return ;
1377+ }
1378+ }
1379+ }
13081380 }
13091381 }
13101382
@@ -1354,74 +1426,3 @@ impl ArgKind {
13541426 }
13551427 }
13561428}
1357-
1358- /// Suggest restricting a type param with a new bound.
1359- pub fn suggest_constraining_type_param (
1360- generics : & hir:: Generics < ' _ > ,
1361- err : & mut DiagnosticBuilder < ' _ > ,
1362- param_name : & str ,
1363- constraint : & str ,
1364- source_map : & SourceMap ,
1365- span : Span ,
1366- ) -> bool {
1367- let restrict_msg = "consider further restricting this bound" ;
1368- if let Some ( param) =
1369- generics. params . iter ( ) . filter ( |p| p. name . ident ( ) . as_str ( ) == param_name) . next ( )
1370- {
1371- if param_name. starts_with ( "impl " ) {
1372- // `impl Trait` in argument:
1373- // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
1374- err. span_suggestion (
1375- param. span ,
1376- restrict_msg,
1377- // `impl CurrentTrait + MissingTrait`
1378- format ! ( "{} + {}" , param_name, constraint) ,
1379- Applicability :: MachineApplicable ,
1380- ) ;
1381- } else if generics. where_clause . predicates . is_empty ( ) && param. bounds . is_empty ( ) {
1382- // If there are no bounds whatsoever, suggest adding a constraint
1383- // to the type parameter:
1384- // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
1385- err. span_suggestion (
1386- param. span ,
1387- "consider restricting this bound" ,
1388- format ! ( "{}: {}" , param_name, constraint) ,
1389- Applicability :: MachineApplicable ,
1390- ) ;
1391- } else if !generics. where_clause . predicates . is_empty ( ) {
1392- // There is a `where` clause, so suggest expanding it:
1393- // `fn foo<T>(t: T) where T: Debug {}` →
1394- // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
1395- err. span_suggestion (
1396- generics. where_clause . span ( ) . unwrap ( ) . shrink_to_hi ( ) ,
1397- & format ! ( "consider further restricting type parameter `{}`" , param_name) ,
1398- format ! ( ", {}: {}" , param_name, constraint) ,
1399- Applicability :: MachineApplicable ,
1400- ) ;
1401- } else {
1402- // If there is no `where` clause lean towards constraining to the
1403- // type parameter:
1404- // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
1405- // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
1406- let sp = param. span . with_hi ( span. hi ( ) ) ;
1407- let span = source_map. span_through_char ( sp, ':' ) ;
1408- if sp != param. span && sp != span {
1409- // Only suggest if we have high certainty that the span
1410- // covers the colon in `foo<T: Trait>`.
1411- err. span_suggestion (
1412- span,
1413- restrict_msg,
1414- format ! ( "{}: {} + " , param_name, constraint) ,
1415- Applicability :: MachineApplicable ,
1416- ) ;
1417- } else {
1418- err. span_label (
1419- param. span ,
1420- & format ! ( "consider adding a `where {}: {}` bound" , param_name, constraint) ,
1421- ) ;
1422- }
1423- }
1424- return true ;
1425- }
1426- false
1427- }
0 commit comments