Skip to content

Commit ba21ceb

Browse files
committed
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
1 parent 9d306cd commit ba21ceb

File tree

32 files changed

+499
-108
lines changed

32 files changed

+499
-108
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3348,11 +3348,18 @@ pub struct Impl {
33483348
pub items: ThinVec<P<AssocItem>>,
33493349
}
33503350

3351+
#[derive(Clone, Encodable, Decodable, Debug, Default)]
3352+
pub struct FnContract {
3353+
pub requires: Option<P<Expr>>,
3354+
pub ensures: Option<P<Expr>>,
3355+
}
3356+
33513357
#[derive(Clone, Encodable, Decodable, Debug)]
33523358
pub struct Fn {
33533359
pub defaultness: Defaultness,
33543360
pub generics: Generics,
33553361
pub sig: FnSig,
3362+
pub contract: Option<P<FnContract>>,
33563363
pub body: Option<P<Block>>,
33573364
}
33583365

@@ -3650,7 +3657,7 @@ mod size_asserts {
36503657
static_assert_size!(Block, 32);
36513658
static_assert_size!(Expr, 72);
36523659
static_assert_size!(ExprKind, 40);
3653-
static_assert_size!(Fn, 160);
3660+
static_assert_size!(Fn, 168);
36543661
static_assert_size!(ForeignItem, 88);
36553662
static_assert_size!(ForeignItemKind, 16);
36563663
static_assert_size!(GenericArg, 24);

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ pub trait MutVisitor: Sized {
143143
walk_flat_map_assoc_item(self, i, ctxt)
144144
}
145145

146+
fn visit_contract(&mut self, c: &mut P<FnContract>) {
147+
walk_contract(self, c);
148+
}
149+
146150
fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
147151
walk_fn_decl(self, d);
148152
}
@@ -954,11 +958,19 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
954958

955959
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
956960
match kind {
957-
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
961+
FnKind::Fn(
962+
_ctxt,
963+
_ident,
964+
_vis,
965+
Fn { generics, body, sig: FnSig { header, decl, span }, contract, .. },
966+
) => {
958967
// Identifier and visibility are visited as a part of the item.
959968
vis.visit_fn_header(header);
960969
vis.visit_generics(generics);
961970
vis.visit_fn_decl(decl);
971+
if let Some(contract) = contract {
972+
vis.visit_contract(contract);
973+
}
962974
if let Some(body) = body {
963975
vis.visit_block(body);
964976
}
@@ -973,6 +985,16 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
973985
}
974986
}
975987

