Express contracts as part of function header and lower it to the contract lang items

includes post-developed commit: do not suggest internal-only keywords as corrections to parse failures.

includes post-developed commit: removed tabs that creeped in into rustfmt tool source code.

includes post-developed commit, placating rustfmt self dogfooding.

includes post-developed commit: add backquotes to prevent markdown checking from trying to treat an attr as a markdown hyperlink/

includes post-developed commit: fix lowering to keep contracts from being erroneously inherited by nested bodies (like closures).

Rebase Conflicts:
 - compiler/rustc_parse/src/parser/diagnostics.rs
 - compiler/rustc_parse/src/parser/item.rs
 - compiler/rustc_span/src/hygiene.rs

Remove contracts keywords from diagnostic messages
This commit is contained in:
Celina G. Val 2025-01-08 16:38:25 -08:00
parent 777def87d5
commit 38eff16d0a
27 changed files with 405 additions and 17 deletions

View file

@ -297,6 +297,28 @@ impl<'a> Parser<'a> {
})
}
/// Parses a rustc-internal fn contract
/// (`rustc_contract_requires(WWW) rustc_contract_ensures(ZZZ)`)
pub(super) fn parse_contract(
&mut self,
) -> PResult<'a, Option<rustc_ast::ptr::P<ast::FnContract>>> {
let requires = if self.eat_keyword_noexpect(exp!(RustcContractRequires).kw) {
Some(self.parse_expr()?)
} else {
None
};
let ensures = if self.eat_keyword_noexpect(exp!(RustcContractEnsures).kw) {
Some(self.parse_expr()?)
} else {
None
};
if requires.is_none() && ensures.is_none() {
Ok(None)
} else {
Ok(Some(rustc_ast::ptr::P(ast::FnContract { requires, ensures })))
}
}
/// Parses an optional where-clause.
///
/// ```ignore (only-for-syntax-highlight)

View file

@ -213,9 +213,12 @@ impl<'a> Parser<'a> {
self.parse_use_item()?
} else if self.check_fn_front_matter(check_pub, case) {
// FUNCTION ITEM
let (ident, sig, generics, body) =
let (ident, sig, generics, contract, body) =
self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body })))
(
ident,
ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, contract, body })),
)
} else if self.eat_keyword(exp!(Extern)) {
if self.eat_keyword(exp!(Crate)) {
// EXTERN CRATE
@ -2372,7 +2375,7 @@ impl<'a> Parser<'a> {
sig_lo: Span,
vis: &Visibility,
case: Case,
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<FnContract>>, Option<P<Block>>)> {
let fn_span = self.token.span;
let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
let ident = self.parse_ident()?; // `foo`
@ -2398,6 +2401,8 @@ impl<'a> Parser<'a> {
// inside `parse_fn_body()`.
let fn_params_end = self.prev_token.span.shrink_to_hi();
let contract = self.parse_contract()?;
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
// `fn_params_end` is needed only when it's followed by a where clause.
@ -2409,7 +2414,7 @@ impl<'a> Parser<'a> {
let body =
self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body, fn_params_end)?;
let fn_sig_span = sig_lo.to(sig_hi);
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, contract, body))
}
/// Provide diagnostics when function body is not found

View file

@ -108,6 +108,8 @@ pub enum TokenType {
KwRef,
KwReturn,
KwReuse,
KwRustcContractEnsures,
KwRustcContractRequires,
KwSafe,
KwSelfUpper,
KwStatic,
@ -242,6 +244,8 @@ impl TokenType {
KwRef,
KwReturn,
KwReuse,
KwRustcContractEnsures,
KwRustcContractRequires,
KwSafe,
KwSelfUpper,
KwStatic,
@ -314,6 +318,8 @@ impl TokenType {
TokenType::KwRef => Some(kw::Ref),
TokenType::KwReturn => Some(kw::Return),
TokenType::KwReuse => Some(kw::Reuse),
TokenType::KwRustcContractEnsures => Some(kw::RustcContractEnsures),
TokenType::KwRustcContractRequires => Some(kw::RustcContractRequires),
TokenType::KwSafe => Some(kw::Safe),
TokenType::KwSelfUpper => Some(kw::SelfUpper),
TokenType::KwStatic => Some(kw::Static),
@ -544,6 +550,8 @@ macro_rules! exp {
(Ref) => { exp!(@kw, Ref, KwRef) };
(Return) => { exp!(@kw, Return, KwReturn) };
(Reuse) => { exp!(@kw, Reuse, KwReuse) };
(RustcContractEnsures) => { exp!(@kw, RustcContractEnsures, KwRustcContractEnsures) };
(RustcContractRequires) => { exp!(@kw, RustcContractRequires, KwRustcContractRequires) };
(Safe) => { exp!(@kw, Safe, KwSafe) };
(SelfUpper) => { exp!(@kw, SelfUpper, KwSelfUpper) };
(Static) => { exp!(@kw, Static, KwStatic) };