Skip to content

Commit

Permalink
Refactor AST validator
Browse files Browse the repository at this point in the history
  • Loading branch information
fmease committed Jan 2, 2024
1 parent 8eb7a14 commit 50d96c7
Showing 1 changed file with 52 additions and 53 deletions.
105 changes: 52 additions & 53 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,33 @@ enum DisallowTildeConstContext<'a> {
Item,
}

enum TraitOrImpl<'a> {
Trait { span: Span, constness: Option<Span> },
Impl { trait_: Option<(Const, ImplPolarity, &'a TraitRef)> },
}

impl<'a> TraitOrImpl<'a> {
fn constness(&self) -> Option<Span> {
match self {
Self::Trait { constness: Some(span), .. }
| Self::Impl { trait_: Some((Const::Yes(span), ..)) } => Some(*span),
_ => None,
}
}

fn is_trait_or_trait_impl(&self) -> bool {
matches!(self, Self::Trait { .. } | Self::Impl { trait_: Some(_) })
}
}

struct AstValidator<'a> {
session: &'a Session,
features: &'a Features,

/// The span of the `extern` in an `extern { ... }` block, if any.
extern_mod: Option<&'a Item>,

/// Are we inside a trait impl?
///
/// If so, this is the trait ref together with its polarity.
in_trait_impl: Option<(ImplPolarity, &'a TraitRef)>,

/// Are we inside a const trait defn or impl?
///
/// If so, this is the span of the constness.
in_const_trait_or_impl: Option<Span>,

/// Are we inside a trait?
///
/// If so, this is the span of the trait.
in_trait: Option<Span>,
outer_trait_or_impl: Option<TraitOrImpl<'a>>,

has_proc_macro_decls: bool,

Expand All @@ -87,31 +93,24 @@ struct AstValidator<'a> {
impl<'a> AstValidator<'a> {
fn with_in_trait_impl(
&mut self,
trait_ref: Option<(Const, ImplPolarity, &'a TraitRef)>,
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
f: impl FnOnce(&mut Self),
) {
let old = mem::replace(
&mut self.in_trait_impl,
trait_ref.map(|(_, polarity, trait_ref)| (polarity, trait_ref)),
);
let old_const = mem::replace(
&mut self.in_const_trait_or_impl,
match trait_ref {
Some((Const::Yes(span), ..)) => Some(span),
_ => None,
},
&mut self.outer_trait_or_impl,
trait_.map(|trait_| TraitOrImpl::Impl { trait_: Some(trait_) }),
);
f(self);
self.in_trait_impl = old;
self.in_const_trait_or_impl = old_const;
self.outer_trait_or_impl = old;
}

fn with_in_trait(&mut self, span: Span, is_const: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const);
let old_trait = mem::replace(&mut self.in_trait, Some(span));
fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(
&mut self.outer_trait_or_impl,
Some(TraitOrImpl::Trait { span, constness }),
);
f(self);
self.in_const_trait_or_impl = old;
self.in_trait = old_trait;
self.outer_trait_or_impl = old;
}

fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
Expand Down Expand Up @@ -307,36 +306,36 @@ impl<'a> AstValidator<'a> {
}
}

fn check_trait_fn_not_const(&self, constness: Const) {
fn check_trait_fn_not_const(&self, constness: Const, trait_or_impl: &TraitOrImpl<'a>) {
let Const::Yes(span) = constness else {
return;
};

let make_impl_const_sugg = if self.in_const_trait_or_impl.is_none()
&& let Some((ImplPolarity::Positive, trait_ref)) = self.in_trait_impl
&& self.features.const_trait_impl
let make_impl_const_sugg = if self.features.const_trait_impl
&& let TraitOrImpl::Impl { trait_: Some(trait_) } = trait_or_impl
&& let (Const::No, ImplPolarity::Positive, trait_ref) = trait_
{
Some(trait_ref.path.span.shrink_to_lo())
} else {
None
};

let make_trait_const_sugg = if self.in_const_trait_or_impl.is_none()
&& let Some(trait_) = self.in_trait
&& self.features.const_trait_impl
let make_trait_const_sugg = if self.features.const_trait_impl
&& let TraitOrImpl::Trait { span, constness: None } = trait_or_impl
{
Some(trait_.shrink_to_lo())
Some(span.shrink_to_lo())
} else {
None
};

let parent_constness = trait_or_impl.constness();
self.dcx().emit_err(errors::TraitFnConst {
span,
in_impl: self.in_trait_impl.is_some(),
const_context_label: self.in_const_trait_or_impl,
in_impl: matches!(trait_or_impl, TraitOrImpl::Impl { .. }),
const_context_label: parent_constness,
remove_const_sugg: (
self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span),
match self.in_const_trait_or_impl {
match parent_constness {
Some(_) => rustc_errors::Applicability::MachineApplicable,
None => rustc_errors::Applicability::MaybeIncorrect,
},
Expand Down Expand Up @@ -1391,10 +1390,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}

let tilde_const_allowed = matches!(
fk.header(),
Some(FnHeader { constness: ast::Const::Yes(_), .. })
) || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl.is_some());
let tilde_const_allowed =
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
&& self.outer_trait_or_impl.as_ref().and_then(TraitOrImpl::constness).is_some();

let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
Expand All @@ -1405,7 +1404,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_nomangle_item_asciionly(item.ident, item.span);
}

if ctxt == AssocCtxt::Trait || self.in_trait_impl.is_none() {
if self.outer_trait_or_impl.as_ref().is_some_and(TraitOrImpl::is_trait_or_trait_impl) {
self.check_defaultness(item.span, item.kind.defaultness());
}

Expand Down Expand Up @@ -1453,10 +1452,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
}

if ctxt == AssocCtxt::Trait || self.in_trait_impl.is_some() {
if let Some(trait_or_impl) = &self.outer_trait_or_impl
&& trait_or_impl.is_trait_or_trait_impl()
{
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_const(sig.header.constness, trait_or_impl);
}
}

Expand All @@ -1466,7 +1467,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {

match &item.kind {
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
if self.in_const_trait_or_impl.is_some()
if self.outer_trait_or_impl.as_ref().and_then(TraitOrImpl::constness).is_some()
|| ctxt == AssocCtxt::Trait
|| matches!(sig.header.constness, Const::Yes(_)) =>
{
Expand Down Expand Up @@ -1598,9 +1599,7 @@ pub fn check_crate(
session,
features,
extern_mod: None,
in_trait_impl: None,
in_const_trait_or_impl: None,
in_trait: None,
outer_trait_or_impl: None,
has_proc_macro_decls: false,
outer_impl_trait: None,
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
Expand Down

0 comments on commit 50d96c7

Please sign in to comment.