// This pass is supposed to perform only simple checks not requiring name resolution
// or type checking or some other kind of complex analysis.
+use rustc_ast::ast::*;
+use rustc_ast::attr;
+use rustc_ast::expand::is_proc_macro_attr;
+use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
+use rustc_ast::walk_list;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{error_code, struct_span_err, Applicability, FatalError};
+use rustc_errors::{error_code, struct_span_err, Applicability};
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
use rustc_session::lint::LintBuffer;
use rustc_span::symbol::{kw, sym};
use rustc_span::Span;
use std::mem;
-use syntax::ast::*;
-use syntax::attr;
-use syntax::expand::is_proc_macro_attr;
-use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use syntax::walk_list;
const MORE_EXTERN: &str =
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
}
}
-enum GenericPosition {
- Param,
- Arg,
-}
-
-fn validate_generics_order<'a>(
+fn validate_generic_param_order<'a>(
sess: &Session,
handler: &rustc_errors::Handler,
generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
- pos: GenericPosition,
span: Span,
) {
let mut max_param: Option<ParamKindOrd> = None;
let mut out_of_order = FxHashMap::default();
let mut param_idents = vec![];
- let mut found_type = false;
- let mut found_const = false;
for (kind, bounds, span, ident) in generics {
if let Some(ident) = ident {
}
Some(_) | None => *max_param = Some(kind),
};
- match kind {
- ParamKindOrd::Type => found_type = true,
- ParamKindOrd::Const => found_const = true,
- _ => {}
- }
}
let mut ordered_params = "<".to_string();
}
ordered_params += ">";
- let pos_str = match pos {
- GenericPosition::Param => "parameter",
- GenericPosition::Arg => "argument",
- };
-
for (param_ord, (max_param, spans)) in &out_of_order {
- let mut err = handler.struct_span_err(
- spans.clone(),
- &format!(
- "{} {pos}s must be declared prior to {} {pos}s",
- param_ord,
- max_param,
- pos = pos_str,
- ),
- );
- if let GenericPosition::Param = pos {
- err.span_suggestion(
- span,
+ let mut err =
+ handler.struct_span_err(
+ spans.clone(),
&format!(
- "reorder the {}s: lifetimes, then types{}",
- pos_str,
- if sess.features_untracked().const_generics { ", then consts" } else { "" },
+ "{} parameters must be declared prior to {} parameters",
+ param_ord, max_param,
),
- ordered_params.clone(),
- Applicability::MachineApplicable,
);
- }
+ err.span_suggestion(
+ span,
+ &format!(
+ "reorder the parameters: lifetimes, then types{}",
+ if sess.features_untracked().const_generics { ", then consts" } else { "" },
+ ),
+ ordered_params.clone(),
+ Applicability::MachineApplicable,
+ );
err.emit();
}
-
- // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
- // if we don't. Const parameters and type parameters can currently conflict if they
- // are out-of-order.
- if !out_of_order.is_empty() && found_type && found_const {
- FatalError.raise();
- }
}
impl<'a> Visitor<'a> for AstValidator<'a> {
match *generic_args {
GenericArgs::AngleBracketed(ref data) => {
walk_list!(self, visit_generic_arg, &data.args);
- validate_generics_order(
- self.session,
- self.err_handler(),
- data.args.iter().map(|arg| {
- (
- match arg {
- GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
- GenericArg::Type(..) => ParamKindOrd::Type,
- GenericArg::Const(..) => ParamKindOrd::Const,
- },
- None,
- arg.span(),
- None,
- )
- }),
- GenericPosition::Arg,
- generic_args.span(),
- );
// Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
// are allowed to contain nested `impl Trait`.
}
}
- validate_generics_order(
+ validate_generic_param_order(
self.session,
self.err_handler(),
generics.params.iter().map(|param| {
};
(kind, Some(&*param.bounds), param.ident.span, ident)
}),
- GenericPosition::Param,
generics.span,
);