diff options
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 103 |
1 files changed, 73 insertions, 30 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 232b8bb5966..955dce47721 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5611,49 +5611,92 @@ impl<'a> Parser<'a> { } } - if !bad_lifetime_pos.is_empty() { - let mut err = self.struct_span_err( + self.maybe_report_incorrect_generic_argument_order( + bad_lifetime_pos, bad_type_pos, lifetime_suggestions, type_suggestions + ); + + Ok((args, bindings)) + } + + /// Maybe report an error about incorrect generic argument order - "lifetime parameters + /// must be declared before type parameters", "type parameters must be declared before + /// associated type bindings" or both. + fn maybe_report_incorrect_generic_argument_order( + &self, + bad_lifetime_pos: Vec<Span>, + bad_type_pos: Vec<Span>, + lifetime_suggestions: Vec<(Span, String)>, + type_suggestions: Vec<(Span, String)>, + ) { + let mut err = if !bad_lifetime_pos.is_empty() && !bad_type_pos.is_empty() { + let mut positions = bad_lifetime_pos.clone(); + positions.extend_from_slice(&bad_type_pos); + + self.struct_span_err( + positions, + "generic arguments must declare lifetimes, types and associated type bindings in \ + that order", + ) + } else if !bad_lifetime_pos.is_empty() { + self.struct_span_err( bad_lifetime_pos.clone(), "lifetime parameters must be declared prior to type parameters" - ); + ) + } else if !bad_type_pos.is_empty() { + self.struct_span_err( + bad_type_pos.clone(), + "type parameters must be declared prior to associated type bindings" + ) + } else { + return; + }; + + if !bad_lifetime_pos.is_empty() { for sp in &bad_lifetime_pos { err.span_label(*sp, "must be declared prior to type parameters"); } - 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 { "" }, - ), - 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)) + if !lifetime_suggestions.is_empty() && !type_suggestions.is_empty() { + let mut suggestions = lifetime_suggestions; + suggestions.extend_from_slice(&type_suggestions); + + let plural = bad_lifetime_pos.len() + bad_type_pos.len() > 1; + err.multipart_suggestion_with_applicability( + &format!( + "move the parameter{}", + if plural { "s" } else { "" }, + ), + suggestions, + Applicability::MachineApplicable, + ); + } else 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 { "" }, + ), + lifetime_suggestions, + Applicability::MachineApplicable, + ); + } else 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(); } /// Parses an optional `where` clause and places it in `generics`. |
