diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a121b5a9bed..3d59c034210 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -286,41 +286,16 @@ impl ParenthesizedArgs { pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; -/// A modifier on a bound, e.g., `?Trait` or `~const Trait`. -/// -/// Negative bounds should also be handled here. +/// Modifiers on a trait bound like `~const`, `?` and `!`. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] -pub enum TraitBoundModifier { - /// No modifiers - None, - - /// `!Trait` - Negative, - - /// `?Trait` - Maybe, - - /// `~const Trait` - MaybeConst(Span), - - /// `~const !Trait` - // - // This parses but will be rejected during AST validation. - MaybeConstNegative, - - /// `~const ?Trait` - // - // This parses but will be rejected during AST validation. - MaybeConstMaybe, +pub struct TraitBoundModifiers { + pub constness: BoundConstness, + pub polarity: BoundPolarity, } -impl TraitBoundModifier { - pub fn to_constness(self) -> Const { - match self { - Self::MaybeConst(span) => Const::Yes(span), - _ => Const::No, - } - } +impl TraitBoundModifiers { + pub const NONE: Self = + Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive }; } /// The AST represents all type param bounds as types. @@ -329,7 +304,7 @@ impl TraitBoundModifier { /// detects `Copy`, `Send` and `Sync`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum GenericBound { - Trait(PolyTraitRef, TraitBoundModifier), + Trait(PolyTraitRef, TraitBoundModifiers), Outlives(Lifetime), } @@ -1193,7 +1168,7 @@ impl Expr { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( PolyTraitRef::new(ThinVec::new(), path.clone(), self.span), - TraitBoundModifier::None, + TraitBoundModifiers::NONE, )), _ => None, } @@ -2491,6 +2466,15 @@ pub enum Const { No, } +impl From for Const { + fn from(constness: BoundConstness) -> Self { + match constness { + BoundConstness::Maybe(span) => Self::Yes(span), + BoundConstness::Never => Self::No, + } + } +} + /// Item defaultness. /// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532). #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -2516,7 +2500,9 @@ impl fmt::Debug for ImplPolarity { } } -#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)] +/// The polarity of a trait bound. +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(HashStable_Generic)] pub enum BoundPolarity { /// `Type: Trait` Positive, @@ -2526,6 +2512,35 @@ pub enum BoundPolarity { Maybe(Span), } +impl BoundPolarity { + pub fn as_str(self) -> &'static str { + match self { + Self::Positive => "", + Self::Negative(_) => "!", + Self::Maybe(_) => "?", + } + } +} + +/// The constness of a trait bound. +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] +#[derive(HashStable_Generic)] +pub enum BoundConstness { + /// `Type: Trait` + Never, + /// `Type: ~const Trait` + Maybe(Span), +} + +impl BoundConstness { + pub fn as_str(self) -> &'static str { + match self { + Self::Never => "", + Self::Maybe(_) => "~const", + } + } +} + #[derive(Clone, Encodable, Decodable, Debug)] pub enum FnRetTy { /// Returns type is not specified. @@ -3259,7 +3274,7 @@ mod size_asserts { static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItemKind, 24); static_assert_size!(GenericArg, 24); - static_assert_size!(GenericBound, 64); + static_assert_size!(GenericBound, 72); static_assert_size!(Generics, 40); static_assert_size!(Impl, 136); static_assert_size!(Item, 136); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5bddbe5f417..9c990cb4619 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1372,7 +1372,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // need to compute this at all unless there is a Maybe bound. let mut is_param: Option = None; for bound in &bound_pred.bounds { - if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) { + if !matches!( + *bound, + GenericBound::Trait( + _, + TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. } + ) + ) { continue; } let is_param = *is_param.get_or_insert_with(compute_is_param); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 47b92981626..ed033d86008 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1425,19 +1425,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound { GenericBound::Trait( ty, - modifier @ (TraitBoundModifier::None - | TraitBoundModifier::MaybeConst(_) - | TraitBoundModifier::Negative), - ) => { - Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness())) - } - // `~const ?Bound` will cause an error during AST validation - // anyways, so treat it like `?Bound` as compilation proceeds. + TraitBoundModifiers { + polarity: BoundPolarity::Positive | BoundPolarity::Negative(_), + constness, + }, + ) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())), + // We can safely ignore constness here, since AST validation + // will take care of invalid modifier combinations. GenericBound::Trait( _, - TraitBoundModifier::Maybe - | TraitBoundModifier::MaybeConstMaybe - | TraitBoundModifier::MaybeConstNegative, + TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. }, ) => None, GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { @@ -2028,9 +2025,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx: &ImplTraitContext, ) -> hir::GenericBound<'hir> { match tpb { - GenericBound::Trait(p, modifier) => hir::GenericBound::Trait( - self.lower_poly_trait_ref(p, itctx, modifier.to_constness()), - self.lower_trait_bound_modifier(*modifier), + GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait( + self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()), + self.lower_trait_bound_modifiers(*modifiers), ), GenericBound::Outlives(lifetime) => { hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) @@ -2316,25 +2313,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier { - match f { - TraitBoundModifier::None => hir::TraitBoundModifier::None, - TraitBoundModifier::MaybeConst(_) => hir::TraitBoundModifier::MaybeConst, - - TraitBoundModifier::Negative => { + fn lower_trait_bound_modifiers( + &mut self, + modifiers: TraitBoundModifiers, + ) -> hir::TraitBoundModifier { + match (modifiers.constness, modifiers.polarity) { + (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None, + (BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, + (BoundConstness::Never, BoundPolarity::Negative(_)) => { if self.tcx.features().negative_bounds { hir::TraitBoundModifier::Negative } else { hir::TraitBoundModifier::None } } - - // `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a - // placeholder for compilation to proceed. - TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => { - hir::TraitBoundModifier::Maybe + (BoundConstness::Maybe(_), BoundPolarity::Positive) => { + hir::TraitBoundModifier::MaybeConst + } + // Invalid modifier combinations will cause an error during AST validation. + // Arbitrarily pick a placeholder for compilation to proceed. + (BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, + (BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => { + hir::TraitBoundModifier::MaybeConst } - TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst, } } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 1c5ad820bd6..ea3cd3e4bee 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -152,6 +152,8 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features +ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive + ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .because = {$annotation} because of this .type = inherent impl for this type @@ -195,8 +197,6 @@ ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax .help = use `auto trait Trait {"{}"}` instead -ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive - ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 887cb434a60..23a45749455 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1196,18 +1196,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { - if let GenericBound::Trait(poly, modify) = bound { - match (ctxt, modify) { - (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { + if let GenericBound::Trait(poly, modifiers) = bound { + match (ctxt, modifiers.constness, modifiers.polarity) { + (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { self.dcx().emit_err(errors::OptionalTraitSupertrait { span: poly.span, path_str: pprust::path_to_string(&poly.trait_ref.path), }); } - (BoundKind::TraitObject, TraitBoundModifier::Maybe) => { + (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); } - (_, &TraitBoundModifier::MaybeConst(span)) + (_, BoundConstness::Maybe(span), BoundPolarity::Positive) if let Some(reason) = &self.disallow_tilde_const => { let reason = match reason { @@ -1235,16 +1235,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); } - (_, TraitBoundModifier::MaybeConstMaybe) => { - self.dcx().emit_err(errors::OptionalConstExclusive { + ( + _, + BoundConstness::Maybe(_), + BoundPolarity::Maybe(_) | BoundPolarity::Negative(_), + ) => { + self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { span: bound.span(), - modifier: "?", - }); - } - (_, TraitBoundModifier::MaybeConstNegative) => { - self.dcx().emit_err(errors::OptionalConstExclusive { - span: bound.span(), - modifier: "!", + left: modifiers.constness.as_str(), + right: modifiers.polarity.as_str(), }); } _ => {} @@ -1252,7 +1251,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } // Negative trait bounds are not allowed to have associated constraints - if let GenericBound::Trait(trait_ref, TraitBoundModifier::Negative) = bound + if let GenericBound::Trait(trait_ref, modifiers) = bound + && let BoundPolarity::Negative(_) = modifiers.polarity && let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref() { @@ -1494,7 +1494,8 @@ fn deny_equality_constraints( for param in &generics.params { if param.ident == potential_param.ident { for bound in ¶m.bounds { - if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound + if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) = + bound { if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] { let assoc = pprust::path_to_string(&ast::Path::from_ident( diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 304c5c1bde9..a5b842b320e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -580,11 +580,12 @@ pub enum TildeConstReason { } #[derive(Diagnostic)] -#[diag(ast_passes_optional_const_exclusive)] -pub struct OptionalConstExclusive { +#[diag(ast_passes_incompatible_trait_bound_modifiers)] +pub struct IncompatibleTraitBoundModifiers { #[primary_span] pub span: Span, - pub modifier: &'static str, + pub left: &'static str, + pub right: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 670f2a45835..100b2988982 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -4,6 +4,7 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![feature(box_patterns)] +#![feature(let_chains)] #![recursion_limit = "256"] mod helpers; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index d6c15ec35b6..2ad8aa38bcc 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -17,7 +17,7 @@ use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser; use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind}; use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term}; -use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier}; +use rustc_ast::{GenericArg, GenericBound, SelfKind}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_span::edition::Edition; @@ -1559,26 +1559,20 @@ impl<'a> State<'a> { match bound { GenericBound::Trait(tref, modifier) => { - match modifier { - TraitBoundModifier::None => {} - TraitBoundModifier::Negative => { - self.word("!"); - } - TraitBoundModifier::Maybe => { - self.word("?"); - } - TraitBoundModifier::MaybeConst(_) => { - self.word_space("~const"); - } - TraitBoundModifier::MaybeConstNegative => { - self.word_space("~const"); - self.word("!"); - } - TraitBoundModifier::MaybeConstMaybe => { - self.word_space("~const"); - self.word("?"); + match modifier.constness { + ast::BoundConstness::Never => {} + ast::BoundConstness::Maybe(_) => { + self.word_space(modifier.constness.as_str()); } } + + match modifier.polarity { + ast::BoundPolarity::Positive => {} + ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => { + self.word(modifier.polarity.as_str()); + } + } + self.print_poly_trait_ref(tref); } GenericBound::Outlives(lt) => self.print_lifetime(*lt), diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 405ccc722d4..247061c5ca7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -339,13 +339,15 @@ impl<'a> State<'a> { self.print_ident(item.ident); self.print_generic_params(&generics.params); let mut real_bounds = Vec::with_capacity(bounds.len()); - for b in bounds.iter() { - if let GenericBound::Trait(ptr, ast::TraitBoundModifier::Maybe) = b { + for bound in bounds.iter() { + if let GenericBound::Trait(ptr, modifiers) = bound + && let ast::BoundPolarity::Maybe(_) = modifiers.polarity + { self.space(); self.word_space("for ?"); self.print_trait_ref(&ptr.trait_ref); } else { - real_bounds.push(b.clone()); + real_bounds.push(bound.clone()); } } if !real_bounds.is_empty() { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 86f555fa08b..f9eddfeeaa8 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -134,10 +134,13 @@ impl<'a> ExtCtxt<'a> { pub fn trait_bound(&self, path: ast::Path, is_const: bool) -> ast::GenericBound { ast::GenericBound::Trait( self.poly_trait_ref(path.span, path), - if is_const { - ast::TraitBoundModifier::MaybeConst(DUMMY_SP) - } else { - ast::TraitBoundModifier::None + ast::TraitBoundModifiers { + polarity: ast::BoundPolarity::Positive, + constness: if is_const { + ast::BoundConstness::Maybe(DUMMY_SP) + } else { + ast::BoundConstness::Never + }, }, ) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3179fd73604..26430dcf965 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -417,8 +417,7 @@ pub enum GenericArgsParentheses { ParenSugar, } -/// A modifier on a bound, currently this is only used for `?Sized`, where the -/// modifier is `Maybe`. Negative bounds should also be handled here. +/// A modifier on a trait bound. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum TraitBoundModifier { None, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 8970a99f1b7..405531c1e41 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -840,7 +840,7 @@ impl<'a> Parser<'a> { { return Ok((false, seg.ident, seg.args.as_deref().cloned())); } else if let ast::TyKind::TraitObject(bounds, ast::TraitObjectSyntax::None) = &ty.kind - && let [ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)] = + && let [ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifiers::NONE)] = bounds.as_slice() && let [seg] = trait_ref.trait_ref.path.segments.as_slice() { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index da8cc05ff66..f89d6d1d965 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -13,37 +13,15 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, BareFnTy, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam, - Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, - TraitObjectSyntax, Ty, TyKind, + self as ast, BareFnTy, BoundConstness, BoundPolarity, FnRetTy, GenericBound, GenericBounds, + GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, + TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, }; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{Span, Symbol}; use thin_vec::{thin_vec, ThinVec}; -/// Any `?`, `!`, or `~const` modifiers that appear at the start of a bound. -struct BoundModifiers { - /// `?Trait`. - bound_polarity: BoundPolarity, - - /// `~const Trait`. - maybe_const: Option, -} - -impl BoundModifiers { - fn to_trait_bound_modifier(&self) -> TraitBoundModifier { - match (self.bound_polarity, self.maybe_const) { - (BoundPolarity::Positive, None) => TraitBoundModifier::None, - (BoundPolarity::Negative(_), None) => TraitBoundModifier::Negative, - (BoundPolarity::Maybe(_), None) => TraitBoundModifier::Maybe, - (BoundPolarity::Positive, Some(sp)) => TraitBoundModifier::MaybeConst(sp), - (BoundPolarity::Negative(_), Some(_)) => TraitBoundModifier::MaybeConstNegative, - (BoundPolarity::Maybe(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe, - } - } -} - #[derive(Copy, Clone, PartialEq)] pub(super) enum AllowPlus { Yes, @@ -461,7 +439,7 @@ impl<'a> Parser<'a> { parse_plus: bool, ) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_token.span)); - let bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; + let bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifiers::NONE)]; self.parse_remaining_bounds(bounds, parse_plus) } @@ -800,7 +778,7 @@ impl<'a> Parser<'a> { let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis)); let inner_lo = self.token.span; - let modifiers = self.parse_ty_bound_modifiers()?; + let modifiers = self.parse_trait_bound_modifiers()?; let bound = if self.token.is_lifetime() { self.error_lt_bound_with_modifiers(modifiers); self.parse_generic_lt_bound(lo, inner_lo, has_parens)? @@ -831,18 +809,21 @@ impl<'a> Parser<'a> { } /// Emits an error if any trait bound modifiers were present. - fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) { - if let Some(span) = modifiers.maybe_const { - self.sess.emit_err(errors::TildeConstLifetime { span }); + fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) { + match modifiers.constness { + BoundConstness::Never => {} + BoundConstness::Maybe(span) => { + self.sess.emit_err(errors::TildeConstLifetime { span }); + } } - match modifiers.bound_polarity { + match modifiers.polarity { BoundPolarity::Positive => {} - BoundPolarity::Negative(span) => { - self.sess.emit_err(errors::ModifierLifetime { span, sigil: "!" }); - } - BoundPolarity::Maybe(span) => { - self.sess.emit_err(errors::ModifierLifetime { span, sigil: "?" }); + BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => { + self.sess.emit_err(errors::ModifierLifetime { + span, + sigil: modifiers.polarity.as_str(), + }); } } } @@ -867,26 +848,26 @@ impl<'a> Parser<'a> { /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// TY_BOUND_MODIFIERS = ["~const"] ["?"] + /// TRAIT_BOUND_MODIFIERS = ["~const"] ["?" | "!"] /// ``` - fn parse_ty_bound_modifiers(&mut self) -> PResult<'a, BoundModifiers> { - let maybe_const = if self.eat(&token::Tilde) { + fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { + let constness = if self.eat(&token::Tilde) { let tilde = self.prev_token.span; self.expect_keyword(kw::Const)?; let span = tilde.to(self.prev_token.span); self.sess.gated_spans.gate(sym::const_trait_impl, span); - Some(span) + BoundConstness::Maybe(span) } else if self.eat_keyword(kw::Const) { let span = self.prev_token.span; self.sess.gated_spans.gate(sym::const_trait_impl, span); self.sess.emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() }); - Some(span) + BoundConstness::Maybe(span) } else { - None + BoundConstness::Never }; - let bound_polarity = if self.eat(&token::Question) { + let polarity = if self.eat(&token::Question) { BoundPolarity::Maybe(self.prev_token.span) } else if self.eat(&token::Not) { self.sess.gated_spans.gate(sym::negative_bounds, self.prev_token.span); @@ -895,13 +876,13 @@ impl<'a> Parser<'a> { BoundPolarity::Positive }; - Ok(BoundModifiers { bound_polarity, maybe_const }) + Ok(TraitBoundModifiers { constness, polarity }) } /// Parses a type bound according to: /// ```ebnf /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for] SIMPLE_PATH + /// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [for] SIMPLE_PATH /// ``` /// /// For example, this grammar accepts `~const ?for<'a: 'b> m::Trait<'a>`. @@ -909,7 +890,7 @@ impl<'a> Parser<'a> { &mut self, lo: Span, has_parens: bool, - modifiers: BoundModifiers, + modifiers: TraitBoundModifiers, leading_token: &Token, ) -> PResult<'a, GenericBound> { let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?; @@ -991,9 +972,8 @@ impl<'a> Parser<'a> { } } - let modifier = modifiers.to_trait_bound_modifier(); let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_token.span)); - Ok(GenericBound::Trait(poly_trait, modifier)) + Ok(GenericBound::Trait(poly_trait, modifiers)) } // recovers a `Fn(..)` parenthesized-style path from `fn(..)` diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d767ed74139..376ccfba9d8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -520,7 +520,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { continue; }; for bound in bounds { - let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None) = bound + let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifiers::NONE) = bound else { continue; }; @@ -1242,7 +1242,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } if let ( [ast::PathSegment { args: None, .. }], - [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)], + [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifiers::NONE)], ) = (&type_param_path.segments[..], &bounds[..]) { if let [ast::PathSegment { ident, args: None, .. }] = @@ -3276,7 +3276,7 @@ fn mk_where_bound_predicate( }, span: DUMMY_SP, }, - ast::TraitBoundModifier::None, + ast::TraitBoundModifiers::NONE, )], }; diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index a5a4244903c..cd2582e66be 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -537,28 +537,19 @@ impl Rewrite for ast::Lifetime { impl Rewrite for ast::GenericBound { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { match *self { - ast::GenericBound::Trait(ref poly_trait_ref, trait_bound_modifier) => { + ast::GenericBound::Trait(ref poly_trait_ref, modifiers) => { let snippet = context.snippet(self.span()); let has_paren = snippet.starts_with('(') && snippet.ends_with(')'); - let rewrite = match trait_bound_modifier { - ast::TraitBoundModifier::None => poly_trait_ref.rewrite(context, shape), - ast::TraitBoundModifier::Maybe => poly_trait_ref - .rewrite(context, shape.offset_left(1)?) - .map(|s| format!("?{}", s)), - ast::TraitBoundModifier::MaybeConst(_) => poly_trait_ref - .rewrite(context, shape.offset_left(7)?) - .map(|s| format!("~const {}", s)), - ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref - .rewrite(context, shape.offset_left(8)?) - .map(|s| format!("~const ?{}", s)), - ast::TraitBoundModifier::Negative => poly_trait_ref - .rewrite(context, shape.offset_left(1)?) - .map(|s| format!("!{}", s)), - ast::TraitBoundModifier::MaybeConstNegative => poly_trait_ref - .rewrite(context, shape.offset_left(8)?) - .map(|s| format!("~const !{}", s)), - }; - rewrite.map(|s| if has_paren { format!("({})", s) } else { s }) + let mut constness = modifiers.constness.as_str().to_string(); + if !constness.is_empty() { + constness.push(' '); + } + let polarity = modifiers.polarity.as_str(); + let shape = shape.offset_left(constness.len() + polarity.len())?; + poly_trait_ref + .rewrite(context, shape) + .map(|s| format!("{constness}{polarity}{s}")) + .map(|s| if has_paren { format!("({})", s) } else { s }) } ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape), } diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index e6da83296ce..070dbbb10bb 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -15,20 +15,20 @@ ast-stats-1 Arm 96 ( 1.5%) 2 48 ast-stats-1 ForeignItem 96 ( 1.5%) 1 96 ast-stats-1 - Fn 96 ( 1.5%) 1 ast-stats-1 FnDecl 120 ( 1.8%) 5 24 -ast-stats-1 FieldDef 160 ( 2.5%) 2 80 -ast-stats-1 Stmt 160 ( 2.5%) 5 32 +ast-stats-1 FieldDef 160 ( 2.4%) 2 80 +ast-stats-1 Stmt 160 ( 2.4%) 5 32 ast-stats-1 - Local 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 ast-stats-1 - Expr 96 ( 1.5%) 3 -ast-stats-1 Param 160 ( 2.5%) 4 40 +ast-stats-1 Param 160 ( 2.4%) 4 40 ast-stats-1 Block 192 ( 2.9%) 6 32 ast-stats-1 Variant 208 ( 3.2%) 2 104 -ast-stats-1 GenericBound 256 ( 3.9%) 4 64 -ast-stats-1 - Trait 256 ( 3.9%) 4 +ast-stats-1 GenericBound 288 ( 4.4%) 4 72 +ast-stats-1 - Trait 288 ( 4.4%) 4 ast-stats-1 AssocItem 352 ( 5.4%) 4 88 ast-stats-1 - Type 176 ( 2.7%) 2 ast-stats-1 - Fn 176 ( 2.7%) 2 -ast-stats-1 GenericParam 480 ( 7.4%) 5 96 +ast-stats-1 GenericParam 480 ( 7.3%) 5 96 ast-stats-1 Pat 504 ( 7.7%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 @@ -45,15 +45,15 @@ ast-stats-1 - Ptr 64 ( 1.0%) 1 ast-stats-1 - Ref 64 ( 1.0%) 1 ast-stats-1 - ImplicitSelf 128 ( 2.0%) 2 ast-stats-1 - Path 640 ( 9.8%) 10 -ast-stats-1 Item 1_224 (18.8%) 9 136 +ast-stats-1 Item 1_224 (18.7%) 9 136 ast-stats-1 - Trait 136 ( 2.1%) 1 ast-stats-1 - Enum 136 ( 2.1%) 1 ast-stats-1 - ForeignMod 136 ( 2.1%) 1 ast-stats-1 - Impl 136 ( 2.1%) 1 ast-stats-1 - Fn 272 ( 4.2%) 2 -ast-stats-1 - Use 408 ( 6.3%) 3 +ast-stats-1 - Use 408 ( 6.2%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_520 +ast-stats-1 Total 6_552 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -81,16 +81,16 @@ ast-stats-2 - Expr 96 ( 1.3%) 3 ast-stats-2 Param 160 ( 2.2%) 4 40 ast-stats-2 Block 192 ( 2.7%) 6 32 ast-stats-2 Variant 208 ( 2.9%) 2 104 -ast-stats-2 GenericBound 256 ( 3.6%) 4 64 -ast-stats-2 - Trait 256 ( 3.6%) 4 +ast-stats-2 GenericBound 288 ( 4.0%) 4 72 +ast-stats-2 - Trait 288 ( 4.0%) 4 ast-stats-2 AssocItem 352 ( 4.9%) 4 88 ast-stats-2 - Type 176 ( 2.5%) 2 ast-stats-2 - Fn 176 ( 2.5%) 2 ast-stats-2 GenericParam 480 ( 6.7%) 5 96 -ast-stats-2 Pat 504 ( 7.1%) 7 72 +ast-stats-2 Pat 504 ( 7.0%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 -ast-stats-2 - Ident 360 ( 5.1%) 5 +ast-stats-2 - Ident 360 ( 5.0%) 5 ast-stats-2 Expr 648 ( 9.1%) 9 72 ast-stats-2 - Path 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1 @@ -99,12 +99,12 @@ ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Lit 144 ( 2.0%) 2 ast-stats-2 - Block 216 ( 3.0%) 3 ast-stats-2 PathSegment 792 (11.1%) 33 24 -ast-stats-2 Ty 896 (12.6%) 14 64 +ast-stats-2 Ty 896 (12.5%) 14 64 ast-stats-2 - Ptr 64 ( 0.9%) 1 ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - ImplicitSelf 128 ( 1.8%) 2 -ast-stats-2 - Path 640 ( 9.0%) 10 -ast-stats-2 Item 1_496 (21.0%) 11 136 +ast-stats-2 - Path 640 ( 8.9%) 10 +ast-stats-2 Item 1_496 (20.9%) 11 136 ast-stats-2 - Trait 136 ( 1.9%) 1 ast-stats-2 - Enum 136 ( 1.9%) 1 ast-stats-2 - ExternCrate 136 ( 1.9%) 1 @@ -113,7 +113,7 @@ ast-stats-2 - Impl 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.8%) 2 ast-stats-2 - Use 544 ( 7.6%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_120 +ast-stats-2 Total 7_152 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size