From c293af9b57a3eae2969d49f629b67bb3d88c1bf3 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak
Date: Wed, 26 Feb 2025 22:04:51 +0000
Subject: [PATCH 10/15] Spruce up `AttributeKind` docs
- Remove dead link to `rustc_attr` crate.
- Add link to `rustc_attr_parsing` crate.
- Split up first paragraph so it looks better at crate-level summary
---
.../rustc_attr_data_structures/src/attributes.rs | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 9ac8de0227d79..d2d1285b0756f 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -138,13 +138,14 @@ impl Deprecation {
}
}
-/// Attributes represent parsed, *built in*, inert attributes. That means,
-/// attributes that are not actually ever expanded.
-/// For more information on this, see the module docs on the rustc_attr_parsing crate.
+/// Represent parsed, *built in*, inert attributes.
+///
+/// That means attributes that are not actually ever expanded.
+/// For more information on this, see the module docs on the [`rustc_attr_parsing`] crate.
/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler.
/// These are kept around after the AST, into the HIR and further on.
///
-/// The word parsed could be a little misleading here, because the parser already parses
+/// The word "parsed" could be a little misleading here, because the parser already parses
/// attributes early on. However, the result, an [`ast::Attribute`]
/// is only parsed at a high level, still containing a token stream in many cases. That is
/// because the structure of the contents varies from attribute to attribute.
@@ -153,7 +154,9 @@ impl Deprecation {
/// the place where `must_use` is checked) little to no extra parsing or validating needs to
/// happen.
///
-/// For more docs, look in [`rustc_attr`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_attr/index.html)
+/// For more docs, look in [`rustc_attr_parsing`].
+///
+/// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub enum AttributeKind {
// tidy-alphabetical-start
From a8364f3b2ad63c19037bdf060e49ad9ca07e16b6 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Thu, 19 Dec 2024 16:24:06 +1100
Subject: [PATCH 11/15] In `AssocOp::AssignOp`, use `BinOpKind` instead of
`BinOpToken`
`AssocOp::AssignOp` contains a `BinOpToken`. `ExprKind::AssignOp`
contains a `BinOpKind`. Given that `AssocOp` is basically a cut-down
version of `ExprKind`, it makes sense to make `AssocOp` more like
`ExprKind`. Especially given that `AssocOp` and `BinOpKind` use semantic
operation names (e.g. `Mul`, `Div`), but `BinOpToken` uses syntactic
names (e.g. `Star`, `Slash`).
This results in more concise code, and removes the need for various
conversions. (Note that the removed functions `hirbinop2assignop` and
`astbinop2assignop` are semantically identical, because `hir::BinOp` is
just a synonum for `ast::BinOp`!)
The only downside to this is that it allows the possibility of some
nonsensical combinations, such as `AssocOp::AssignOp(BinOpKind::Lt)`.
But `ExprKind::AssignOp` already has that problem. The problem can be
fixed for both types in the future with some effort, by introducing an
`AssignOpKind` type.
---
compiler/rustc_ast/src/util/parser.rs | 25 ++++++----
compiler/rustc_parse/src/parser/expr.rs | 16 +------
src/tools/clippy/clippy_utils/src/lib.rs | 1 -
src/tools/clippy/clippy_utils/src/sugg.rs | 58 ++---------------------
4 files changed, 23 insertions(+), 77 deletions(-)
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 8f2b7a23c01c8..69df9ff93b4f6 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -46,8 +46,8 @@ pub enum AssocOp {
GreaterEqual,
/// `=`
Assign,
- /// `?=` where ? is one of the BinOpToken
- AssignOp(BinOpToken),
+ /// `?=` where ? is one of the assignable BinOps
+ AssignOp(BinOpKind),
/// `as`
As,
/// `..` range
@@ -71,18 +71,27 @@ impl AssocOp {
pub fn from_token(t: &Token) -> Option {
use AssocOp::*;
match t.kind {
- token::BinOpEq(k) => Some(AssignOp(k)),
token::Eq => Some(Assign),
+ token::BinOpEq(BinOpToken::Plus) => Some(AssignOp(BinOpKind::Add)),
+ token::BinOpEq(BinOpToken::Minus) => Some(AssignOp(BinOpKind::Sub)),
+ token::BinOpEq(BinOpToken::Star) => Some(AssignOp(BinOpKind::Mul)),
+ token::BinOpEq(BinOpToken::Slash) => Some(AssignOp(BinOpKind::Div)),
+ token::BinOpEq(BinOpToken::Percent) => Some(AssignOp(BinOpKind::Rem)),
+ token::BinOpEq(BinOpToken::Caret) => Some(AssignOp(BinOpKind::BitXor)),
+ token::BinOpEq(BinOpToken::And) => Some(AssignOp(BinOpKind::BitAnd)),
+ token::BinOpEq(BinOpToken::Or) => Some(AssignOp(BinOpKind::BitOr)),
+ token::BinOpEq(BinOpToken::Shl) => Some(AssignOp(BinOpKind::Shl)),
+ token::BinOpEq(BinOpToken::Shr) => Some(AssignOp(BinOpKind::Shr)),
+ token::BinOp(BinOpToken::Plus) => Some(Add),
+ token::BinOp(BinOpToken::Minus) => Some(Subtract),
token::BinOp(BinOpToken::Star) => Some(Multiply),
token::BinOp(BinOpToken::Slash) => Some(Divide),
token::BinOp(BinOpToken::Percent) => Some(Modulus),
- token::BinOp(BinOpToken::Plus) => Some(Add),
- token::BinOp(BinOpToken::Minus) => Some(Subtract),
- token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
- token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
- token::BinOp(BinOpToken::And) => Some(BitAnd),
token::BinOp(BinOpToken::Caret) => Some(BitXor),
+ token::BinOp(BinOpToken::And) => Some(BitAnd),
token::BinOp(BinOpToken::Or) => Some(BitOr),
+ token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
+ token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
token::Lt => Some(Less),
token::Le => Some(LessEqual),
token::Ge => Some(GreaterEqual),
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index b2e58c9428064..935e13cedef82 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -313,19 +313,7 @@ impl<'a> Parser<'a> {
self.mk_expr(span, binary)
}
AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),
- AssocOp::AssignOp(k) => {
- let aop = match k {
- token::Plus => BinOpKind::Add,
- token::Minus => BinOpKind::Sub,
- token::Star => BinOpKind::Mul,
- token::Slash => BinOpKind::Div,
- token::Percent => BinOpKind::Rem,
- token::Caret => BinOpKind::BitXor,
- token::And => BinOpKind::BitAnd,
- token::Or => BinOpKind::BitOr,
- token::Shl => BinOpKind::Shl,
- token::Shr => BinOpKind::Shr,
- };
+ AssocOp::AssignOp(aop) => {
let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
self.mk_expr(span, aopexpr)
}
@@ -395,7 +383,7 @@ impl<'a> Parser<'a> {
AssocOp::ShiftRight
| AssocOp::Greater
| AssocOp::GreaterEqual
- | AssocOp::AssignOp(token::BinOpToken::Shr),
+ | AssocOp::AssignOp(BinOpKind::Shr),
),
_,
) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 7fc25e3617d07..f7266ef4d4ebb 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -31,7 +31,6 @@
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
extern crate rustc_abi;
extern crate rustc_ast;
-extern crate rustc_ast_pretty;
extern crate rustc_attr_parsing;
extern crate rustc_const_eval;
extern crate rustc_data_structures;
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index d5e0e2e3436e2..ff5bcba5adb8f 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -5,8 +5,7 @@ use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_wi
use crate::ty::expr_sig;
use crate::{get_parent_expr_for_hir, higher};
use rustc_ast::util::parser::AssocOp;
-use rustc_ast::{ast, token};
-use rustc_ast_pretty::pprust::token_kind_to_string;
+use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind};
@@ -158,7 +157,7 @@ impl<'a> Sugg<'a> {
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
},
ExprKind::AssignOp(op, lhs, rhs) => {
- Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span))
+ Sugg::BinOp(AssocOp::AssignOp(op.node), get_snippet(lhs.span), get_snippet(rhs.span))
},
ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp(
AssocOp::from_ast_binop(op.node),
@@ -245,7 +244,7 @@ impl<'a> Sugg<'a> {
snippet(rhs.span),
),
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
- astbinop2assignop(op),
+ AssocOp::AssignOp(op.node),
snippet(lhs.span),
snippet(rhs.span),
),
@@ -389,7 +388,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
},
AssocOp::Assign => format!("{lhs} = {rhs}"),
AssocOp::AssignOp(op) => {
- format!("{lhs} {}= {rhs}", token_kind_to_string(&token::BinOp(op)))
+ format!("{lhs} {}= {rhs}", op.as_str())
},
AssocOp::As => format!("{lhs} as {rhs}"),
AssocOp::DotDot => format!("{lhs}..{rhs}"),
@@ -619,55 +618,6 @@ fn associativity(op: AssocOp) -> Associativity {
}
}
-/// Converts a `hir::BinOp` to the corresponding assigning binary operator.
-fn hirbinop2assignop(op: hir::BinOp) -> AssocOp {
- use rustc_ast::token::BinOpToken::{And, Caret, Minus, Or, Percent, Plus, Shl, Shr, Slash, Star};
-
- AssocOp::AssignOp(match op.node {
- hir::BinOpKind::Add => Plus,
- hir::BinOpKind::BitAnd => And,
- hir::BinOpKind::BitOr => Or,
- hir::BinOpKind::BitXor => Caret,
- hir::BinOpKind::Div => Slash,
- hir::BinOpKind::Mul => Star,
- hir::BinOpKind::Rem => Percent,
- hir::BinOpKind::Shl => Shl,
- hir::BinOpKind::Shr => Shr,
- hir::BinOpKind::Sub => Minus,
-
- hir::BinOpKind::And
- | hir::BinOpKind::Eq
- | hir::BinOpKind::Ge
- | hir::BinOpKind::Gt
- | hir::BinOpKind::Le
- | hir::BinOpKind::Lt
- | hir::BinOpKind::Ne
- | hir::BinOpKind::Or => panic!("This operator does not exist"),
- })
-}
-
-/// Converts an `ast::BinOp` to the corresponding assigning binary operator.
-fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
- use rustc_ast::ast::BinOpKind::{
- Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub,
- };
- use rustc_ast::token::BinOpToken;
-
- AssocOp::AssignOp(match op.node {
- Add => BinOpToken::Plus,
- BitAnd => BinOpToken::And,
- BitOr => BinOpToken::Or,
- BitXor => BinOpToken::Caret,
- Div => BinOpToken::Slash,
- Mul => BinOpToken::Star,
- Rem => BinOpToken::Percent,
- Shl => BinOpToken::Shl,
- Shr => BinOpToken::Shr,
- Sub => BinOpToken::Minus,
- And | Eq | Ge | Gt | Le | Lt | Ne | Or => panic!("This operator does not exist"),
- })
-}
-
/// Returns the indentation before `span` if there are nothing but `[ \t]`
/// before it on its line.
fn indentation(cx: &T, span: Span) -> Option {
From ceafbad81fcf71423d4dc7a90fe962bc5895b108 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Thu, 19 Dec 2024 18:24:07 +1100
Subject: [PATCH 12/15] Introduce `AssocOp::Binary`.
It mirrors `ExprKind::Binary`, and contains a `BinOpKind`. This makes
`AssocOp` more like `ExprKind`. Note that the variants removed from
`AssocOp` are all named differently to `BinOpToken`, e.g. `Multiply`
instead of `Mul`, so that's an inconsistency removed.
The commit adds `precedence` and `fixity` methods to `BinOpKind`, and
calls them from the corresponding methods in `AssocOp`. This avoids the
need to create an `AssocOp` from a `BinOpKind` in a bunch of places, and
`AssocOp::from_ast_binop` is removed.
`AssocOp::to_ast_binop` is also no longer needed.
Overall things are shorter and nicer.
---
compiler/rustc_ast/src/ast.rs | 35 +++-
compiler/rustc_ast/src/util/parser.rs | 182 ++++--------------
.../rustc_ast_pretty/src/pprust/state/expr.rs | 7 +-
compiler/rustc_hir/src/hir.rs | 4 +-
compiler/rustc_hir_pretty/src/lib.rs | 7 +-
compiler/rustc_middle/src/ty/print/pretty.rs | 5 +-
.../rustc_parse/src/parser/diagnostics.rs | 36 ++--
compiler/rustc_parse/src/parser/expr.rs | 61 ++----
.../operators/float_equality_without_abs.rs | 2 +-
src/tools/clippy/clippy_utils/src/sugg.rs | 69 +++----
10 files changed, 152 insertions(+), 256 deletions(-)
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 29c1d34a125a4..65dd0a34aecad 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -39,7 +39,7 @@ pub use crate::format::*;
use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
-use crate::util::parser::{AssocOp, ExprPrecedence};
+use crate::util::parser::{ExprPrecedence, Fixity};
/// A "Label" is an identifier of some point in sources,
/// e.g. in the following code:
@@ -937,8 +937,37 @@ impl BinOpKind {
matches!(self, BinOpKind::And | BinOpKind::Or)
}
+ pub fn precedence(&self) -> ExprPrecedence {
+ use BinOpKind::*;
+ match *self {
+ Mul | Div | Rem => ExprPrecedence::Product,
+ Add | Sub => ExprPrecedence::Sum,
+ Shl | Shr => ExprPrecedence::Shift,
+ BitAnd => ExprPrecedence::BitAnd,
+ BitXor => ExprPrecedence::BitXor,
+ BitOr => ExprPrecedence::BitOr,
+ Lt | Gt | Le | Ge | Eq | Ne => ExprPrecedence::Compare,
+ And => ExprPrecedence::LAnd,
+ Or => ExprPrecedence::LOr,
+ }
+ }
+
+ pub fn fixity(&self) -> Fixity {
+ use BinOpKind::*;
+ match self {
+ Eq | Ne | Lt | Le | Gt | Ge => Fixity::None,
+ Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => {
+ Fixity::Left
+ }
+ }
+ }
+
pub fn is_comparison(self) -> bool {
- crate::util::parser::AssocOp::from_ast_binop(self).is_comparison()
+ use BinOpKind::*;
+ match self {
+ Eq | Ne | Lt | Le | Gt | Ge => true,
+ Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => false,
+ }
}
/// Returns `true` if the binary operator takes its arguments by value.
@@ -1332,7 +1361,7 @@ impl Expr {
ExprKind::Range(..) => ExprPrecedence::Range,
// Binop-like expr kinds, handled by `AssocOp`.
- ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(),
+ ExprKind::Binary(op, ..) => op.node.precedence(),
ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::Assign(..) |
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 69df9ff93b4f6..e7c26aa30928a 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -3,51 +3,15 @@ use rustc_span::kw;
use crate::ast::{self, BinOpKind};
use crate::token::{self, BinOpToken, Token};
-/// Associative operator with precedence.
-///
-/// This is the enum which specifies operator precedence and fixity to the parser.
+/// Associative operator.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AssocOp {
- /// `+`
- Add,
- /// `-`
- Subtract,
- /// `*`
- Multiply,
- /// `/`
- Divide,
- /// `%`
- Modulus,
- /// `&&`
- LAnd,
- /// `||`
- LOr,
- /// `^`
- BitXor,
- /// `&`
- BitAnd,
- /// `|`
- BitOr,
- /// `<<`
- ShiftLeft,
- /// `>>`
- ShiftRight,
- /// `==`
- Equal,
- /// `<`
- Less,
- /// `<=`
- LessEqual,
- /// `!=`
- NotEqual,
- /// `>`
- Greater,
- /// `>=`
- GreaterEqual,
- /// `=`
- Assign,
+ /// A binary op.
+ Binary(BinOpKind),
/// `?=` where ? is one of the assignable BinOps
AssignOp(BinOpKind),
+ /// `=`
+ Assign,
/// `as`
As,
/// `..` range
@@ -67,11 +31,21 @@ pub enum Fixity {
}
impl AssocOp {
- /// Creates a new AssocOP from a token
+ /// Creates a new AssocOp from a token.
pub fn from_token(t: &Token) -> Option {
use AssocOp::*;
match t.kind {
token::Eq => Some(Assign),
+ token::BinOp(BinOpToken::Plus) => Some(Binary(BinOpKind::Add)),
+ token::BinOp(BinOpToken::Minus) => Some(Binary(BinOpKind::Sub)),
+ token::BinOp(BinOpToken::Star) => Some(Binary(BinOpKind::Mul)),
+ token::BinOp(BinOpToken::Slash) => Some(Binary(BinOpKind::Div)),
+ token::BinOp(BinOpToken::Percent) => Some(Binary(BinOpKind::Rem)),
+ token::BinOp(BinOpToken::Caret) => Some(Binary(BinOpKind::BitXor)),
+ token::BinOp(BinOpToken::And) => Some(Binary(BinOpKind::BitAnd)),
+ token::BinOp(BinOpToken::Or) => Some(Binary(BinOpKind::BitOr)),
+ token::BinOp(BinOpToken::Shl) => Some(Binary(BinOpKind::Shl)),
+ token::BinOp(BinOpToken::Shr) => Some(Binary(BinOpKind::Shr)),
token::BinOpEq(BinOpToken::Plus) => Some(AssignOp(BinOpKind::Add)),
token::BinOpEq(BinOpToken::Minus) => Some(AssignOp(BinOpKind::Sub)),
token::BinOpEq(BinOpToken::Star) => Some(AssignOp(BinOpKind::Mul)),
@@ -82,74 +56,31 @@ impl AssocOp {
token::BinOpEq(BinOpToken::Or) => Some(AssignOp(BinOpKind::BitOr)),
token::BinOpEq(BinOpToken::Shl) => Some(AssignOp(BinOpKind::Shl)),
token::BinOpEq(BinOpToken::Shr) => Some(AssignOp(BinOpKind::Shr)),
- token::BinOp(BinOpToken::Plus) => Some(Add),
- token::BinOp(BinOpToken::Minus) => Some(Subtract),
- token::BinOp(BinOpToken::Star) => Some(Multiply),
- token::BinOp(BinOpToken::Slash) => Some(Divide),
- token::BinOp(BinOpToken::Percent) => Some(Modulus),
- token::BinOp(BinOpToken::Caret) => Some(BitXor),
- token::BinOp(BinOpToken::And) => Some(BitAnd),
- token::BinOp(BinOpToken::Or) => Some(BitOr),
- token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
- token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
- token::Lt => Some(Less),
- token::Le => Some(LessEqual),
- token::Ge => Some(GreaterEqual),
- token::Gt => Some(Greater),
- token::EqEq => Some(Equal),
- token::Ne => Some(NotEqual),
- token::AndAnd => Some(LAnd),
- token::OrOr => Some(LOr),
+ token::Lt => Some(Binary(BinOpKind::Lt)),
+ token::Le => Some(Binary(BinOpKind::Le)),
+ token::Ge => Some(Binary(BinOpKind::Ge)),
+ token::Gt => Some(Binary(BinOpKind::Gt)),
+ token::EqEq => Some(Binary(BinOpKind::Eq)),
+ token::Ne => Some(Binary(BinOpKind::Ne)),
+ token::AndAnd => Some(Binary(BinOpKind::And)),
+ token::OrOr => Some(Binary(BinOpKind::Or)),
token::DotDot => Some(DotDot),
token::DotDotEq => Some(DotDotEq),
// DotDotDot is no longer supported, but we need some way to display the error
token::DotDotDot => Some(DotDotEq),
// `<-` should probably be `< -`
- token::LArrow => Some(Less),
+ token::LArrow => Some(Binary(BinOpKind::Lt)),
_ if t.is_keyword(kw::As) => Some(As),
_ => None,
}
}
- /// Creates a new AssocOp from ast::BinOpKind.
- pub fn from_ast_binop(op: BinOpKind) -> Self {
- use AssocOp::*;
- match op {
- BinOpKind::Lt => Less,
- BinOpKind::Gt => Greater,
- BinOpKind::Le => LessEqual,
- BinOpKind::Ge => GreaterEqual,
- BinOpKind::Eq => Equal,
- BinOpKind::Ne => NotEqual,
- BinOpKind::Mul => Multiply,
- BinOpKind::Div => Divide,
- BinOpKind::Rem => Modulus,
- BinOpKind::Add => Add,
- BinOpKind::Sub => Subtract,
- BinOpKind::Shl => ShiftLeft,
- BinOpKind::Shr => ShiftRight,
- BinOpKind::BitAnd => BitAnd,
- BinOpKind::BitXor => BitXor,
- BinOpKind::BitOr => BitOr,
- BinOpKind::And => LAnd,
- BinOpKind::Or => LOr,
- }
- }
-
/// Gets the precedence of this operator
pub fn precedence(&self) -> ExprPrecedence {
use AssocOp::*;
match *self {
As => ExprPrecedence::Cast,
- Multiply | Divide | Modulus => ExprPrecedence::Product,
- Add | Subtract => ExprPrecedence::Sum,
- ShiftLeft | ShiftRight => ExprPrecedence::Shift,
- BitAnd => ExprPrecedence::BitAnd,
- BitXor => ExprPrecedence::BitXor,
- BitOr => ExprPrecedence::BitOr,
- Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => ExprPrecedence::Compare,
- LAnd => ExprPrecedence::LAnd,
- LOr => ExprPrecedence::LOr,
+ Binary(bin_op) => bin_op.precedence(),
DotDot | DotDotEq => ExprPrecedence::Range,
Assign | AssignOp(_) => ExprPrecedence::Assign,
}
@@ -161,22 +92,17 @@ impl AssocOp {
// NOTE: it is a bug to have an operators that has same precedence but different fixities!
match *self {
Assign | AssignOp(_) => Fixity::Right,
- As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
- | BitXor | BitOr | LAnd | LOr => Fixity::Left,
- Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | DotDot | DotDotEq => {
- Fixity::None
- }
+ Binary(binop) => binop.fixity(),
+ As => Fixity::Left,
+ DotDot | DotDotEq => Fixity::None,
}
}
pub fn is_comparison(&self) -> bool {
use AssocOp::*;
match *self {
- Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
- Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
- | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq => {
- false
- }
+ Binary(binop) => binop.is_comparison(),
+ Assign | AssignOp(_) | As | DotDot | DotDotEq => false,
}
}
@@ -184,34 +110,7 @@ impl AssocOp {
use AssocOp::*;
match *self {
Assign | AssignOp(_) => true,
- Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply
- | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor
- | BitOr | LAnd | LOr | DotDot | DotDotEq => false,
- }
- }
-
- pub fn to_ast_binop(&self) -> Option {
- use AssocOp::*;
- match *self {
- Less => Some(BinOpKind::Lt),
- Greater => Some(BinOpKind::Gt),
- LessEqual => Some(BinOpKind::Le),
- GreaterEqual => Some(BinOpKind::Ge),
- Equal => Some(BinOpKind::Eq),
- NotEqual => Some(BinOpKind::Ne),
- Multiply => Some(BinOpKind::Mul),
- Divide => Some(BinOpKind::Div),
- Modulus => Some(BinOpKind::Rem),
- Add => Some(BinOpKind::Add),
- Subtract => Some(BinOpKind::Sub),
- ShiftLeft => Some(BinOpKind::Shl),
- ShiftRight => Some(BinOpKind::Shr),
- BitAnd => Some(BinOpKind::BitAnd),
- BitXor => Some(BinOpKind::BitXor),
- BitOr => Some(BinOpKind::BitOr),
- LAnd => Some(BinOpKind::And),
- LOr => Some(BinOpKind::Or),
- Assign | AssignOp(_) | As | DotDot | DotDotEq => None,
+ As | Binary(_) | DotDot | DotDotEq => false,
}
}
@@ -221,16 +120,19 @@ impl AssocOp {
/// parentheses while having a high degree of confidence on the correctness of the suggestion.
pub fn can_continue_expr_unambiguously(&self) -> bool {
use AssocOp::*;
+ use BinOpKind::*;
matches!(
self,
- BitXor | // `{ 42 } ^ 3`
Assign | // `{ 42 } = { 42 }`
- Divide | // `{ 42 } / 42`
- Modulus | // `{ 42 } % 2`
- ShiftRight | // `{ 42 } >> 2`
- LessEqual | // `{ 42 } <= 3`
- Greater | // `{ 42 } > 3`
- GreaterEqual | // `{ 42 } >= 3`
+ Binary(
+ BitXor | // `{ 42 } ^ 3`
+ Div | // `{ 42 } / 42`
+ Rem | // `{ 42 } % 2`
+ Shr | // `{ 42 } >> 2`
+ Le | // `{ 42 } <= 3`
+ Gt | // `{ 42 } > 3`
+ Ge // `{ 42 } >= 3`
+ ) |
AssignOp(_) | // `{ 42 } +=`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 4b1374ceef31e..496323a35b8d9 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -5,7 +5,7 @@ use itertools::{Itertools, Position};
use rustc_ast::ptr::P;
use rustc_ast::util::classify;
use rustc_ast::util::literal::escape_byte_str_symbol;
-use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity};
+use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
use rustc_ast::{
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
FormatDebugHex, FormatSign, FormatTrait, token,
@@ -279,12 +279,11 @@ impl<'a> State<'a> {
rhs: &ast::Expr,
fixup: FixupContext,
) {
- let assoc_op = AssocOp::from_ast_binop(op.node);
- let binop_prec = assoc_op.precedence();
+ let binop_prec = op.node.precedence();
let left_prec = lhs.precedence();
let right_prec = rhs.precedence();
- let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() {
+ let (mut left_needs_paren, right_needs_paren) = match op.node.fixity() {
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index f0eaec55dbdd3..3c75bc588a138 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -4,7 +4,7 @@ use std::fmt;
use rustc_abi::ExternAbi;
use rustc_ast::attr::AttributeExt;
use rustc_ast::token::CommentKind;
-use rustc_ast::util::parser::{AssocOp, ExprPrecedence};
+use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::{
self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType,
LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind,
@@ -2124,7 +2124,7 @@ impl Expr<'_> {
| ExprKind::Become(..) => ExprPrecedence::Jump,
// Binop-like expr kinds, handled by `AssocOp`.
- ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(),
+ ExprKind::Binary(op, ..) => op.node.precedence(),
ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::Assign(..) |
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 5c7426d76b31c..b3377b487694b 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -10,7 +10,7 @@ use std::cell::Cell;
use std::vec;
use rustc_abi::ExternAbi;
-use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity};
+use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
use rustc_ast::{AttrStyle, DUMMY_NODE_ID, DelimArgs};
use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
use rustc_ast_pretty::pp::{self, Breaks};
@@ -1296,12 +1296,11 @@ impl<'a> State<'a> {
}
fn print_expr_binary(&mut self, op: hir::BinOp, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) {
- let assoc_op = AssocOp::from_ast_binop(op.node);
- let binop_prec = assoc_op.precedence();
+ let binop_prec = op.node.precedence();
let left_prec = lhs.precedence();
let right_prec = rhs.precedence();
- let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() {
+ let (mut left_needs_paren, right_needs_paren) = match op.node.fixity() {
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ed0839f47e696..4a4e4a8c33d8b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1516,10 +1516,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
ty::ExprKind::Binop(op) => {
let (_, _, c1, c2) = expr.binop_args();
- let precedence = |binop: crate::mir::BinOp| {
- use rustc_ast::util::parser::AssocOp;
- AssocOp::from_ast_binop(binop.to_hir_binop()).precedence()
- };
+ let precedence = |binop: crate::mir::BinOp| binop.to_hir_binop().precedence();
let op_precedence = precedence(op);
let formatted_op = op.to_hir_binop().as_str();
let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 67abc2d539401..b35a57ae49299 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1350,13 +1350,13 @@ impl<'a> Parser<'a> {
}
return match (op.node, &outer_op.node) {
// `x == y == z`
- (BinOpKind::Eq, AssocOp::Equal) |
+ (BinOpKind::Eq, AssocOp::Binary(BinOpKind::Eq)) |
// `x < y < z` and friends.
- (BinOpKind::Lt, AssocOp::Less | AssocOp::LessEqual) |
- (BinOpKind::Le, AssocOp::LessEqual | AssocOp::Less) |
+ (BinOpKind::Lt, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
+ (BinOpKind::Le, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
// `x > y > z` and friends.
- (BinOpKind::Gt, AssocOp::Greater | AssocOp::GreaterEqual) |
- (BinOpKind::Ge, AssocOp::GreaterEqual | AssocOp::Greater) => {
+ (BinOpKind::Gt, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) |
+ (BinOpKind::Ge, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) => {
let expr_to_str = |e: &Expr| {
self.span_to_snippet(e.span)
.unwrap_or_else(|_| pprust::expr_to_string(e))
@@ -1368,7 +1368,10 @@ impl<'a> Parser<'a> {
false // Keep the current parse behavior, where the AST is `(x < y) < z`.
}
// `x == y < z`
- (BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => {
+ (
+ BinOpKind::Eq,
+ AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge)
+ ) => {
// Consume `z`/outer-op-rhs.
let snapshot = self.create_snapshot_for_diagnostic();
match self.parse_expr() {
@@ -1389,7 +1392,10 @@ impl<'a> Parser<'a> {
}
}
// `x > y == z`
- (BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, AssocOp::Equal) => {
+ (
+ BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge,
+ AssocOp::Binary(BinOpKind::Eq)
+ ) => {
let snapshot = self.create_snapshot_for_diagnostic();
// At this point it is always valid to enclose the lhs in parentheses, no
// further checks are necessary.
@@ -1457,10 +1463,10 @@ impl<'a> Parser<'a> {
// Include `<` to provide this recommendation even in a case like
// `Foo>>`
- if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Less
- || outer_op.node == AssocOp::Greater
+ if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Binary(BinOpKind::Lt)
+ || outer_op.node == AssocOp::Binary(BinOpKind::Gt)
{
- if outer_op.node == AssocOp::Less {
+ if outer_op.node == AssocOp::Binary(BinOpKind::Lt) {
let snapshot = self.create_snapshot_for_diagnostic();
self.bump();
// So far we have parsed `foo Parser<'a> {
) -> PResult<'a, GenericArg> {
let is_op_or_dot = AssocOp::from_token(&self.token)
.and_then(|op| {
- if let AssocOp::Greater
- | AssocOp::Less
- | AssocOp::ShiftRight
- | AssocOp::GreaterEqual
+ if let AssocOp::Binary(
+ BinOpKind::Gt
+ | BinOpKind::Lt
+ | BinOpKind::Shr
+ | BinOpKind::Ge
+ )
// Don't recover from `foo::`, because this could be an attempt to
// assign a value to a defaulted generic parameter.
| AssocOp::Assign
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 935e13cedef82..00a5f2fa28fbc 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -188,17 +188,12 @@ impl<'a> Parser<'a> {
}
// Look for JS' `===` and `!==` and recover
- if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual)
+ if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node
&& self.token == token::Eq
&& self.prev_token.span.hi() == self.token.span.lo()
{
let sp = op.span.to(self.token.span);
- let sugg = match op.node {
- AssocOp::Equal => "==",
- AssocOp::NotEqual => "!=",
- _ => unreachable!(),
- }
- .into();
+ let sugg = bop.as_str().into();
let invalid = format!("{sugg}=");
self.dcx().emit_err(errors::InvalidComparisonOperator {
span: sp,
@@ -213,7 +208,7 @@ impl<'a> Parser<'a> {
}
// Look for PHP's `<>` and recover
- if op.node == AssocOp::Less
+ if op.node == AssocOp::Binary(BinOpKind::Lt)
&& self.token == token::Gt
&& self.prev_token.span.hi() == self.token.span.lo()
{
@@ -231,7 +226,7 @@ impl<'a> Parser<'a> {
}
// Look for C++'s `<=>` and recover
- if op.node == AssocOp::LessEqual
+ if op.node == AssocOp::Binary(BinOpKind::Le)
&& self.token == token::Gt
&& self.prev_token.span.hi() == self.token.span.lo()
{
@@ -290,25 +285,7 @@ impl<'a> Parser<'a> {
let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
lhs = match op {
- AssocOp::Add
- | AssocOp::Subtract
- | AssocOp::Multiply
- | AssocOp::Divide
- | AssocOp::Modulus
- | AssocOp::LAnd
- | AssocOp::LOr
- | AssocOp::BitXor
- | AssocOp::BitAnd
- | AssocOp::BitOr
- | AssocOp::ShiftLeft
- | AssocOp::ShiftRight
- | AssocOp::Equal
- | AssocOp::Less
- | AssocOp::LessEqual
- | AssocOp::NotEqual
- | AssocOp::Greater
- | AssocOp::GreaterEqual => {
- let ast_op = op.to_ast_binop().unwrap();
+ AssocOp::Binary(ast_op) => {
let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
self.mk_expr(span, binary)
}
@@ -335,13 +312,14 @@ impl<'a> Parser<'a> {
// An exhaustive check is done in the following block, but these are checked first
// because they *are* ambiguous but also reasonable looking incorrect syntax, so we
// want to keep their span info to improve diagnostics in these cases in a later stage.
- (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
- (true, Some(AssocOp::Subtract)) | // `{ 42 } -5`
- (true, Some(AssocOp::Add)) | // `{ 42 } + 42` (unary plus)
- (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
- (true, Some(AssocOp::LOr)) | // `{ 42 } || 42` ("logical or" or closure)
- (true, Some(AssocOp::BitOr)) // `{ 42 } | 42` or `{ 42 } |x| 42`
- => {
+ (true, Some(AssocOp::Binary(
+ BinOpKind::Mul | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
+ BinOpKind::Sub | // `{ 42 } -5`
+ BinOpKind::Add | // `{ 42 } + 42` (unary plus)
+ BinOpKind::And | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+ BinOpKind::Or | // `{ 42 } || 42` ("logical or" or closure)
+ BinOpKind::BitOr // `{ 42 } | 42` or `{ 42 } |x| 42`
+ ))) => {
// These cases are ambiguous and can't be identified in the parser alone.
//
// Bitwise AND is left out because guessing intent is hard. We can make
@@ -380,21 +358,20 @@ impl<'a> Parser<'a> {
// When parsing const expressions, stop parsing when encountering `>`.
(
Some(
- AssocOp::ShiftRight
- | AssocOp::Greater
- | AssocOp::GreaterEqual
+ AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
| AssocOp::AssignOp(BinOpKind::Shr),
),
_,
) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
return None;
}
- // When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`.
+ // When recovering patterns as expressions, stop parsing when encountering an
+ // assignment `=`, an alternative `|`, or a range `..`.
(
Some(
AssocOp::Assign
| AssocOp::AssignOp(_)
- | AssocOp::BitOr
+ | AssocOp::Binary(BinOpKind::BitOr)
| AssocOp::DotDot
| AssocOp::DotDotEq,
),
@@ -411,7 +388,7 @@ impl<'a> Parser<'a> {
incorrect: "and".into(),
sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span),
});
- (AssocOp::LAnd, span)
+ (AssocOp::Binary(BinOpKind::And), span)
}
(None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {
self.dcx().emit_err(errors::InvalidLogicalOperator {
@@ -419,7 +396,7 @@ impl<'a> Parser<'a> {
incorrect: "or".into(),
sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span),
});
- (AssocOp::LOr, span)
+ (AssocOp::Binary(BinOpKind::Or), span)
}
_ => return None,
};
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
index 34f7dbea84e49..74e0a6333db0f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
@@ -50,7 +50,7 @@ pub(crate) fn check<'tcx>(
// format the suggestion
let suggestion = format!(
"{}.abs()",
- sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()
+ sugg::make_assoc(AssocOp::Binary(BinOpKind::Sub), &sug_l, &sug_r).maybe_par()
);
// spans the lint
span_lint_and_then(
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index ff5bcba5adb8f..6e16778b343de 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -160,7 +160,7 @@ impl<'a> Sugg<'a> {
Sugg::BinOp(AssocOp::AssignOp(op.node), get_snippet(lhs.span), get_snippet(rhs.span))
},
ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp(
- AssocOp::from_ast_binop(op.node),
+ AssocOp::Binary(op.node),
get_snippet(lhs.span),
get_snippet(rhs.span),
),
@@ -249,7 +249,7 @@ impl<'a> Sugg<'a> {
snippet(rhs.span),
),
ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
- AssocOp::from_ast_binop(op.node),
+ AssocOp::Binary(op.node),
snippet(lhs.span),
snippet(rhs.span),
),
@@ -366,30 +366,9 @@ impl<'a> Sugg<'a> {
/// Generates a string from the operator and both sides.
fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
match op {
- AssocOp::Add
- | AssocOp::Subtract
- | AssocOp::Multiply
- | AssocOp::Divide
- | AssocOp::Modulus
- | AssocOp::LAnd
- | AssocOp::LOr
- | AssocOp::BitXor
- | AssocOp::BitAnd
- | AssocOp::BitOr
- | AssocOp::ShiftLeft
- | AssocOp::ShiftRight
- | AssocOp::Equal
- | AssocOp::Less
- | AssocOp::LessEqual
- | AssocOp::NotEqual
- | AssocOp::Greater
- | AssocOp::GreaterEqual => {
- format!("{lhs} {} {rhs}", op.to_ast_binop().expect("Those are AST ops").as_str())
- },
+ AssocOp::Binary(op) => format!("{lhs} {} {rhs}", op.as_str()),
AssocOp::Assign => format!("{lhs} = {rhs}"),
- AssocOp::AssignOp(op) => {
- format!("{lhs} {}= {rhs}", op.as_str())
- },
+ AssocOp::AssignOp(op) => format!("{lhs} {}= {rhs}", op.as_str()),
AssocOp::As => format!("{lhs} as {rhs}"),
AssocOp::DotDot => format!("{lhs}..{rhs}"),
AssocOp::DotDotEq => format!("{lhs}..={rhs}"),
@@ -476,16 +455,17 @@ impl Neg for Sugg<'_> {
impl<'a> Not for Sugg<'a> {
type Output = Sugg<'a>;
fn not(self) -> Sugg<'a> {
- use AssocOp::{Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual};
+ use AssocOp::Binary;
+ use ast::BinOpKind::{Eq, Gt, Ge, Lt, Le, Ne};
if let Sugg::BinOp(op, lhs, rhs) = self {
let to_op = match op {
- Equal => NotEqual,
- NotEqual => Equal,
- Less => GreaterEqual,
- GreaterEqual => Less,
- Greater => LessEqual,
- LessEqual => Greater,
+ Binary(Eq) => Binary(Ne),
+ Binary(Ne) => Binary(Eq),
+ Binary(Lt) => Binary(Ge),
+ Binary(Ge) => Binary(Lt),
+ Binary(Gt) => Binary(Le),
+ Binary(Le) => Binary(Gt),
_ => return make_unop("!", Sugg::BinOp(op, lhs, rhs)),
};
Sugg::BinOp(to_op, lhs, rhs)
@@ -537,7 +517,7 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
/// Returns `true` if the operator is a shift operator `<<` or `>>`.
fn is_shift(op: AssocOp) -> bool {
- matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
+ matches!(op, AssocOp::Binary(ast::BinOpKind::Shl | ast::BinOpKind::Shr))
}
/// Returns `true` if the operator is an arithmetic operator
@@ -545,7 +525,13 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static>
fn is_arith(op: AssocOp) -> bool {
matches!(
op,
- AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus
+ AssocOp::Binary(
+ ast::BinOpKind::Add
+ | ast::BinOpKind::Sub
+ | ast::BinOpKind::Mul
+ | ast::BinOpKind::Div
+ | ast::BinOpKind::Rem
+ )
)
}
@@ -577,9 +563,9 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static>
Sugg::BinOp(op, lhs.into(), rhs.into())
}
-/// Convenience wrapper around `make_assoc` and `AssocOp::from_ast_binop`.
+/// Convenience wrapper around `make_assoc` and `AssocOp::Binary`.
pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
- make_assoc(AssocOp::from_ast_binop(op), lhs, rhs)
+ make_assoc(AssocOp::Binary(op), lhs, rhs)
}
#[derive(PartialEq, Eq, Clone, Copy)]
@@ -604,16 +590,15 @@ enum Associativity {
/// associative.
#[must_use]
fn associativity(op: AssocOp) -> Associativity {
- use rustc_ast::util::parser::AssocOp::{
- Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd,
- LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
+ use rustc_ast::util::parser::AssocOp::{As, Assign, AssignOp, Binary, DotDot, DotDotEq};
+ use ast::BinOpKind::{
+ Add, BitAnd, BitOr, BitXor, Div, Eq, Gt, Ge, And, Or, Lt, Le, Rem, Mul, Ne, Shl, Shr, Sub,
};
match op {
Assign | AssignOp(_) => Associativity::Right,
- Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As => Associativity::Both,
- Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight
- | Subtract => Associativity::Left,
+ Binary(Add | BitAnd | BitOr | BitXor | And | Or | Mul) | As => Associativity::Both,
+ Binary(Div | Eq | Gt | Ge | Lt | Le | Rem | Ne | Shl | Shr | Sub) => Associativity::Left,
DotDot | DotDotEq => Associativity::None,
}
}
From fc8e87b27418704316047eb15ff40382d8d847bc Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Thu, 19 Dec 2024 21:42:46 +1100
Subject: [PATCH 13/15] Replace `AssocOp::DotDot{,Eq}` with `AssocOp::Range`.
It makes `AssocOp` more similar to `ExprKind` and makes things a little
simpler. And the semantic names make more sense here than the syntactic
names.
---
compiler/rustc_ast/src/ast.rs | 9 +++++++
compiler/rustc_ast/src/util/parser.rs | 21 +++++++---------
compiler/rustc_parse/src/parser/expr.rs | 15 +++++-------
src/tools/clippy/clippy_utils/src/sugg.rs | 30 ++++++-----------------
4 files changed, 32 insertions(+), 43 deletions(-)
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 65dd0a34aecad..5c44fda226241 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1453,6 +1453,15 @@ pub enum RangeLimits {
Closed,
}
+impl RangeLimits {
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ RangeLimits::HalfOpen => "..",
+ RangeLimits::Closed => "..=",
+ }
+ }
+}
+
/// A method call (e.g. `x.foo::(a, b, c)`).
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct MethodCall {
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index e7c26aa30928a..c610f933074d6 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -1,6 +1,6 @@
use rustc_span::kw;
-use crate::ast::{self, BinOpKind};
+use crate::ast::{self, BinOpKind, RangeLimits};
use crate::token::{self, BinOpToken, Token};
/// Associative operator.
@@ -14,10 +14,8 @@ pub enum AssocOp {
Assign,
/// `as`
As,
- /// `..` range
- DotDot,
- /// `..=` range
- DotDotEq,
+ /// `..` or `..=` range
+ Range(RangeLimits),
}
#[derive(PartialEq, Debug)]
@@ -64,10 +62,9 @@ impl AssocOp {
token::Ne => Some(Binary(BinOpKind::Ne)),
token::AndAnd => Some(Binary(BinOpKind::And)),
token::OrOr => Some(Binary(BinOpKind::Or)),
- token::DotDot => Some(DotDot),
- token::DotDotEq => Some(DotDotEq),
+ token::DotDot => Some(Range(RangeLimits::HalfOpen)),
// DotDotDot is no longer supported, but we need some way to display the error
- token::DotDotDot => Some(DotDotEq),
+ token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)),
// `<-` should probably be `< -`
token::LArrow => Some(Binary(BinOpKind::Lt)),
_ if t.is_keyword(kw::As) => Some(As),
@@ -81,7 +78,7 @@ impl AssocOp {
match *self {
As => ExprPrecedence::Cast,
Binary(bin_op) => bin_op.precedence(),
- DotDot | DotDotEq => ExprPrecedence::Range,
+ Range(_) => ExprPrecedence::Range,
Assign | AssignOp(_) => ExprPrecedence::Assign,
}
}
@@ -94,7 +91,7 @@ impl AssocOp {
Assign | AssignOp(_) => Fixity::Right,
Binary(binop) => binop.fixity(),
As => Fixity::Left,
- DotDot | DotDotEq => Fixity::None,
+ Range(_) => Fixity::None,
}
}
@@ -102,7 +99,7 @@ impl AssocOp {
use AssocOp::*;
match *self {
Binary(binop) => binop.is_comparison(),
- Assign | AssignOp(_) | As | DotDot | DotDotEq => false,
+ Assign | AssignOp(_) | As | Range(_) => false,
}
}
@@ -110,7 +107,7 @@ impl AssocOp {
use AssocOp::*;
match *self {
Assign | AssignOp(_) => true,
- As | Binary(_) | DotDot | DotDotEq => false,
+ As | Binary(_) | Range(_) => false,
}
}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 00a5f2fa28fbc..50ce6fa1a906c 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -171,7 +171,7 @@ impl<'a> Parser<'a> {
break;
}
// Check for deprecated `...` syntax
- if self.token == token::DotDotDot && op.node == AssocOp::DotDotEq {
+ if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) {
self.err_dotdotdot_syntax(self.token.span);
}
@@ -267,10 +267,10 @@ impl<'a> Parser<'a> {
if op == AssocOp::As {
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
continue;
- } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
+ } else if let AssocOp::Range(limits) = op {
// If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
// generalise it to the Fixity::None code.
- lhs = self.parse_expr_range(prec, lhs, op, cur_op_span)?;
+ lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?;
break;
}
@@ -294,7 +294,7 @@ impl<'a> Parser<'a> {
let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
self.mk_expr(span, aopexpr)
}
- AssocOp::As | AssocOp::DotDot | AssocOp::DotDotEq => {
+ AssocOp::As | AssocOp::Range(_) => {
self.dcx().span_bug(span, "AssocOp should have been handled by special case")
}
};
@@ -372,8 +372,7 @@ impl<'a> Parser<'a> {
AssocOp::Assign
| AssocOp::AssignOp(_)
| AssocOp::Binary(BinOpKind::BitOr)
- | AssocOp::DotDot
- | AssocOp::DotDotEq,
+ | AssocOp::Range(_),
),
_,
) if self.restrictions.contains(Restrictions::IS_PAT) => {
@@ -414,7 +413,7 @@ impl<'a> Parser<'a> {
&mut self,
prec: ExprPrecedence,
lhs: P,
- op: AssocOp,
+ limits: RangeLimits,
cur_op_span: Span,
) -> PResult<'a, P> {
let rhs = if self.is_at_start_of_range_notation_rhs() {
@@ -430,8 +429,6 @@ impl<'a> Parser<'a> {
};
let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
- let limits =
- if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
let range = self.mk_range(Some(lhs), rhs, limits);
Ok(self.mk_expr(span, range))
}
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 6e16778b343de..fe5ae54fe50b8 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -113,10 +113,7 @@ impl<'a> Sugg<'a> {
/// function variants of `Sugg`, since these use different snippet functions.
fn hir_from_snippet(expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>) -> Self {
if let Some(range) = higher::Range::hir(expr) {
- let op = match range.limits {
- ast::RangeLimits::HalfOpen => AssocOp::DotDot,
- ast::RangeLimits::Closed => AssocOp::DotDotEq,
- };
+ let op = AssocOp::Range(range.limits);
let start = range.start.map_or("".into(), |expr| get_snippet(expr.span));
let end = range.end.map_or("".into(), |expr| get_snippet(expr.span));
@@ -178,8 +175,6 @@ impl<'a> Sugg<'a> {
ctxt: SyntaxContext,
app: &mut Applicability,
) -> Self {
- use rustc_ast::ast::RangeLimits;
-
let mut snippet = |span: Span| snippet_with_context(cx, span, ctxt, default, app).0;
match expr.kind {
@@ -228,13 +223,8 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::Err(_)
| ast::ExprKind::Dummy
| ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)),
- ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
- AssocOp::DotDot,
- lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),
- rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)),
- ),
- ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
- AssocOp::DotDotEq,
+ ast::ExprKind::Range(ref lhs, ref rhs, limits) => Sugg::BinOp(
+ AssocOp::Range(limits),
lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),
rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)),
),
@@ -326,11 +316,8 @@ impl<'a> Sugg<'a> {
/// Convenience method to create the `..` or `...`
/// suggestion.
- pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
- match limit {
- ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, end),
- ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotEq, &self, end),
- }
+ pub fn range(self, end: &Self, limits: ast::RangeLimits) -> Sugg<'static> {
+ make_assoc(AssocOp::Range(limits), &self, end)
}
/// Adds parentheses to any expression that might need them. Suitable to the
@@ -370,8 +357,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
AssocOp::Assign => format!("{lhs} = {rhs}"),
AssocOp::AssignOp(op) => format!("{lhs} {}= {rhs}", op.as_str()),
AssocOp::As => format!("{lhs} as {rhs}"),
- AssocOp::DotDot => format!("{lhs}..{rhs}"),
- AssocOp::DotDotEq => format!("{lhs}..={rhs}"),
+ AssocOp::Range(limits) => format!("{lhs}{}{rhs}", limits.as_str()),
}
}
@@ -590,7 +576,7 @@ enum Associativity {
/// associative.
#[must_use]
fn associativity(op: AssocOp) -> Associativity {
- use rustc_ast::util::parser::AssocOp::{As, Assign, AssignOp, Binary, DotDot, DotDotEq};
+ use rustc_ast::util::parser::AssocOp::{As, Assign, AssignOp, Binary, Range};
use ast::BinOpKind::{
Add, BitAnd, BitOr, BitXor, Div, Eq, Gt, Ge, And, Or, Lt, Le, Rem, Mul, Ne, Shl, Shr, Sub,
};
@@ -599,7 +585,7 @@ fn associativity(op: AssocOp) -> Associativity {
Assign | AssignOp(_) => Associativity::Right,
Binary(Add | BitAnd | BitOr | BitXor | And | Or | Mul) | As => Associativity::Both,
Binary(Div | Eq | Gt | Ge | Lt | Le | Rem | Ne | Shl | Shr | Sub) => Associativity::Left,
- DotDot | DotDotEq => Associativity::None,
+ Range(_) => Associativity::None,
}
}
From 2ac46f651789950b6bafabcd5621080c9ff649f7 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Thu, 19 Dec 2024 21:46:44 +1100
Subject: [PATCH 14/15] Rename `AssocOp::As` as `AssocOp::Cast`.
To match `ExprKind::Cast`, and because a semantic name makes more sense
here than a syntactic name.
---
compiler/rustc_ast/src/util/parser.rs | 14 +++++++-------
compiler/rustc_parse/src/parser/expr.rs | 4 ++--
src/tools/clippy/clippy_utils/src/sugg.rs | 14 +++++++-------
3 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index c610f933074d6..69454967eed62 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -13,7 +13,7 @@ pub enum AssocOp {
/// `=`
Assign,
/// `as`
- As,
+ Cast,
/// `..` or `..=` range
Range(RangeLimits),
}
@@ -67,7 +67,7 @@ impl AssocOp {
token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)),
// `<-` should probably be `< -`
token::LArrow => Some(Binary(BinOpKind::Lt)),
- _ if t.is_keyword(kw::As) => Some(As),
+ _ if t.is_keyword(kw::As) => Some(Cast),
_ => None,
}
}
@@ -76,7 +76,7 @@ impl AssocOp {
pub fn precedence(&self) -> ExprPrecedence {
use AssocOp::*;
match *self {
- As => ExprPrecedence::Cast,
+ Cast => ExprPrecedence::Cast,
Binary(bin_op) => bin_op.precedence(),
Range(_) => ExprPrecedence::Range,
Assign | AssignOp(_) => ExprPrecedence::Assign,
@@ -90,7 +90,7 @@ impl AssocOp {
match *self {
Assign | AssignOp(_) => Fixity::Right,
Binary(binop) => binop.fixity(),
- As => Fixity::Left,
+ Cast => Fixity::Left,
Range(_) => Fixity::None,
}
}
@@ -99,7 +99,7 @@ impl AssocOp {
use AssocOp::*;
match *self {
Binary(binop) => binop.is_comparison(),
- Assign | AssignOp(_) | As | Range(_) => false,
+ Assign | AssignOp(_) | Cast | Range(_) => false,
}
}
@@ -107,7 +107,7 @@ impl AssocOp {
use AssocOp::*;
match *self {
Assign | AssignOp(_) => true,
- As | Binary(_) | Range(_) => false,
+ Cast | Binary(_) | Range(_) => false,
}
}
@@ -133,7 +133,7 @@ impl AssocOp {
AssignOp(_) | // `{ 42 } +=`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
- As // `{ 42 } as usize`
+ Cast // `{ 42 } as usize`
)
}
}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 50ce6fa1a906c..c934c1e36d528 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -264,7 +264,7 @@ impl<'a> Parser<'a> {
let op = op.node;
// Special cases:
- if op == AssocOp::As {
+ if op == AssocOp::Cast {
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
continue;
} else if let AssocOp::Range(limits) = op {
@@ -294,7 +294,7 @@ impl<'a> Parser<'a> {
let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
self.mk_expr(span, aopexpr)
}
- AssocOp::As | AssocOp::Range(_) => {
+ AssocOp::Cast | AssocOp::Range(_) => {
self.dcx().span_bug(span, "AssocOp should have been handled by special case")
}
};
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index fe5ae54fe50b8..4a9ab17d4a609 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -163,7 +163,7 @@ impl<'a> Sugg<'a> {
),
ExprKind::Cast(lhs, ty) |
//FIXME(chenyukang), remove this after type ascription is removed from AST
- ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
+ ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::Cast, get_snippet(lhs.span), get_snippet(ty.span)),
}
}
@@ -246,7 +246,7 @@ impl<'a> Sugg<'a> {
ast::ExprKind::Cast(ref lhs, ref ty) |
//FIXME(chenyukang), remove this after type ascription is removed from AST
ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
- AssocOp::As,
+ AssocOp::Cast,
snippet(lhs.span),
snippet(ty.span),
),
@@ -265,7 +265,7 @@ impl<'a> Sugg<'a> {
/// Convenience method to create the ` as ` suggestion.
pub fn as_ty(self, rhs: R) -> Sugg<'static> {
- make_assoc(AssocOp::As, &self, &Sugg::NonParen(rhs.to_string().into()))
+ make_assoc(AssocOp::Cast, &self, &Sugg::NonParen(rhs.to_string().into()))
}
/// Convenience method to create the `&` suggestion.
@@ -356,7 +356,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
AssocOp::Binary(op) => format!("{lhs} {} {rhs}", op.as_str()),
AssocOp::Assign => format!("{lhs} = {rhs}"),
AssocOp::AssignOp(op) => format!("{lhs} {}= {rhs}", op.as_str()),
- AssocOp::As => format!("{lhs} as {rhs}"),
+ AssocOp::Cast => format!("{lhs} as {rhs}"),
AssocOp::Range(limits) => format!("{lhs}{}{rhs}", limits.as_str()),
}
}
@@ -432,7 +432,7 @@ impl Neg for Sugg<'_> {
type Output = Sugg<'static>;
fn neg(self) -> Sugg<'static> {
match &self {
- Self::BinOp(AssocOp::As, ..) => Sugg::MaybeParen(format!("-({self})").into()),
+ Self::BinOp(AssocOp::Cast, ..) => Sugg::MaybeParen(format!("-({self})").into()),
_ => make_unop("-", self),
}
}
@@ -576,14 +576,14 @@ enum Associativity {
/// associative.
#[must_use]
fn associativity(op: AssocOp) -> Associativity {
- use rustc_ast::util::parser::AssocOp::{As, Assign, AssignOp, Binary, Range};
+ use rustc_ast::util::parser::AssocOp::{Assign, AssignOp, Binary, Cast, Range};
use ast::BinOpKind::{
Add, BitAnd, BitOr, BitXor, Div, Eq, Gt, Ge, And, Or, Lt, Le, Rem, Mul, Ne, Shl, Shr, Sub,
};
match op {
Assign | AssignOp(_) => Associativity::Right,
- Binary(Add | BitAnd | BitOr | BitXor | And | Or | Mul) | As => Associativity::Both,
+ Binary(Add | BitAnd | BitOr | BitXor | And | Or | Mul) | Cast => Associativity::Both,
Binary(Div | Eq | Gt | Ge | Lt | Le | Rem | Ne | Shl | Shr | Sub) => Associativity::Left,
Range(_) => Associativity::None,
}
From ef66cbb27bc2a911edf4541e1c56102dc03e42d9 Mon Sep 17 00:00:00 2001
From: Deadbeef
Date: Fri, 7 Feb 2025 21:58:08 +0800
Subject: [PATCH 15/15] require trait impls to have matching const stabilities
as the traits
---
.../rustc_const_eval/src/check_consts/mod.rs | 5 ++
compiler/rustc_passes/messages.ftl | 6 ++
compiler/rustc_passes/src/errors.rs | 39 +++++++++++
compiler/rustc_passes/src/stability.rs | 60 ++++++++++++----
library/core/src/ops/arith.rs | 1 +
library/core/src/ops/deref.rs | 3 +
tests/ui/traits/const-traits/staged-api.rs | 32 +++++++++
.../ui/traits/const-traits/staged-api.stderr | 69 ++++++++++++++++++-
8 files changed, 200 insertions(+), 15 deletions(-)
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 659d4a304563e..607cb2e497d8d 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -94,6 +94,11 @@ pub fn rustc_allow_const_fn_unstable(
/// world into two functions: those that are safe to expose on stable (and hence may not use
/// unstable features, not even recursively), and those that are not.
pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ // A default body in a `#[const_trait]` is const-stable when the trait is const-stable.
+ if tcx.is_const_default_method(def_id) {
+ return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id));
+ }
+
match tcx.lookup_const_stability(def_id) {
None => {
// In a `staged_api` crate, we do enforce recursive const stability for all unmarked
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index bc43580a7f00d..b65430c348027 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -725,6 +725,12 @@ passes_target_feature_on_statement =
.warn = {-passes_previously_accepted}
.label = {passes_should_be_applied_to_fn.label}
+passes_trait_impl_const_stability_mismatch = const stability on the impl does not match the const stability on the trait
+passes_trait_impl_const_stability_mismatch_impl_stable = this impl is (implicitly) stable...
+passes_trait_impl_const_stability_mismatch_impl_unstable = this impl is unstable...
+passes_trait_impl_const_stability_mismatch_trait_stable = ...but the trait is stable
+passes_trait_impl_const_stability_mismatch_trait_unstable = ...but the trait is unstable
+
passes_trait_impl_const_stable =
trait implementations cannot be const stable yet
.note = see issue #67792 for more information
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 51b5861ee0ae6..9bb9b2353dc86 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1552,6 +1552,45 @@ pub(crate) struct TraitImplConstStable {
pub span: Span,
}
+#[derive(Diagnostic)]
+#[diag(passes_trait_impl_const_stability_mismatch)]
+pub(crate) struct TraitImplConstStabilityMismatch {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub impl_stability: ImplConstStability,
+ #[subdiagnostic]
+ pub trait_stability: TraitConstStability,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum TraitConstStability {
+ #[note(passes_trait_impl_const_stability_mismatch_trait_stable)]
+ Stable {
+ #[primary_span]
+ span: Span,
+ },
+ #[note(passes_trait_impl_const_stability_mismatch_trait_unstable)]
+ Unstable {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ImplConstStability {
+ #[note(passes_trait_impl_const_stability_mismatch_impl_stable)]
+ Stable {
+ #[primary_span]
+ span: Span,
+ },
+ #[note(passes_trait_impl_const_stability_mismatch_impl_unstable)]
+ Unstable {
+ #[primary_span]
+ span: Span,
+ },
+}
+
#[derive(Diagnostic)]
#[diag(passes_unknown_feature, code = E0635)]
pub(crate) struct UnknownFeature {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 8a4bdf3875c4b..0fcf6a80ec4de 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -313,7 +313,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
.map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect));
// If this is a const fn but not annotated with stability markers, see if we can inherit regular stability.
- if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
+ if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
// We only ever inherit unstable features.
let Some(inherit_regular_stab) =
final_stab.filter(|s| s.is_unstable())
@@ -826,24 +826,56 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
}
}
- // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
- // needs to have an error emitted.
if features.const_trait_impl()
- && self.tcx.is_const_trait_impl(item.owner_id.to_def_id())
- && const_stab.is_some_and(|stab| stab.is_const_stable())
+ && let hir::Constness::Const = constness
{
- self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });
+ let stable_or_implied_stable = match const_stab {
+ None => true,
+ Some(stab) if stab.is_const_stable() => {
+ // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
+ // needs to have an error emitted.
+ // Note: Remove this error once `const_trait_impl` is stabilized
+ self.tcx
+ .dcx()
+ .emit_err(errors::TraitImplConstStable { span: item.span });
+ true
+ }
+ Some(_) => false,
+ };
+
+ if let Some(trait_id) = t.trait_def_id()
+ && let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
+ {
+ // the const stability of a trait impl must match the const stability on the trait.
+ if const_stab.is_const_stable() != stable_or_implied_stable {
+ let trait_span = self.tcx.def_ident_span(trait_id).unwrap();
+
+ let impl_stability = if stable_or_implied_stable {
+ errors::ImplConstStability::Stable { span: item.span }
+ } else {
+ errors::ImplConstStability::Unstable { span: item.span }
+ };
+ let trait_stability = if const_stab.is_const_stable() {
+ errors::TraitConstStability::Stable { span: trait_span }
+ } else {
+ errors::TraitConstStability::Unstable { span: trait_span }
+ };
+
+ self.tcx.dcx().emit_err(errors::TraitImplConstStabilityMismatch {
+ span: item.span,
+ impl_stability,
+ trait_stability,
+ });
+ }
+ }
}
}
- match constness {
- rustc_hir::Constness::Const => {
- if let Some(def_id) = t.trait_def_id() {
- // FIXME(const_trait_impl): Improve the span here.
- self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
- }
- }
- rustc_hir::Constness::NotConst => {}
+ if let hir::Constness::Const = constness
+ && let Some(def_id) = t.trait_def_id()
+ {
+ // FIXME(const_trait_impl): Improve the span here.
+ self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
}
for impl_item_ref in *items {
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index fe7ff2d9ede6a..54d79beca95ab 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -96,6 +96,7 @@ pub trait Add {
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Add for $t {
type Output = $t;
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index 11490ea2bfcb4..e74f5443ac2d8 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -150,6 +150,7 @@ pub trait Deref {
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl const Deref for &T {
type Target = T;
@@ -163,6 +164,7 @@ impl const Deref for &T {
impl !DerefMut for &T {}
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl const Deref for &mut T {
type Target = T;
@@ -273,6 +275,7 @@ pub trait DerefMut: ~const Deref {
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl const DerefMut for &mut T {
fn deref_mut(&mut self) -> &mut T {
*self
diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs
index 9a030dafd6bc4..8dd7226fc298e 100644
--- a/tests/ui/traits/const-traits/staged-api.rs
+++ b/tests/ui/traits/const-traits/staged-api.rs
@@ -85,4 +85,36 @@ const fn implicitly_stable_const_context() {
//~^ ERROR cannot use `#[feature(const_trait_impl)]`
}
+// check that const stability of impls and traits must match
+#[const_trait]
+#[rustc_const_unstable(feature = "beef", issue = "none")]
+trait U {}
+
+#[const_trait]
+#[rustc_const_stable(since = "0.0.0", feature = "beef2")]
+trait S {}
+
+// implied stable
+impl const U for u8 {}
+//~^ const stability on the impl does not match the const stability on the trait
+
+#[rustc_const_stable(since = "0.0.0", feature = "beef2")]
+impl const U for u16 {}
+//~^ const stability on the impl does not match the const stability on the trait
+//~| trait implementations cannot be const stable yet
+
+#[rustc_const_unstable(feature = "beef", issue = "none")]
+impl const U for u32 {}
+
+// implied stable
+impl const S for u8 {}
+
+#[rustc_const_stable(since = "0.0.0", feature = "beef2")]
+impl const S for u16 {}
+//~^ trait implementations cannot be const stable yet
+
+#[rustc_const_unstable(feature = "beef", issue = "none")]
+impl const S for u32 {}
+//~^ const stability on the impl does not match the const stability on the trait
+
fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api.stderr b/tests/ui/traits/const-traits/staged-api.stderr
index a7a7a1ee7215b..cdf577287eec5 100644
--- a/tests/ui/traits/const-traits/staged-api.stderr
+++ b/tests/ui/traits/const-traits/staged-api.stderr
@@ -1,3 +1,70 @@
+error: const stability on the impl does not match the const stability on the trait
+ --> $DIR/staged-api.rs:98:1
+ |
+LL | impl const U for u8 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this impl is (implicitly) stable...
+ --> $DIR/staged-api.rs:98:1
+ |
+LL | impl const U for u8 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+note: ...but the trait is unstable
+ --> $DIR/staged-api.rs:91:7
+ |
+LL | trait U {}
+ | ^
+
+error: trait implementations cannot be const stable yet
+ --> $DIR/staged-api.rs:102:1
+ |
+LL | impl const U for u16 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #67792 for more information
+
+error: const stability on the impl does not match the const stability on the trait
+ --> $DIR/staged-api.rs:102:1
+ |
+LL | impl const U for u16 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this impl is (implicitly) stable...
+ --> $DIR/staged-api.rs:102:1
+ |
+LL | impl const U for u16 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+note: ...but the trait is unstable
+ --> $DIR/staged-api.rs:91:7
+ |
+LL | trait U {}
+ | ^
+
+error: trait implementations cannot be const stable yet
+ --> $DIR/staged-api.rs:113:1
+ |
+LL | impl const S for u16 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #67792 for more information
+
+error: const stability on the impl does not match the const stability on the trait
+ --> $DIR/staged-api.rs:117:1
+ |
+LL | impl const S for u32 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this impl is unstable...
+ --> $DIR/staged-api.rs:117:1
+ |
+LL | impl const S for u32 {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+note: ...but the trait is stable
+ --> $DIR/staged-api.rs:95:7
+ |
+LL | trait S {}
+ | ^
+
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
--> $DIR/staged-api.rs:38:5
|
@@ -323,5 +390,5 @@ LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
LL | const fn implicitly_stable_const_context() {
|
-error: aborting due to 19 previous errors
+error: aborting due to 24 previous errors