Suggestion moving types before associated types.
This commit extends existing suggestions to move lifetimes before types in generic arguments to also suggest moving types behind associated type bindings.
This commit is contained in:
parent
095b44c83b
commit
463e623ca9
4 changed files with 148 additions and 16 deletions
|
@ -5530,22 +5530,31 @@ impl<'a> Parser<'a> {
|
|||
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> {
|
||||
let mut args = Vec::new();
|
||||
let mut bindings = Vec::new();
|
||||
|
||||
let mut seen_type = false;
|
||||
let mut seen_binding = false;
|
||||
let mut first_type_or_binding_span: Option<Span> = None;
|
||||
let mut bad_lifetime_pos = vec![];
|
||||
|
||||
let mut last_comma_span = None;
|
||||
let mut suggestions = vec![];
|
||||
let mut first_type_or_binding_span: Option<Span> = None;
|
||||
let mut first_binding_span: Option<Span> = None;
|
||||
|
||||
let mut bad_lifetime_pos = vec![];
|
||||
let mut bad_type_pos = vec![];
|
||||
|
||||
let mut lifetime_suggestions = vec![];
|
||||
let mut type_suggestions = vec![];
|
||||
loop {
|
||||
if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
||||
// Parse lifetime argument.
|
||||
args.push(GenericArg::Lifetime(self.expect_lifetime()));
|
||||
|
||||
if seen_type || seen_binding {
|
||||
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
|
||||
bad_lifetime_pos.push(self.prev_span);
|
||||
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
|
||||
suggestions.push((remove_sp, String::new()));
|
||||
suggestions.push((
|
||||
lifetime_suggestions.push((remove_sp, String::new()));
|
||||
lifetime_suggestions.push((
|
||||
first_type_or_binding_span.unwrap().shrink_to_lo(),
|
||||
format!("{}, ", snippet)));
|
||||
}
|
||||
|
@ -5563,24 +5572,29 @@ impl<'a> Parser<'a> {
|
|||
ty,
|
||||
span,
|
||||
});
|
||||
|
||||
seen_binding = true;
|
||||
if first_type_or_binding_span.is_none() {
|
||||
first_type_or_binding_span = Some(span);
|
||||
}
|
||||
if first_binding_span.is_none() {
|
||||
first_binding_span = Some(span);
|
||||
}
|
||||
} else if self.check_type() {
|
||||
// Parse type argument.
|
||||
let ty_param = self.parse_ty()?;
|
||||
if seen_binding {
|
||||
self.struct_span_err(
|
||||
ty_param.span,
|
||||
"type parameters must be declared prior to associated type bindings"
|
||||
)
|
||||
.span_label(
|
||||
ty_param.span,
|
||||
"must be declared prior to associated type bindings",
|
||||
)
|
||||
.emit();
|
||||
let remove_sp = last_comma_span.unwrap_or(self.prev_span).to(self.prev_span);
|
||||
bad_type_pos.push(self.prev_span);
|
||||
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.prev_span) {
|
||||
type_suggestions.push((remove_sp, String::new()));
|
||||
type_suggestions.push((
|
||||
first_binding_span.unwrap().shrink_to_lo(),
|
||||
format!("{}, ", snippet)));
|
||||
}
|
||||
}
|
||||
|
||||
if first_type_or_binding_span.is_none() {
|
||||
first_type_or_binding_span = Some(ty_param.span);
|
||||
}
|
||||
|
@ -5596,6 +5610,7 @@ impl<'a> Parser<'a> {
|
|||
last_comma_span = Some(self.prev_span);
|
||||
}
|
||||
}
|
||||
|
||||
if !bad_lifetime_pos.is_empty() {
|
||||
let mut err = self.struct_span_err(
|
||||
bad_lifetime_pos.clone(),
|
||||
|
@ -5604,18 +5619,40 @@ impl<'a> Parser<'a> {
|
|||
for sp in &bad_lifetime_pos {
|
||||
err.span_label(*sp, "must be declared prior to type parameters");
|
||||
}
|
||||
if !suggestions.is_empty() {
|
||||
if !lifetime_suggestions.is_empty() {
|
||||
err.multipart_suggestion_with_applicability(
|
||||
&format!(
|
||||
"move the lifetime parameter{} prior to the first type parameter",
|
||||
if bad_lifetime_pos.len() > 1 { "s" } else { "" },
|
||||
),
|
||||
suggestions,
|
||||
lifetime_suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
if !bad_type_pos.is_empty() {
|
||||
let mut err = self.struct_span_err(
|
||||
bad_type_pos.clone(),
|
||||
"type parameters must be declared prior to associated type bindings"
|
||||
);
|
||||
for sp in &bad_type_pos {
|
||||
err.span_label(*sp, "must be declared prior to associated type bindings");
|
||||
}
|
||||
if !type_suggestions.is_empty() {
|
||||
err.multipart_suggestion_with_applicability(
|
||||
&format!(
|
||||
"move the type parameter{} prior to the first associated type binding",
|
||||
if bad_type_pos.len() > 1 { "s" } else { "" },
|
||||
),
|
||||
type_suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
Ok((args, bindings))
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue