summaryrefslogtreecommitdiff
path: root/compiler/rustc_parse
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-04-25 05:15:50 +0000
committerMichael Goulet <michael@errs.io>2023-05-02 22:36:24 +0000
commit6e01e910cb8ab0109235be7cc7ab7ef465724255 (patch)
treed63e7272022d540f0a93d43f36e359ff31c3f56d /compiler/rustc_parse
parent98c33e47a495fbd7b22bce9ce32f2815991bc414 (diff)
downloadrust-6e01e910cb8ab0109235be7cc7ab7ef465724255.tar.gz
Implement negative bounds
Diffstat (limited to 'compiler/rustc_parse')
-rw-r--r--compiler/rustc_parse/messages.ftl10
-rw-r--r--compiler/rustc_parse/src/errors.rs31
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs4
-rw-r--r--compiler/rustc_parse/src/parser/item.rs10
-rw-r--r--compiler/rustc_parse/src/parser/path.rs2
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs125
7 files changed, 59 insertions, 125 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 9a5232b1bcd..cd296dca133 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -615,13 +615,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
.help = `dyn` is only needed at the start of a trait `+`-separated list
.suggestion = remove this keyword
-parse_negative_bounds_not_supported = negative bounds are not supported
- .label = negative bounds are not supported
- .suggestion = {$num_bounds ->
- [one] remove the bound
- *[other] remove the bounds
- }
-
parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
@@ -772,7 +765,8 @@ parse_assoc_lifetime = associated lifetimes are not supported
parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
-parse_maybe_lifetime = `?` may only modify trait bounds, not lifetime bounds
+parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
+ .suggestion = remove the `{$sigil}`
parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
.suggestion = remove the parentheses
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index b445ccc7ad0..010a13aefa4 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2280,31 +2280,6 @@ pub(crate) struct InvalidDynKeyword {
pub span: Span,
}
-#[derive(Diagnostic)]
-#[diag(parse_negative_bounds_not_supported)]
-pub(crate) struct NegativeBoundsNotSupported {
- #[primary_span]
- pub negative_bounds: Vec<Span>,
- #[label]
- pub last_span: Span,
- #[subdiagnostic]
- pub sub: Option<NegativeBoundsNotSupportedSugg>,
-}
-
-#[derive(Subdiagnostic)]
-#[suggestion(
- parse_suggestion,
- style = "tool-only",
- code = "{fixed}",
- applicability = "machine-applicable"
-)]
-pub(crate) struct NegativeBoundsNotSupportedSugg {
- #[primary_span]
- pub bound_list: Span,
- pub num_bounds: usize,
- pub fixed: String,
-}
-
#[derive(Subdiagnostic)]
pub enum HelpUseLatestEdition {
#[help(parse_help_set_edition_cargo)]
@@ -2412,10 +2387,12 @@ pub(crate) struct TildeConstLifetime {
}
#[derive(Diagnostic)]
-#[diag(parse_maybe_lifetime)]
-pub(crate) struct MaybeLifetime {
+#[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,
}
#[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 638a432cea5..e974df61dc9 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1284,7 +1284,7 @@ impl<'a> Parser<'a> {
}
self.bump(); // `+`
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
let sum_span = ty.span.to(self.prev_token.span);
let sub = match &ty.kind {
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 61a7ae93bfa..e6d0f9fbc76 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -78,7 +78,7 @@ impl<'a> Parser<'a> {
}
self.restore_snapshot(snapshot);
}
- self.parse_generic_bounds(colon_span)?
+ self.parse_generic_bounds()?
} else {
Vec::new()
};
@@ -419,7 +419,7 @@ impl<'a> Parser<'a> {
// or with mandatory equality sign and the second type.
let ty = self.parse_ty_for_where_clause()?;
if self.eat(&token::Colon) {
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ let bounds = self.parse_generic_bounds()?;
Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
span: lo.to(self.prev_token.span),
bound_generic_params: lifetime_defs,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 64ff7f1fb2c..10a95cae3e1 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -788,11 +788,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon);
let span_at_colon = self.prev_token.span;
- let bounds = if had_colon {
- self.parse_generic_bounds(Some(self.prev_token.span))?
- } else {
- Vec::new()
- };
+ let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };
let span_before_eq = self.prev_token.span;
if self.eat(&token::Eq) {
@@ -802,7 +798,7 @@ impl<'a> Parser<'a> {
self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
}
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?;
@@ -883,7 +879,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and param bounds.
let bounds =
- if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
+ if self.eat(&token::Colon) { self.parse_generic_bounds()? } else { Vec::new() };
let before_where_clause = self.parse_where_clause()?;
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index b9a2b141bce..205d4d15e2e 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -606,7 +606,7 @@ impl<'a> Parser<'a> {
let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound.
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ let bounds = self.parse_generic_bounds()?;
AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) {
self.parse_assoc_equality_term(ident, self.prev_token.span)?
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 37c441fbecb..04f7eea90ed 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -3,8 +3,7 @@ use super::{Parser, PathStyle, TokenType};
use crate::errors::{
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
- InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
- NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType,
+ InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
ReturnTypesUseThinArrow,
};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -14,8 +13,9 @@ 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, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
- MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
+ self as ast, BareFnTy, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam,
+ Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier,
+ TraitObjectSyntax, Ty, TyKind,
};
use rustc_errors::{Applicability, PResult};
use rustc_span::source_map::Span;
@@ -23,10 +23,10 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use thin_vec::{thin_vec, ThinVec};
-/// Any `?` or `~const` modifiers that appear at the start of a bound.
+/// Any `?`, `!`, or `~const` modifiers that appear at the start of a bound.
struct BoundModifiers {
/// `?Trait`.
- maybe: Option<Span>,
+ bound_polarity: BoundPolarity,
/// `~const Trait`.
maybe_const: Option<Span>,
@@ -34,11 +34,13 @@ struct BoundModifiers {
impl BoundModifiers {
fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
- match (self.maybe, self.maybe_const) {
- (None, None) => TraitBoundModifier::None,
- (Some(_), None) => TraitBoundModifier::Maybe,
- (None, Some(_)) => TraitBoundModifier::MaybeConst,
- (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
+ 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(_)) => TraitBoundModifier::MaybeConst,
+ (BoundPolarity::Negative(_), Some(_)) => TraitBoundModifier::MaybeConstNegative,
+ (BoundPolarity::Maybe(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
}
}
}
@@ -368,7 +370,7 @@ impl<'a> Parser<'a> {
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
- let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
+ let bounds = self.parse_generic_bounds_common(allow_plus)?;
if lt_no_plus {
self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
}
@@ -395,7 +397,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, TyKind> {
if plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
- bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
+ bounds.append(&mut self.parse_generic_bounds()?);
}
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
}
@@ -598,7 +600,7 @@ impl<'a> Parser<'a> {
}
})
}
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
}
@@ -629,7 +631,7 @@ impl<'a> Parser<'a> {
};
// Always parse bounds greedily for better error recovery.
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::TraitObject(bounds, syntax))
}
@@ -660,23 +662,15 @@ impl<'a> Parser<'a> {
}
}
- pub(super) fn parse_generic_bounds(
- &mut self,
- colon_span: Option<Span>,
- ) -> PResult<'a, GenericBounds> {
- self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
+ pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
+ self.parse_generic_bounds_common(AllowPlus::Yes)
}
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
///
/// See `parse_generic_bound` for the `BOUND` grammar.
- fn parse_generic_bounds_common(
- &mut self,
- allow_plus: AllowPlus,
- colon_span: Option<Span>,
- ) -> PResult<'a, GenericBounds> {
+ fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
let mut bounds = Vec::new();
- let mut negative_bounds = Vec::new();
// In addition to looping while we find generic bounds:
// We continue even if we find a keyword. This is necessary for error recovery on,
@@ -693,19 +687,12 @@ impl<'a> Parser<'a> {
self.sess.emit_err(InvalidDynKeyword { span: self.token.span });
self.bump();
}
- match self.parse_generic_bound()? {
- Ok(bound) => bounds.push(bound),
- Err(neg_sp) => negative_bounds.push(neg_sp),
- }
+ bounds.push(self.parse_generic_bound()?);
if allow_plus == AllowPlus::No || !self.eat_plus() {
break;
}
}
- if !negative_bounds.is_empty() {
- self.error_negative_bounds(colon_span, &bounds, negative_bounds);
- }
-
Ok(bounds)
}
@@ -713,55 +700,22 @@ impl<'a> Parser<'a> {
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) // Used for error reporting only.
- || self.check(&token::Question)
- || self.check(&token::Tilde)
- || self.check_keyword(kw::For)
- || self.check(&token::OpenDelim(Delimiter::Parenthesis))
- }
-
- fn error_negative_bounds(
- &self,
- colon_span: Option<Span>,
- bounds: &[GenericBound],
- negative_bounds: Vec<Span>,
- ) {
- let sub = if let Some(bound_list) = colon_span {
- let bound_list = bound_list.to(self.prev_token.span);
- let mut new_bound_list = String::new();
- if !bounds.is_empty() {
- let mut snippets = bounds.iter().map(|bound| self.span_to_snippet(bound.span()));
- while let Some(Ok(snippet)) = snippets.next() {
- new_bound_list.push_str(" + ");
- new_bound_list.push_str(&snippet);
- }
- new_bound_list = new_bound_list.replacen(" +", ":", 1);
- }
-
- Some(NegativeBoundsNotSupportedSugg {
- bound_list,
- num_bounds: negative_bounds.len(),
- fixed: new_bound_list,
- })
- } else {
- None
- };
-
- let last_span = *negative_bounds.last().expect("no negative bounds, but still error?");
- self.sess.emit_err(NegativeBoundsNotSupported { negative_bounds, last_span, sub });
+ || self.check_lifetime()
+ || self.check(&token::Not)
+ || self.check(&token::Question)
+ || self.check(&token::Tilde)
+ || self.check_keyword(kw::For)
+ || self.check(&token::OpenDelim(Delimiter::Parenthesis))
}
/// Parses a bound according to the grammar:
/// ```ebnf
/// BOUND = TY_BOUND | LT_BOUND
/// ```
- fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
- let anchor_lo = self.prev_token.span;
+ fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let lo = self.token.span;
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
let inner_lo = self.token.span;
- let is_negative = self.eat(&token::Not);
let modifiers = self.parse_ty_bound_modifiers()?;
let bound = if self.token.is_lifetime() {
@@ -771,7 +725,7 @@ impl<'a> Parser<'a> {
self.parse_generic_ty_bound(lo, has_parens, modifiers)?
};
- Ok(if is_negative { Err(anchor_lo.to(self.prev_token.span)) } else { Ok(bound) })
+ Ok(bound)
}
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
@@ -799,8 +753,14 @@ impl<'a> Parser<'a> {
self.sess.emit_err(errors::TildeConstLifetime { span });
}
- if let Some(span) = modifiers.maybe {
- self.sess.emit_err(errors::MaybeLifetime { span });
+ match modifiers.bound_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: "?" });
+ }
}
}
@@ -843,9 +803,16 @@ impl<'a> Parser<'a> {
None
};
- let maybe = self.eat(&token::Question).then_some(self.prev_token.span);
+ let bound_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);
+ BoundPolarity::Negative(self.prev_token.span)
+ } else {
+ BoundPolarity::Positive
+ };
- Ok(BoundModifiers { maybe, maybe_const })
+ Ok(BoundModifiers { bound_polarity, maybe_const })
}
/// Parses a type bound according to: