Add BoundCtxt in visit_param_bounds to check questions in bounds

This commit is contained in:
SparrowLii 2022-04-20 19:06:32 +08:00
parent 27af517549
commit 4375b36117
5 changed files with 67 additions and 57 deletions

View File

@ -32,6 +32,13 @@ pub enum FnCtxt {
Assoc(AssocCtxt), Assoc(AssocCtxt),
} }
#[derive(Copy, Clone, Debug)]
pub enum BoundCtxt {
Normal,
TraitObject,
SuperTraits,
}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> { pub enum FnKind<'a> {
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
@ -139,7 +146,7 @@ pub trait Visitor<'ast>: Sized {
fn visit_trait_ref(&mut self, t: &'ast TraitRef) { fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
walk_trait_ref(self, t) walk_trait_ref(self, t)
} }
fn visit_param_bound(&mut self, bounds: &'ast GenericBound) { fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundCtxt) {
walk_param_bound(self, bounds) walk_param_bound(self, bounds)
} }
fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
@ -311,7 +318,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::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => { ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
walk_list!(visitor, visit_ty, ty); walk_list!(visitor, visit_ty, ty);
} }
ItemKind::Enum(ref enum_definition, ref generics) => { ItemKind::Enum(ref enum_definition, ref generics) => {
@ -346,12 +353,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
ref items, ref items,
}) => { }) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::SuperTraits);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
} }
ItemKind::TraitAlias(ref generics, ref bounds) => { ItemKind::TraitAlias(ref generics, ref bounds) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
} }
ItemKind::MacCall(ref mac) => visitor.visit_mac_call(mac), ItemKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
@ -416,8 +423,11 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
visitor.visit_ty(ty); visitor.visit_ty(ty);
visitor.visit_anon_const(length) visitor.visit_anon_const(length)
} }
TyKind::TraitObject(ref bounds, ..) | TyKind::ImplTrait(_, ref bounds) => { TyKind::TraitObject(ref bounds, ..) => {
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::TraitObject);
}
TyKind::ImplTrait(_, ref bounds) => {
walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
} }
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
@ -503,7 +513,7 @@ pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'
Term::Const(c) => visitor.visit_anon_const(c), Term::Const(c) => visitor.visit_anon_const(c),
}, },
AssocConstraintKind::Bound { ref bounds } => { AssocConstraintKind::Bound { ref bounds } => {
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
} }
} }
} }
@ -566,7 +576,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
} }
ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
walk_list!(visitor, visit_ty, ty); walk_list!(visitor, visit_ty, ty);
} }
ForeignItemKind::MacCall(mac) => { ForeignItemKind::MacCall(mac) => {
@ -585,7 +595,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) { pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParam) {
visitor.visit_ident(param.ident); visitor.visit_ident(param.ident);
walk_list!(visitor, visit_attribute, param.attrs.iter()); walk_list!(visitor, visit_attribute, param.attrs.iter());
walk_list!(visitor, visit_param_bound, &param.bounds); walk_list!(visitor, visit_param_bound, &param.bounds, BoundCtxt::Normal);
match param.kind { match param.kind {
GenericParamKind::Lifetime => (), GenericParamKind::Lifetime => (),
GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default), GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
@ -612,14 +622,14 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a
.. ..
}) => { }) => {
visitor.visit_ty(bounded_ty); visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
walk_list!(visitor, visit_generic_param, bound_generic_params); walk_list!(visitor, visit_generic_param, bound_generic_params);
} }
WherePredicate::RegionPredicate(WhereRegionPredicate { WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime, ref bounds, .. ref lifetime, ref bounds, ..
}) => { }) => {
visitor.visit_lifetime(lifetime); visitor.visit_lifetime(lifetime);
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
} }
WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => { WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
visitor.visit_ty(lhs_ty); visitor.visit_ty(lhs_ty);
@ -672,7 +682,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
} }
AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds, BoundCtxt::Normal);
walk_list!(visitor, visit_ty, ty); walk_list!(visitor, visit_ty, ty);
} }
AssocItemKind::MacCall(mac) => { AssocItemKind::MacCall(mac) => {

View File

@ -8,7 +8,7 @@
use itertools::{Either, Itertools}; use itertools::{Either, Itertools};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::visit::{self, AssocCtxt, BoundCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::walk_list; use rustc_ast::walk_list;
use rustc_ast::*; use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State}; 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]) { fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
// Check only lifetime parameters are present and that the lifetime // Check only lifetime parameters are present and that the lifetime
// parameters that are present have no bounds. // parameters that are present have no bounds.
@ -873,7 +856,6 @@ impl<'a> AstValidator<'a> {
any_lifetime_bounds = true; any_lifetime_bounds = true;
} }
} }
self.no_questions_in_bounds(bounds, "trait object types", false);
} }
TyKind::ImplTrait(_, ref bounds) => { TyKind::ImplTrait(_, ref bounds) => {
if self.is_impl_trait_banned { 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_where_clause(&generics.where_clause, item.ident.span);
self.deny_items(items, 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 // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
// context for the supertraits. // context for the supertraits.
self.visit_vis(&item.vis); self.visit_vis(&item.vis);
self.visit_ident(item.ident); self.visit_ident(item.ident);
self.visit_generics(generics); 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, BoundCtxt::SuperTraits)
});
walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait); walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
walk_list!(self, visit_attribute, &item.attrs); walk_list!(self, visit_attribute, &item.attrs);
return; return;
@ -1476,23 +1459,39 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_generic_param(self, param); visit::walk_generic_param(self, param);
} }
fn visit_param_bound(&mut self, bound: &'a GenericBound) { fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundCtxt) {
match bound { if let GenericBound::Trait(ref poly, modify) = *bound {
GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => { match (ctxt, modify) {
if !self.is_tilde_const_allowed { (BoundCtxt::SuperTraits, TraitBoundModifier::Maybe) => {
self.err_handler() let mut err = self.err_handler().struct_span_err(
.struct_span_err(bound.span(), "`~const` is not allowed here") poly.span,
.note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions") &format!("`?Trait` is not permitted in supertraits"),
.emit(); );
let path_str = pprust::path_to_string(&poly.trait_ref.path);
err.note(&format!("traits are `?{}` by default", path_str));
err.emit();
} }
(BoundCtxt::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) visit::walk_param_bound(self, bound)
@ -1662,7 +1661,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
walk_list!(self, visit_attribute, &item.attrs); walk_list!(self, visit_attribute, &item.attrs);
self.with_tilde_const_allowed(|this| { self.with_tilde_const_allowed(|this| {
this.visit_generics(generics); this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds); walk_list!(this, visit_param_bound, bounds, BoundCtxt::Normal);
}); });
walk_list!(self, visit_ty, ty); walk_list!(self, visit_ty, ty);
} }

View File

@ -76,7 +76,7 @@ impl<'ast> Visitor<'ast> for NodeCounter {
self.count += 1; self.count += 1;
walk_trait_ref(self, t) walk_trait_ref(self, t)
} }
fn visit_param_bound(&mut self, bounds: &GenericBound) { fn visit_param_bound(&mut self, bounds: &GenericBound, _ctxt: BoundCtxt) {
self.count += 1; self.count += 1;
walk_param_bound(self, bounds) walk_param_bound(self, bounds)
} }

View File

@ -3,6 +3,7 @@
// completely accurate (some things might be counted twice, others missed). // completely accurate (some things might be counted twice, others missed).
use rustc_ast::visit as ast_visit; use rustc_ast::visit as ast_visit;
use rustc_ast::visit::BoundCtxt;
use rustc_ast::{self as ast, AttrId, NodeId}; use rustc_ast::{self as ast, AttrId, NodeId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir; 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); 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: BoundCtxt) {
self.record("GenericBound", Id::None, bounds); self.record("GenericBound", Id::None, bounds);
ast_visit::walk_param_bound(self, bounds) ast_visit::walk_param_bound(self, bounds)
} }

