@@ -27,7 +27,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
27
27
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
28
28
use rustc_hir as hir;
29
29
use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
30
- use rustc_span:: source_map:: SourceMap ;
31
30
use rustc_span:: { ExpnKind , Span , DUMMY_SP } ;
32
31
use std:: fmt;
33
32
use syntax:: ast;
@@ -1034,6 +1033,10 @@ pub fn report_object_safety_error(
1034
1033
violations : Vec < ObjectSafetyViolation > ,
1035
1034
) -> DiagnosticBuilder < ' tcx > {
1036
1035
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
+ } ) ;
1037
1040
let span = tcx. sess . source_map ( ) . def_span ( span) ;
1038
1041
let mut err = struct_span_err ! (
1039
1042
tcx. sess,
@@ -1045,14 +1048,45 @@ pub fn report_object_safety_error(
1045
1048
err. span_label ( span, format ! ( "the trait `{}` cannot be made into an object" , trait_str) ) ;
1046
1049
1047
1050
let mut reported_violations = FxHashSet :: default ( ) ;
1051
+ let mut had_span_label = false ;
1048
1052
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
+ }
1049
1060
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( ) )
1053
1067
} ;
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
+ }
1054
1085
}
1055
1086
}
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
+ }
1056
1090
1057
1091
if tcx. sess . trait_methods_not_found . borrow ( ) . contains ( & span) {
1058
1092
// Avoid emitting error caused by non-existing method (#58734)
@@ -1305,6 +1339,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
1305
1339
& obligation. cause . code ,
1306
1340
& mut vec ! [ ] ,
1307
1341
) ;
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
+ }
1308
1380
}
1309
1381
}
1310
1382
@@ -1354,74 +1426,3 @@ impl ArgKind {
1354
1426
}
1355
1427
}
1356
1428
}
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