diff options
| author | León Orell Valerian Liehr <me@fmease.dev> | 2023-12-18 17:55:55 +0100 |
|---|---|---|
| committer | León Orell Valerian Liehr <me@fmease.dev> | 2023-12-27 12:51:32 +0100 |
| commit | 3eb48a35c8ae8335da66dc2bdb4f60e6ae22e1dd (patch) | |
| tree | eadb378f48629728c106252798e74f8faf1bf745 /compiler | |
| parent | 2fe50cd72c476ebacdedb14893e9632b4de961c2 (diff) | |
Introduce `const Trait` (always-const trait bounds)
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast/src/ast.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/token.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/item.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/lib.rs | 86 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/path.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/src/ast_validation.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/src/errors.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_ast_pretty/src/pprust/state.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/messages.ftl | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/astconv/bounds.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/astconv/mod.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/errors.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_parse/messages.ftl | 9 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 35 |
18 files changed, 128 insertions, 110 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3496cfc38c8..9a9c769fd7c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2481,15 +2481,6 @@ pub enum Const { No, } -impl From<BoundConstness> 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)] @@ -2543,6 +2534,8 @@ impl BoundPolarity { pub enum BoundConstness { /// `Type: Trait` Never, + /// `Type: const Trait` + Always(Span), /// `Type: ~const Trait` Maybe(Span), } @@ -2551,6 +2544,7 @@ impl BoundConstness { pub fn as_str(self) -> &'static str { match self { Self::Never => "", + Self::Always(_) => "const", Self::Maybe(_) => "~const", } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index b0cd2ec9815..d62462b1ae3 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -528,15 +528,6 @@ impl Token { } } - /// Returns `true` if the token can appear at the start of a generic bound. - pub fn can_begin_bound(&self) -> bool { - self.is_path_start() - || self.is_lifetime() - || self.is_keyword(kw::For) - || self == &Question - || self == &OpenDelim(Delimiter::Parenthesis) - } - /// Returns `true` if the token can appear at the start of an item. pub fn can_begin_item(&self) -> bool { match self.kind { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b70b9356226..3848f3b7782 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -339,9 +339,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = self.lower_generics(ast_generics, *constness, id, &itctx, |this| { + let constness = match *constness { + Const::Yes(span) => BoundConstness::Maybe(span), + Const::No => BoundConstness::Never, + }; + let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( - *constness, + constness, trait_ref, &ImplTraitContext::Disallowed(ImplTraitPosition::Trait), ) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e3954116288..4c4cf593bda 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1324,7 +1324,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: t.span, }, itctx, - ast::Const::No, + ast::BoundConstness::Never, ); let bounds = this.arena.alloc_from_iter([bound]); let lifetime_bound = this.elided_dyn_bound(t.span); @@ -1435,7 +1435,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { polarity: BoundPolarity::Positive | BoundPolarity::Negative(_), constness, }, - ) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())), + ) => Some(this.lower_poly_trait_ref(ty, itctx, *constness)), // We can safely ignore constness here, since AST validation // will take care of invalid modifier combinations. GenericBound::Trait( @@ -2174,7 +2174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_ref( &mut self, - constness: ast::Const, + constness: ast::BoundConstness, p: &TraitRef, itctx: &ImplTraitContext, ) -> hir::TraitRef<'hir> { @@ -2197,7 +2197,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, p: &PolyTraitRef, itctx: &ImplTraitContext, - constness: ast::Const, + constness: ast::BoundConstness, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); @@ -2322,9 +2322,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, modifiers: TraitBoundModifiers, ) -> hir::TraitBoundModifier { + // Invalid modifier combinations will cause an error during AST validation. + // Arbitrarily pick a placeholder for them to make compilation proceed. match (modifiers.constness, modifiers.polarity) { (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None, - (BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, + (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, (BoundConstness::Never, BoundPolarity::Negative(_)) => { if self.tcx.features().negative_bounds { hir::TraitBoundModifier::Negative @@ -2332,15 +2334,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TraitBoundModifier::None } } - (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 - } + (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const, + (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst, } } @@ -2558,45 +2553,62 @@ struct GenericArgsCtor<'hir> { } impl<'hir> GenericArgsCtor<'hir> { - fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) { + fn push_constness( + &mut self, + lcx: &mut LoweringContext<'_, 'hir>, + constness: ast::BoundConstness, + ) { if !lcx.tcx.features().effects { return; } - // if bound is non-const, don't add host effect param - let ast::Const::Yes(span) = constness else { return }; + let (span, body) = match constness { + BoundConstness::Never => return, + BoundConstness::Always(span) => { + let span = lcx.lower_span(span); - let span = lcx.lower_span(span); + let body = hir::ExprKind::Lit( + lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }), + ); - let id = lcx.next_node_id(); - let hir_id = lcx.next_id(); + (span, body) + } + BoundConstness::Maybe(span) => { + let span = lcx.lower_span(span); - let Some(host_param_id) = lcx.host_param_id else { - lcx.dcx().span_delayed_bug( - span, - "no host param id for call in const yet no errors reported", - ); - return; - }; + let Some(host_param_id) = lcx.host_param_id else { + lcx.dcx().span_delayed_bug( + span, + "no host param id for call in const yet no errors reported", + ); + return; + }; - let body = lcx.lower_body(|lcx| { - (&[], { let hir_id = lcx.next_id(); let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id()); - let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved( + let body = hir::ExprKind::Path(hir::QPath::Resolved( None, lcx.arena.alloc(hir::Path { span, res, - segments: arena_vec![lcx; hir::PathSegment::new(Ident { - name: sym::host, - span, - }, hir_id, res)], + segments: arena_vec![ + lcx; + hir::PathSegment::new( + Ident { name: sym::host, span }, + hir_id, + res + ) + ], }), )); - lcx.expr(span, expr_kind) - }) - }); + + (span, body) + } + }; + let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body))); + + let id = lcx.next_node_id(); + let hir_id = lcx.next_id(); let def_id = lcx.create_def( lcx.current_hir_id_owner.def_id, diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 130eb3521c3..c679ee56fcd 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -25,7 +25,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, itctx: &ImplTraitContext, // constness of the impl/bound if this is a trait path - constness: Option<ast::Const>, + constness: Option<ast::BoundConstness>, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); @@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, itctx: &ImplTraitContext, - constness: Option<ast::Const>, + constness: Option<ast::BoundConstness>, ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment); let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() { diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index ea3cd3e4bee..b5612c1820d 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -46,6 +46,8 @@ ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadi .const = `const` because of this .variadic = C-variadic because of this +ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types + ast_passes_const_without_body = free constant item without body .suggestion = provide a definition for the constant diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 3600e4960af..bc5cf463f12 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1207,6 +1207,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); } + (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => { + self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span }); + } (_, BoundConstness::Maybe(span), BoundPolarity::Positive) if let Some(reason) = &self.disallow_tilde_const => { @@ -1237,8 +1240,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ( _, - BoundConstness::Maybe(_), - BoundPolarity::Maybe(_) | BoundPolarity::Negative(_), + BoundConstness::Always(_) | BoundConstness::Maybe(_), + BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), ) => { self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { span: bound.span(), diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index a5b842b320e..0cec4374be2 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -541,6 +541,13 @@ pub struct OptionalTraitObject { } #[derive(Diagnostic)] +#[diag(ast_passes_const_bound_trait_object)] +pub struct ConstBoundTraitObject { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_tilde_const_disallowed)] pub struct TildeConstDisallowed { #[primary_span] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 12d37cf5a7a..0543c8e1d44 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1561,7 +1561,7 @@ impl<'a> State<'a> { GenericBound::Trait(tref, modifier) => { match modifier.constness { ast::BoundConstness::Never => {} - ast::BoundConstness::Maybe(_) => { + ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => { self.word_space(modifier.constness.as_str()); } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2b840860166..b76edd554f8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -420,9 +420,15 @@ pub enum GenericArgsParentheses { /// A modifier on a trait bound. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum TraitBoundModifier { + /// `Type: Trait` None, + /// `Type: !Trait` Negative, + /// `Type: ?Trait` Maybe, + /// `Type: const Trait` + Const, + /// `Type: ~const Trait` MaybeConst, } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 139e1c0ac5f..d8b6b9a1272 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -70,7 +70,7 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found hir_analysis_const_bound_for_non_const_trait = - ~const can only be applied to `#[const_trait]` traits + `{$modifier}` can only be applied to `#[const_trait]` traits hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 6e71cf16ee8..91b3807d744 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -112,6 +112,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { match ast_bound { hir::GenericBound::Trait(poly_trait_ref, modifier) => { let (constness, polarity) = match modifier { + hir::TraitBoundModifier::Const => { + (ty::BoundConstness::Const, ty::ImplPolarity::Positive) + } hir::TraitBoundModifier::MaybeConst => { (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive) } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 8197fea5b29..092df257dbf 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -560,11 +560,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { inferred_params: vec![], infer_args, }; - if let ty::BoundConstness::ConstIfConst = constness + if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) { - let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span }); + let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { + span, + modifier: constness.as_str(), + }); arg_count.correct = Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] }); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 41f30057902..75e7a5524a7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -408,6 +408,7 @@ pub struct ConstImplForNonConstTrait { pub struct ConstBoundForNonConstTrait { #[primary_span] pub span: Span, + pub modifier: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9f1ff4538aa..0653796ec7f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -309,23 +309,22 @@ impl Visibility { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] pub enum BoundConstness { - /// `T: Trait` + /// `Type: Trait` NotConst, - /// `T: ~const Trait` + /// `Type: const Trait` + Const, + /// `Type: ~const Trait` /// /// Requires resolving to const only when we are in a const context. ConstIfConst, } impl BoundConstness { - /// Reduce `self` and `constness` to two possible combined states instead of four. - pub fn and(&mut self, constness: hir::Constness) -> hir::Constness { - match (constness, self) { - (hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const, - (_, this) => { - *this = BoundConstness::NotConst; - hir::Constness::NotConst - } + pub fn as_str(self) -> &'static str { + match self { + Self::NotConst => "", + Self::Const => "const", + Self::ConstIfConst => "~const", } } } @@ -334,7 +333,7 @@ impl fmt::Display for BoundConstness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NotConst => f.write_str("normal"), - Self::ConstIfConst => f.write_str("`~const`"), + _ => write!(f, "`{self}`"), } } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 363b8f4bfb9..c6bddbfacd6 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -95,9 +95,6 @@ parse_compound_assignment_expression_in_let = can't reassign to an uninitialized .suggestion = initialize the variable .help = if you meant to overwrite, remove the `let` binding -parse_const_bounds_missing_tilde = const bounds must start with `~` - .suggestion = add `~` - parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments .suggestion = enclose the `const` expression in braces @@ -555,8 +552,8 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl .suggestion_add_trait = add a trait here .suggestion_remove_for = for an inherent impl, drop this `for` -parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds - .suggestion = remove the `{$sigil}` +parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds + .suggestion = remove the `{$modifier}` parse_more_than_one_char = character literal may only contain one codepoint .followed_by = this `{$chr}` is followed by the combining {$len -> @@ -729,8 +726,6 @@ parse_switch_ref_box_order = switch the order of `ref` and `box` parse_ternary_operator = Rust has no ternary operator .help = use an `if-else` expression instead -parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds - parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator .suggestion = use `!` to perform bitwise not diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 53cce9e2883..e276b34ca37 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2556,19 +2556,12 @@ pub(crate) struct AssocLifetime { } #[derive(Diagnostic)] -#[diag(parse_tilde_const_lifetime)] -pub(crate) struct TildeConstLifetime { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(parse_modifier_lifetime)] pub(crate) struct ModifierLifetime { #[primary_span] #[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")] pub span: Span, - pub sigil: &'static str, + pub modifier: &'static str, } #[derive(Diagnostic)] @@ -2582,15 +2575,6 @@ pub(crate) struct ParenthesizedLifetime { } #[derive(Diagnostic)] -#[diag(parse_const_bounds_missing_tilde)] -pub(crate) struct ConstMissingTilde { - #[primary_span] - pub span: Span, - #[suggestion(code = "~", applicability = "machine-applicable")] - pub start: Span, -} - -#[derive(Diagnostic)] #[diag(parse_underscore_literal_suffix)] pub(crate) struct UnderscoreLiteralSuffix { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 42ab23d6292..4be2c662d03 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -86,6 +86,18 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { t == &token::ModSep || t == &token::Lt || t == &token::BinOp(token::Shl) } +fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { + // `Not`, `Tilde` & `Const` are deliberately not part of this list to + // contain the number of potential regressions esp. in MBE code. + // `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`. + // `Not` would regress `dyn!(...)` macro calls in Rust 2015. + t.is_path_start() + || t.is_lifetime() + || t == &TokenKind::Question + || t.is_keyword(kw::For) + || t == &TokenKind::OpenDelim(Delimiter::Parenthesis) +} + impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { @@ -665,7 +677,8 @@ impl<'a> Parser<'a> { self.check_keyword(kw::Dyn) && (self.token.uninterpolated_span().at_least_rust_2018() || self.look_ahead(1, |t| { - (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star)) + (can_begin_dyn_bound_in_edition_2015(t) + || t.kind == TokenKind::BinOp(token::Star)) && !can_continue_type_after_non_fn_ident(t) })) } @@ -758,12 +771,12 @@ impl<'a> Parser<'a> { /// Can the current token begin a bound? fn can_begin_bound(&mut self) -> bool { - // This needs to be synchronized with `TokenKind::can_begin_bound`. self.check_path() || self.check_lifetime() || self.check(&token::Not) || self.check(&token::Question) || self.check(&token::Tilde) + || self.check_keyword(kw::Const) || self.check_keyword(kw::For) || self.check(&token::OpenDelim(Delimiter::Parenthesis)) } @@ -812,8 +825,11 @@ impl<'a> Parser<'a> { fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) { match modifiers.constness { BoundConstness::Never => {} - BoundConstness::Maybe(span) => { - self.dcx().emit_err(errors::TildeConstLifetime { span }); + BoundConstness::Always(span) | BoundConstness::Maybe(span) => { + self.dcx().emit_err(errors::ModifierLifetime { + span, + modifier: modifiers.constness.as_str(), + }); } } @@ -822,7 +838,7 @@ impl<'a> Parser<'a> { BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => { self.dcx().emit_err(errors::ModifierLifetime { span, - sigil: modifiers.polarity.as_str(), + modifier: modifiers.polarity.as_str(), }); } } @@ -848,7 +864,7 @@ impl<'a> Parser<'a> { /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// TRAIT_BOUND_MODIFIERS = ["~const"] ["?" | "!"] + /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["?" | "!"] /// ``` fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { let constness = if self.eat(&token::Tilde) { @@ -858,11 +874,8 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::const_trait_impl, 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.dcx().emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() }); - - BoundConstness::Maybe(span) + self.sess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span); + BoundConstness::Always(self.prev_token.span) } else { BoundConstness::Never }; |