View File

@ -12,7 +12,7 @@ use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
use crate::{ResolutionError, Resolver, Segment, UseError}; use crate::{ResolutionError, Resolver, Segment, UseError};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::visit::{self, AssocCtxt, BoundCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::*; use rustc_ast::*;
use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; 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_generic_param_vec(&bound_generic_params, false);
this.visit_ty(bounded_ty); this.visit_ty(bounded_ty);
for bound in bounds { for bound in bounds {
this.visit_param_bound(bound) this.visit_param_bound(bound, BoundCtxt::Normal)
} }
}, },
); );
@ -1026,12 +1026,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
match param.kind { match param.kind {
GenericParamKind::Lifetime => { GenericParamKind::Lifetime => {
for bound in &param.bounds { for bound in &param.bounds {
this.visit_param_bound(bound); this.visit_param_bound(bound, BoundCtxt::Normal);
} }
} }
GenericParamKind::Type { ref default } => { GenericParamKind::Type { ref default } => {
for bound in &param.bounds { for bound in &param.bounds {
this.visit_param_bound(bound); this.visit_param_bound(bound, BoundCtxt::Normal);
} }
if let Some(ref ty) = default { 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 }, Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
|this| { |this| {
this.visit_generics(generics); this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds); walk_list!(this, visit_param_bound, bounds, BoundCtxt::SuperTraits);
let walk_assoc_item = let walk_assoc_item =
|this: &mut Self, |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 }, Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
|this| { |this| {
this.visit_generics(generics); this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds); walk_list!(this, visit_param_bound, bounds, BoundCtxt::Normal);
}, },
); );
}, },