Skip to content

Add BoundKind in visit_param_bounds to check questions in bounds #96246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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., `<T: Bound>`, `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()`.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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 => {}
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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) => {
Expand All @@ -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, &param.bounds);
walk_list!(visitor, visit_param_bound, &param.bounds, BoundKind::Bound);
match param.kind {
GenericParamKind::Lifetime => (),
GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
Expand All @@ -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);
Expand Down Expand Up @@ -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) => {
Expand Down
71 changes: 35 additions & 36 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
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()
.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();
.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)
Expand Down Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/node_count.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_passes/src/hir_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
}
},
);
Expand Down Expand Up @@ -1026,12 +1026,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
match param.kind {
GenericParamKind::Lifetime => {
for bound in &param.bounds {
this.visit_param_bound(bound);
this.visit_param_bound(bound, BoundKind::Bound);
}
}
GenericParamKind::Type { ref default } => {
for bound in &param.bounds {
this.visit_param_bound(bound);
this.visit_param_bound(bound, BoundKind::Bound);
}

if let Some(ref ty) = default {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
},
);
},
Expand Down