Rollup merge of #56220 - estebank:suggest-lifetime-move, r=nikomatsakis
Suggest appropriate place for lifetime when declared after type arguments
This commit is contained in:
@@ -5172,8 +5172,12 @@ impl<'a> Parser<'a> {
|
||||
/// Parses (possibly empty) list of lifetime and type parameters, possibly including
|
||||
/// trailing comma and erroneous trailing attributes.
|
||||
crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
|
||||
let mut lifetimes = Vec::new();
|
||||
let mut params = Vec::new();
|
||||
let mut seen_ty_param = false;
|
||||
let mut seen_ty_param: Option<Span> = None;
|
||||
let mut last_comma_span = None;
|
||||
let mut bad_lifetime_pos = vec![];
|
||||
let mut suggestions = vec![];
|
||||
loop {
|
||||
let attrs = self.parse_outer_attributes()?;
|
||||
if self.check_lifetime() {
|
||||
@@ -5184,25 +5188,42 @@ impl<'a> Parser<'a> {
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
params.push(ast::GenericParam {
|
||||
lifetimes.push(ast::GenericParam {
|
||||
ident: lifetime.ident,
|
||||
id: lifetime.id,
|
||||
attrs: attrs.into(),
|
||||
bounds,
|
||||
kind: ast::GenericParamKind::Lifetime,
|
||||
});
|
||||
if seen_ty_param {
|
||||
self.span_err(self.prev_span,
|
||||
"lifetime parameters must be declared prior to type parameters");
|
||||
if let Some(sp) = seen_ty_param {
|
||||
let param_span = self.prev_span;
|
||||
let ate_comma = self.eat(&token::Comma);
|
||||
let remove_sp = if ate_comma {
|
||||
param_span.until(self.span)
|
||||
} else {
|
||||
last_comma_span.unwrap_or(param_span).to(param_span)
|
||||
};
|
||||
bad_lifetime_pos.push(param_span);
|
||||
|
||||
if let Ok(snippet) = self.sess.source_map().span_to_snippet(param_span) {
|
||||
suggestions.push((remove_sp, String::new()));
|
||||
suggestions.push((sp.shrink_to_lo(), format!("{}, ", snippet)));
|
||||
}
|
||||
if ate_comma {
|
||||
last_comma_span = Some(self.prev_span);
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else if self.check_ident() {
|
||||
// Parse type parameter.
|
||||
params.push(self.parse_ty_param(attrs)?);
|
||||
seen_ty_param = true;
|
||||
if seen_ty_param.is_none() {
|
||||
seen_ty_param = Some(self.prev_span);
|
||||
}
|
||||
} else {
|
||||
// Check for trailing attributes and stop parsing.
|
||||
if !attrs.is_empty() {
|
||||
let param_kind = if seen_ty_param { "type" } else { "lifetime" };
|
||||
let param_kind = if seen_ty_param.is_some() { "type" } else { "lifetime" };
|
||||
self.span_err(attrs[0].span,
|
||||
&format!("trailing attribute after {} parameters", param_kind));
|
||||
}
|
||||
@@ -5212,8 +5233,24 @@ impl<'a> Parser<'a> {
|
||||
if !self.eat(&token::Comma) {
|
||||
break
|
||||
}
|
||||
last_comma_span = Some(self.prev_span);
|
||||
}
|
||||
Ok(params)
|
||||
if !bad_lifetime_pos.is_empty() {
|
||||
let mut err = self.struct_span_err(
|
||||
bad_lifetime_pos,
|
||||
"lifetime parameters must be declared prior to type parameters",
|
||||
);
|
||||
if !suggestions.is_empty() {
|
||||
err.multipart_suggestion_with_applicability(
|
||||
"move the lifetime parameter prior to the first type parameter",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
lifetimes.extend(params); // ensure the correct order of lifetimes and type params
|
||||
Ok(lifetimes)
|
||||
}
|
||||
|
||||
/// Parse a set of optional generic type parameter declarations. Where
|
||||
|
||||
Reference in New Issue
Block a user