988+
fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut P<FnContract>) {
989+
let FnContract { requires, ensures } = contract.deref_mut();
990+
if let Some(pred) = requires {
991+
vis.visit_expr(pred);
992+
}
993+
if let Some(pred) = ensures {
994+
vis.visit_expr(pred);
995+
}
996+
}
997+
976998
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
977999
let FnDecl { inputs, output } = decl.deref_mut();
9781000
inputs.flat_map_in_place(|param| vis.flat_map_param(param));
@@ -1205,13 +1227,9 @@ impl WalkItemKind for ItemKind {
12051227
ItemKind::Const(item) => {
12061228
visit_const_item(item, vis);
12071229
}
1208-
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
1209-
visit_defaultness(vis, defaultness);
1210-
vis.visit_fn(
1211-
FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
1212-
span,
1213-
id,
1214-
);
1230+
ItemKind::Fn(func) => {
1231+
visit_defaultness(vis, &mut func.defaultness);
1232+
vis.visit_fn(FnKind::Fn(FnCtxt::Free, ident, visibility, &mut *func), span, id);
12151233
}
12161234
ItemKind::Mod(safety, mod_kind) => {
12171235
visit_safety(vis, safety);
@@ -1329,10 +1347,10 @@ impl WalkItemKind for AssocItemKind {
13291347
AssocItemKind::Const(item) => {
13301348
visit_const_item(item, visitor);
13311349
}
1332-
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
1333-
visit_defaultness(visitor, defaultness);
1350+
AssocItemKind::Fn(func) => {
1351+
visit_defaultness(visitor, &mut func.defaultness);
13341352
visitor.visit_fn(
1335-
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
1353+
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, visibility, &mut *func),
13361354
span,
13371355
id,
13381356
);
@@ -1476,10 +1494,10 @@ impl WalkItemKind for ForeignItemKind {
14761494
visitor.visit_ty(ty);
14771495
visit_opt(expr, |expr| visitor.visit_expr(expr));
14781496
}
1479-
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
1480-
visit_defaultness(visitor, defaultness);
1497+
ForeignItemKind::Fn(func) => {
1498+
visit_defaultness(visitor, &mut func.defaultness);
14811499
visitor.visit_fn(
1482-
FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
1500+
FnKind::Fn(FnCtxt::Foreign, ident, visibility, &mut *func),
14831501
span,
14841502
id,
14851503
);
@@ -1965,14 +1983,7 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
19651983
#[derive(Debug)]
19661984
pub enum FnKind<'a> {
19671985
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
1968-
Fn(
1969-
FnCtxt,
1970-
&'a mut Ident,
1971-
&'a mut FnSig,
1972-
&'a mut Visibility,
1973-
&'a mut Generics,
1974-
&'a mut Option<P<Block>>,
1975-
),
1986+
Fn(FnCtxt, &'a mut Ident, &'a mut Visibility, &'a mut Fn),
19761987

19771988
/// E.g., `|x, y| body`.
19781989
Closure(

compiler/rustc_ast/src/visit.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl BoundKind {
6565
#[derive(Copy, Clone, Debug)]
6666
pub enum FnKind<'a> {
6767
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
68-
Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
68+
Fn(FnCtxt, &'a Ident, &'a Visibility, &'a Fn),
6969

7070
/// E.g., `|x, y| body`.
7171
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
@@ -74,7 +74,7 @@ pub enum FnKind<'a> {
7474
impl<'a> FnKind<'a> {
7575
pub fn header(&self) -> Option<&'a FnHeader> {
7676
match *self {
77-
FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
77+
FnKind::Fn(_, _, _, Fn { sig, .. }) => Some(&sig.header),
7878
FnKind::Closure(..) => None,
7979
}
8080
}
@@ -88,7 +88,7 @@ impl<'a> FnKind<'a> {
8888

8989
pub fn decl(&self) -> &'a FnDecl {
9090
match self {
91-
FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
91+
FnKind::Fn(_, _, _, Fn { sig, .. }) => &sig.decl,
9292
FnKind::Closure(_, _, decl, _) => decl,
9393
}
9494
}
@@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized {
188188
fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result {
189189
walk_closure_binder(self, b)
190190
}
191+
fn visit_contract(&mut self, c: &'ast FnContract) -> Self::Result {
192+
walk_contract(self, c)
193+
}
191194
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result {
192195
walk_where_predicate(self, p)
193196
}
@@ -374,8 +377,8 @@ impl WalkItemKind for ItemKind {
374377
try_visit!(visitor.visit_ty(ty));
375378
visit_opt!(visitor, visit_expr, expr);
376379
}
377-
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
378-
let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
380+
ItemKind::Fn(func) => {
381+
let kind = FnKind::Fn(FnCtxt::Free, ident, vis, &*func);
379382
try_visit!(visitor.visit_fn(kind, span, id));
380383
}
381384
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
@@ -715,8 +718,8 @@ impl WalkItemKind for ForeignItemKind {
715718
try_visit!(visitor.visit_ty(ty));
716719
visit_opt!(visitor, visit_expr, expr);
717720
}
718-
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
719-
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
721+
ForeignItemKind::Fn(func) => {
722+
let kind = FnKind::Fn(FnCtxt::Foreign, ident, vis, &*func);
720723
try_visit!(visitor.visit_fn(kind, span, id));
721724
}
722725
ForeignItemKind::TyAlias(box TyAlias {
@@ -800,6 +803,17 @@ pub fn walk_closure_binder<'a, V: Visitor<'a>>(
800803
V::Result::output()
801804
}
802805

806+
pub fn walk_contract<'a, V: Visitor<'a>>(visitor: &mut V, c: &'a FnContract) -> V::Result {
807+
let FnContract { requires, ensures } = c;
808+
if let Some(pred) = requires {
809+
visitor.visit_expr(pred);
810+
}
811+
if let Some(pred) = ensures {
812+
visitor.visit_expr(pred);
813+
}
814+
V::Result::output()
815+
}
816+
803817
pub fn walk_where_predicate<'a, V: Visitor<'a>>(
804818
visitor: &mut V,
805819
predicate: &'a WherePredicate,
@@ -858,11 +872,17 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(
858872

859873
pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result {
860874
match kind {
861-
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) => {
875+
FnKind::Fn(
876+
_ctxt,
877+
_ident,
878+
_vis,
879+
Fn { sig: FnSig { header, decl, span: _ }, generics, contract, body, .. },
880+
) => {
862881
// Identifier and visibility are visited as a part of the item.
863882
try_visit!(visitor.visit_fn_header(header));
864883
try_visit!(visitor.visit_generics(generics));
865884
try_visit!(visitor.visit_fn_decl(decl));
885+
visit_opt!(visitor, visit_contract, contract);
866886
visit_opt!(visitor, visit_block, body);
867887
}
868888
FnKind::Closure(binder, coroutine_kind, decl, body) => {
@@ -892,8 +912,8 @@ impl WalkItemKind for AssocItemKind {
892912
try_visit!(visitor.visit_ty(ty));
893913
visit_opt!(visitor, visit_expr, expr);
894914
}
895-
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
896-
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
915+
AssocItemKind::Fn(func) => {
916+
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, vis, &*func);
897917
try_visit!(visitor.visit_fn(kind, span, id));
898918
}
899919
AssocItemKind::Type(box TyAlias {

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
314314
hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
315315
}
316316
ExprKind::Ret(e) => {
317-
let e = e.as_ref().map(|x| self.lower_expr(x));
317+
let mut e = e.as_ref().map(|x| self.lower_expr(x));
318+
if let Some(Some((span, fresh_ident))) = self
319+
.contract
320+
.as_ref()
321+
.map(|c| c.ensures.as_ref().map(|e| (e.expr.span, e.fresh_ident)))
322+
{
323+
let checker_fn = self.expr_ident(span, fresh_ident.0, fresh_ident.2);
324+
let args = if let Some(e) = e {
325+
std::slice::from_ref(e)
326+
} else {
327+
std::slice::from_ref(self.expr_unit(span))
328+
};
329+
e = Some(self.expr_call(span, checker_fn, args));
330+
}
318331
hir::ExprKind::Ret(e)
319332
}
320333
ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
@@ -2125,7 +2138,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
21252138
self.arena.alloc(self.expr_call_mut(span, e, args))
21262139
}
21272140

2128-
fn expr_call_lang_item_fn_mut(
2141+
pub(super) fn expr_call_lang_item_fn_mut(
21292142
&mut self,
21302143
span: Span,
21312144
lang_item: hir::LangItem,
@@ -2135,7 +2148,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
21352148
self.expr_call_mut(span, path, args)
21362149
}
21372150

2138-
fn expr_call_lang_item_fn(
2151+
pub(super) fn expr_call_lang_item_fn(
21392152
&mut self,
21402153
span: Span,
21412154
lang_item: hir::LangItem,

0 commit comments

Comments
 (0)