diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d925c6dd354..e08ba73e0ae 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -32,6 +32,25 @@ pub enum FnCtxt { Assoc(AssocCtxt), } +#[derive(Copy, Clone, Debug)] +pub enum BoundKind { + /// Trait bounds in generics bounds and type/trait alias. + /// E.g., ``, `type A: Bound`, or `where T: Bound`. + Bound, + + /// Trait bounds in `impl` type. + /// E.g., `type Foo = impl Bound1 + Bound2 + Bound3`. + Impl, + + /// Trait bounds in trait object type. + /// E.g., `dyn Bound1 + Bound2 + Bound3`. + TraitObject, + + /// Super traits of a trait. + /// E.g., `trait A: B` + SuperTraits, +} + #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. @@ -139,7 +158,7 @@ pub trait Visitor<'ast>: Sized { fn visit_trait_ref(&mut self, t: &'ast TraitRef) { walk_trait_ref(self, t) } - fn visit_param_bound(&mut self, bounds: &'ast GenericBound) { + fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) { walk_param_bound(self, bounds) } fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { @@ -311,7 +330,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm), ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => { visitor.visit_generics(generics); - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); walk_list!(visitor, visit_ty, ty); } ItemKind::Enum(ref enum_definition, ref generics) => { @@ -346,12 +365,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ref items, }) => { visitor.visit_generics(generics); - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits); walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); } ItemKind::TraitAlias(ref generics, ref bounds) => { visitor.visit_generics(generics); - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } ItemKind::MacCall(ref mac) => visitor.visit_mac_call(mac), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), @@ -416,8 +435,11 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { visitor.visit_ty(ty); visitor.visit_anon_const(length) } - TyKind::TraitObject(ref bounds, ..) | TyKind::ImplTrait(_, ref bounds) => { - walk_list!(visitor, visit_param_bound, bounds); + TyKind::TraitObject(ref bounds, ..) => { + walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); + } + TyKind::ImplTrait(_, ref bounds) => { + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); } TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} @@ -503,7 +525,7 @@ pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &' Term::Const(c) => visitor.visit_anon_const(c), }, AssocConstraintKind::Bound { ref bounds } => { - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } } } @@ -566,7 +588,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI } ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { visitor.visit_generics(generics); - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); walk_list!(visitor, visit_ty, ty); } ForeignItemKind::MacCall(mac) => { @@ -585,7 +607,7 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParam) { visitor.visit_ident(param.ident); walk_list!(visitor, visit_attribute, param.attrs.iter()); - walk_list!(visitor, visit_param_bound, ¶m.bounds); + walk_list!(visitor, visit_param_bound, ¶m.bounds, BoundKind::Bound); match param.kind { GenericParamKind::Lifetime => (), GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default), @@ -612,14 +634,14 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a .. }) => { visitor.visit_ty(bounded_ty); - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); walk_list!(visitor, visit_generic_param, bound_generic_params); } WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, ref bounds, .. }) => { visitor.visit_lifetime(lifetime); - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); } WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => { visitor.visit_ty(lhs_ty); @@ -672,7 +694,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, } AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { visitor.visit_generics(generics); - walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); walk_list!(visitor, visit_ty, ty); } AssocItemKind::MacCall(mac) => { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 8d815e95528..058a0f975a7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -8,7 +8,7 @@ use itertools::{Either, Itertools}; use rustc_ast::ptr::P; -use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; +use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::walk_list; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; @@ -345,23 +345,6 @@ impl<'a> AstValidator<'a> { } } - // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`. - fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) { - for bound in bounds { - if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound { - let mut err = self.err_handler().struct_span_err( - poly.span, - &format!("`?Trait` is not permitted in {}", where_), - ); - if is_trait { - let path_str = pprust::path_to_string(&poly.trait_ref.path); - err.note(&format!("traits are `?{}` by default", path_str)); - } - err.emit(); - } - } - } - fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { // Check only lifetime parameters are present and that the lifetime // parameters that are present have no bounds. @@ -873,7 +856,6 @@ impl<'a> AstValidator<'a> { any_lifetime_bounds = true; } } - self.no_questions_in_bounds(bounds, "trait object types", false); } TyKind::ImplTrait(_, ref bounds) => { if self.is_impl_trait_banned { @@ -1242,14 +1224,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.deny_where_clause(&generics.where_clause, item.ident.span); self.deny_items(items, item.ident.span); } - self.no_questions_in_bounds(bounds, "supertraits", true); // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. self.visit_vis(&item.vis); self.visit_ident(item.ident); self.visit_generics(generics); - self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds)); + self.with_banned_tilde_const(|this| { + walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) + }); walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait); walk_list!(self, visit_attribute, &item.attrs); return; @@ -1476,23 +1459,39 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_generic_param(self, param); } - fn visit_param_bound(&mut self, bound: &'a GenericBound) { - match bound { - GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => { - if !self.is_tilde_const_allowed { - self.err_handler() - .struct_span_err(bound.span(), "`~const` is not allowed here") - .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions") - .emit(); + fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { + if let GenericBound::Trait(ref poly, modify) = *bound { + match (ctxt, modify) { + (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { + let mut err = self.err_handler().struct_span_err( + poly.span, + &format!("`?Trait` is not permitted in supertraits"), + ); + let path_str = pprust::path_to_string(&poly.trait_ref.path); + err.note(&format!("traits are `?{}` by default", path_str)); + err.emit(); } + (BoundKind::TraitObject, TraitBoundModifier::Maybe) => { + let mut err = self.err_handler().struct_span_err( + poly.span, + &format!("`?Trait` is not permitted in trait object types"), + ); + err.emit(); + } + (_, TraitBoundModifier::MaybeConst) => { + if !self.is_tilde_const_allowed { + self.err_handler() + .struct_span_err(bound.span(), "`~const` is not allowed here") + .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions") + .emit(); + } + } + (_, TraitBoundModifier::MaybeConstMaybe) => { + self.err_handler() + .span_err(bound.span(), "`~const` and `?` are mutually exclusive"); + } + _ => {} } - - GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { - self.err_handler() - .span_err(bound.span(), "`~const` and `?` are mutually exclusive"); - } - - _ => {} } visit::walk_param_bound(self, bound) @@ -1662,7 +1661,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); self.with_tilde_const_allowed(|this| { this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds); + walk_list!(this, visit_param_bound, bounds, BoundKind::Bound); }); walk_list!(self, visit_ty, ty); } diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index a4a48cc8e8a..48b79809c1b 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -76,7 +76,7 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_trait_ref(self, t) } - fn visit_param_bound(&mut self, bounds: &GenericBound) { + fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundKind) { self.count += 1; walk_param_bound(self, bounds) } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 6cf1aa480d2..237a8abfabe 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -3,6 +3,7 @@ // completely accurate (some things might be counted twice, others missed). use rustc_ast::visit as ast_visit; +use rustc_ast::visit::BoundKind; use rustc_ast::{self as ast, AttrId, NodeId}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; @@ -302,7 +303,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_assoc_item(self, item, ctxt); } - fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) { + fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound, _ctxt: BoundKind) { self.record("GenericBound", Id::None, bounds); ast_visit::walk_param_bound(self, bounds) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7635ad9bd87..50055f8030c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -12,7 +12,7 @@ use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; use rustc_ast::ptr::P; -use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; +use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::*; use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -835,7 +835,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { this.visit_generic_param_vec(&bound_generic_params, false); this.visit_ty(bounded_ty); for bound in bounds { - this.visit_param_bound(bound) + this.visit_param_bound(bound, BoundKind::Bound) } }, ); @@ -1026,12 +1026,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { match param.kind { GenericParamKind::Lifetime => { for bound in ¶m.bounds { - this.visit_param_bound(bound); + this.visit_param_bound(bound, BoundKind::Bound); } } GenericParamKind::Type { ref default } => { for bound in ¶m.bounds { - this.visit_param_bound(bound); + this.visit_param_bound(bound, BoundKind::Bound); } if let Some(ref ty) = default { @@ -1496,7 +1496,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Res::SelfTy { trait_: Some(local_def_id), alias_to: None }, |this| { this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds); + walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits); let walk_assoc_item = |this: &mut Self, @@ -1580,7 +1580,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Res::SelfTy { trait_: Some(local_def_id), alias_to: None }, |this| { this.visit_generics(generics); - walk_list!(this, visit_param_bound, bounds); + walk_list!(this, visit_param_bound, bounds, BoundKind::Bound); }, ); },