Skip to content

Commit 5b0caef

Browse files
committed
Auto merge of rust-lang#68377 - estebank:fn-obligations-spans, r=oli-obk
Tweak obligation error output - Point at arguments or output when fn obligations come from them, or ident when they don't - Point at `Sized` bound (fix rust-lang#47990) - When object unsafe trait uses itself in associated item suggest using `Self` (fix rust-lang#66424, fix rust-lang#33375, partially address rust-lang#38376, cc rust-lang#61525) - Point at reason in object unsafe trait with `Self` in supertraits or `where`-clause (cc rust-lang#40533, cc rust-lang#68377) - On implicit type parameter `Sized` obligations, suggest `?Sized` (fix rust-lang#57744, fix rust-lang#46683)
2 parents 126ad2b + 0e58411 commit 5b0caef

File tree

145 files changed

+1428
-835
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+1428
-835
lines changed

src/librustc/traits/error_reporting/mod.rs

+76-75
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2727
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
2828
use rustc_hir as hir;
2929
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
30-
use rustc_span::source_map::SourceMap;
3130
use rustc_span::{ExpnKind, Span, DUMMY_SP};
3231
use std::fmt;
3332
use 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-
}

src/librustc/traits/error_reporting/suggestions.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
145145
let param_name = self_ty.to_string();
146146
let constraint = trait_ref.print_only_trait_path().to_string();
147147
if suggest_constraining_type_param(
148+
self.tcx,
148149
generics,
149150
&mut err,
150151
&param_name,
151152
&constraint,
152153
self.tcx.sess.source_map(),
153154
*span,
155+
Some(trait_ref.def_id()),
154156
) {
155157
return;
156158
}
@@ -1652,18 +1654,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16521654

16531655
/// Suggest restricting a type param with a new bound.
16541656
pub fn suggest_constraining_type_param(
1657+
tcx: TyCtxt<'_>,
16551658
generics: &hir::Generics<'_>,
16561659
err: &mut DiagnosticBuilder<'_>,
16571660
param_name: &str,
16581661
constraint: &str,
16591662
source_map: &SourceMap,
16601663
span: Span,
1664+
def_id: Option<DefId>,
16611665
) -> bool {
16621666
let restrict_msg = "consider further restricting this bound";
16631667
if let Some(param) =
16641668
generics.params.iter().filter(|p| p.name.ident().as_str() == param_name).next()
16651669
{
1666-
if param_name.starts_with("impl ") {
1670+
if def_id == tcx.lang_items().sized_trait() {
1671+
// Type parameters are already `Sized` by default.
1672+
err.span_label(
1673+
param.span,
1674+
&format!("this type parameter needs to be `{}`", constraint),
1675+
);
1676+
} else if param_name.starts_with("impl ") {
16671677
// `impl Trait` in argument:
16681678
// `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
16691679
err.span_suggestion(

0 commit comments

Comments
 (0)