Introduce ~const

- [x] Removed `?const` and change uses of `?const`
 - [x] Added `~const` to the AST. It is gated behind const_trait_impl.
 - [x] Validate `~const` in ast_validation.
 - [ ] Add enum `BoundConstness` to the HIR. (With variants `NotConst` and
 `ConstIfConst` allowing future extensions)
 - [ ] Adjust trait selection and pre-existing code to use `BoundConstness`.
 - [ ] Optional steps (*for this PR, obviously*)
      - [ ] Fix #88155
      - [ ] Do something with constness bounds in chalk
This commit is contained in:
Deadbeef 2021-08-25 11:53:16 +00:00
parent d5cd3205fd
commit 8660832086
No known key found for this signature in database
GPG key ID: 027DF9338862ADDD
16 changed files with 178 additions and 125 deletions

View file

@ -11,12 +11,12 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym};
/// 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>,
/// `?const Trait`.
/// `~const Trait`.
maybe_const: Option<Span>,
}
@ -609,6 +609,7 @@ impl<'a> Parser<'a> {
|| 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(token::Paren))
}
@ -655,7 +656,7 @@ impl<'a> Parser<'a> {
let inner_lo = self.token.span;
let is_negative = self.eat(&token::Not);
let modifiers = self.parse_ty_bound_modifiers();
let modifiers = self.parse_ty_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)?
@ -690,7 +691,7 @@ impl<'a> Parser<'a> {
if let Some(span) = modifiers.maybe_const {
self.struct_span_err(
span,
"`?const` may only modify trait bounds, not lifetime bounds",
"`~const` may only modify trait bounds, not lifetime bounds",
)
.emit();
}
@ -721,34 +722,27 @@ impl<'a> Parser<'a> {
Ok(())
}
/// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
/// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `~const Trait`.
///
/// If no modifiers are present, this does not consume any tokens.
///
/// ```
/// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
/// TY_BOUND_MODIFIERS = ["~const"] ["?"]
/// ```
fn parse_ty_bound_modifiers(&mut self) -> BoundModifiers {
if !self.eat(&token::Question) {
return BoundModifiers { maybe: None, maybe_const: None };
}
fn parse_ty_bound_modifiers(&mut self) -> PResult<'a, BoundModifiers> {
let maybe_const = 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)
} else {
None
};
// `? ...`
let first_question = self.prev_token.span;
if !self.eat_keyword(kw::Const) {
return BoundModifiers { maybe: Some(first_question), maybe_const: None };
}
let maybe = if self.eat(&token::Question) { Some(self.prev_token.span) } else { None };
// `?const ...`
let maybe_const = first_question.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::const_trait_bound_opt_out, maybe_const);
if !self.eat(&token::Question) {
return BoundModifiers { maybe: None, maybe_const: Some(maybe_const) };
}
// `?const ? ...`
let second_question = self.prev_token.span;
BoundModifiers { maybe: Some(second_question), maybe_const: Some(maybe_const) }
Ok(BoundModifiers { maybe, maybe_const })
}
/// Parses a type bound according to:
@ -757,7 +751,7 @@ impl<'a> Parser<'a> {
/// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
/// ```
///
/// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
/// For example, this grammar accepts `~const ?for<'a: 'b> m::Trait<'a>`.
fn parse_generic_ty_bound(
&mut self,
lo: Span,