Skip to content

Commit 861e96f

Browse files
committed
Auto merge of #66567 - estebank:suggest-copy, r=Centril
Use structured suggestion when requiring `Copy` constraint in type param
2 parents 61e1c3d + 0f530ec commit 861e96f

13 files changed

+187
-121
lines changed

src/librustc/traits/error_reporting.rs

+91-65
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use syntax::ast;
3939
use syntax::symbol::{sym, kw};
4040
use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan};
4141
use rustc::hir::def_id::LOCAL_CRATE;
42+
use syntax_pos::source_map::SourceMap;
4243

4344
use rustc_error_codes::*;
4445

@@ -1091,7 +1092,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10911092
}
10921093
fn suggest_restricting_param_bound(
10931094
&self,
1094-
err: &mut DiagnosticBuilder<'_>,
1095+
mut err: &mut DiagnosticBuilder<'_>,
10951096
trait_ref: &ty::PolyTraitRef<'_>,
10961097
body_id: hir::HirId,
10971098
) {
@@ -1102,7 +1103,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11021103
_ => return,
11031104
};
11041105

1105-
let mut suggest_restriction = |generics: &hir::Generics, msg| {
1106+
let suggest_restriction = |
1107+
generics: &hir::Generics,
1108+
msg,
1109+
err: &mut DiagnosticBuilder<'_>,
1110+
| {
11061111
let span = generics.where_clause.span_for_predicates_or_empty_place();
11071112
if !span.from_expansion() && span.desugaring_kind().is_none() {
11081113
err.span_suggestion(
@@ -1132,7 +1137,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11321137
kind: hir::TraitItemKind::Method(..), ..
11331138
}) if param_ty && self_ty == self.tcx.types.self_param => {
11341139
// Restricting `Self` for a single method.
1135-
suggest_restriction(&generics, "`Self`");
1140+
suggest_restriction(&generics, "`Self`", err);
11361141
return;
11371142
}
11381143

@@ -1154,7 +1159,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11541159
kind: hir::ItemKind::Impl(_, _, _, generics, ..), ..
11551160
}) if projection.is_some() => {
11561161
// Missing associated type bound.
1157-
suggest_restriction(&generics, "the associated type");
1162+
suggest_restriction(&generics, "the associated type", err);
11581163
return;
11591164
}
11601165

@@ -1183,68 +1188,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11831188
hir::Node::ImplItem(hir::ImplItem { generics, span, .. })
11841189
if param_ty => {
11851190
// Missing generic type parameter bound.
1186-
let restrict_msg = "consider further restricting this bound";
11871191
let param_name = self_ty.to_string();
1188-
for param in generics.params.iter().filter(|p| {
1189-
p.name.ident().as_str() == param_name
1190-
}) {
1191-
if param_name.starts_with("impl ") {
1192-
// `impl Trait` in argument:
1193-
// `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
1194-
err.span_suggestion(
1195-
param.span,
1196-
restrict_msg,
1197-
// `impl CurrentTrait + MissingTrait`
1198-
format!("{} + {}", param.name.ident(), trait_ref),
1199-
Applicability::MachineApplicable,
1200-
);
1201-
} else if generics.where_clause.predicates.is_empty() &&
1202-
param.bounds.is_empty()
1203-
{
1204-
// If there are no bounds whatsoever, suggest adding a constraint
1205-
// to the type parameter:
1206-
// `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
1207-
err.span_suggestion(
1208-
param.span,
1209-
"consider restricting this bound",
1210-
format!("{}", trait_ref.to_predicate()),
1211-
Applicability::MachineApplicable,
1212-
);
1213-
} else if !generics.where_clause.predicates.is_empty() {
1214-
// There is a `where` clause, so suggest expanding it:
1215-
// `fn foo<T>(t: T) where T: Debug {}` →
1216-
// `fn foo<T>(t: T) where T: Debug, T: Trait {}`
1217-
err.span_suggestion(
1218-
generics.where_clause.span().unwrap().shrink_to_hi(),
1219-
&format!(
1220-
"consider further restricting type parameter `{}`",
1221-
param_name,
1222-
),
1223-
format!(", {}", trait_ref.to_predicate()),
1224-
Applicability::MachineApplicable,
1225-
);
1226-
} else {
1227-
// If there is no `where` clause lean towards constraining to the
1228-
// type parameter:
1229-
// `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
1230-
// `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
1231-
let sp = param.span.with_hi(span.hi());
1232-
let span = self.tcx.sess.source_map()
1233-
.span_through_char(sp, ':');
1234-
if sp != param.span && sp != span {
1235-
// Only suggest if we have high certainty that the span
1236-
// covers the colon in `foo<T: Trait>`.
1237-
err.span_suggestion(span, restrict_msg, format!(
1238-
"{} + ",
1239-
trait_ref.to_predicate(),
1240-
), Applicability::MachineApplicable);
1241-
} else {
1242-
err.span_label(param.span, &format!(
1243-
"consider adding a `where {}` bound",
1244-
trait_ref.to_predicate(),
1245-
));
1246-
}
1247-
}
1192+
let constraint = trait_ref.to_string();
1193+
if suggest_constraining_type_param(
1194+
generics,
1195+
&mut err,
1196+
&param_name,
1197+
&constraint,
1198+
self.tcx.sess.source_map(),
1199+
*span,
1200+
) {
12481201
return;
12491202
}
12501203
}
@@ -2546,3 +2499,76 @@ impl ArgKind {
25462499
}
25472500
}
25482501
}
2502+
2503+
/// Suggest restricting a type param with a new bound.
2504+
pub fn suggest_constraining_type_param(
2505+
generics: &hir::Generics,
2506+
err: &mut DiagnosticBuilder<'_>,
2507+
param_name: &str,
2508+
constraint: &str,
2509+
source_map: &SourceMap,
2510+
span: Span,
2511+
) -> bool {
2512+
let restrict_msg = "consider further restricting this bound";
2513+
if let Some(param) = generics.params.iter().filter(|p| {
2514+
p.name.ident().as_str() == param_name
2515+
}).next() {
2516+
if param_name.starts_with("impl ") {
2517+
// `impl Trait` in argument:
2518+
// `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
2519+
err.span_suggestion(
2520+
param.span,
2521+
restrict_msg,
2522+
// `impl CurrentTrait + MissingTrait`
2523+
format!("{} + {}", param_name, constraint),
2524+
Applicability::MachineApplicable,
2525+
);
2526+
} else if generics.where_clause.predicates.is_empty() &&
2527+
param.bounds.is_empty()
2528+
{
2529+
// If there are no bounds whatsoever, suggest adding a constraint
2530+
// to the type parameter:
2531+
// `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
2532+
err.span_suggestion(
2533+
param.span,
2534+
"consider restricting this bound",
2535+
format!("{}: {}", param_name, constraint),
2536+
Applicability::MachineApplicable,
2537+
);
2538+
} else if !generics.where_clause.predicates.is_empty() {
2539+
// There is a `where` clause, so suggest expanding it:
2540+
// `fn foo<T>(t: T) where T: Debug {}` →
2541+
// `fn foo<T>(t: T) where T: Debug, T: Trait {}`
2542+
err.span_suggestion(
2543+
generics.where_clause.span().unwrap().shrink_to_hi(),
2544+
&format!("consider further restricting type parameter `{}`", param_name),
2545+
format!(", {}: {}", param_name, constraint),
2546+
Applicability::MachineApplicable,
2547+
);
2548+
} else {
2549+
// If there is no `where` clause lean towards constraining to the
2550+
// type parameter:
2551+
// `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
2552+
// `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
2553+
let sp = param.span.with_hi(span.hi());
2554+
let span = source_map.span_through_char(sp, ':');
2555+
if sp != param.span && sp != span {
2556+
// Only suggest if we have high certainty that the span
2557+
// covers the colon in `foo<T: Trait>`.
2558+
err.span_suggestion(
2559+
span,
2560+
restrict_msg,
2561+
format!("{}: {} + ", param_name, constraint),
2562+
Applicability::MachineApplicable,
2563+
);
2564+
} else {
2565+
err.span_label(
2566+
param.span,
2567+
&format!("consider adding a `where {}: {}` bound", param_name, constraint),
2568+
);
2569+
}
2570+
}
2571+
return true;
2572+
}
2573+
false
2574+
}

src/librustc_mir/borrow_check/conflict_errors.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc::mir::{
77
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
88
};
99
use rustc::ty::{self, Ty};
10+
use rustc::traits::error_reporting::suggest_constraining_type_param;
1011
use rustc_data_structures::fx::FxHashSet;
1112
use rustc_index::vec::Idx;
1213
use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -231,13 +232,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
231232
if let ty::Param(param_ty) = ty.kind {
232233
let tcx = self.infcx.tcx;
233234
let generics = tcx.generics_of(self.mir_def_id);
234-
let def_id = generics.type_param(&param_ty, tcx).def_id;
235-
if let Some(sp) = tcx.hir().span_if_local(def_id) {
236-
err.span_label(
237-
sp,
238-
"consider adding a `Copy` constraint to this type argument",
239-
);
240-
}
235+
let param = generics.type_param(&param_ty, tcx);
236+
let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
237+
suggest_constraining_type_param(
238+
generics,
239+
&mut err,
240+
&param.name.as_str(),
241+
"Copy",
242+
tcx.sess.source_map(),
243+
span,
244+
);
241245
}
242246
let span = if let Some(local) = place.as_local() {
243247
let decl = &self.body.local_decls[local];

0 commit comments

Comments
 (0)