diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 937031324f57f..8a836951ff432 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3246,11 +3246,18 @@ pub struct Impl { pub items: ThinVec<P<AssocItem>>, } +#[derive(Clone, Encodable, Decodable, Debug, Default)] +pub struct FnContract { + pub requires: Option<P<Expr>>, + pub ensures: Option<P<Expr>>, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub struct Fn { pub defaultness: Defaultness, pub generics: Generics, pub sig: FnSig, + pub contract: FnContract, pub body: Option<P<Block>>, } @@ -3548,7 +3555,7 @@ mod size_asserts { static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 160); + static_assert_size!(Fn, 176); static_assert_size!(ForeignItem, 88); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 1a7da46913d7e..471a459294776 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -119,6 +119,10 @@ pub trait MutVisitor: Sized { walk_flat_map_item(self, i) } + fn visit_contract(&mut self, c: &mut FnContract) { + walk_contract(self, c); + } + fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) { walk_fn_decl(self, d); } @@ -898,6 +902,15 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) { } } +fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut FnContract) { + if let Some(pred) = &mut contract.requires { + vis.visit_expr(pred); + } + if let Some(pred) = &mut contract.ensures { + vis.visit_expr(pred); + } +} + fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) { let FnDecl { inputs, output } = decl.deref_mut(); inputs.flat_map_in_place(|param| vis.flat_map_param(param)); @@ -1100,8 +1113,9 @@ impl WalkItemKind for ItemKind { ItemKind::Const(item) => { visit_const_item(item, vis); } - ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { + ItemKind::Fn(box Fn { defaultness, generics, sig, contract, body }) => { visit_defaultness(vis, defaultness); + vis.visit_contract(contract); vis.visit_fn(FnKind::Fn(sig, generics, body), span, id); } ItemKind::Mod(safety, mod_kind) => { @@ -1206,8 +1220,9 @@ impl WalkItemKind for AssocItemKind { AssocItemKind::Const(item) => { visit_const_item(item, visitor); } - AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { + AssocItemKind::Fn(box Fn { defaultness, generics, sig, contract, body }) => { visit_defaultness(visitor, defaultness); + visitor.visit_contract(contract); visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); } AssocItemKind::Type(box TyAlias { @@ -1311,8 +1326,9 @@ impl WalkItemKind for ForeignItemKind { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } - ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => { + ForeignItemKind::Fn(box Fn { defaultness, generics, sig, contract, body }) => { visit_defaultness(visitor, defaultness); + visitor.visit_contract(contract); visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id); } ForeignItemKind::TyAlias(box TyAlias { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 4dcadb8517eb4..dd30a7f1ce013 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -15,8 +15,8 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; -use rustc_span::Span; use rustc_span::symbol::Ident; +use rustc_span::Span; use crate::ast::*; use crate::ptr::P; @@ -66,7 +66,7 @@ impl BoundKind { #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>), + Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a FnContract, Option<&'a Block>), /// E.g., `|x, y| body`. Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr), @@ -75,7 +75,7 @@ pub enum FnKind<'a> { impl<'a> FnKind<'a> { pub fn header(&self) -> Option<&'a FnHeader> { match *self { - FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header), + FnKind::Fn(_, _, sig, _, _, _, _) => Some(&sig.header), FnKind::Closure(..) => None, } } @@ -89,7 +89,7 @@ impl<'a> FnKind<'a> { pub fn decl(&self) -> &'a FnDecl { match self { - FnKind::Fn(_, _, sig, _, _, _) => &sig.decl, + FnKind::Fn(_, _, sig, _, _, _, _) => &sig.decl, FnKind::Closure(_, _, decl, _) => decl, } } @@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized { fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result { walk_closure_binder(self, b) } + fn visit_contract(&mut self, c: &'ast FnContract) -> Self::Result { + walk_contract(self, c) + } fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result { walk_where_predicate(self, p) } @@ -359,8 +362,16 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } - ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref()); + ItemKind::Fn(box Fn { defaultness: _, generics, sig, contract, body }) => { + let kind = FnKind::Fn( + FnCtxt::Free, + *ident, + sig, + vis, + generics, + &contract, + body.as_deref(), + ); try_visit!(visitor.visit_fn(kind, *span, *id)); } ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { @@ -695,8 +706,16 @@ impl WalkItemKind for ForeignItemKind { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } - ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref()); + ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, contract, body }) => { + let kind = FnKind::Fn( + FnCtxt::Foreign, + ident, + sig, + vis, + generics, + contract, + body.as_deref(), + ); try_visit!(visitor.visit_fn(kind, span, id)); } ForeignItemKind::TyAlias(box TyAlias { @@ -784,6 +803,17 @@ pub fn walk_closure_binder<'a, V: Visitor<'a>>( V::Result::output() } +pub fn walk_contract<'a, V: Visitor<'a>>(visitor: &mut V, c: &'a FnContract) -> V::Result { + let FnContract { requires, ensures } = c; + if let Some(pred) = requires { + visitor.visit_expr(pred); + } + if let Some(pred) = ensures { + visitor.visit_expr(pred); + } + V::Result::output() +} + pub fn walk_where_predicate<'a, V: Visitor<'a>>( visitor: &mut V, predicate: &'a WherePredicate, @@ -829,11 +859,20 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>( pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result { match kind { - FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) => { + FnKind::Fn( + _ctxt, + _ident, + FnSig { header, decl, span: _ }, + _vis, + generics, + contract, + body, + ) => { // Identifier and visibility are visited as a part of the item. try_visit!(visitor.visit_fn_header(header)); try_visit!(visitor.visit_generics(generics)); try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_contract(contract)); visit_opt!(visitor, visit_block, body); } FnKind::Closure(binder, _coroutine_kind, decl, body) => { @@ -859,9 +898,16 @@ impl WalkItemKind for AssocItemKind { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } - AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => { - let kind = - FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref()); + AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, contract, body }) => { + let kind = FnKind::Fn( + FnCtxt::Assoc(ctxt), + ident, + sig, + vis, + generics, + contract, + body.as_deref(), + ); try_visit!(visitor.visit_fn(kind, span, id)); } AssocItemKind::Type(box TyAlias { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 1273b50dff816..c9485aa565e57 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -3,17 +3,17 @@ use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_hir::PredicateOrigin; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::PredicateOrigin; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{Ident, kw, sym}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{DesugaringKind, Span, Symbol}; use rustc_target::spec::abi; -use smallvec::{SmallVec, smallvec}; +use smallvec::{smallvec, SmallVec}; use thin_vec::ThinVec; use tracing::instrument; @@ -206,6 +206,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, generics, + contract, body, .. }) => { @@ -223,6 +224,9 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_kind, body.as_deref(), ); + let last_recorded_body = this.bodies.last().unwrap(); + assert_eq!(last_recorded_body.0, body_id.hir_id.local_id); + let contract_params: &'hir [hir::Param<'hir>] = last_recorded_body.1.params; let itctx = ImplTraitContext::Universal; let (generics, decl) = @@ -240,7 +244,8 @@ impl<'hir> LoweringContext<'_, 'hir> { header: this.lower_fn_header(*header, hir::Safety::Safe), span: this.lower_span(*fn_sig_span), }; - hir::ItemKind::Fn(sig, generics, body_id) + let contract_ids = this.lower_contract(id, contract_params, contract); + hir::ItemKind::Fn(sig, generics, Some(contract_ids), body_id) }) } ItemKind::Mod(_, mod_kind) => match mod_kind { @@ -281,12 +286,15 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) } - Some(ty) => this.lower_ty(ty, ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(id), - in_assoc_ty: false, + Some(ty) => this.lower_ty( + ty, + ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(id), + in_assoc_ty: false, + }, }, - }), + ), }, ); hir::ItemKind::TyAlias(ty, generics) @@ -457,6 +465,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Fn( delegation_results.sig, delegation_results.generics, + None, delegation_results.body_id, ) } @@ -977,12 +986,15 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Type(ty) } Some(ty) => { - let ty = this.lower_ty(ty, ImplTraitContext::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(i.id), - in_assoc_ty: true, + let ty = this.lower_ty( + ty, + ImplTraitContext::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { + parent: this.local_def_id(i.id), + in_assoc_ty: true, + }, }, - }); + ); hir::ImplItemKind::Type(ty) } }, @@ -1121,13 +1133,57 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { self.lower_body(|this| { - (&[], match expr { - Some(expr) => this.lower_expr_mut(expr), - None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), - }) + ( + &[], + match expr { + Some(expr) => this.lower_expr_mut(expr), + None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), + }, + ) }) } + fn lower_contract( + &mut self, + parent_node_id: NodeId, + params: &'hir [hir::Param<'hir>], + contract: &ast::FnContract, + ) -> &'hir hir::FnContractIds { + let precond: Option<&P<Expr>> = contract.requires.as_ref(); + let postcond: Option<&P<Expr>> = contract.ensures.as_ref(); + let precond: Option<hir::Contract> = precond.map(|e| { + let parent_node_hir_id = self.lower_node_id(parent_node_id); + let contract_node_id = self.next_node_id(); + + let def_id = self.create_def( + self.local_def_id(parent_node_id), + contract_node_id, + kw::Empty, + DefKind::Contract, + e.span, + ); + self.children.push((def_id, hir::MaybeOwner::NonOwner(parent_node_hir_id))); + let body_id = self.lower_body(|this| (params, this.lower_expr_mut(e))); + hir::Contract { def_id, body_id } + }); + let postcond: Option<hir::Contract> = postcond.map(|e| { + let parent_node_hir_id = self.lower_node_id(parent_node_id); + let contract_node_id = self.next_node_id(); + let def_id = self.create_def( + self.local_def_id(parent_node_id), + contract_node_id, + kw::Empty, + DefKind::Contract, + e.span, + ); + self.children.push((def_id, hir::MaybeOwner::NonOwner(parent_node_hir_id))); + let body_id = self.lower_body(|this| (params, this.lower_expr_mut(e))); + hir::Contract { def_id, body_id } + }); + + self.arena.alloc(hir::FnContractIds { precond, postcond }) + } + /// Takes what may be the body of an `async fn` or a `gen fn` and wraps it in an `async {}` or /// `gen {}` block as appropriate. fn lower_maybe_coroutine_body( @@ -1504,10 +1560,10 @@ impl<'hir> LoweringContext<'_, 'hir> { for bound in &bound_pred.bounds { if !matches!( *bound, - GenericBound::Trait(_, TraitBoundModifiers { - polarity: BoundPolarity::Maybe(_), - .. - }) + GenericBound::Trait( + _, + TraitBoundModifiers { polarity: BoundPolarity::Maybe(_), .. } + ) ) { continue; } @@ -1608,13 +1664,16 @@ impl<'hir> LoweringContext<'_, 'hir> { self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id))); let const_body = self.lower_body(|this| { - (&[], hir::Expr { - hir_id: const_expr_id, - kind: hir::ExprKind::Lit( - this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), - ), - span, - }) + ( + &[], + hir::Expr { + hir_id: const_expr_id, + kind: hir::ExprKind::Lit( + this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), + ), + span, + }, + ) }); let default_ac = self.arena.alloc(hir::AnonConst { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 365924ef782e8..bdf63bf3dec99 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -53,7 +53,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate, @@ -63,9 +63,9 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, DesugaringKind, Span}; -use smallvec::{SmallVec, smallvec}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{DesugaringKind, Span, DUMMY_SP}; +use smallvec::{smallvec, SmallVec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -598,7 +598,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); - let current_trait_map = std::mem::take(&mut self.trait_map); + let current_trait_map: rustc_data_structures::unord::UnordMap< + rustc_hir::ItemLocalId, + Box<[TraitCandidate]>, + > = std::mem::take(&mut self.trait_map); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); let current_local_counter = diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 87e3a6871b9e1..56b0572fb58e6 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -961,7 +961,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. } - ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => { + ItemKind::Fn(box Fn { defaultness, sig, generics, contract, body }) => { self.check_defaultness(item.span, *defaultness); if body.is_none() { @@ -989,8 +989,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_vis(&item.vis); self.visit_ident(item.ident); + // self.visit_contract(contract); let kind = - FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref()); + FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, contract, body.as_deref()); self.visit_fn(kind, item.span, item.id); walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. @@ -1396,13 +1397,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { _, _, _, + _, ) = fk { self.maybe_lint_missing_abi(*sig_span, id); } // Functions without bodies cannot have patterns. - if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk { + if let FnKind::Fn(ctxt, _, sig, _, _, _, None) = fk { Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { @@ -1436,7 +1438,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .is_some(); let disallowed = (!tilde_const_allowed).then(|| match fk { - FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span }, + FnKind::Fn(_, ident, _, _, _, _, _) => TildeConstReason::Function { ident: ident.span }, FnKind::Closure(..) => TildeConstReason::Closure, }); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); @@ -1512,7 +1514,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some(); match &item.kind { - AssocItemKind::Fn(box Fn { sig, generics, body, .. }) + AssocItemKind::Fn(box Fn { sig, generics, contract, body, .. }) if parent_is_const || ctxt == AssocCtxt::Trait || matches!(sig.header.constness, Const::Yes(_)) => @@ -1525,6 +1527,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { sig, &item.vis, generics, + contract, body.as_deref(), ); walk_list!(self, visit_attribute, &item.attrs); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 8217b6df5b470..41f7fba2c42f2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -34,8 +34,8 @@ impl<'a> State<'a> { self.maybe_print_comment(span.lo()); self.print_outer_attributes(attrs); match kind { - ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { - self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); + ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, contract, body }) => { + self.print_fn_full(sig, ident, generics, vis, *defaultness, contract, body.as_deref(), attrs); } ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => { self.print_safety(*safety); @@ -195,13 +195,14 @@ impl<'a> State<'a> { *defaultness, ); } - ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { + ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, contract, body }) => { self.print_fn_full( sig, item.ident, generics, &item.vis, *defaultness, + contract, body.as_deref(), &item.attrs, ); @@ -538,8 +539,8 @@ impl<'a> State<'a> { self.maybe_print_comment(span.lo()); self.print_outer_attributes(attrs); match kind { - ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { - self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); + ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, contract, body }) => { + self.print_fn_full(sig, ident, generics, vis, *defaultness, contract, body.as_deref(), attrs); } ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => { self.print_item_const( @@ -653,6 +654,7 @@ impl<'a> State<'a> { generics: &ast::Generics, vis: &ast::Visibility, defaultness: ast::Defaultness, + contract: &ast::FnContract, body: Option<&ast::Block>, attrs: &[ast::Attribute], ) { @@ -662,6 +664,7 @@ impl<'a> State<'a> { self.print_visibility(vis); self.print_defaultness(defaultness); self.print_fn(&sig.decl, sig.header, Some(name), generics); + self.print_contract(contract); if let Some(body) = body { self.nbsp(); self.print_block_with_attrs(body, attrs); @@ -670,6 +673,17 @@ impl<'a> State<'a> { } } + fn print_contract(&mut self, contract: &ast::FnContract) { + if let Some(pred) = &contract.requires { + self.word("rustc_requires"); + self.print_expr(pred, FixupContext::default()); + } + if let Some(pred) = &contract.ensures { + self.word("rustc_ensures"); + self.print_expr(pred, FixupContext::default()); + } + } + pub(crate) fn print_fn( &mut self, decl: &ast::FnDecl, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index fa44ffcd17dd0..6a8327c43e16d 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -20,9 +20,9 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Diag; -use rustc_hir::BodyOwnerKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; +use rustc_hir::BodyOwnerKind; use rustc_index::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_macros::extension; @@ -37,8 +37,8 @@ use rustc_span::symbol::{kw, sym}; use rustc_span::{ErrorGuaranteed, Symbol}; use tracing::{debug, instrument}; -use crate::BorrowckInferCtxt; use crate::renumber::RegionCtxt; +use crate::BorrowckInferCtxt; #[derive(Debug)] pub(crate) struct UniversalRegions<'tcx> { @@ -98,6 +98,9 @@ pub(crate) struct UniversalRegions<'tcx> { /// appear bound in the signature. #[derive(Copy, Clone, Debug)] pub(crate) enum DefiningTy<'tcx> { + /// The MIR is a contract. + Contract(DefId, GenericArgsRef<'tcx>), + /// The MIR is a closure. The signature is found via /// `ClosureArgs::closure_sig_ty`. Closure(DefId, GenericArgsRef<'tcx>), @@ -138,9 +141,10 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(), DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(), DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(), - DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { - ty::List::empty() - } + DefiningTy::Contract(..) + | DefiningTy::FnDef(..) + | DefiningTy::Const(..) + | DefiningTy::InlineConst(..) => ty::List::empty(), } } @@ -152,6 +156,7 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(..) | DefiningTy::CoroutineClosure(..) | DefiningTy::Coroutine(..) => 1, + DefiningTy::Contract(..) => 0, // FIXME: this should probably be a 0 for precond and 1 for postcond. DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, } } @@ -167,6 +172,7 @@ impl<'tcx> DefiningTy<'tcx> { pub(crate) fn def_id(&self) -> DefId { match *self { DefiningTy::Closure(def_id, ..) + | DefiningTy::Contract(def_id, ..) | DefiningTy::CoroutineClosure(def_id, ..) | DefiningTy::Coroutine(def_id, ..) | DefiningTy::FnDef(def_id, ..) @@ -356,12 +362,10 @@ impl<'tcx> UniversalRegions<'tcx> { pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) { match self.defining_ty { DefiningTy::Closure(def_id, args) => { - let v = with_no_trimmed_paths!( - args[tcx.generics_of(def_id).parent_count..] - .iter() - .map(|arg| arg.to_string()) - .collect::<Vec<_>>() - ); + let v = with_no_trimmed_paths!(args[tcx.generics_of(def_id).parent_count..] + .iter() + .map(|arg| arg.to_string()) + .collect::<Vec<_>>()); err.note(format!( "defining type: {} with closure args [\n {},\n]", tcx.def_path_str_with_args(def_id, args), @@ -377,16 +381,14 @@ impl<'tcx> UniversalRegions<'tcx> { err.note(format!("late-bound region is {:?}", self.to_region_vid(r))); }); } - DefiningTy::CoroutineClosure(..) => { + DefiningTy::Contract(..) | DefiningTy::CoroutineClosure(..) => { todo!() } DefiningTy::Coroutine(def_id, args) => { - let v = with_no_trimmed_paths!( - args[tcx.generics_of(def_id).parent_count..] - .iter() - .map(|arg| arg.to_string()) - .collect::<Vec<_>>() - ); + let v = with_no_trimmed_paths!(args[tcx.generics_of(def_id).parent_count..] + .iter() + .map(|arg| arg.to_string()) + .collect::<Vec<_>>()); err.note(format!( "defining type: {} with coroutine args [\n {},\n]", tcx.def_path_str_with_args(def_id, args), @@ -629,15 +631,22 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = tcx .typeck(self.mir_def) .node_type(tcx.local_def_id_to_hir_id(self.mir_def)); - let args = InlineConstArgs::new(tcx, InlineConstArgsParts { - parent_args: identity_args, - ty, - }) + let args = InlineConstArgs::new( + tcx, + InlineConstArgsParts { parent_args: identity_args, ty }, + ) .args; let args = self.infcx.replace_free_regions_with_nll_infer_vars(FR, args); DefiningTy::InlineConst(self.mir_def.to_def_id(), args) } } + BodyOwnerKind::Contract => { + let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); + debug!("identity_args: {:?}", identity_args); + assert_eq!(self.mir_def.to_def_id(), typeck_root_def_id); + let args = self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_args); + DefiningTy::Contract(self.mir_def.to_def_id(), args) + } } } @@ -670,7 +679,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { args } - DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args, + DefiningTy::Contract(_, args) + | DefiningTy::FnDef(_, args) + | DefiningTy::Const(_, args) => args, }; let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); @@ -789,6 +800,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { ) } + DefiningTy::Contract(_def_id, _) => { + todo!() + } + DefiningTy::FnDef(def_id, _) => { let sig = tcx.fn_sig(def_id).instantiate_identity(); let sig = indices.fold_to_region_vids(tcx, sig); diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 0caad997b9df1..7830630ad5314 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -1,6 +1,7 @@ use rustc_ast::ptr::P; use rustc_ast::{ - self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind, + self as ast, Fn, FnContract, FnHeader, FnSig, Generics, ItemKind, + Safety, Stmt, StmtKind, TyKind, }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::Span; @@ -86,6 +87,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span defaultness: ast::Defaultness::Final, sig, generics: Generics::default(), + contract: FnContract::default(), body, })); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 82baaca9a4641..c095b321148f6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1043,6 +1043,7 @@ impl<'a> MethodDef<'a> { defaultness, sig, generics: fn_generics, + contract: ast::FnContract::default(), body: Some(body_block), })), tokens: None, diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index b4b18409a18eb..59086e36d8a6a 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -82,6 +82,7 @@ impl AllocFnFactory<'_, '_> { defaultness: ast::Defaultness::Final, sig, generics: Generics::default(), + contract: ast::FnContract::default(), body, })); let item = self.cx.item( diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 953484533087c..24e460cda4279 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -346,6 +346,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { defaultness, sig, generics: ast::Generics::default(), + contract: ast::FnContract::default(), body: Some(main_body), })); diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index aaa95f6b7f19e..1ae34be4e7198 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -1,3 +1,5 @@ +use std::panic::Location; + use crate::stable_hasher::{HashStable, StableHasher}; use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; @@ -24,18 +26,25 @@ use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; #[derive(Debug)] pub struct Steal<T> { value: RwLock<Option<T>>, + prev_stolen_by: RwLock<Option<&'static Location<'static>>>, } impl<T> Steal<T> { pub fn new(value: T) -> Self { - Steal { value: RwLock::new(Some(value)) } + Steal { value: RwLock::new(Some(value)), prev_stolen_by: RwLock::new(None) } } #[track_caller] pub fn borrow(&self) -> MappedReadGuard<'_, T> { let borrow = self.value.borrow(); if borrow.is_none() { - panic!("attempted to read from stolen value: {}", std::any::type_name::<T>()); + panic!( + "attempted to read from stolen value: {}, last stolen by: {}", + std::any::type_name::<T>(), + self.prev_stolen_by + .read() + .expect("if its stolen then prev_stolen_by should be set"), + ); } ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) } @@ -47,9 +56,24 @@ impl<T> Steal<T> { #[track_caller] pub fn steal(&self) -> T { + let caller = Location::caller(); + tracing::debug!( + "starting steal of {T} *{ADDR:x} initiated by {caller}", + T = std::any::type_name::<T>(), + ADDR = (self as *const _ as u64), + ); let value_ref = &mut *self.value.try_write().expect("stealing value which is locked"); let value = value_ref.take(); - value.expect("attempt to steal from stolen value") + let mut prev_stolen_by = self.prev_stolen_by.write(); + let ret = value.unwrap_or_else(|| { + panic!( + "attempt to steal from stolen value, last stolen by: {}", + prev_stolen_by.expect("if its stolen then prev_stolen_by should be set") + ); + }); + assert_eq!(*prev_stolen_by, None); + *prev_stolen_by = Some(caller); + ret } /// Writers of rustc drivers often encounter stealing issues. This function makes it possible to diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 3276f516a52a1..aee88f9494249 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -109,6 +109,8 @@ pub enum DefKind { Use, /// An `extern` block. ForeignMod, + /// A contract associated with a function definition + Contract, /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]` AnonConst, /// An inline constant, e.g. `const { 1 + 2 }` @@ -173,6 +175,7 @@ impl DefKind { DefKind::LifetimeParam => "lifetime parameter", DefKind::Use => "import", DefKind::ForeignMod => "foreign module", + DefKind::Contract => "contract", DefKind::AnonConst => "constant expression", DefKind::InlineConst => "inline constant", DefKind::Field => "field", @@ -230,7 +233,8 @@ impl DefKind { DefKind::Macro(..) => Some(Namespace::MacroNS), // Not namespaced. - DefKind::AnonConst + DefKind::Contract + | DefKind::AnonConst | DefKind::InlineConst | DefKind::Field | DefKind::LifetimeParam @@ -282,6 +286,7 @@ impl DefKind { DefKind::Impl { .. } => DefPathData::Impl, DefKind::Closure => DefPathData::Closure, DefKind::SyntheticCoroutineBody => DefPathData::Closure, + DefKind::Contract => DefPathData::Contract, } } @@ -323,6 +328,7 @@ impl DefKind { | DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam + | DefKind::Contract | DefKind::AnonConst | DefKind::InlineConst | DefKind::GlobalAsm diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 9873a58cfe99f..84d0323020fb1 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -291,6 +291,8 @@ pub enum DefPathData { OpaqueTy, /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }` AnonAdt, + /// A contract attached to a function definition + Contract, } impl Definitions { @@ -415,7 +417,7 @@ impl DefPathData { TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst - | OpaqueTy | AnonAdt => None, + | OpaqueTy | AnonAdt | Contract => None, } } @@ -439,6 +441,7 @@ impl DefPathData { AnonConst => DefPathDataName::Anon { namespace: sym::constant }, OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, AnonAdt => DefPathDataName::Anon { namespace: sym::anon_adt }, + Contract => DefPathDataName::Anon { namespace: sym::contract }, } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2ef6fa53f4edd..2e02798cd40fd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -17,18 +17,18 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{BytePos, ErrorGuaranteed, Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; use rustc_target::spec::abi::Abi; use smallvec::SmallVec; use tracing::debug; -use crate::LangItem; use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::FnKind; +use crate::LangItem; #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Lifetime { @@ -127,7 +127,11 @@ impl LifetimeName { impl fmt::Display for Lifetime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.ident.name != kw::Empty { self.ident.name.fmt(f) } else { "'_".fmt(f) } + if self.ident.name != kw::Empty { + self.ident.name.fmt(f) + } else { + "'_".fmt(f) + } } } @@ -1266,7 +1270,11 @@ impl DotDotPos { } pub fn as_opt_usize(&self) -> Option<usize> { - if self.0 == u32::MAX { None } else { Some(self.0 as usize) } + if self.0 == u32::MAX { + None + } else { + Some(self.0 as usize) + } } } @@ -1441,6 +1449,18 @@ pub struct BodyId { pub hir_id: HirId, } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +pub struct Contract { + pub def_id: LocalDefId, + pub body_id: BodyId, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +pub struct FnContractIds { + pub precond: Option<Contract>, + pub postcond: Option<Contract>, +} + /// The body of a function, closure, or constant value. In the case of /// a function, the body contains not only the function body itself /// (which is an expression), but also the argument patterns, since @@ -1597,13 +1617,18 @@ pub enum BodyOwnerKind { /// Initializer of a `static` item. Static(Mutability), + + /// Contract attached to a function + Contract, } impl BodyOwnerKind { pub fn is_fn_or_closure(self) -> bool { match self { BodyOwnerKind::Fn | BodyOwnerKind::Closure => true, - BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false, + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) | BodyOwnerKind::Contract => { + false + } } } } @@ -2596,10 +2621,10 @@ impl<'hir> Ty<'hir> { fn visit_ty(&mut self, t: &'v Ty<'v>) { if matches!( &t.kind, - TyKind::Path(QPath::Resolved(_, Path { - res: crate::def::Res::SelfTyAlias { .. }, - .. - },)) + TyKind::Path(QPath::Resolved( + _, + Path { res: crate::def::Res::SelfTyAlias { .. }, .. }, + )) ) { self.0.push(t.span); return; @@ -2942,11 +2967,10 @@ impl<'hir> InlineAsmOperand<'hir> { } pub fn is_clobber(&self) -> bool { - matches!(self, InlineAsmOperand::Out { - reg: InlineAsmRegOrRegClass::Reg(_), - late: _, - expr: None - }) + matches!( + self, + InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(_), late: _, expr: None } + ) } } @@ -3325,8 +3349,8 @@ impl<'hir> Item<'hir> { expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Const(ty, generics, body), (ty, generics, *body); - expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId), - ItemKind::Fn(sig, generics, body), (sig, generics, *body); + expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, Option<&'hir FnContractIds>, BodyId), + ItemKind::Fn(sig, generics, contract_ids, body), (sig, generics, *contract_ids, *body); expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk); @@ -3441,7 +3465,7 @@ pub enum ItemKind<'hir> { /// A `const` item. Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId), /// A function declaration. - Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId), + Fn(FnSig<'hir>, &'hir Generics<'hir>, Option<&'hir FnContractIds>, BodyId), /// A MBE macro definition (`macro_rules!` or `macro`). Macro(&'hir ast::MacroDef, MacroKind), /// A module. @@ -3492,7 +3516,7 @@ pub struct Impl<'hir> { impl ItemKind<'_> { pub fn generics(&self) -> Option<&Generics<'_>> { Some(match *self { - ItemKind::Fn(_, ref generics, _) + ItemKind::Fn(_, ref generics, _, _) | ItemKind::TyAlias(_, ref generics) | ItemKind::Const(_, ref generics, _) | ItemKind::Enum(_, ref generics) @@ -3677,7 +3701,7 @@ impl<'hir> OwnerNode<'hir> { match self { OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) - | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) + | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _, _), .. }) | OwnerNode::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig), @@ -3689,7 +3713,7 @@ impl<'hir> OwnerNode<'hir> { match self { OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) - | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) + | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _, _), .. }) | OwnerNode::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), @@ -3703,7 +3727,7 @@ impl<'hir> OwnerNode<'hir> { kind: ItemKind::Static(_, _, body) | ItemKind::Const(_, _, body) - | ItemKind::Fn(_, _, body), + | ItemKind::Fn(_, _, _, body), .. }) | OwnerNode::TraitItem(TraitItem { @@ -3882,7 +3906,7 @@ impl<'hir> Node<'hir> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) - | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) + | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _, _), .. }) | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => { Some(fn_sig.decl) } @@ -3912,7 +3936,7 @@ impl<'hir> Node<'hir> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) - | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) + | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _, _), .. }) | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => { Some(fn_sig) } @@ -4015,7 +4039,7 @@ impl<'hir> Node<'hir> { pub fn fn_kind(self) -> Option<FnKind<'hir>> { match self { Node::Item(i) => match i.kind { - ItemKind::Fn(ref sig, ref generics, _) => { + ItemKind::Fn(ref sig, ref generics, _, _) => { Some(FnKind::ItemFn(i.ident, generics, sig.header)) } _ => None, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 58916d0586593..b6afcc06572f9 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -64,11 +64,11 @@ //! This order consistency is required in a few places in rustc, for //! example coroutine inference, and possibly also HIR borrowck. -use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list}; +use rustc_ast::visit::{try_visit, visit_opt, walk_list, VisitorResult}; use rustc_ast::{Attribute, Label}; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::Span; use crate::hir::*; @@ -313,6 +313,12 @@ pub trait Visitor<'v>: Sized { fn visit_id(&mut self, _hir_id: HirId) -> Self::Result { Self::Result::output() } + fn visit_contract(&mut self, contract: &Contract) -> Self::Result { + self.visit_nested_body(contract.body_id) + } + fn visit_fn_contract_ids(&mut self, fn_contract_ids: &FnContractIds) -> Self::Result { + walk_fn_contract_ids(self, fn_contract_ids) + } fn visit_name(&mut self, _name: Symbol) -> Self::Result { Self::Result::output() } @@ -487,6 +493,19 @@ pub trait Visitor<'v>: Sized { } } +pub fn walk_fn_contract_ids<'v, V: Visitor<'v>>( + visitor: &mut V, + fn_contract_ids: &FnContractIds, +) -> V::Result { + if let Some(precond) = &fn_contract_ids.precond { + try_visit!(visitor.visit_contract(precond)); + } + if let Some(postcond) = &fn_contract_ids.postcond { + try_visit!(visitor.visit_contract(postcond)); + } + V::Result::output() +} + pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result { try_visit!(visitor.visit_id(param.hir_id)); visitor.visit_pat(param.pat) @@ -513,8 +532,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_nested_body(body)); } - ItemKind::Fn(ref sig, ref generics, body_id) => { + ItemKind::Fn(ref sig, ref generics, fn_contract_ids, body_id) => { try_visit!(visitor.visit_id(item.hir_id())); + if let Some(fn_contract_ids) = fn_contract_ids { + try_visit!(visitor.visit_fn_contract_ids(fn_contract_ids)); + } try_visit!(visitor.visit_fn( FnKind::ItemFn(item.ident, generics, sig.header), sig.decl, diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 7da2cd93d4e01..f29c2ff15bf56 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -45,7 +45,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return None; } match tcx.hir_node_by_def_id(def_id.expect_local()) { - Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => { + Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _, _), .. }) => { generics.params.is_empty().not().then_some(generics.span) } _ => { @@ -59,7 +59,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return None; } match tcx.hir_node_by_def_id(def_id.expect_local()) { - Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => { + Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _, _), .. }) => { Some(generics.where_clause_span) } _ => { @@ -80,7 +80,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return None; } match tcx.hir_node_by_def_id(def_id.expect_local()) { - Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. }) => { + Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _, _), .. }) => { Some(fn_sig.decl.output.span()) } _ => { @@ -202,7 +202,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { match start_t.kind() { ty::FnDef(..) => { if let Node::Item(it) = tcx.hir_node(start_id) { - if let hir::ItemKind::Fn(sig, generics, _) = &it.kind { + if let hir::ItemKind::Fn(sig, generics, _, _) = &it.kind { let mut error = false; if !generics.params.is_empty() { tcx.dcx().emit_err(errors::StartFunctionParameters { span: generics.span }); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 06317a3b3049c..70f6da6a30956 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -28,7 +28,7 @@ fn equate_intrinsic_type<'tcx>( sig: ty::PolyFnSig<'tcx>, ) { let (generics, span) = match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _, _), .. }) | hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(_, _, generics), .. diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 3a9d2640eee93..f53b90527aac0 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2234,7 +2234,8 @@ fn lint_redundant_lifetimes<'tcx>( | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Closure - | DefKind::SyntheticCoroutineBody => return, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => return, } // The ordering of this lifetime map is a bit subtle. diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f63e2d40e3906..93bad3f5b76c2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1315,7 +1315,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn generics, .. }) - | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => { + | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _, _), .. }) => { infer_return_ty_for_fn_sig(sig, generics, def_id, &icx) } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 14b6b17ed18a7..634081c287e72 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -8,8 +8,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; +use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -use rustc_span::symbol::{Symbol, kw}; use tracing::{debug, instrument}; use crate::delegation::inherit_generics_for_delegation_item; @@ -326,7 +326,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { prev + type_start }; - const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ + const TYPE_DEFAULT_NOT_ALLOWED: &'static str = + "defaults for type parameters are only allowed in \ `struct`, `enum`, `type`, or `trait` definitions"; own_params.extend(hir_generics.params.iter().filter_map(|param| match param.kind { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 6d30f7c7b9d07..1b0a28764981b 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, GenericPredicates, ImplTraitInTraitData, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Ident; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{Span, DUMMY_SP}; use tracing::{debug, instrument, trace}; use crate::bounds::Bounds; @@ -379,10 +379,10 @@ fn compute_bidirectional_outlives_predicates<'tcx>( for param in opaque_own_params { let orig_lifetime = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()); if let ty::ReEarlyParam(..) = *orig_lifetime { - let dup_lifetime = ty::Region::new_early_param(tcx, ty::EarlyParamRegion { - index: param.index, - name: param.name, - }); + let dup_lifetime = ty::Region::new_early_param( + tcx, + ty::EarlyParamRegion { index: param.index, name: param.name }, + ); let span = tcx.def_span(param.def_id); predicates.push(( ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_lifetime, dup_lifetime)) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index c8852a3a3695a..ca0ef9664f923 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -521,7 +521,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { _ => {} } match item.kind { - hir::ItemKind::Fn(_, generics, _) => { + hir::ItemKind::Fn(_, generics, _, _) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_item(this, item); }); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 11c0450bfe211..b673a223e745b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -3,8 +3,8 @@ use rustc_errors::codes::*; use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_lint_defs::Applicability; use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS; +use rustc_lint_defs::Applicability; use rustc_span::Span; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; @@ -189,7 +189,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // 2. Functions inside trait blocks // 3. Functions inside impl blocks let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _, _), .. }) => { (sig, generics) } hir::Node::TraitItem(hir::TraitItem { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9fe6a8ee3425a..d103cee946c18 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -363,6 +363,7 @@ impl<'a> State<'a> { generics, arg_names, None, + None, ); self.end(); // end head-ibox self.word(";"); @@ -522,7 +523,7 @@ impl<'a> State<'a> { self.word(";"); self.end(); // end the outer cbox } - hir::ItemKind::Fn(ref sig, generics, body) => { + hir::ItemKind::Fn(ref sig, generics, fn_contract_ids, body) => { self.head(""); self.print_fn( sig.decl, @@ -530,6 +531,7 @@ impl<'a> State<'a> { Some(item.ident.name), generics, &[], + fn_contract_ids, Some(body), ); self.word(" "); @@ -792,7 +794,7 @@ impl<'a> State<'a> { arg_names: &[Ident], body_id: Option<hir::BodyId>, ) { - self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id); + self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, None, body_id); } fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { @@ -1942,6 +1944,7 @@ impl<'a> State<'a> { name: Option<Symbol>, generics: &hir::Generics<'_>, arg_names: &[Ident], + fn_contract_ids: Option<&hir::FnContractIds>, body_id: Option<hir::BodyId>, ) { self.print_fn_header_info(header); @@ -1982,6 +1985,9 @@ impl<'a> State<'a> { self.pclose(); self.print_fn_output(decl); + if let Some(contract_ids) = fn_contract_ids { + self.print_contracts(contract_ids); + } self.print_where_clause(generics) } @@ -2146,6 +2152,23 @@ impl<'a> State<'a> { self.print_ident(lifetime.ident) } + fn print_contracts(&mut self, fn_contract_ids: &hir::FnContractIds) { + if let Some(precond) = fn_contract_ids.precond { + self.space(); + self.word("rustc_contract_requires"); + self.popen(); + self.ann.nested(self, Nested::Body(precond.body_id)); + self.pclose(); + } + if let Some(postcond) = fn_contract_ids.postcond { + self.space(); + self.word("rustc_contract_ensures"); + self.popen(); + self.ann.nested(self, Nested::Body(postcond.body_id)); + self.pclose(); + } + } + fn print_where_clause(&mut self, generics: &hir::Generics<'_>) { if generics.predicates.is_empty() { return; @@ -2260,6 +2283,7 @@ impl<'a> State<'a> { generics, arg_names, None, + None, ); self.end(); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index fa471647d02d0..44df9647ccf24 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1988,7 +1988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn parent_item_span(&self, id: HirId) -> Option<Span> { let node = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(id).def_id); match node { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, _, body_id), .. }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { let body = self.tcx.hir().body(body_id); if let ExprKind::Block(block, _) = &body.value.kind { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1df4d32f3cbac..9f74c016597b3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -989,6 +989,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. }, hir::Generics { params, predicates, .. }, + _, _body_id, ), .. diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 63cf483aa2274..885b97cda2fab 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1924,7 +1924,7 @@ fn drop_location_span(tcx: TyCtxt<'_>, hir_id: HirId) -> Span { let owner_node = tcx.hir_node(owner_id); let owner_span = match owner_node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Fn(_, _, owner_id) => tcx.hir().span(owner_id.hir_id), + hir::ItemKind::Fn(_, _, _, owner_id) => tcx.hir().span(owner_id.hir_id), _ => { bug!("Drop location span error: need to handle more ItemKind '{:?}'", item.kind); } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index b193b81f6de48..a3241feba37d8 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -7,16 +7,16 @@ use std::mem; use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::HirId; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperFoldable}; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::Span; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::solve; use tracing::{debug, instrument}; @@ -56,7 +56,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id); wbcx.visit_node_id(body.value.span, item_hir_id); } - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), + hir::BodyOwnerKind::Contract | hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => { + () + } } wbcx.visit_body(body); wbcx.visit_min_capture_map(); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8bd9c899a6286..f38e60aa4ee48 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -349,6 +349,7 @@ impl EarlyLintPass for UnsafeCode { ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. }, _, _, + _, body, ) = fk { @@ -1036,7 +1037,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { } }; match it.kind { - hir::ItemKind::Fn(.., generics, _) => { + hir::ItemKind::Fn(.., generics, _, _) => { if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 2285877c9ef26..3f8f5e7ef8bde 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -157,7 +157,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> // Explicitly check for lints associated with 'closure_id', since // it does not have a corresponding AST node - if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk { + if let ast_visit::FnKind::Fn(_, _, sig, _, _, _, _) = fk { if let Some(coroutine_kind) = sig.header.coroutine_kind { self.check_id(coroutine_kind.closure_id()); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index afe03531861c9..8f426ad26f4bb 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -878,7 +878,8 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::Field | DefKind::Impl { .. } | DefKind::Closure - | DefKind::SyntheticCoroutineBody => true, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => true, DefKind::ForeignMod | DefKind::GlobalAsm => false, } } @@ -902,7 +903,8 @@ fn should_encode_attrs(def_kind: DefKind) -> bool { | DefKind::AssocConst | DefKind::Macro(_) | DefKind::Field - | DefKind::Impl { .. } => true, + | DefKind::Impl { .. } + | DefKind::Contract => true, // Tools may want to be able to detect their tool lints on // closures from upstream crates, too. This is used by // https://github.com/model-checking/kani and is not a performance @@ -956,7 +958,8 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool { | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Closure - | DefKind::SyntheticCoroutineBody => false, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => false, } } @@ -993,7 +996,8 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::Impl { .. } | DefKind::Closure | DefKind::ExternCrate - | DefKind::SyntheticCoroutineBody => false, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => false, } } @@ -1029,7 +1033,8 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::GlobalAsm | DefKind::Closure | DefKind::ExternCrate - | DefKind::SyntheticCoroutineBody => false, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => false, } } @@ -1124,7 +1129,8 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def | DefKind::GlobalAsm | DefKind::Closure | DefKind::ExternCrate - | DefKind::SyntheticCoroutineBody => false, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => false, DefKind::TyAlias => tcx.type_alias_is_lazy(def_id), } } @@ -1161,7 +1167,8 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::Use | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::ExternCrate => false, + | DefKind::ExternCrate + | DefKind::Contract => false, } } @@ -1185,7 +1192,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst - | DefKind::SyntheticCoroutineBody => true, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => true, DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(def_id); @@ -1258,7 +1266,8 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool { | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::ExternCrate - | DefKind::SyntheticCoroutineBody => false, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => false, } } @@ -1296,7 +1305,8 @@ fn should_encode_constness(def_kind: DefKind) -> bool { | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::ExternCrate - | DefKind::SyntheticCoroutineBody => false, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => false, } } @@ -1330,7 +1340,8 @@ fn should_encode_const(def_kind: DefKind) -> bool { | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::ExternCrate - | DefKind::SyntheticCoroutineBody => false, + | DefKind::SyntheticCoroutineBody + | DefKind::Contract => false, } } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 3a6f3543317f6..4cd49d8a3aa0e 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -156,6 +156,7 @@ fixed_size_enum! { ( Impl { of_trait: false } ) ( Impl { of_trait: true } ) ( Closure ) + ( Contract ) ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } ) ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } ) ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } ) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8fd5ff1f369d4..21225a31bc081 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,16 +1,16 @@ -use rustc_ast::visit::{VisitorResult, walk_list}; +use rustc_ast::visit::{walk_list, VisitorResult}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in}; +use rustc_data_structures::sync::{par_for_each_in, try_par_for_each_in, DynSend, DynSync}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::Visitor; use rustc_hir::*; use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::spec::abi::Abi; use {rustc_ast as ast, rustc_hir_pretty as pprust_hir}; @@ -311,6 +311,7 @@ impl<'hir> Map<'hir> { DefKind::Static { safety: _, mutability, nested: false } => { BodyOwnerKind::Static(mutability) } + DefKind::Contract => BodyOwnerKind::Contract, dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } @@ -334,6 +335,7 @@ impl<'hir> Map<'hir> { } BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn, BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None, + BodyOwnerKind::Contract => return None, }; Some(ccx) @@ -1352,6 +1354,17 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_foreign_item(self, item) } + fn visit_fn_contract_ids(&mut self, c: &FnContractIds) { + if let Some(precond) = c.precond { + self.body_owners.push(precond.def_id); + } + if let Some(postcond) = c.postcond { + self.body_owners.push(postcond.def_id); + } + // TODO: add contract ids to self.body_owners, analogous to items and consts. + intravisit::walk_fn_contract_ids(self, c) + } + fn visit_anon_const(&mut self, c: &'hir AnonConst) { self.body_owners.push(c.def_id); intravisit::walk_anon_const(self, c) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index fe865b8a51508..4b6a7f33851fc 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -16,7 +16,7 @@ use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; -use rustc_index::{IndexVec, newtype_index}; +use rustc_index::{newtype_index, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable}; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; @@ -102,6 +102,7 @@ thir_with_elements! { pub enum BodyTy<'tcx> { Const(Ty<'tcx>), Fn(FnSig<'tcx>), + Contract, } /// Description of a type-checked function parameter. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1bdcae4dfb479..893d9d2993074 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -31,7 +31,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; @@ -46,16 +46,16 @@ use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; use rustc_session::{Limit, MetadataKind, Session}; -use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::def_id::{DefPathHash, StableCrateId, CRATE_DEF_ID}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; -use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::solve::SolverMode; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; +use rustc_type_ir::TyKind::*; +use rustc_type_ir::{search_graph, CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, trace}; use crate::arena::Arena; @@ -1027,10 +1027,10 @@ impl<'tcx> CommonLifetimes<'tcx> { .map(|i| { (0..NUM_PREINTERNED_RE_LATE_BOUNDS_V) .map(|v| { - mk(ty::ReBound(ty::DebruijnIndex::from(i), ty::BoundRegion { - var: ty::BoundVar::from(v), - kind: ty::BrAnon, - })) + mk(ty::ReBound( + ty::DebruijnIndex::from(i), + ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BrAnon }, + )) }) .collect() }) @@ -1396,7 +1396,11 @@ impl<'tcx> TyCtxt<'tcx> { self.codegen_fn_attrs(def_id) } else if matches!( def_kind, - DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst + DefKind::AnonConst + | DefKind::AssocConst + | DefKind::Const + | DefKind::InlineConst + | DefKind::Contract ) { CodegenFnAttrs::EMPTY } else { @@ -1452,11 +1456,9 @@ impl<'tcx> TyCtxt<'tcx> { }; debug!("layout_scalar_valid_range: attr={:?}", attr); if let Some( - &[ - ast::MetaItemInner::Lit(ast::MetaItemLit { - kind: ast::LitKind::Int(a, _), .. - }), - ], + &[ast::MetaItemInner::Lit(ast::MetaItemLit { + kind: ast::LitKind::Int(a, _), .. + })], ) = attr.meta_item_list().as_deref() { Bound::Included(a.get()) @@ -2108,7 +2110,7 @@ macro_rules! nop_lift { tcx.interners .$set - .contains_pointer_to(&InternedInSet(&*self.0.0)) + .contains_pointer_to(&InternedInSet(&*self.0 .0)) // SAFETY: `self` is interned and therefore valid // for the entire lifetime of the `TyCtxt`. .then(|| unsafe { mem::transmute(self) }) @@ -2550,7 +2552,11 @@ impl<'tcx> TyCtxt<'tcx> { pred: Predicate<'tcx>, binder: Binder<'tcx, PredicateKind<'tcx>>, ) -> Predicate<'tcx> { - if pred.kind() != binder { self.mk_predicate(binder) } else { pred } + if pred.kind() != binder { + self.mk_predicate(binder) + } else { + pred + } } pub fn check_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) -> bool { @@ -2733,11 +2739,9 @@ impl<'tcx> TyCtxt<'tcx> { eps: &[PolyExistentialPredicate<'tcx>], ) -> &'tcx List<PolyExistentialPredicate<'tcx>> { assert!(!eps.is_empty()); - assert!( - eps.array_windows() - .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder()) - != Ordering::Greater) - ); + assert!(eps + .array_windows() + .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder()) != Ordering::Greater)); self.intern_poly_existential_predicates(eps) } @@ -2767,9 +2771,9 @@ impl<'tcx> TyCtxt<'tcx> { where I: Iterator<Item = T>, T: CollectAndApply< - &'tcx ty::CapturedPlace<'tcx>, - &'tcx List<&'tcx ty::CapturedPlace<'tcx>>, - >, + &'tcx ty::CapturedPlace<'tcx>, + &'tcx List<&'tcx ty::CapturedPlace<'tcx>>, + >, { T::collect_and_apply(iter, |xs| self.intern_captures(xs)) } @@ -2810,9 +2814,9 @@ impl<'tcx> TyCtxt<'tcx> { where I: Iterator<Item = T>, T: CollectAndApply< - PolyExistentialPredicate<'tcx>, - &'tcx List<PolyExistentialPredicate<'tcx>>, - >, + PolyExistentialPredicate<'tcx>, + &'tcx List<PolyExistentialPredicate<'tcx>>, + >, { T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs)) } @@ -3053,12 +3057,15 @@ impl<'tcx> TyCtxt<'tcx> { } let generics = self.generics_of(new_parent); - return ty::Region::new_early_param(self, ty::EarlyParamRegion { - index: generics - .param_def_id_to_index(self, ebv.to_def_id()) - .expect("early-bound var should be present in fn generics"), - name: self.item_name(ebv.to_def_id()), - }); + return ty::Region::new_early_param( + self, + ty::EarlyParamRegion { + index: generics + .param_def_id_to_index(self, ebv.to_def_id()) + .expect("early-bound var should be present in fn generics"), + name: self.item_name(ebv.to_def_id()), + }, + ); } Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { let new_parent = self.local_parent(lbv); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 8c20d2e0d3a62..4f8175a99408e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,6 +1,6 @@ use itertools::Itertools; -use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_apfloat::Float; use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; @@ -57,6 +57,7 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx let build_mir = |thir: &Thir<'tcx>| match thir.body_type { thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig), thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty), + thir::BodyTy::Contract => construct_contract(tcx, def, thir, expr), }; // this must run before MIR dump, because @@ -593,6 +594,35 @@ fn construct_const<'a, 'tcx>( builder.finish() } +fn construct_contract<'tcx>( + tcx: TyCtxt<'tcx>, + def: LocalDefId, + thir: &Thir<'tcx>, + expr: ExprId, +) -> Body<'tcx> { + let span = tcx.def_span(def); + let hir_id = tcx.local_def_id_to_hir_id(def); + let infcx = tcx.infer_ctxt().build(); + let fn_decl = tcx + .hir() + .fn_decl_by_hir_id(hir_id) + .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", def)); + let span_with_body = tcx.hir().span_with_body(hir_id); + let return_ty_span = fn_decl.output.span(); + let return_ty = tcx.types.bool; + let mut builder = + Builder::new(thir, infcx, def, hir_id, span_with_body, 0, return_ty, return_ty_span, None); + let arguments = &thir.params; + let body = tcx.hir().body_owned_by(def); + let arg_scope = + region::Scope { id: body.id().hir_id.local_id, data: region::ScopeData::Arguments }; + let block = builder.args_and_body(START_BLOCK, arguments, arg_scope, expr).into_block(); + let source_info = builder.source_info(span_with_body); + builder.cfg.terminate(block, source_info, TerminatorKind::Return); + builder.build_drop_trees(); + builder.finish() +} + /// Construct MIR for an item that has had errors in type checking. /// /// This is required because we may still want to run MIR passes on an item diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 377931e3be730..a8624fb8c8d11 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -5,10 +5,10 @@ use rustc_data_structures::steal::Steal; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_hir::HirId; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; +use rustc_hir::HirId; use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::thir::*; @@ -79,6 +79,8 @@ impl<'tcx> Cx<'tcx> { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) + } else if let hir::BodyOwnerKind::Contract = hir.body_owner_kind(def) { + BodyTy::Contract } else { // Get the revealed type of this const. This is *not* the adjusted // type of its body, which may be a subtype of this type. For @@ -182,11 +184,9 @@ impl<'tcx> Cx<'tcx> { let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() { let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span)); - self.tcx.type_of(va_list_did).instantiate(self.tcx, &[self - .tcx - .lifetimes - .re_erased - .into()]) + self.tcx + .type_of(va_list_did) + .instantiate(self.tcx, &[self.tcx.lifetimes.re_erased.into()]) } else { fn_sig.inputs()[index] }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index ae77bce6bb199..f7c1430b6b23c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -3,7 +3,7 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::codes::*; -use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err}; +use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed, MultiSpan}; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; @@ -22,7 +22,7 @@ use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; use rustc_span::hygiene::DesugaringKind; -use rustc_span::{Span, sym}; +use rustc_span::{sym, Span}; use tracing::instrument; use crate::errors::*; @@ -49,11 +49,15 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err let origin = match tcx.def_kind(def_id) { DefKind::AssocFn | DefKind::Fn => "function argument", + DefKind::Contract => "contract-inherited function argument", DefKind::Closure => "closure argument", // other types of MIR don't have function parameters, and we don't need to // categorize those for the irrefutable check. _ if thir.params.is_empty() => "", - kind => bug!("unexpected function parameters in THIR: {kind:?} {def_id:?}"), + kind => bug!( + "unexpected function parameters in THIR: {kind:?} {def_id:?}, params: {:?}", + thir.params + ), }; for param in thir.params.iter() { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index e049fe996645a..76077485ec780 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -5,9 +5,9 @@ //! generic parameters are unused (and eventually, in what ways generic parameters are used - only //! for their size, offset of a field, etc.). -use rustc_hir::ConstContext; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_hir::ConstContext; use rustc_middle::mir::visit::{TyContext, Visitor}; use rustc_middle::mir::{self, Local, LocalDecl, Location}; use rustc_middle::query::Providers; @@ -161,6 +161,7 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm + | DefKind::Contract | DefKind::Impl { .. } => { for param in &generics.own_params { debug!(?param, "(other)"); diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 5aebe716b0a10..e06f51479416c 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -295,6 +295,21 @@ impl<'a> Parser<'a> { }) } + /// Parses an optional fn contract (`requires XXX ensures YYY``) + pub(super) fn parse_contract(&mut self) -> PResult<'a, ast::FnContract> { + let pre_cond = if self.eat_keyword(kw::RustcContractRequires) { + Some(self.parse_expr()?) + } else { + None + }; + let post_cond = if self.eat_keyword(kw::RustcContractEnsures) { + Some(self.parse_expr()?) + } else { + None + }; + Ok(ast::FnContract { requires: pre_cond, ensures: post_cond }) + } + /// Parses an optional where-clause. /// /// ```ignore (only-for-syntax-highlight) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 36733726564fb..0d72ae712f7c3 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -197,9 +197,9 @@ 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(kw::Extern) { if self.eat_keyword(kw::Crate) { // EXTERN CRATE @@ -2312,7 +2312,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, 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` @@ -2338,18 +2338,20 @@ 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. let fn_params_end = if generics.where_clause.has_where_token { Some(fn_params_end) } else { None }; - + let mut sig_hi = self.prev_token.span; // Either `;` or `{ ... }`. 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 diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 44a62383e6eed..667c70c73f0bf 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1531,7 +1531,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }; let Some(ItemLike::Item(Item { - kind: ItemKind::Fn(FnSig { decl, .. }, generics, _), .. + kind: ItemKind::Fn(FnSig { decl, .. }, generics, _, _), .. })) = item else { bug!("should be a function item"); diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index b2f8d7dadff37..b2b6f1407f7cc 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -31,7 +31,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { } let (fn_header, body_id) = match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, _, body_id), .. }) | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), .. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 751c87a9fe519..f135f9f25b847 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -380,7 +380,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ) } } - hir::ItemKind::Fn(ref item_fn_sig, _, _) => { + hir::ItemKind::Fn(ref item_fn_sig, _, _, _) => { fn_sig = Some(item_fn_sig); } _ => {} diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index f67c4cb922cee..e40cd02cd952a 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -20,12 +20,12 @@ use errors::{ ItemIsPrivate, PrivateInterfacesOrBoundsLint, ReportEffectiveVisibility, UnnameableTypesLint, UnnamedItemIsPrivate, }; +use rustc_ast::visit::{try_visit, VisitorResult}; use rustc_ast::MacroDef; -use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind}; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; @@ -37,9 +37,9 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; -use rustc_span::Span; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{Ident, kw, sym}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; use tracing::debug; use {rustc_attr as attr, rustc_hir as hir}; @@ -75,7 +75,7 @@ pub trait DefIdVisitor<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) - -> Self::Result; + -> Self::Result; /// Not overridden, but used to actually visit types and traits. fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { @@ -116,7 +116,11 @@ where "trait", &trait_ref.print_only_trait_path() )); - if V::SHALLOW { V::Result::output() } else { args.visit_with(self) } + if V::SHALLOW { + V::Result::output() + } else { + args.visit_with(self) + } } fn visit_projection_term(&mut self, projection: ty::AliasTerm<'tcx>) -> V::Result { @@ -201,9 +205,10 @@ where // so we need to visit the self type additionally. if let Some(assoc_item) = tcx.opt_associated_item(def_id) { if let Some(impl_def_id) = assoc_item.impl_container(tcx) { - try_visit!( - tcx.type_of(impl_def_id).instantiate_identity().visit_with(self) - ); + try_visit!(tcx + .type_of(impl_def_id) + .instantiate_identity() + .visit_with(self)); } } } @@ -291,7 +296,11 @@ where } } - if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) } + if V::SHALLOW { + V::Result::output() + } else { + ty.super_visit_with(self) + } } fn visit_const(&mut self, c: Const<'tcx>) -> Self::Result { @@ -301,7 +310,11 @@ where } fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility { - if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 } + if vis1.is_at_least(vis2, tcx) { + vis2 + } else { + vis1 + } } //////////////////////////////////////////////////////////////////////////////// @@ -607,6 +620,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { DefKind::AssocConst | DefKind::AssocTy | DefKind::ConstParam + | DefKind::Contract | DefKind::Ctor(_, _) | DefKind::Enum | DefKind::ForeignTy diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0145ffd3a4b7c..c41cdd003eccf 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -262,8 +262,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | DefKind::GlobalAsm | DefKind::Closure | DefKind::SyntheticCoroutineBody - | DefKind::Impl { .. }, - _, + | DefKind::Impl { .. } + | DefKind::Contract, + _ ) | Res::Local(..) | Res::SelfTyParam { .. } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 0047f2c4b51e9..e8b939ede9aed 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -240,11 +240,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { match fn_kind { - FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) + FnKind::Fn(_ctxt, _ident, + FnSig { header, decl, span: _ }, + _vis, generics, contract, body) if let Some(coroutine_kind) = header.coroutine_kind => { self.visit_fn_header(header); self.visit_generics(generics); + self.visit_contract(contract); // XXX // For async functions, we need to create their inner defs inside of a // closure to match their desugared representation. Besides that, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 66c1ff93ce1ce..106c1261d33d3 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -961,8 +961,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. - FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) - | FnKind::Fn(_, _, sig, _, generics, None) => { + FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _, _) + | FnKind::Fn(_, _, sig, _, generics, _, None) => { self.visit_fn_header(&sig.header); self.visit_generics(generics); self.with_lifetime_rib( @@ -1002,7 +1002,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r // Create a label rib for the function. this.with_label_rib(RibKind::FnOrCoroutine, |this| { match fn_kind { - FnKind::Fn(_, _, sig, _, generics, body) => { + FnKind::Fn(_, _, sig, _, generics, contract, body) => { this.visit_generics(generics); let declaration = &sig.decl; @@ -1033,6 +1033,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }, ); + this.visit_contract(contract); + if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index fce5ec36c661b..c6ffdd3b94fa8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3169,7 +3169,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { { let pre = if lt.kind == MissingLifetimeKind::Ampersand && let Some((kind, _span)) = self.diag_metadata.current_function - && let FnKind::Fn(_, _, sig, _, _, _) = kind + && let FnKind::Fn(_, _, sig, _, _, _, _) = kind && !sig.decl.inputs.is_empty() && let sugg = sig .decl @@ -3210,7 +3210,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else if (lt.kind == MissingLifetimeKind::Ampersand || lt.kind == MissingLifetimeKind::Underscore) && let Some((kind, _span)) = self.diag_metadata.current_function - && let FnKind::Fn(_, _, sig, _, _, _) = kind + && let FnKind::Fn(_, _, sig, _, _, _, _) = kind && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output && !sig.decl.inputs.is_empty() && let arg_refs = sig @@ -3270,7 +3270,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand; let mut sugg = vec![(lt.span, String::new())]; if let Some((kind, _span)) = self.diag_metadata.current_function - && let FnKind::Fn(_, _, sig, _, _, _) = kind + && let FnKind::Fn(_, _, sig, _, _, _, _) = kind && let ast::FnRetTy::Ty(ty) = &sig.decl.output { let mut lt_finder = diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 53834198f6328..8a161ba310951 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -7,7 +7,7 @@ use std::fmt::Write as _; -use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, CASE_INSENSITIVE, ToBaseN}; +use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY, CASE_INSENSITIVE}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_middle::bug; @@ -22,8 +22,8 @@ use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; use tracing::instrument; -use crate::cfi::typeid::TypeIdOptions; use crate::cfi::typeid::itanium_cxx_abi::transform::{TransformTy, TransformTyOptions}; +use crate::cfi::typeid::TypeIdOptions; /// Options for encode_ty. pub(crate) type EncodeTyOptions = TypeIdOptions; @@ -714,7 +714,8 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { | hir::definitions::DefPathData::GlobalAsm | hir::definitions::DefPathData::MacroNs(..) | hir::definitions::DefPathData::LifetimeNs(..) - | hir::definitions::DefPathData::AnonAdt => { + | hir::definitions::DefPathData::AnonAdt + | hir::definitions::DefPathData::Contract => { bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } }); diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 9b27b94fb5a56..1039aa8c3391d 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -111,7 +111,8 @@ pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind { | DefKind::Field | DefKind::LifetimeParam | DefKind::Impl { .. } - | DefKind::GlobalAsm => { + | DefKind::GlobalAsm + | DefKind::Contract => { unreachable!("Not a valid item kind: {kind:?}"); } DefKind::Closure | DefKind::AssocFn | DefKind::Fn | DefKind::SyntheticCoroutineBody => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cc3bda99a117b..9e8792346a0d0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -103,6 +103,8 @@ symbols! { MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", + RustcContractEnsures: "rustc_contract_ensures", + RustcContractRequires: "rustc_contract_requires", Safe: "safe", Union: "union", Yeet: "yeet", @@ -650,6 +652,7 @@ symbols! { const_try, constant, constructor, + contract, convert_identity, copy, copy_closures, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f3da7ff1ca7b0..099053435089b 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -774,7 +774,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | DefPathData::Impl | DefPathData::MacroNs(_) | DefPathData::LifetimeNs(_) - | DefPathData::AnonAdt => { + | DefPathData::AnonAdt + | DefPathData::Contract => { bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) } }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index bd78a6ee3aff7..07ceba89123fc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1729,7 +1729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, _, body_id), .. }) => { let body = hir.body(*body_id); struct LetVisitor { span: Span, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 709b6eb18e35f..217f42f519ff8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -816,7 +816,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pat.walk(&mut find_compatible_candidates); } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, _, body), .. }) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 824c25db07d2e..a39ec249722aa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -898,7 +898,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); let body_id = match self.tcx.hir_node(hir_id) { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => body_id, + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, _, body_id), .. }) => body_id, _ => return false, }; let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span }) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 87834c329e19f..ffecaea64ff04 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -308,7 +308,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .. }) | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(fn_sig, generics, _), .. + kind: hir::ItemKind::Fn(fn_sig, generics, _, _), .. }) if projection.is_some() => { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( @@ -352,7 +352,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Union(_, generics) | hir::ItemKind::Trait(_, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) - | hir::ItemKind::Fn(_, generics, _) + | hir::ItemKind::Fn(_, generics, _, _) | hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _), @@ -418,7 +418,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Union(_, generics) | hir::ItemKind::Trait(_, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) - | hir::ItemKind::Fn(_, generics, _) + | hir::ItemKind::Fn(_, generics, _, _) | hir::ItemKind::TyAlias(_, generics) | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _), @@ -1729,7 +1729,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> bool { let hir = self.tcx.hir(); let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id); - if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = node + if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, _, body_id), .. }) = node && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind && sig.decl.output.span().overlaps(span) && blk.expr.is_none() @@ -1877,7 +1877,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let hir = self.tcx.hir(); let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id); - if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) = node { + if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, _, body_id), .. }) = node { let body = hir.body(*body_id); // Point at all the `return`s in the function as they have failed trait bounds. let mut visitor = ReturnsVisitor::default(); @@ -4668,7 +4668,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { node: hir::Node<'hir>, ) -> Option<(&'hir hir::FnDecl<'hir>, hir::BodyId)> { match node { - hir::Node::Item(item) if let hir::ItemKind::Fn(sig, _, body_id) = item.kind => { + hir::Node::Item(item) if let hir::ItemKind::Fn(sig, _, _, body_id) = item.kind => { Some((sig.decl, body_id)) } hir::Node::ImplItem(item) diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 5cd10e9053872..faad40fffebd3 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -78,10 +78,10 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' if matches!(*orig_lt, ty::ReLateParam(..)) { mapping.insert( orig_lt, - ty::Region::new_early_param(tcx, ty::EarlyParamRegion { - index: param.index, - name: param.name, - }), + ty::Region::new_early_param( + tcx, + ty::EarlyParamRegion { index: param.index, name: param.name }, + ), ); } } @@ -145,6 +145,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Closure + | DefKind::Contract | DefKind::SyntheticCoroutineBody => ty::List::empty(), } } diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 5e2232ff47d73..5e585cbd7bc15 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{CRATE_HIR_ID, intravisit}; +use rustc_hir::{intravisit, CRATE_HIR_ID}; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; @@ -348,6 +348,7 @@ fn opaque_types_defined_by<'tcx>( | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm + | DefKind::Contract | DefKind::Impl { .. } | DefKind::SyntheticCoroutineBody => {} // Closures and coroutines are type checked with their parent, so we need to allow all diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index 6f1cbb0fee700..3976e659a340a 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -47,6 +47,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( // Walk over the type behind the alias DefKind::TyAlias { .. } | DefKind::AssocTy | // Walk over the type of the item + DefKind::Contract | DefKind::Static { .. } | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { if let Some(ty) = tcx.hir_node_by_def_id(item).ty() { // If the type of the item uses `_`, we're gonna error out anyway, but diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fa73733360ca1..a633df4a4ffe4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2791,7 +2791,7 @@ fn clean_maybe_renamed_item<'tcx>( } ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx), // proc macros can have a name set by attributes - ItemKind::Fn(ref sig, generics, body_id) => { + ItemKind::Fn(ref sig, generics, _, body_id) => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } ItemKind::Trait(_, _, generics, bounds, item_ids) => { diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 383e3135faa86..8d9d9cc6ef7d7 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -163,6 +163,7 @@ impl ItemType { | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::Closure + | DefKind::Contract | DefKind::SyntheticCoroutineBody => Self::ForeignType, } } diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index b314b060368aa..fcc85e5399f54 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -230,7 +230,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { match item.kind { ItemKind::Static(_, _, _) | ItemKind::Const(_, _, _) - | ItemKind::Fn(_, _, _) + | ItemKind::Fn(_, _, _, _) | ItemKind::Macro(_, _) | ItemKind::TyAlias(_, _) | ItemKind::Enum(_, _) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index db235786cf49a..da4c4f34d1a12 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1866,6 +1866,7 @@ fn resolution_failure( Variant | Field | Closure + | Contract | AssocTy | AssocConst | AssocFn diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 9b10ae8365149..fded2df706c1b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -21,7 +21,7 @@ pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool { } pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Fn(_, _, eid) = item.kind { + if let ItemKind::Fn(_, _, _, eid) = item.kind { is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) } else { true diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index e090644ae4410..9db5864c4cb2f 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -23,12 +23,12 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_resolve::rustdoc::{ - DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, - span_of_fragments, + add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, + DocFragment, }; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{Span, sym}; +use rustc_span::{sym, Span}; use std::ops::Range; use url::Url; @@ -579,7 +579,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { self.check_private_items, ); match item.kind { - ItemKind::Fn(sig, _, body_id) => { + ItemKind::Fn(sig, _, _, body_id) => { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index 6ad879b9fe7ae..b880c4a3ddaad 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::{is_from_proc_macro, trait_ref_of_method}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; -use rustc_hir::intravisit::{Visitor, walk_impl_item, walk_item, walk_param_bound, walk_ty}; +use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; use rustc_hir::{ BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, WherePredicate, @@ -12,8 +12,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; -use rustc_span::Span; use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -252,7 +252,7 @@ fn is_empty_body(cx: &LateContext<'_>, body: BodyId) -> bool { impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Fn(_, generics, body_id) = item.kind + if let ItemKind::Fn(_, generics, _, body_id) = item.kind && !generics.params.is_empty() && !is_empty_body(cx, body_id) && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index cfd11e9339fb7..c59b87e3a2015 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{Span, sym}; +use rustc_span::{sym, Span}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; @@ -25,7 +25,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { + if let hir::ItemKind::Fn(ref sig, _generics, _contracts, ref body_id) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index d4eaa1663208c..e5f2121663222 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -3,11 +3,11 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{Span, sym}; +use rustc_span::{sym, Span}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::trait_ref_of_method; -use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item}; +use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item, AdtVariantInfo}; use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; @@ -35,7 +35,7 @@ fn result_err_ty<'tcx>( } pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) { - if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind + if let hir::ItemKind::Fn(ref sig, _generics, _, _) = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) { if cx.effective_visibilities.is_exported(item.owner_id.def_id) { diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 4c5375730b8e3..0f804d257b6f6 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -3,18 +3,18 @@ use std::collections::BTreeMap; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; -use rustc_hir::intravisit::{Visitor, walk_body, walk_expr, walk_inf, walk_ty}; +use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { @@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { ); } }, - ItemKind::Fn(ref sig, generics, body_id) => { + ItemKind::Fn(ref sig, generics, _, body_id) => { let body = cx.tcx.hir().body(body_id); for ty in sig.decl.inputs { diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index ec28671a061e4..174783e786408 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -3,25 +3,25 @@ use clippy_utils::trait_ref_of_method; use itertools::Itertools; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; -use rustc_hir::FnRetTy::Return; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; use rustc_hir::intravisit::{ - Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, - walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate, + walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_param_bound, walk_poly_trait_ref, + walk_trait_ref, walk_ty, walk_where_predicate, Visitor, }; +use rustc_hir::FnRetTy::Return; use rustc_hir::{ - BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, - Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef, - PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items, + lang_items, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, + Generics, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, + PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{Ident, kw}; +use rustc_span::symbol::{kw, Ident}; +use rustc_span::Span; use std::ops::ControlFlow; declare_clippy_lint! { @@ -93,7 +93,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Fn(ref sig, generics, id) = item.kind { + if let ItemKind::Fn(ref sig, generics, _, id) = item.kind { check_fn_inner(cx, sig, Some(id), None, generics, item.span, true); } else if let ItemKind::Impl(impl_) = item.kind { if !item.span.from_expansion() { diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs index 858e3be5093ef..60db5db766e93 100644 --- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed}; -use hir::intravisit::{Visitor, walk_expr}; +use hir::intravisit::{walk_expr, Visitor}; use hir::{Expr, ExprKind, FnRetTy, FnSig, Node}; use rustc_ast::Label; use rustc_errors::Applicability; @@ -69,7 +69,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option for (_, parent_node) in cx.tcx.hir().parent_iter(expr.hir_id) { match parent_node { Node::Item(hir::Item { - kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _), + kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _, _), .. }) | Node::TraitItem(hir::TraitItem { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index cfa1fdb81372f..acfcb0d01fe66 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,7 +2,7 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ @@ -19,7 +19,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; -use rustc_span::{Symbol, sym}; +use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -496,7 +496,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Stmt(_) => return true, Node::Block(..) => continue, Node::Item(item) => { - if let ItemKind::Fn(_, _, body_id) = &item.kind + if let ItemKind::Fn(_, _, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) && rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty) { diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs index d276e29bacecf..c76ffe862e703 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs @@ -39,7 +39,7 @@ declare_lint_pass!(MultipleBoundLocations => [MULTIPLE_BOUND_LOCATIONS]); impl EarlyLintPass for MultipleBoundLocations { fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: NodeId) { - if let FnKind::Fn(_, _, _, _, generics, _) = kind + if let FnKind::Fn(_, _, _, _, generics, _, _) = kind && !generics.params.is_empty() && !generics.where_clause.predicates.is_empty() { diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index 8d5a523fd8f6a..cf56a089df429 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -37,7 +37,7 @@ declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]); impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Fn(fn_sig, _, _) = &item.kind { + if let ItemKind::Fn(fn_sig, _, _, _) = &item.kind { let attrs = cx.tcx.hir().attrs(item.hir_id()); let mut app = Applicability::MaybeIncorrect; let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app); diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 565294bb40a82..db6669584067b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -82,7 +82,7 @@ impl Context { } self.const_span = Some(body_span); }, - hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (), + hir::BodyOwnerKind::Contract | hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (), } } diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 662745e4b5d67..16e983fb0599c 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{Descend, for_each_expr, for_each_unconsumed_temporary}; +use clippy_utils::visitors::{for_each_expr, for_each_unconsumed_temporary, Descend}; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -9,8 +9,8 @@ use clippy_utils::{ use core::ops::ControlFlow; use rustc_ast::MetaItemInner; use rustc_errors::Applicability; -use rustc_hir::LangItem::ResultErr; use rustc_hir::intravisit::FnKind; +use rustc_hir::LangItem::ResultErr; use rustc_hir::{ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, StmtKind, @@ -21,7 +21,7 @@ use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{BytePos, Pos, Span, sym}; +use rustc_span::{sym, BytePos, Pos, Span}; use std::borrow::Cow; use std::fmt::Display; @@ -204,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { // Ensure this is not the final stmt, otherwise removing it would cause a compile error && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id)) - && let ItemKind::Fn(_, _, body) = item.kind + && let ItemKind::Fn(_, _, _, body) = item.kind && let block = cx.tcx.hir().body(body).value && let ExprKind::Block(block, _) = block.kind && !is_inside_let_else(cx.tcx, expr) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 68f74e52ed7b7..d5314372d32db 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -362,18 +362,21 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { defaultness: ld, sig: lf, generics: lg, + contract: lc, body: lb, }), Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, + contract: rc, body: rb, }), ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) + && eq_contracts(lc, rc) && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r)) }, (Mod(lu, lmk), Mod(ru, rmk)) => { @@ -497,18 +500,21 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { defaultness: ld, sig: lf, generics: lg, + contract: lc, body: lb, }), Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, + contract: rc, body: rb, }), ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) + && eq_contracts(lc, rc) && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r)) }, ( @@ -559,18 +565,21 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { defaultness: ld, sig: lf, generics: lg, + contract: lc, body: lb, }), Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, + contract: rc, body: rb, }), ) => { eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) + && eq_contracts(lc, rc) && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r)) }, ( @@ -677,6 +686,20 @@ pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool { } } +pub fn eq_contracts(l: &FnContract, r: &FnContract) -> bool { + let req_cmp = match (&l.requires, &r.requires) { + (Some(l_expr), Some(r_expr)) => eq_expr(l_expr, r_expr), + (None, None) => true, + _ => return false, + }; + let ens_cmp = match (&l.ensures, &r.ensures) { + (Some(l_expr), Some(r_expr)) => eq_expr(l_expr, r_expr), + (None, None) => true, + _ => return false, + }; + req_cmp && ens_cmp +} + pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool { eq_path(&l.prefix, &r.prefix) && eq_use_tree_kind(&l.kind, &r.kind) } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 10e258444a676..33cf4d70317b8 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -77,7 +77,7 @@ pub mod visitors; pub use self::attrs::*; pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ - HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, + both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; use core::mem; @@ -93,20 +93,20 @@ use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; -use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalModDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefPath, DefPathData}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; -use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; +use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, - Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, - ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, - PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, - TyKind, UnOp, def, + self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, + ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, + ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, + Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, + TraitRef, TyKind, UnOp, }; -use rustc_lexer::{TokenKind, tokenize}; +use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::Const; @@ -119,12 +119,12 @@ use rustc_middle::ty::{ }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{Ident, Symbol, kw}; -use rustc_span::{InnerSpan, Span, sym}; +use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::{sym, InnerSpan, Span}; use rustc_target::abi::Integer; use visitors::Visitable; -use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; +use crate::consts::{mir_to_const, ConstEvalCtxt, Constant}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; @@ -1400,7 +1400,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio enclosing_node.and_then(|node| match node { Node::Block(block) => Some(block), Node::Item(&Item { - kind: ItemKind::Fn(_, _, eid), + kind: ItemKind::Fn(_, _, _, eid), .. }) | Node::ImplItem(&ImplItem { @@ -2609,7 +2609,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool { // function scope .any(|(_id, node)| { if let Node::Item(item) = node { - if let ItemKind::Fn(_, _, _) = item.kind { + if let ItemKind::Fn(_, _, _, _) = item.kind { // Note that we have sorted the item names in the visitor, // so the binary_search gets the same as `contains`, but faster. return names.binary_search(&item.ident.name).is_ok(); diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index fc043a697e039..63647f812765f 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -333,12 +333,12 @@ impl<'a> FnSig<'a> { defaultness: ast::Defaultness, ) -> FnSig<'a> { match *fn_kind { - visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, fn_sig, vis, generics, _) => { + visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, fn_sig, vis, generics, _, _) => { let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis); fn_sig.defaultness = defaultness; fn_sig } - visit::FnKind::Fn(_, _, fn_sig, vis, generics, _) => FnSig { + visit::FnKind::Fn(_, _, fn_sig, vis, generics, _, _) => FnSig { decl, generics, ext: fn_sig.header.ext, @@ -3432,6 +3432,7 @@ impl Rewrite for ast::ForeignItem { defaultness, ref sig, ref generics, + ref contract, ref body, } = **fn_kind; if let Some(ref body) = body { @@ -3447,6 +3448,7 @@ impl Rewrite for ast::ForeignItem { sig, &self.vis, generics, + contract, Some(body), ), &sig.decl, diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 8102fe7ad8f29..b0d2f45d79b91 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -386,7 +386,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let indent = self.block_indent; let block; let rewrite = match fk { - visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => { + visit::FnKind::Fn(_, ident, _, _, _, _, Some(ref b)) => { block = b; self.rewrite_fn_before_block( indent, @@ -538,6 +538,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { defaultness, ref sig, ref generics, + ref contract, ref body, } = **fn_kind; if let Some(ref body) = body { @@ -553,6 +554,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { sig, &item.vis, generics, + contract, Some(body), ), &sig.decl, @@ -646,13 +648,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { defaultness, ref sig, ref generics, + ref contract, ref body, } = **fn_kind; if let Some(ref body) = body { let inner_attrs = inner_attributes(&ai.attrs); let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt); self.visit_fn( - visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)), + visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, contract, Some(body)), &sig.decl, ai.span, defaultness,