1 // Validate AST before lowering it to HIR.
3 // This pass is supposed to catch things that fit into AST data structures,
4 // but not permitted by the language. It runs after expansion when AST is frozen,
5 // so it can check for erroneous constructions produced by syntax extensions.
6 // This pass is supposed to perform only simple checks not requiring name resolution
7 // or type checking or some other kind of complex analysis.
9 use itertools::{Either, Itertools};
10 use rustc_ast::ptr::P;
11 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
12 use rustc_ast::walk_list;
14 use rustc_ast_pretty::pprust;
15 use rustc_data_structures::fx::FxHashMap;
16 use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
17 use rustc_parse::validate_attr;
18 use rustc_session::lint::builtin::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY};
19 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
20 use rustc_session::Session;
21 use rustc_span::source_map::Spanned;
22 use rustc_span::symbol::{kw, sym, Ident};
24 use rustc_target::spec::abi;
26 use std::ops::{Deref, DerefMut};
28 const MORE_EXTERN: &str =
29 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
31 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
37 struct AstValidator<'a> {
40 /// The span of the `extern` in an `extern { ... }` block, if any.
41 extern_mod: Option<&'a Item>,
43 /// Are we inside a trait impl?
46 in_const_trait_impl: bool,
48 has_proc_macro_decls: bool,
50 /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
51 /// Nested `impl Trait` _is_ allowed in associated type position,
52 /// e.g., `impl Iterator<Item = impl Debug>`.
53 outer_impl_trait: Option<Span>,
55 is_tilde_const_allowed: bool,
57 /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
58 /// or `Foo::Bar<impl Trait>`
59 is_impl_trait_banned: bool,
61 /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
62 /// certain positions.
63 is_assoc_ty_bound_banned: bool,
65 /// Used to allow `let` expressions in certain syntactic locations.
68 lint_buffer: &'a mut LintBuffer,
71 impl<'a> AstValidator<'a> {
72 fn with_in_trait_impl(
75 constness: Option<Const>,
76 f: impl FnOnce(&mut Self),
78 let old = mem::replace(&mut self.in_trait_impl, is_in);
80 mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
82 self.in_trait_impl = old;
83 self.in_const_trait_impl = old_const;
86 fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
87 let old = mem::replace(&mut self.is_impl_trait_banned, true);
89 self.is_impl_trait_banned = old;
92 fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
93 let old = mem::replace(&mut self.is_tilde_const_allowed, true);
95 self.is_tilde_const_allowed = old;
98 fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
99 let old = mem::replace(&mut self.is_tilde_const_allowed, false);
101 self.is_tilde_const_allowed = old;
104 fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
105 let old = mem::replace(&mut self.is_let_allowed, allowed);
107 self.is_let_allowed = old;
110 /// Emits an error banning the `let` expression provided in the given location.
111 fn ban_let_expr(&self, expr: &'a Expr) {
112 let sess = &self.session;
113 if sess.opts.unstable_features.is_nightly_build() {
114 sess.struct_span_err(expr.span, "`let` expressions are not supported here")
115 .note("only supported directly in conditions of `if`- and `while`-expressions")
116 .note("as well as when nested within `&&` and parentheses in those conditions")
119 sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
120 .note("variable declaration using `let` is a statement")
125 fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
126 let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
128 self.is_assoc_ty_bound_banned = old;
131 fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
132 let old = mem::replace(&mut self.outer_impl_trait, outer);
134 self.with_banned_tilde_const(f);
138 self.outer_impl_trait = old;
141 fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
142 match constraint.kind {
143 AssocConstraintKind::Equality { .. } => {}
144 AssocConstraintKind::Bound { .. } => {
145 if self.is_assoc_ty_bound_banned {
146 self.err_handler().span_err(
148 "associated type bounds are not allowed within structs, enums, or unions",
153 self.visit_assoc_constraint(constraint);
156 // Mirrors `visit::walk_ty`, but tracks relevant state.
157 fn walk_ty(&mut self, t: &'a Ty) {
159 TyKind::ImplTrait(..) => {
160 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
162 TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
163 TyKind::Path(ref qself, ref path) => {
165 // - `Option<impl Trait>`
166 // - `option::Option<impl Trait>`
167 // - `option::Option<T>::Foo<impl Trait>
170 // - `<impl Trait>::Foo`
171 // - `option::Option<impl Trait>::Foo`.
173 // To implement this, we disallow `impl Trait` from `qself`
174 // (for cases like `<impl Trait>::Foo>`)
175 // but we allow `impl Trait` in `GenericArgs`
176 // iff there are no more PathSegments.
177 if let Some(ref qself) = *qself {
178 // `impl Trait` in `qself` is always illegal
179 self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
182 // Note that there should be a call to visit_path here,
183 // so if any logic is added to process `Path`s a call to it should be
184 // added both in visit_path and here. This code mirrors visit::walk_path.
185 for (i, segment) in path.segments.iter().enumerate() {
186 // Allow `impl Trait` iff we're on the final path segment
187 if i == path.segments.len() - 1 {
188 self.visit_path_segment(path.span, segment);
190 self.with_banned_impl_trait(|this| {
191 this.visit_path_segment(path.span, segment)
196 _ => visit::walk_ty(self, t),
200 fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
201 if let Some(ident) = field.ident {
202 if ident.name == kw::Underscore {
203 self.visit_vis(&field.vis);
204 self.visit_ident(ident);
205 self.visit_ty_common(&field.ty);
206 self.walk_ty(&field.ty);
207 walk_list!(self, visit_attribute, &field.attrs);
211 self.visit_field_def(field);
214 fn err_handler(&self) -> &rustc_errors::Handler {
215 &self.session.diagnostic()
218 fn check_lifetime(&self, ident: Ident) {
219 let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
220 if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
221 self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
225 fn check_label(&self, ident: Ident) {
226 if ident.without_first_quote().is_reserved() {
228 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
232 fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
233 if let VisibilityKind::Inherited = vis.kind {
238 struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
239 if vis.kind.is_pub() {
240 err.span_label(vis.span, "`pub` not permitted here because it's implied");
242 if let Some(note) = note {
248 fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
249 for Param { pat, .. } in &decl.inputs {
251 PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
252 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
253 report_err(pat.span, Some(ident), true)
255 _ => report_err(pat.span, None, false),
260 fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
261 if let Async::Yes { span, .. } = asyncness {
266 "functions in traits cannot be declared `async`"
268 .span_label(span, "`async` because of this")
269 .note("`async` trait functions are not currently supported")
270 .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
275 fn check_trait_fn_not_const(&self, constness: Const) {
276 if let Const::Yes(span) = constness {
281 "functions in traits cannot be declared const"
283 .span_label(span, "functions in traits cannot be const")
288 // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
289 fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
290 for bound in bounds {
291 if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
292 let mut err = self.err_handler().struct_span_err(
294 &format!("`?Trait` is not permitted in {}", where_),
297 let path_str = pprust::path_to_string(&poly.trait_ref.path);
298 err.note(&format!("traits are `?{}` by default", path_str));
305 fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
306 // Check only lifetime parameters are present and that the lifetime
307 // parameters that are present have no bounds.
308 let non_lt_param_spans: Vec<_> = params
310 .filter_map(|param| match param.kind {
311 GenericParamKind::Lifetime { .. } => {
312 if !param.bounds.is_empty() {
313 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
315 .span_err(spans, "lifetime bounds cannot be used in this context");
319 _ => Some(param.ident.span),
322 if !non_lt_param_spans.is_empty() {
323 self.err_handler().span_err(
325 "only lifetime parameters can be used in this context",
330 fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
331 self.check_decl_num_args(fn_decl);
332 self.check_decl_cvaradic_pos(fn_decl);
333 self.check_decl_attrs(fn_decl);
334 self.check_decl_self_param(fn_decl, self_semantic);
337 /// Emits fatal error if function declaration has more than `u16::MAX` arguments
338 /// Error is fatal to prevent errors during typechecking
339 fn check_decl_num_args(&self, fn_decl: &FnDecl) {
340 let max_num_args: usize = u16::MAX.into();
341 if fn_decl.inputs.len() > max_num_args {
342 let Param { span, .. } = fn_decl.inputs[0];
343 self.err_handler().span_fatal(
345 &format!("function can not have more than {} arguments", max_num_args),
350 fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
351 match &*fn_decl.inputs {
352 [Param { ty, span, .. }] => {
353 if let TyKind::CVarArgs = ty.kind {
354 self.err_handler().span_err(
356 "C-variadic function must be declared with at least one named argument",
361 for Param { ty, span, .. } in ps {
362 if let TyKind::CVarArgs = ty.kind {
363 self.err_handler().span_err(
365 "`...` must be the last argument of a C-variadic function",
374 fn check_decl_attrs(&self, fn_decl: &FnDecl) {
378 .flat_map(|i| i.attrs.as_ref())
380 let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
381 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
384 if attr.is_doc_comment() {
388 "documentation comments cannot be applied to function parameters",
390 .span_label(attr.span, "doc comments are not allowed here")
393 self.err_handler().span_err(
395 "allow, cfg, cfg_attr, deny, \
396 forbid, and warn are the only allowed built-in attributes in function parameters",
402 fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
403 if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
408 "`self` parameter is only allowed in associated functions",
410 .span_label(param.span, "not semantically valid as function parameter")
411 .note("associated functions are those in `impl` or `trait` definitions")
417 fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
418 if let Defaultness::Default(def_span) = defaultness {
419 let span = self.session.source_map().guess_head_span(span);
421 .struct_span_err(span, "`default` is only allowed on items in trait impls")
422 .span_label(def_span, "`default` because of this")
427 fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
429 .struct_span_err(sp, msg)
431 self.session.source_map().end_point(sp),
432 &format!("provide a definition for the {}", ctx),
434 Applicability::HasPlaceholders,
439 fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
441 let msg = format!("associated {} in `impl` without body", ctx);
442 self.error_item_without_body(sp, ctx, &msg, sugg);
446 fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
447 let span = match bounds {
450 [b0, .., bl] => b0.span().to(bl.span()),
453 .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
457 fn check_foreign_ty_genericless(&self, generics: &Generics) {
458 let cannot_have = |span, descr, remove_descr| {
462 &format!("`type`s inside `extern` blocks cannot have {}", descr),
466 &format!("remove the {}", remove_descr),
468 Applicability::MaybeIncorrect,
470 .span_label(self.current_extern_span(), "`extern` block begins here")
475 if !generics.params.is_empty() {
476 cannot_have(generics.span, "generic parameters", "generic parameters");
479 if !generics.where_clause.predicates.is_empty() {
480 cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
484 fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
485 let Some(body) = body else {
489 .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
490 .span_label(ident.span, "cannot have a body")
491 .span_label(body, "the invalid body")
493 self.current_extern_span(),
495 "`extern` blocks define existing foreign {0}s and {0}s \
496 inside of them cannot have a body",
504 /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
505 fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
506 let Some(body) = body else {
510 .struct_span_err(ident.span, "incorrect function inside `extern` block")
511 .span_label(ident.span, "cannot have a body")
514 "remove the invalid body",
516 Applicability::MaybeIncorrect,
519 "you might have meant to write a function accessible through FFI, \
520 which can be done by writing `extern fn` outside of the `extern` block",
523 self.current_extern_span(),
524 "`extern` blocks define existing foreign functions and functions \
525 inside of them cannot have a body",
531 fn current_extern_span(&self) -> Span {
532 self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
535 /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
536 fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
537 if header.has_qualifiers() {
539 .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
540 .span_label(self.current_extern_span(), "in this `extern` block")
541 .span_suggestion_verbose(
542 span.until(ident.span.shrink_to_lo()),
543 "remove the qualifiers",
545 Applicability::MaybeIncorrect,
551 /// An item in `extern { ... }` cannot use non-ascii identifier.
552 fn check_foreign_item_ascii_only(&self, ident: Ident) {
553 if !ident.as_str().is_ascii() {
558 "items in `extern` blocks cannot use non-ascii identifiers",
560 .span_label(self.current_extern_span(), "in this `extern` block")
562 "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
569 /// Reject C-varadic type unless the function is foreign,
570 /// or free and `unsafe extern "C"` semantically.
571 fn check_c_varadic_type(&self, fk: FnKind<'a>) {
572 match (fk.ctxt(), fk.header()) {
573 (Some(FnCtxt::Foreign), _) => return,
574 (Some(FnCtxt::Free), Some(header)) => match header.ext {
575 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
576 if matches!(header.unsafety, Unsafe::Yes(_)) =>
585 for Param { ty, span, .. } in &fk.decl().inputs {
586 if let TyKind::CVarArgs = ty.kind {
590 "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
597 fn check_item_named(&self, ident: Ident, kind: &str) {
598 if ident.name != kw::Underscore {
602 .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
603 .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
607 fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
608 if ident.name.as_str().is_ascii() {
611 let head_span = self.session.source_map().guess_head_span(item_span);
616 "`#[no_mangle]` requires ASCII identifier"
621 fn check_mod_file_item_asciionly(&self, ident: Ident) {
622 if ident.name.as_str().is_ascii() {
629 "trying to load file for module `{}` with non-ascii identifier name",
632 .help("consider using `#[path]` attribute to specify filesystem path")
636 fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
637 if !generics.params.is_empty() {
642 "auto traits cannot have generic parameters"
644 .span_label(ident_span, "auto trait cannot have generic parameters")
647 "remove the parameters",
649 Applicability::MachineApplicable,
655 fn emit_e0568(&self, span: Span, ident_span: Span) {
660 "auto traits cannot have super traits or lifetime bounds"
662 .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
665 "remove the super traits or lifetime bounds",
667 Applicability::MachineApplicable,
672 fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
673 if let [.., last] = &bounds[..] {
674 let span = ident_span.shrink_to_hi().to(last.span());
675 self.emit_e0568(span, ident_span);
679 fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
680 if !where_clause.predicates.is_empty() {
681 self.emit_e0568(where_clause.span, ident_span);
685 fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
686 if !trait_items.is_empty() {
687 let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
688 let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
693 "auto traits cannot have associated items"
697 "remove these associated items",
699 Applicability::MachineApplicable,
701 .span_label(ident_span, "auto trait cannot have associated items")
706 fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
707 // Lifetimes always come first.
708 let lt_sugg = data.args.iter().filter_map(|arg| match arg {
709 AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
710 Some(pprust::to_string(|s| s.print_generic_arg(lt)))
714 let args_sugg = data.args.iter().filter_map(|a| match a {
715 AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
718 AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
720 // Constraints always come last.
721 let constraint_sugg = data.args.iter().filter_map(|a| match a {
722 AngleBracketedArg::Arg(_) => None,
723 AngleBracketedArg::Constraint(c) => {
724 Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
729 lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
733 /// Enforce generic args coming before constraints in `<...>` of a path segment.
734 fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
735 // Early exit in case it's partitioned as it should be.
736 if data.args.iter().is_partitioned(|arg| matches!(arg, AngleBracketedArg::Arg(_))) {
739 // Find all generic argument coming after the first constraint...
740 let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
741 data.args.iter().partition_map(|arg| match arg {
742 AngleBracketedArg::Constraint(c) => Either::Left(c.span),
743 AngleBracketedArg::Arg(a) => Either::Right(a.span()),
745 let args_len = arg_spans.len();
746 let constraint_len = constraint_spans.len();
747 // ...and then error:
751 "generic arguments must come before the first constraint",
753 .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
755 *arg_spans.iter().last().unwrap(),
756 &format!("generic argument{}", pluralize!(args_len)),
758 .span_labels(constraint_spans, "")
759 .span_labels(arg_spans, "")
760 .span_suggestion_verbose(
763 "move the constraint{} after the generic argument{}",
764 pluralize!(constraint_len),
767 self.correct_generic_order_suggestion(&data),
768 Applicability::MachineApplicable,
773 fn visit_ty_common(&mut self, ty: &'a Ty) {
775 TyKind::BareFn(ref bfty) => {
776 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
777 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
782 "patterns aren't allowed in function pointer types"
786 self.check_late_bound_lifetime_defs(&bfty.generic_params);
787 if let Extern::Implicit = bfty.ext {
788 let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
789 self.maybe_lint_missing_abi(sig_span, ty.id);
792 TyKind::TraitObject(ref bounds, ..) => {
793 let mut any_lifetime_bounds = false;
794 for bound in bounds {
795 if let GenericBound::Outlives(ref lifetime) = *bound {
796 if any_lifetime_bounds {
801 "only a single explicit lifetime bound is permitted"
806 any_lifetime_bounds = true;
809 self.no_questions_in_bounds(bounds, "trait object types", false);
811 TyKind::ImplTrait(_, ref bounds) => {
812 if self.is_impl_trait_banned {
817 "`impl Trait` is not allowed in path parameters"
822 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
827 "nested `impl Trait` is not allowed"
829 .span_label(outer_impl_trait_sp, "outer `impl Trait`")
830 .span_label(ty.span, "nested `impl Trait` here")
834 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
835 self.err_handler().span_err(ty.span, "at least one trait must be specified");
842 fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
843 // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
844 // call site which do not have a macro backtrace. See #61963.
845 let is_macro_callsite = self
848 .span_to_snippet(span)
849 .map(|snippet| snippet.starts_with("#["))
851 if !is_macro_callsite {
852 self.lint_buffer.buffer_lint_with_diagnostic(
856 "extern declarations without an explicit ABI are deprecated",
857 BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
863 /// Checks that generic parameters are in the correct order,
864 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
865 fn validate_generic_param_order(
866 handler: &rustc_errors::Handler,
867 generics: &[GenericParam],
870 let mut max_param: Option<ParamKindOrd> = None;
871 let mut out_of_order = FxHashMap::default();
872 let mut param_idents = Vec::with_capacity(generics.len());
874 for (idx, param) in generics.iter().enumerate() {
875 let ident = param.ident;
876 let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
877 let (ord_kind, ident) = match ¶m.kind {
878 GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
879 GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
880 GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
881 let ty = pprust::ty_to_string(ty);
882 (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
885 param_idents.push((kind, ord_kind, bounds, idx, ident));
887 Some(max_param) if max_param > ord_kind => {
888 let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
891 Some(_) | None => max_param = Some(ord_kind),
895 if !out_of_order.is_empty() {
896 let mut ordered_params = "<".to_string();
897 param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
898 let mut first = true;
899 for (kind, _, bounds, _, ident) in param_idents {
901 ordered_params += ", ";
903 ordered_params += &ident;
905 if !bounds.is_empty() {
906 ordered_params += ": ";
907 ordered_params += &pprust::bounds_to_string(&bounds);
911 GenericParamKind::Type { default: Some(default) } => {
912 ordered_params += " = ";
913 ordered_params += &pprust::ty_to_string(default);
915 GenericParamKind::Type { default: None } => (),
916 GenericParamKind::Lifetime => (),
917 GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
918 ordered_params += " = ";
919 ordered_params += &pprust::expr_to_string(&*default.value);
921 GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
926 ordered_params += ">";
928 for (param_ord, (max_param, spans)) in &out_of_order {
929 let mut err = handler.struct_span_err(
932 "{} parameters must be declared prior to {} parameters",
933 param_ord, max_param,
938 "reorder the parameters: lifetimes, then consts and types",
939 ordered_params.clone(),
940 Applicability::MachineApplicable,
947 impl<'a> Visitor<'a> for AstValidator<'a> {
948 fn visit_attribute(&mut self, attr: &Attribute) {
949 validate_attr::check_meta(&self.session.parse_sess, attr);
952 fn visit_expr(&mut self, expr: &'a Expr) {
953 self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
954 ExprKind::If(cond, then, opt_else) => {
955 this.visit_block(then);
956 walk_list!(this, visit_expr, opt_else);
957 this.with_let_allowed(true, |this, _| this.visit_expr(cond));
960 ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
961 ExprKind::Match(expr, arms) => {
962 this.visit_expr(expr);
964 this.visit_expr(&arm.body);
965 this.visit_pat(&arm.pat);
966 walk_list!(this, visit_attribute, &arm.attrs);
967 if let Some(ref guard) = arm.guard {
968 if let ExprKind::Let(_, ref expr, _) = guard.kind {
969 this.with_let_allowed(true, |this, _| this.visit_expr(expr));
975 ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
976 this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
979 ExprKind::While(cond, then, opt_label) => {
980 walk_list!(this, visit_label, opt_label);
981 this.visit_block(then);
982 this.with_let_allowed(true, |this, _| this.visit_expr(cond));
985 _ => visit::walk_expr(this, expr),
989 fn visit_ty(&mut self, ty: &'a Ty) {
990 self.visit_ty_common(ty);
994 fn visit_label(&mut self, label: &'a Label) {
995 self.check_label(label.ident);
996 visit::walk_label(self, label);
999 fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
1000 self.check_lifetime(lifetime.ident);
1001 visit::walk_lifetime(self, lifetime);
1004 fn visit_field_def(&mut self, s: &'a FieldDef) {
1005 visit::walk_field_def(self, s)
1008 fn visit_item(&mut self, item: &'a Item) {
1009 if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
1010 self.has_proc_macro_decls = true;
1013 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1014 self.check_nomangle_item_asciionly(item.ident, item.span);
1018 ItemKind::Impl(box Impl {
1024 of_trait: Some(ref t),
1028 self.with_in_trait_impl(true, Some(constness), |this| {
1029 this.invalid_visibility(&item.vis, None);
1030 if let TyKind::Err = self_ty.kind {
1034 "`impl Trait for .. {}` is an obsolete syntax",
1036 .help("use `auto trait Trait {}` instead")
1039 if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
1044 "negative impls cannot be unsafe"
1046 .span_label(sp, "negative because of this")
1047 .span_label(span, "unsafe because of this")
1051 this.visit_vis(&item.vis);
1052 this.visit_ident(item.ident);
1053 if let Const::Yes(_) = constness {
1054 this.with_tilde_const_allowed(|this| this.visit_generics(generics));
1056 this.visit_generics(generics);
1058 this.visit_trait_ref(t);
1059 this.visit_ty(self_ty);
1061 walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
1063 return; // Avoid visiting again.
1065 ItemKind::Impl(box Impl {
1075 let error = |annotation_span, annotation| {
1076 let mut err = self.err_handler().struct_span_err(
1078 &format!("inherent impls cannot be {}", annotation),
1080 err.span_label(annotation_span, &format!("{} because of this", annotation));
1081 err.span_label(self_ty.span, "inherent impl for this type");
1085 self.invalid_visibility(
1087 Some("place qualifiers on individual impl items instead"),
1089 if let Unsafe::Yes(span) = unsafety {
1090 error(span, "unsafe").code(error_code!(E0197)).emit();
1092 if let ImplPolarity::Negative(span) = polarity {
1093 error(span, "negative").emit();
1095 if let Defaultness::Default(def_span) = defaultness {
1096 error(def_span, "`default`")
1097 .note("only trait implementations may be annotated with `default`")
1100 if let Const::Yes(span) = constness {
1101 error(span, "`const`")
1102 .note("only trait implementations may be annotated with `const`")
1106 ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
1107 self.check_defaultness(item.span, defaultness);
1110 let msg = "free function without a body";
1111 self.error_item_without_body(item.span, "function", msg, " { <body> }");
1113 self.visit_vis(&item.vis);
1114 self.visit_ident(item.ident);
1115 if let Const::Yes(_) = sig.header.constness {
1116 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1118 self.visit_generics(generics);
1120 let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
1121 self.visit_fn(kind, item.span, item.id);
1122 walk_list!(self, visit_attribute, &item.attrs);
1123 return; // Avoid visiting again.
1125 ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
1126 let old_item = mem::replace(&mut self.extern_mod, Some(item));
1127 self.invalid_visibility(
1129 Some("place qualifiers on individual foreign items instead"),
1131 if let Unsafe::Yes(span) = unsafety {
1132 self.err_handler().span_err(span, "extern block cannot be declared unsafe");
1135 self.maybe_lint_missing_abi(item.span, item.id);
1137 visit::walk_item(self, item);
1138 self.extern_mod = old_item;
1139 return; // Avoid visiting again.
1141 ItemKind::Enum(ref def, _) => {
1142 for variant in &def.variants {
1143 self.invalid_visibility(&variant.vis, None);
1144 for field in variant.data.fields() {
1145 self.invalid_visibility(&field.vis, None);
1149 ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
1150 if is_auto == IsAuto::Yes {
1151 // Auto traits cannot have generics, super traits nor contain items.
1152 self.deny_generic_params(generics, item.ident.span);
1153 self.deny_super_traits(bounds, item.ident.span);
1154 self.deny_where_clause(&generics.where_clause, item.ident.span);
1155 self.deny_items(items, item.ident.span);
1157 self.no_questions_in_bounds(bounds, "supertraits", true);
1159 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
1160 // context for the supertraits.
1161 self.visit_vis(&item.vis);
1162 self.visit_ident(item.ident);
1163 self.visit_generics(generics);
1164 self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
1165 walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
1166 walk_list!(self, visit_attribute, &item.attrs);
1169 ItemKind::Mod(unsafety, ref mod_kind) => {
1170 if let Unsafe::Yes(span) = unsafety {
1171 self.err_handler().span_err(span, "module cannot be declared unsafe");
1173 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
1174 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
1175 && !self.session.contains_name(&item.attrs, sym::path)
1177 self.check_mod_file_item_asciionly(item.ident);
1180 ItemKind::Struct(ref vdata, ref generics) => match vdata {
1181 // Duplicating the `Visitor` logic allows catching all cases
1182 // of `Anonymous(Struct, Union)` outside of a field struct or union.
1184 // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1185 // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1186 // it uses `visit_ty_common`, which doesn't contain that specific check.
1187 VariantData::Struct(ref fields, ..) => {
1188 self.visit_vis(&item.vis);
1189 self.visit_ident(item.ident);
1190 self.visit_generics(generics);
1191 self.with_banned_assoc_ty_bound(|this| {
1192 walk_list!(this, visit_struct_field_def, fields);
1194 walk_list!(self, visit_attribute, &item.attrs);
1199 ItemKind::Union(ref vdata, ref generics) => {
1200 if vdata.fields().is_empty() {
1201 self.err_handler().span_err(item.span, "unions cannot have zero fields");
1204 VariantData::Struct(ref fields, ..) => {
1205 self.visit_vis(&item.vis);
1206 self.visit_ident(item.ident);
1207 self.visit_generics(generics);
1208 self.with_banned_assoc_ty_bound(|this| {
1209 walk_list!(this, visit_struct_field_def, fields);
1211 walk_list!(self, visit_attribute, &item.attrs);
1217 ItemKind::Const(def, .., None) => {
1218 self.check_defaultness(item.span, def);
1219 let msg = "free constant item without body";
1220 self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
1222 ItemKind::Static(.., None) => {
1223 let msg = "free static item without body";
1224 self.error_item_without_body(item.span, "static", msg, " = <expr>;");
1226 ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => {
1227 self.check_defaultness(item.span, defaultness);
1229 let msg = "free type alias without body";
1230 self.error_item_without_body(item.span, "type", msg, " = <type>;");
1232 self.check_type_no_bounds(bounds, "this context");
1237 visit::walk_item(self, item);
1240 fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
1242 ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1243 self.check_defaultness(fi.span, *defaultness);
1244 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
1245 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
1246 self.check_foreign_item_ascii_only(fi.ident);
1248 ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
1249 self.check_defaultness(fi.span, *defaultness);
1250 self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
1251 self.check_type_no_bounds(bounds, "`extern` blocks");
1252 self.check_foreign_ty_genericless(generics);
1253 self.check_foreign_item_ascii_only(fi.ident);
1255 ForeignItemKind::Static(_, _, body) => {
1256 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
1257 self.check_foreign_item_ascii_only(fi.ident);
1259 ForeignItemKind::MacCall(..) => {}
1262 visit::walk_foreign_item(self, fi)
1265 // Mirrors `visit::walk_generic_args`, but tracks relevant state.
1266 fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
1267 match *generic_args {
1268 GenericArgs::AngleBracketed(ref data) => {
1269 self.check_generic_args_before_constraints(data);
1271 for arg in &data.args {
1273 AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
1274 // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
1275 // are allowed to contain nested `impl Trait`.
1276 AngleBracketedArg::Constraint(constraint) => {
1277 self.with_impl_trait(None, |this| {
1278 this.visit_assoc_constraint_from_generic_args(constraint);
1284 GenericArgs::Parenthesized(ref data) => {
1285 walk_list!(self, visit_ty, &data.inputs);
1286 if let FnRetTy::Ty(ty) = &data.output {
1287 // `-> Foo` syntax is essentially an associated type binding,
1288 // so it is also allowed to contain nested `impl Trait`.
1289 self.with_impl_trait(None, |this| this.visit_ty(ty));
1295 fn visit_generics(&mut self, generics: &'a Generics) {
1296 let mut prev_param_default = None;
1297 for param in &generics.params {
1299 GenericParamKind::Lifetime => (),
1300 GenericParamKind::Type { default: Some(_), .. }
1301 | GenericParamKind::Const { default: Some(_), .. } => {
1302 prev_param_default = Some(param.ident.span);
1304 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
1305 if let Some(span) = prev_param_default {
1306 let mut err = self.err_handler().struct_span_err(
1308 "generic parameters with a default must be trailing",
1317 validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
1319 for predicate in &generics.where_clause.predicates {
1320 if let WherePredicate::EqPredicate(ref predicate) = *predicate {
1321 deny_equality_constraints(self, predicate, generics);
1324 walk_list!(self, visit_generic_param, &generics.params);
1325 for predicate in &generics.where_clause.predicates {
1327 WherePredicate::BoundPredicate(bound_pred) => {
1328 // A type binding, eg `for<'c> Foo: Send+Clone+'c`
1329 self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
1331 // This is slightly complicated. Our representation for poly-trait-refs contains a single
1332 // binder and thus we only allow a single level of quantification. However,
1333 // the syntax of Rust permits quantification in two places in where clauses,
1334 // e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
1335 // defined, then error.
1336 if !bound_pred.bound_generic_params.is_empty() {
1337 for bound in &bound_pred.bounds {
1339 GenericBound::Trait(t, _) => {
1340 if !t.bound_generic_params.is_empty() {
1345 "nested quantification of lifetimes"
1350 GenericBound::Outlives(_) => {}
1357 self.visit_where_predicate(predicate);
1361 fn visit_generic_param(&mut self, param: &'a GenericParam) {
1362 if let GenericParamKind::Lifetime { .. } = param.kind {
1363 self.check_lifetime(param.ident);
1365 visit::walk_generic_param(self, param);
1368 fn visit_param_bound(&mut self, bound: &'a GenericBound) {
1370 GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
1371 if !self.is_tilde_const_allowed {
1373 .struct_span_err(bound.span(), "`~const` is not allowed here")
1374 .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
1379 GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
1381 .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
1387 visit::walk_param_bound(self, bound)
1390 fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
1391 self.check_late_bound_lifetime_defs(&t.bound_generic_params);
1392 visit::walk_poly_trait_ref(self, t, m);
1395 fn visit_variant_data(&mut self, s: &'a VariantData) {
1396 self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
1401 enum_definition: &'a EnumDef,
1402 generics: &'a Generics,
1406 self.with_banned_assoc_ty_bound(|this| {
1407 visit::walk_enum_def(this, enum_definition, generics, item_id)
1411 fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
1412 // Only associated `fn`s can have `self` parameters.
1413 let self_semantic = match fk.ctxt() {
1414 Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
1415 _ => SelfSemantic::No,
1417 self.check_fn_decl(fk.decl(), self_semantic);
1419 self.check_c_varadic_type(fk);
1421 // Functions cannot both be `const async`
1422 if let Some(FnHeader {
1423 constness: Const::Yes(cspan),
1424 asyncness: Async::Yes { span: aspan, .. },
1430 vec![*cspan, *aspan],
1431 "functions cannot be both `const` and `async`",
1433 .span_label(*cspan, "`const` because of this")
1434 .span_label(*aspan, "`async` because of this")
1435 .span_label(span, "") // Point at the fn header.
1442 FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
1447 self.maybe_lint_missing_abi(*sig_span, id);
1450 // Functions without bodies cannot have patterns.
1451 if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
1452 Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
1453 let (code, msg, label) = match ctxt {
1454 FnCtxt::Foreign => (
1456 "patterns aren't allowed in foreign function declarations",
1457 "pattern not allowed in foreign function",
1461 "patterns aren't allowed in functions without bodies",
1462 "pattern not allowed in function without body",
1465 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
1466 if let Some(ident) = ident {
1467 let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
1468 self.lint_buffer.buffer_lint_with_diagnostic(
1469 PATTERNS_IN_FNS_WITHOUT_BODY,
1478 .struct_span_err(span, msg)
1479 .span_label(span, label)
1486 visit::walk_fn(self, fk, span);
1489 fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
1490 if self.session.contains_name(&item.attrs, sym::no_mangle) {
1491 self.check_nomangle_item_asciionly(item.ident, item.span);
1494 if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
1495 self.check_defaultness(item.span, item.kind.defaultness());
1498 if ctxt == AssocCtxt::Impl {
1500 AssocItemKind::Const(_, _, body) => {
1501 self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
1503 AssocItemKind::Fn(box Fn { body, .. }) => {
1504 self.check_impl_item_provided(item.span, body, "function", " { <body> }");
1506 AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
1507 self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
1508 self.check_type_no_bounds(bounds, "`impl`s");
1514 if ctxt == AssocCtxt::Trait || self.in_trait_impl {
1515 self.invalid_visibility(&item.vis, None);
1516 if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1517 self.check_trait_fn_not_const(sig.header.constness);
1518 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
1522 if let AssocItemKind::Const(..) = item.kind {
1523 self.check_item_named(item.ident, "const");
1527 AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
1528 if ctxt == AssocCtxt::Trait =>
1530 self.visit_vis(&item.vis);
1531 self.visit_ident(item.ident);
1532 walk_list!(self, visit_attribute, &item.attrs);
1533 self.with_tilde_const_allowed(|this| {
1534 this.visit_generics(generics);
1535 walk_list!(this, visit_param_bound, bounds);
1537 walk_list!(self, visit_ty, ty);
1539 AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
1540 if self.in_const_trait_impl
1541 || ctxt == AssocCtxt::Trait
1542 || matches!(sig.header.constness, Const::Yes(_)) =>
1544 self.visit_vis(&item.vis);
1545 self.visit_ident(item.ident);
1546 self.with_tilde_const_allowed(|this| this.visit_generics(generics));
1548 FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
1549 self.visit_fn(kind, item.span, item.id);
1552 .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
1557 /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
1558 /// like it's setting an associated type, provide an appropriate suggestion.
1559 fn deny_equality_constraints(
1560 this: &mut AstValidator<'_>,
1561 predicate: &WhereEqPredicate,
1562 generics: &Generics,
1564 let mut err = this.err_handler().struct_span_err(
1566 "equality constraints are not yet supported in `where` clauses",
1568 err.span_label(predicate.span, "not supported");
1570 // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1571 if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind {
1572 if let TyKind::Path(None, path) = &qself.ty.kind {
1573 match &path.segments[..] {
1574 [PathSegment { ident, args: None, .. }] => {
1575 for param in &generics.params {
1576 if param.ident == *ident {
1578 match &full_path.segments[qself.position..] {
1579 [PathSegment { ident, args, .. }] => {
1580 // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1581 let mut assoc_path = full_path.clone();
1582 // Remove `Bar` from `Foo::Bar`.
1583 assoc_path.segments.pop();
1584 let len = assoc_path.segments.len() - 1;
1585 let gen_args = args.as_ref().map(|p| (**p).clone());
1586 // Build `<Bar = RhsTy>`.
1587 let arg = AngleBracketedArg::Constraint(AssocConstraint {
1588 id: rustc_ast::node_id::DUMMY_NODE_ID,
1591 kind: AssocConstraintKind::Equality {
1592 term: predicate.rhs_ty.clone().into(),
1596 // Add `<Bar = RhsTy>` to `Foo`.
1597 match &mut assoc_path.segments[len].args {
1598 Some(args) => match args.deref_mut() {
1599 GenericArgs::Parenthesized(_) => continue,
1600 GenericArgs::AngleBracketed(args) => {
1601 args.args.push(arg);
1605 *empty_args = AngleBracketedArgs {
1612 err.span_suggestion_verbose(
1615 "if `{}` is an associated type you're trying to set, \
1616 use the associated type binding syntax",
1622 pprust::path_to_string(&assoc_path)
1624 Applicability::MaybeIncorrect,
1636 // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1637 if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1638 if let [potential_param, potential_assoc] = &full_path.segments[..] {
1639 for param in &generics.params {
1640 if param.ident == potential_param.ident {
1641 for bound in ¶m.bounds {
1642 if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
1644 if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1645 let assoc = pprust::path_to_string(&ast::Path::from_ident(
1646 potential_assoc.ident,
1648 let ty = pprust::ty_to_string(&predicate.rhs_ty);
1649 let (args, span) = match &trait_segment.args {
1650 Some(args) => match args.deref() {
1651 ast::GenericArgs::AngleBracketed(args) => {
1652 let Some(arg) = args.args.last() else {
1656 format!(", {} = {}", assoc, ty),
1657 arg.span().shrink_to_hi(),
1663 format!("<{} = {}>", assoc, ty),
1664 trait_segment.span().shrink_to_hi(),
1667 err.multipart_suggestion(
1669 "if `{}::{}` is an associated type you're trying to set, \
1670 use the associated type binding syntax",
1671 trait_segment.ident, potential_assoc.ident,
1673 vec![(span, args), (predicate.span, String::new())],
1674 Applicability::MaybeIncorrect,
1684 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
1689 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
1690 let mut validator = AstValidator {
1693 in_trait_impl: false,
1694 in_const_trait_impl: false,
1695 has_proc_macro_decls: false,
1696 outer_impl_trait: None,
1697 is_tilde_const_allowed: false,
1698 is_impl_trait_banned: false,
1699 is_assoc_ty_bound_banned: false,
1700 is_let_allowed: false,
1703 visit::walk_crate(&mut validator, krate);
1705 validator.has_proc_macro_decls