From 335f93fb81cd0873b95a39827b06e21e997bab40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Sat, 10 Oct 2026 18:26:24 +0200 Subject: [PATCH 01/17] test: add guiding testsuite for trait-level specs --- .../lean/HaxTests/Extraction/Funs.lean | 920 ++++++++++++++++-- .../HaxTests/Extraction/ProofObligations.lean | 91 ++ .../lean/HaxTests/Extraction/Specs.lean | 413 +++++++- .../lean/HaxTests/Extraction/Types.lean | 182 +++- tests/hax/src/specs/contracts.rs | 8 + tests/hax/src/specs/mutable_borrows.rs | 9 + tests/hax/src/specs/traits.rs | 16 +- .../hax/src/specs/traits/assoc_type_bounds.rs | 53 + tests/hax/src/specs/traits/basic.rs | 71 ++ tests/hax/src/specs/traits/blanket_impl.rs | 35 + tests/hax/src/specs/traits/builtin_bound.rs | 52 + tests/hax/src/specs/traits/default_methods.rs | 31 + tests/hax/src/specs/traits/diamond.rs | 49 + tests/hax/src/specs/traits/generic_impl.rs | 65 ++ tests/hax/src/specs/traits/impl_contract.rs | 34 + tests/hax/src/specs/traits/method_generics.rs | 28 + tests/hax/src/specs/traits/minimal.rs | 16 + tests/hax/src/specs/traits/mut_self.rs | 22 + tests/hax/src/specs/traits/supertraits.rs | 58 ++ tests/hax/src/specs/traits/trait_generics.rs | 20 + tests/hax/src/specs/traits/unannotated_sub.rs | 26 + tests/lean/HaxSpecs/HaxSpecs.lean | 875 ----------------- tests/src/hax_specs/Cargo.lock | 582 ----------- 23 files changed, 2078 insertions(+), 1578 deletions(-) create mode 100644 tests/hax/src/specs/traits/assoc_type_bounds.rs create mode 100644 tests/hax/src/specs/traits/basic.rs create mode 100644 tests/hax/src/specs/traits/blanket_impl.rs create mode 100644 tests/hax/src/specs/traits/builtin_bound.rs create mode 100644 tests/hax/src/specs/traits/default_methods.rs create mode 100644 tests/hax/src/specs/traits/diamond.rs create mode 100644 tests/hax/src/specs/traits/generic_impl.rs create mode 100644 tests/hax/src/specs/traits/impl_contract.rs create mode 100644 tests/hax/src/specs/traits/method_generics.rs create mode 100644 tests/hax/src/specs/traits/minimal.rs create mode 100644 tests/hax/src/specs/traits/mut_self.rs create mode 100644 tests/hax/src/specs/traits/supertraits.rs create mode 100644 tests/hax/src/specs/traits/trait_generics.rs create mode 100644 tests/hax/src/specs/traits/unannotated_sub.rs delete mode 100644 tests/lean/HaxSpecs/HaxSpecs.lean delete mode 100644 tests/src/hax_specs/Cargo.lock diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean index 079076558d..69ec46fdbf 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean @@ -87,54 +87,59 @@ def specs.contracts.returns_unit (x : Std.U32) : RustM Unit := do def specs.contracts.no_args : RustM Unit := do ok () +/-- [hax_tests::specs::contracts::zero_ret]: + Source: 'src/specs/contracts.rs', lines 35:0-37:1 -/ +def specs.contracts.zero_ret : RustM Std.U32 := do + ok 0#u32 + /-- [hax_tests::specs::contracts::block_in_requires]: - Source: 'src/specs/contracts.rs', lines 33:0-35:1 -/ + Source: 'src/specs/contracts.rs', lines 41:0-43:1 -/ def specs.contracts.block_in_requires (x : Std.U32) : RustM Std.U32 := do ok x /-- [hax_tests::specs::contracts::returns_pair]: - Source: 'src/specs/contracts.rs', lines 39:0-41:1 -/ + Source: 'src/specs/contracts.rs', lines 47:0-49:1 -/ def specs.contracts.returns_pair (x : Std.U32) : RustM (Std.U32 × Std.U32) := do ok (x, x) /-- [hax_tests::specs::contracts::returns_option]: - Source: 'src/specs/contracts.rs', lines 45:0-47:1 -/ + Source: 'src/specs/contracts.rs', lines 53:0-55:1 -/ def specs.contracts.returns_option (x : Std.U32) : RustM (core.option.Option Std.U32) := do ok (core.option.Option.Some x) /-- [hax_tests::specs::contracts::returns_result]: - Source: 'src/specs/contracts.rs', lines 52:0-54:1 -/ + Source: 'src/specs/contracts.rs', lines 60:0-62:1 -/ def specs.contracts.returns_result (x : Std.U32) : RustM (core.result.Result Std.U32 Unit) := do let i ← x + 1#u32 ok (core.result.Result.Ok i) /-- [hax_tests::specs::contracts::may_panic]: - Source: 'src/specs/contracts.rs', lines 59:0-61:1 -/ + Source: 'src/specs/contracts.rs', lines 67:0-69:1 -/ def specs.contracts.may_panic (x : Std.U32) (y : Std.U32) : RustM Std.U32 := do x / y /-- [hax_tests::specs::contracts::explicit_panic]: - Source: 'src/specs/contracts.rs', lines 66:0-71:1 -/ + Source: 'src/specs/contracts.rs', lines 74:0-79:1 -/ def specs.contracts.explicit_panic (x : Std.U32) : RustM Std.U32 := do massert (¬ (x >= 10#u32)) ok x /-- [hax_tests::specs::contracts::implies_cond]: - Source: 'src/specs/contracts.rs', lines 76:0-82:1 -/ + Source: 'src/specs/contracts.rs', lines 84:0-90:1 -/ def specs.contracts.implies_cond (x : Std.U32) (y : Std.U32) : RustM Std.U32 := do if x >= 10#u32 then x + y else ok x -/-- [hax_tests::specs::contracts::_#18::requires::{impl core::ops::function::Fn<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#18::requires::closure<'_0>}::call]: - Source: 'src/specs/contracts.rs', lines 85:18-85:50 -/ +/-- [hax_tests::specs::contracts::_#20::requires::{impl core::ops::function::Fn<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#20::requires::closure<'_0>}::call]: + Source: 'src/specs/contracts.rs', lines 93:18-93:50 -/ def - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.call - (c : specs.contracts.__18.requires.closure) (tupled_args : Std.U32) : + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.call + (c : specs.contracts.__20.requires.closure) (tupled_args : Std.U32) : RustM hax_lib.prop.Prop := do hax_lib.prop.implies (core.convert.Into.Blanket @@ -142,160 +147,160 @@ def hax_lib.prop.Prop.Insts.CoreConvertFromBool) (tupled_args < c) (tupled_args < 100#u32) -/-- [hax_tests::specs::contracts::_#18::requires::{impl core::ops::function::FnMut<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#18::requires::closure<'_0>}::call_mut]: - Source: 'src/specs/contracts.rs', lines 85:18-85:50 -/ +/-- [hax_tests::specs::contracts::_#20::requires::{impl core::ops::function::FnMut<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#20::requires::closure<'_0>}::call_mut]: + Source: 'src/specs/contracts.rs', lines 93:18-93:50 -/ def - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.call_mut - (state : specs.contracts.__18.requires.closure) (args : Std.U32) : - RustM (hax_lib.prop.Prop × specs.contracts.__18.requires.closure) + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.call_mut + (state : specs.contracts.__20.requires.closure) (args : Std.U32) : + RustM (hax_lib.prop.Prop × specs.contracts.__20.requires.closure) := do let p ← - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.call + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.call state args ok (p, state) -/-- [hax_tests::specs::contracts::_#18::requires::{impl core::ops::function::FnOnce<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#18::requires::closure<'_0>}::call_once]: - Source: 'src/specs/contracts.rs', lines 85:18-85:50 -/ +/-- [hax_tests::specs::contracts::_#20::requires::{impl core::ops::function::FnOnce<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#20::requires::closure<'_0>}::call_once]: + Source: 'src/specs/contracts.rs', lines 93:18-93:50 -/ def - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop.call_once - (c : specs.contracts.__18.requires.closure) (i : Std.U32) : + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop.call_once + (c : specs.contracts.__20.requires.closure) (i : Std.U32) : RustM hax_lib.prop.Prop := do let (p, _) ← - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.call_mut + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.call_mut c i ok p -/-- Trait implementation: [hax_tests::specs::contracts::_#18::requires::{impl core::ops::function::FnOnce<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#18::requires::closure<'_0>}] - Source: 'src/specs/contracts.rs', lines 85:18-85:50 -/ +/-- Trait implementation: [hax_tests::specs::contracts::_#20::requires::{impl core::ops::function::FnOnce<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#20::requires::closure<'_0>}] + Source: 'src/specs/contracts.rs', lines 93:18-93:50 -/ @[reducible] def - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop - : core.ops.function.FnOnce specs.contracts.__18.requires.closure Std.U32 + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop + : core.ops.function.FnOnce specs.contracts.__20.requires.closure Std.U32 hax_lib.prop.Prop := { call_once := - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop.call_once + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop.call_once } -/-- Trait implementation: [hax_tests::specs::contracts::_#18::requires::{impl core::ops::function::FnMut<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#18::requires::closure<'_0>}] - Source: 'src/specs/contracts.rs', lines 85:18-85:50 -/ +/-- Trait implementation: [hax_tests::specs::contracts::_#20::requires::{impl core::ops::function::FnMut<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#20::requires::closure<'_0>}] + Source: 'src/specs/contracts.rs', lines 93:18-93:50 -/ @[reducible] def - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop - : core.ops.function.FnMut specs.contracts.__18.requires.closure Std.U32 + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop + : core.ops.function.FnMut specs.contracts.__20.requires.closure Std.U32 hax_lib.prop.Prop := { FnOnceInst := - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop call_mut := - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.call_mut + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.call_mut } -/-- Trait implementation: [hax_tests::specs::contracts::_#18::requires::{impl core::ops::function::Fn<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#18::requires::closure<'_0>}] - Source: 'src/specs/contracts.rs', lines 85:18-85:50 -/ +/-- Trait implementation: [hax_tests::specs::contracts::_#20::requires::{impl core::ops::function::Fn<(u32,), hax_lib::prop::Prop> for hax_tests::specs::contracts::_#20::requires::closure<'_0>}] + Source: 'src/specs/contracts.rs', lines 93:18-93:50 -/ @[reducible] -def specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop : - core.ops.function.Fn specs.contracts.__18.requires.closure Std.U32 +def specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop : + core.ops.function.Fn specs.contracts.__20.requires.closure Std.U32 hax_lib.prop.Prop := { FnMutInst := - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop call := - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.call + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.call } -/-- [hax_tests::specs::contracts::_#19::ensures::{impl core::ops::function::Fn<(u32,), bool> for hax_tests::specs::contracts::_#19::ensures::closure<'_0>}::call]: - Source: 'src/specs/contracts.rs', lines 86:26-86:46 -/ +/-- [hax_tests::specs::contracts::_#21::ensures::{impl core::ops::function::Fn<(u32,), bool> for hax_tests::specs::contracts::_#21::ensures::closure<'_0>}::call]: + Source: 'src/specs/contracts.rs', lines 94:26-94:46 -/ def - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.call - (c : specs.contracts.__19.ensures.closure) (tupled_args : Std.U32) : + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.call + (c : specs.contracts.__21.ensures.closure) (tupled_args : Std.U32) : RustM Bool := do ok (c = tupled_args) -/-- [hax_tests::specs::contracts::_#19::ensures::{impl core::ops::function::FnMut<(u32,), bool> for hax_tests::specs::contracts::_#19::ensures::closure<'_0>}::call_mut]: - Source: 'src/specs/contracts.rs', lines 86:26-86:46 -/ +/-- [hax_tests::specs::contracts::_#21::ensures::{impl core::ops::function::FnMut<(u32,), bool> for hax_tests::specs::contracts::_#21::ensures::closure<'_0>}::call_mut]: + Source: 'src/specs/contracts.rs', lines 94:26-94:46 -/ def - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.call_mut - (state : specs.contracts.__19.ensures.closure) (args : Std.U32) : - RustM (Bool × specs.contracts.__19.ensures.closure) + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.call_mut + (state : specs.contracts.__21.ensures.closure) (args : Std.U32) : + RustM (Bool × specs.contracts.__21.ensures.closure) := do let b ← - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.call + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.call state args ok (b, state) -/-- [hax_tests::specs::contracts::_#19::ensures::{impl core::ops::function::FnOnce<(u32,), bool> for hax_tests::specs::contracts::_#19::ensures::closure<'_0>}::call_once]: - Source: 'src/specs/contracts.rs', lines 86:26-86:46 -/ +/-- [hax_tests::specs::contracts::_#21::ensures::{impl core::ops::function::FnOnce<(u32,), bool> for hax_tests::specs::contracts::_#21::ensures::closure<'_0>}::call_once]: + Source: 'src/specs/contracts.rs', lines 94:26-94:46 -/ def - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool.call_once - (c : specs.contracts.__19.ensures.closure) (i : Std.U32) : RustM Bool := do + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool.call_once + (c : specs.contracts.__21.ensures.closure) (i : Std.U32) : RustM Bool := do let (b, _) ← - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.call_mut + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.call_mut c i ok b -/-- Trait implementation: [hax_tests::specs::contracts::_#19::ensures::{impl core::ops::function::FnOnce<(u32,), bool> for hax_tests::specs::contracts::_#19::ensures::closure<'_0>}] - Source: 'src/specs/contracts.rs', lines 86:26-86:46 -/ +/-- Trait implementation: [hax_tests::specs::contracts::_#21::ensures::{impl core::ops::function::FnOnce<(u32,), bool> for hax_tests::specs::contracts::_#21::ensures::closure<'_0>}] + Source: 'src/specs/contracts.rs', lines 94:26-94:46 -/ @[reducible] def - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool - : core.ops.function.FnOnce specs.contracts.__19.ensures.closure Std.U32 Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool + : core.ops.function.FnOnce specs.contracts.__21.ensures.closure Std.U32 Bool := { call_once := - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool.call_once + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool.call_once } -/-- Trait implementation: [hax_tests::specs::contracts::_#19::ensures::{impl core::ops::function::FnMut<(u32,), bool> for hax_tests::specs::contracts::_#19::ensures::closure<'_0>}] - Source: 'src/specs/contracts.rs', lines 86:26-86:46 -/ +/-- Trait implementation: [hax_tests::specs::contracts::_#21::ensures::{impl core::ops::function::FnMut<(u32,), bool> for hax_tests::specs::contracts::_#21::ensures::closure<'_0>}] + Source: 'src/specs/contracts.rs', lines 94:26-94:46 -/ @[reducible] -def specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool - : core.ops.function.FnMut specs.contracts.__19.ensures.closure Std.U32 Bool +def specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool + : core.ops.function.FnMut specs.contracts.__21.ensures.closure Std.U32 Bool := { FnOnceInst := - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool call_mut := - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.call_mut + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.call_mut } -/-- Trait implementation: [hax_tests::specs::contracts::_#19::ensures::{impl core::ops::function::Fn<(u32,), bool> for hax_tests::specs::contracts::_#19::ensures::closure<'_0>}] - Source: 'src/specs/contracts.rs', lines 86:26-86:46 -/ +/-- Trait implementation: [hax_tests::specs::contracts::_#21::ensures::{impl core::ops::function::Fn<(u32,), bool> for hax_tests::specs::contracts::_#21::ensures::closure<'_0>}] + Source: 'src/specs/contracts.rs', lines 94:26-94:46 -/ @[reducible] -def specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool : - core.ops.function.Fn specs.contracts.__19.ensures.closure Std.U32 Bool := { +def specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool : + core.ops.function.Fn specs.contracts.__21.ensures.closure Std.U32 Bool := { FnMutInst := - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool call := - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.call + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.call } /-- [hax_tests::specs::contracts::quantifiers]: - Source: 'src/specs/contracts.rs', lines 87:0-89:1 -/ + Source: 'src/specs/contracts.rs', lines 95:0-97:1 -/ def specs.contracts.quantifiers (x : Std.U32) : RustM Std.U32 := do ok x /-- [hax_tests::specs::contracts::int_bounds]: - Source: 'src/specs/contracts.rs', lines 95:0-97:1 -/ + Source: 'src/specs/contracts.rs', lines 103:0-105:1 -/ def specs.contracts.int_bounds (x : Std.U32) (y : Std.U32) : RustM Std.U32 := do x + y /-- [hax_tests::specs::contracts::is_small]: - Source: 'src/specs/contracts.rs', lines 99:0-101:1 -/ + Source: 'src/specs/contracts.rs', lines 107:0-109:1 -/ def specs.contracts.is_small (x : Std.U32) : RustM Bool := do ok (x < 100#u32) /-- [hax_tests::specs::contracts::helper_in_requires]: - Source: 'src/specs/contracts.rs', lines 106:0-108:1 -/ + Source: 'src/specs/contracts.rs', lines 114:0-116:1 -/ def specs.contracts.helper_in_requires (x : Std.U32) : RustM Std.U32 := do x + 1#u32 /-- [hax_tests::specs::contracts::calls_contracted]: - Source: 'src/specs/contracts.rs', lines 113:0-115:1 -/ + Source: 'src/specs/contracts.rs', lines 121:0-123:1 -/ def specs.contracts.calls_contracted (x : Std.U32) : RustM Std.U32 := do let i ← specs.contracts.both x i + 1#u32 /-- [hax_tests::specs::contracts::recursive]: - Source: 'src/specs/contracts.rs', lines 120:0-126:1 -/ + Source: 'src/specs/contracts.rs', lines 128:0-134:1 -/ def specs.contracts.recursive (n : Std.U32) : RustM Std.U32 := do if n = 0#u32 then ok 0#u32 @@ -305,7 +310,7 @@ def specs.contracts.recursive (n : Std.U32) : RustM Std.U32 := do partial_fixpoint /-- [hax_tests::specs::contracts::with_loop]: loop body 0: - Source: 'src/specs/contracts.rs', lines 134:4-136:5 -/ + Source: 'src/specs/contracts.rs', lines 142:4-144:5 -/ @[rust_loop_body] def specs.contracts.with_loop_loop.body (iter : core.ops.range.Range Std.U32) (acc : Std.U32) : @@ -321,7 +326,7 @@ def specs.contracts.with_loop_loop.body ok (cont (iter1, acc1)) /-- [hax_tests::specs::contracts::with_loop]: loop 0: - Source: 'src/specs/contracts.rs', lines 134:4-136:5 -/ + Source: 'src/specs/contracts.rs', lines 142:4-144:5 -/ @[rust_loop] def specs.contracts.with_loop_loop (iter : core.ops.range.Range Std.U32) (acc : Std.U32) : RustM Std.U32 := do @@ -330,7 +335,7 @@ def specs.contracts.with_loop_loop (iter, acc) /-- [hax_tests::specs::contracts::with_loop]: - Source: 'src/specs/contracts.rs', lines 132:0-138:1 -/ + Source: 'src/specs/contracts.rs', lines 140:0-146:1 -/ @[reducible] def specs.contracts.with_loop (n : Std.U32) : RustM Std.U32 := do specs.contracts.with_loop_loop { start := 0#u32, «end» := n } 0#u32 @@ -461,19 +466,26 @@ def specs.mutable_borrows.swap_and_add let i ← x + y ok (i, y, x) +/-- [hax_tests::specs::mutable_borrows::incr_ret]: + Source: 'src/specs/mutable_borrows.rs', lines 33:0-36:1 -/ +def specs.mutable_borrows.incr_ret + (x : Std.U8) : RustM (Std.U32 × Std.U8) := do + let x1 ← x + 1#u8 + ok (7#u32, x1) + /-- [hax_tests::specs::mutable_borrows::read_shared]: - Source: 'src/specs/mutable_borrows.rs', lines 31:0-33:1 -/ + Source: 'src/specs/mutable_borrows.rs', lines 40:0-42:1 -/ def specs.mutable_borrows.read_shared (x : Std.U32) : RustM Std.U32 := do ok x /-- [hax_tests::specs::mutable_borrows::add_assign]: - Source: 'src/specs/mutable_borrows.rs', lines 38:0-40:1 -/ + Source: 'src/specs/mutable_borrows.rs', lines 47:0-49:1 -/ def specs.mutable_borrows.add_assign (x : Std.U32) (y : Std.U32) : RustM Std.U32 := do x + y /-- [hax_tests::specs::mutable_borrows::{hax_tests::specs::mutable_borrows::Counter}::bump]: - Source: 'src/specs/mutable_borrows.rs', lines 51:4-53:5 + Source: 'src/specs/mutable_borrows.rs', lines 60:4-62:5 Visibility: public -/ def specs.mutable_borrows.Counter.bump (self : specs.mutable_borrows.Counter) : @@ -512,4 +524,746 @@ def specs.naming.proof : RustM Unit := do def specs.naming.bar.pre : RustM Unit := do ok () +/-- [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Bar for u32}::bar]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 27:4-29:5 -/ +def U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.bar + (self : Std.U32) : RustM Std.U32 := do + ok 0#u32 + +/-- Trait implementation: [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Bar for u32}] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 26:0-30:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar : + specs.traits.assoc_type_bounds.Bar Std.U32 := { + bar := U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.bar +} + +/-- [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Container for hax_tests::specs::traits::assoc_type_bounds::One}::first]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 35:4-37:5 -/ +def + specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32.first + (self : specs.traits.assoc_type_bounds.One) : RustM Std.U32 := do + ok self.x + +/-- Trait implementation: [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Container for hax_tests::specs::traits::assoc_type_bounds::One}] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 32:0-38:1 -/ +@[reducible] +def + specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32 + : specs.traits.assoc_type_bounds.Container specs.traits.assoc_type_bounds.One + Std.U32 := { + BarInst := U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar + first := + specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32.first +} + +/-- [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Container for hax_tests::specs::traits::assoc_type_bounds::Box1}::first]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 45:4-47:5 -/ +def + specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer.first + {T : Type} (BarInst : specs.traits.assoc_type_bounds.Bar T) + (coremarkerCopyInst : core.marker.Copy T) + (self : specs.traits.assoc_type_bounds.Box1 T) : + RustM T + := do + ok self + +/-- Trait implementation: [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Container for hax_tests::specs::traits::assoc_type_bounds::Box1}] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 42:0-48:1 -/ +@[reducible] +def + specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer + {T : Type} (BarInst1 : specs.traits.assoc_type_bounds.Bar T) + (coremarkerCopyInst : core.marker.Copy T) : + specs.traits.assoc_type_bounds.Container (specs.traits.assoc_type_bounds.Box1 + T) T := { + BarInst := BarInst1 + first := + specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer.first + BarInst1 coremarkerCopyInst +} + +/-- [hax_tests::specs::traits::assoc_type_bounds::first_bar]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 51:0-53:1 -/ +def specs.traits.assoc_type_bounds.first_bar + {C : Type} {Clause0_Item : Type} (ContainerInst : + specs.traits.assoc_type_bounds.Container C Clause0_Item) (c : C) : + RustM Std.U32 + := do + let t ← ContainerInst.first c + ContainerInst.BarInst.bar t + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u64}::zero]: + Source: 'src/specs/traits/basic.rs', lines 35:4-37:5 -/ +def U64.Insts.Hax_testsSpecsTraitsBasicFoo.zero : RustM Std.U64 := do + ok 0#u64 + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u64}::make]: + Source: 'src/specs/traits/basic.rs', lines 31:4-33:5 -/ +def U64.Insts.Hax_testsSpecsTraitsBasicFoo.make + (x : Std.U32) : RustM Std.U64 := do + let i ← x % 10#u32 + ok (UScalar.cast .U64 i) + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u64}::f2]: + Source: 'src/specs/traits/basic.rs', lines 27:4-29:5 -/ +def U64.Insts.Hax_testsSpecsTraitsBasicFoo.f2 + (self : Std.U64) : RustM Std.U64 := do + ok self + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u64}::f1]: + Source: 'src/specs/traits/basic.rs', lines 23:4-25:5 -/ +def U64.Insts.Hax_testsSpecsTraitsBasicFoo.f1 + (self : Std.U64) : RustM Bool := do + ok (self <= 10#u64) + +/-- Trait implementation: [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u64}] + Source: 'src/specs/traits/basic.rs', lines 22:0-38:1 -/ +@[reducible] +def U64.Insts.Hax_testsSpecsTraitsBasicFoo : specs.traits.basic.Foo Std.U64 + := { + f1 := U64.Insts.Hax_testsSpecsTraitsBasicFoo.f1 + f2 := U64.Insts.Hax_testsSpecsTraitsBasicFoo.f2 + make := U64.Insts.Hax_testsSpecsTraitsBasicFoo.make + zero := U64.Insts.Hax_testsSpecsTraitsBasicFoo.zero +} + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u32}::zero]: + Source: 'src/specs/traits/basic.rs', lines 53:4-55:5 -/ +def U32.Insts.Hax_testsSpecsTraitsBasicFoo.zero : RustM Std.U32 := do + ok 0#u32 + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u32}::make]: + Source: 'src/specs/traits/basic.rs', lines 49:4-51:5 -/ +def U32.Insts.Hax_testsSpecsTraitsBasicFoo.make + (x : Std.U32) : RustM Std.U32 := do + x % 10#u32 + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u32}::f2]: + Source: 'src/specs/traits/basic.rs', lines 45:4-47:5 -/ +def U32.Insts.Hax_testsSpecsTraitsBasicFoo.f2 + (self : Std.U32) : RustM Std.U64 := do + ok (UScalar.cast .U64 self) + +/-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u32}::f1]: + Source: 'src/specs/traits/basic.rs', lines 41:4-43:5 -/ +def U32.Insts.Hax_testsSpecsTraitsBasicFoo.f1 + (self : Std.U32) : RustM Bool := do + ok (self <= 10#u32) + +/-- Trait implementation: [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u32}] + Source: 'src/specs/traits/basic.rs', lines 40:0-56:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsBasicFoo : specs.traits.basic.Foo Std.U32 + := { + f1 := U32.Insts.Hax_testsSpecsTraitsBasicFoo.f1 + f2 := U32.Insts.Hax_testsSpecsTraitsBasicFoo.f2 + make := U32.Insts.Hax_testsSpecsTraitsBasicFoo.make + zero := U32.Insts.Hax_testsSpecsTraitsBasicFoo.zero +} + +/-- [hax_tests::specs::traits::basic::g]: + Source: 'src/specs/traits/basic.rs', lines 59:0-65:1 -/ +def specs.traits.basic.g + {T : Type} (FooInst : specs.traits.basic.Foo T) (x : T) : RustM Std.U64 := do + let b ← FooInst.f1 x + if b + then FooInst.f2 x + else ok 0#u64 + +/-- [hax_tests::specs::traits::basic::h]: + Source: 'src/specs/traits/basic.rs', lines 69:0-71:1 -/ +def specs.traits.basic.h (x : Std.U64) : RustM Std.U64 := do + specs.traits.basic.g U64.Insts.Hax_testsSpecsTraitsBasicFoo x + +/-- [hax_tests::specs::traits::blanket_impl::{impl hax_tests::specs::traits::blanket_impl::Show for T}::show]: + Source: 'src/specs/traits/blanket_impl.rs', lines 16:4-18:5 -/ +def specs.traits.blanket_impl.Show.Blanket.show + {T : Type} (self : T) : RustM Std.U64 := do + ok 7#u64 + +/-- Trait implementation: [hax_tests::specs::traits::blanket_impl::{impl hax_tests::specs::traits::blanket_impl::Show for T}] + Source: 'src/specs/traits/blanket_impl.rs', lines 15:0-19:1 -/ +@[reducible] +def specs.traits.blanket_impl.Show.Blanket (T : Type) : + specs.traits.blanket_impl.Show T := { + «show» := specs.traits.blanket_impl.Show.Blanket.show +} + +/-- [hax_tests::specs::traits::blanket_impl::show_generic]: + Source: 'src/specs/traits/blanket_impl.rs', lines 23:0-25:1 -/ +def specs.traits.blanket_impl.show_generic + {T : Type} (x : T) : RustM Std.U64 := do + specs.traits.blanket_impl.Show.Blanket.show x + +/-- [hax_tests::specs::traits::blanket_impl::show_u64]: + Source: 'src/specs/traits/blanket_impl.rs', lines 29:0-31:1 -/ +def specs.traits.blanket_impl.show_u64 (x : Std.U64) : RustM Std.U64 := do + specs.traits.blanket_impl.Show.Blanket.show x + +/-- Trait implementation: [hax_tests::specs::traits::blanket_impl::{impl hax_tests::specs::traits::blanket_impl::Tag for T}] + Source: 'src/specs/traits/blanket_impl.rs', lines 35:0-35:26 -/ +@[reducible] +def specs.traits.blanket_impl.Tag.Blanket {T : Type} (ShowInst1 : + specs.traits.blanket_impl.Show T) : specs.traits.blanket_impl.Tag T := { + ShowInst := ShowInst1 +} + +/-- [hax_tests::specs::traits::builtin_bound::dup]: + Source: 'src/specs/traits/builtin_bound.rs', lines 12:0-14:1 -/ +def specs.traits.builtin_bound.dup + {T : Type} (corecloneCloneInst : core.clone.Clone T) (x : T) : + RustM (T × T) + := do + let t ← corecloneCloneInst.clone x + ok (t, t) + +/-- [hax_tests::specs::traits::builtin_bound::{impl hax_tests::specs::traits::builtin_bound::Dup for u32}::dup]: + Source: 'src/specs/traits/builtin_bound.rs', lines 23:4-25:5 -/ +def U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup + (self : Std.U32) : RustM (Std.U32 × Std.U32) := do + ok (self, self) + +/-- Trait implementation: [hax_tests::specs::traits::builtin_bound::{impl hax_tests::specs::traits::builtin_bound::Dup for u32}] + Source: 'src/specs/traits/builtin_bound.rs', lines 22:0-26:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup : + specs.traits.builtin_bound.Dup Std.U32 := { + corecloneCloneInst := core.U32.Insts.CoreCloneClone + dup := U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup +} + +/-- [hax_tests::specs::traits::builtin_bound::{impl core::clone::Clone for hax_tests::specs::traits::builtin_bound::One}::clone]: + Source: 'src/specs/traits/builtin_bound.rs', lines 28:9-28:14 + Visibility: public -/ +def specs.traits.builtin_bound.One.Insts.CoreCloneClone.clone + (self : specs.traits.builtin_bound.One) : + RustM specs.traits.builtin_bound.One + := do + ok () + +/-- Trait implementation: [hax_tests::specs::traits::builtin_bound::{impl core::clone::Clone for hax_tests::specs::traits::builtin_bound::One}] + Source: 'src/specs/traits/builtin_bound.rs', lines 28:9-28:14 -/ +@[reducible] +impl_def specs.traits.builtin_bound.One.Insts.CoreCloneClone : core.clone.Clone + specs.traits.builtin_bound.One := { + clone := specs.traits.builtin_bound.One.Insts.CoreCloneClone.clone + clone_from := core.clone.Clone.clone_from.default + specs.traits.builtin_bound.One.Insts.CoreCloneClone +} + +/-- [hax_tests::specs::traits::builtin_bound::{impl core::default::Default for hax_tests::specs::traits::builtin_bound::One}::default]: + Source: 'src/specs/traits/builtin_bound.rs', lines 32:4-34:5 + Visibility: public -/ +def specs.traits.builtin_bound.One.Insts.CoreDefaultDefault.default + : RustM specs.traits.builtin_bound.One := do + ok () + +/-- Trait implementation: [hax_tests::specs::traits::builtin_bound::{impl core::default::Default for hax_tests::specs::traits::builtin_bound::One}] + Source: 'src/specs/traits/builtin_bound.rs', lines 31:0-35:1 -/ +@[reducible] +def specs.traits.builtin_bound.One.Insts.CoreDefaultDefault : + core.default.Default specs.traits.builtin_bound.One := { + default := specs.traits.builtin_bound.One.Insts.CoreDefaultDefault.default +} + +/-- [hax_tests::specs::traits::builtin_bound::{impl hax_tests::specs::traits::builtin_bound::Dup for hax_tests::specs::traits::builtin_bound::One}::dup]: + Source: 'src/specs/traits/builtin_bound.rs', lines 38:4-40:5 -/ +def + specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup + (self : specs.traits.builtin_bound.One) : + RustM (specs.traits.builtin_bound.One × specs.traits.builtin_bound.One) + := do + let o ← specs.traits.builtin_bound.One.Insts.CoreCloneClone.clone self + ok (o, o) + +/-- Trait implementation: [hax_tests::specs::traits::builtin_bound::{impl hax_tests::specs::traits::builtin_bound::Dup for hax_tests::specs::traits::builtin_bound::One}] + Source: 'src/specs/traits/builtin_bound.rs', lines 37:0-41:1 -/ +@[reducible] +def specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup : + specs.traits.builtin_bound.Dup specs.traits.builtin_bound.One := { + corecloneCloneInst := specs.traits.builtin_bound.One.Insts.CoreCloneClone + dup := + specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup +} + +/-- [hax_tests::specs::traits::builtin_bound::{impl core::clone::Clone for hax_tests::specs::traits::builtin_bound::W}::clone]: + Source: 'src/specs/traits/builtin_bound.rs', lines 43:9-43:14 + Visibility: public -/ +def specs.traits.builtin_bound.W.Insts.CoreCloneClone.clone + {T : Type} (corecloneCloneInst : core.clone.Clone T) + (self : specs.traits.builtin_bound.W T) : + RustM (specs.traits.builtin_bound.W T) + := do + let t ← corecloneCloneInst.clone self.x + ok { x := t } + +/-- Trait implementation: [hax_tests::specs::traits::builtin_bound::{impl core::clone::Clone for hax_tests::specs::traits::builtin_bound::W}] + Source: 'src/specs/traits/builtin_bound.rs', lines 43:9-43:14 -/ +@[reducible] +impl_def specs.traits.builtin_bound.W.Insts.CoreCloneClone {T : Type} + (corecloneCloneInst : core.clone.Clone T) : core.clone.Clone + (specs.traits.builtin_bound.W T) := { + clone := specs.traits.builtin_bound.W.Insts.CoreCloneClone.clone + corecloneCloneInst + clone_from := core.clone.Clone.clone_from.default + (specs.traits.builtin_bound.W.Insts.CoreCloneClone corecloneCloneInst) +} + +/-- [hax_tests::specs::traits::builtin_bound::{impl hax_tests::specs::traits::builtin_bound::Dup for hax_tests::specs::traits::builtin_bound::W}::dup]: + Source: 'src/specs/traits/builtin_bound.rs', lines 49:4-51:5 -/ +def + specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup + (self : specs.traits.builtin_bound.W Std.U32) : + RustM ((specs.traits.builtin_bound.W Std.U32) × + (specs.traits.builtin_bound.W Std.U32)) + := do + let w ← + specs.traits.builtin_bound.W.Insts.CoreCloneClone.clone + core.U32.Insts.CoreCloneClone self + ok (w, w) + +/-- Trait implementation: [hax_tests::specs::traits::builtin_bound::{impl hax_tests::specs::traits::builtin_bound::Dup for hax_tests::specs::traits::builtin_bound::W}] + Source: 'src/specs/traits/builtin_bound.rs', lines 48:0-52:1 -/ +@[reducible] +def specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup + : specs.traits.builtin_bound.Dup (specs.traits.builtin_bound.W Std.U32) := { + corecloneCloneInst := specs.traits.builtin_bound.W.Insts.CoreCloneClone + core.U32.Insts.CoreCloneClone + dup := + specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup +} + +/-- [hax_tests::specs::traits::default_methods::D::next]: + Source: 'src/specs/traits/default_methods.rs', lines 12:4-14:5 -/ +@[trait_default] +def specs.traits.default_methods.D.next.default + {Self : Type} (DInst : specs.traits.default_methods.D Self) (self : Self) : + RustM Std.U32 + := do + let i ← DInst.base self + i + 1#u32 + +/-- [hax_tests::specs::traits::default_methods::{impl hax_tests::specs::traits::default_methods::D for u32}::next]: + Source: 'src/specs/traits/default_methods.rs', lines 22:4-24:5 -/ +def U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.next + (self : Std.U32) : RustM Std.U32 := do + self + 2#u32 + +/-- [hax_tests::specs::traits::default_methods::{impl hax_tests::specs::traits::default_methods::D for u32}::base]: + Source: 'src/specs/traits/default_methods.rs', lines 18:4-20:5 -/ +def U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.base + (self : Std.U32) : RustM Std.U32 := do + ok self + +/-- Trait implementation: [hax_tests::specs::traits::default_methods::{impl hax_tests::specs::traits::default_methods::D for u32}] + Source: 'src/specs/traits/default_methods.rs', lines 17:0-25:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsDefault_methodsD : + specs.traits.default_methods.D Std.U32 := { + base := U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.base + next := U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.next +} + +/-- [hax_tests::specs::traits::default_methods::{impl hax_tests::specs::traits::default_methods::D for u64}::base]: + Source: 'src/specs/traits/default_methods.rs', lines 28:4-30:5 -/ +def U64.Insts.Hax_testsSpecsTraitsDefault_methodsD.base + (self : Std.U64) : RustM Std.U32 := do + ok 0#u32 + +/-- Trait implementation: [hax_tests::specs::traits::default_methods::{impl hax_tests::specs::traits::default_methods::D for u64}] + Source: 'src/specs/traits/default_methods.rs', lines 27:0-31:1 -/ +@[reducible] +impl_def U64.Insts.Hax_testsSpecsTraitsDefault_methodsD : + specs.traits.default_methods.D Std.U64 := { + base := U64.Insts.Hax_testsSpecsTraitsDefault_methodsD.base + next := specs.traits.default_methods.D.next.default + U64.Insts.Hax_testsSpecsTraitsDefault_methodsD +} + +/-- [hax_tests::specs::traits::diamond::{impl hax_tests::specs::traits::diamond::A for u8}::a]: + Source: 'src/specs/traits/diamond.rs', lines 22:4-24:5 -/ +def U8.Insts.Hax_testsSpecsTraitsDiamondA.a + (self : Std.U8) : RustM Std.Usize := do + ok 1#usize + +/-- Trait implementation: [hax_tests::specs::traits::diamond::{impl hax_tests::specs::traits::diamond::A for u8}] + Source: 'src/specs/traits/diamond.rs', lines 21:0-25:1 -/ +@[reducible] +def U8.Insts.Hax_testsSpecsTraitsDiamondA : specs.traits.diamond.A Std.U8 := { + a := U8.Insts.Hax_testsSpecsTraitsDiamondA.a +} + +/-- [hax_tests::specs::traits::diamond::{impl hax_tests::specs::traits::diamond::B for u8}::b]: + Source: 'src/specs/traits/diamond.rs', lines 28:4-30:5 -/ +def U8.Insts.Hax_testsSpecsTraitsDiamondB.b + (self : Std.U8) : RustM Std.Usize := do + ok 2#usize + +/-- Trait implementation: [hax_tests::specs::traits::diamond::{impl hax_tests::specs::traits::diamond::B for u8}] + Source: 'src/specs/traits/diamond.rs', lines 27:0-31:1 -/ +@[reducible] +def U8.Insts.Hax_testsSpecsTraitsDiamondB : specs.traits.diamond.B Std.U8 := { + AInst := U8.Insts.Hax_testsSpecsTraitsDiamondA + b := U8.Insts.Hax_testsSpecsTraitsDiamondB.b +} + +/-- [hax_tests::specs::traits::diamond::{impl hax_tests::specs::traits::diamond::C for u8}::c]: + Source: 'src/specs/traits/diamond.rs', lines 34:4-36:5 -/ +def U8.Insts.Hax_testsSpecsTraitsDiamondC.c + (self : Std.U8) : RustM Std.Usize := do + U8.Insts.Hax_testsSpecsTraitsDiamondA.a self + +/-- Trait implementation: [hax_tests::specs::traits::diamond::{impl hax_tests::specs::traits::diamond::C for u8}] + Source: 'src/specs/traits/diamond.rs', lines 33:0-37:1 -/ +@[reducible] +def U8.Insts.Hax_testsSpecsTraitsDiamondC : specs.traits.diamond.C Std.U8 := { + AInst := U8.Insts.Hax_testsSpecsTraitsDiamondA + BInst := U8.Insts.Hax_testsSpecsTraitsDiamondB + c := U8.Insts.Hax_testsSpecsTraitsDiamondC.c +} + +/-- [hax_tests::specs::traits::diamond::via_b]: + Source: 'src/specs/traits/diamond.rs', lines 40:0-42:1 -/ +def specs.traits.diamond.via_b + {T : Type} (BInst : specs.traits.diamond.B T) (x : T) : RustM Std.Usize := do + BInst.AInst.a x + +/-- [hax_tests::specs::traits::diamond::diamond]: + Source: 'src/specs/traits/diamond.rs', lines 47:0-49:1 -/ +def specs.traits.diamond.diamond + {T : Type} (CInst : specs.traits.diamond.C T) (x : T) : RustM Std.Usize := do + let i ← CInst.AInst.a x + let i1 ← specs.traits.diamond.via_b CInst.BInst x + i + i1 + +/-- [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for u64}::f]: + Source: 'src/specs/traits/generic_impl.rs', lines 25:4-27:5 -/ +def U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + (self : Std.U64) : RustM Std.U64 := do + ok 0#u64 + +/-- Trait implementation: [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for u64}] + Source: 'src/specs/traits/generic_impl.rs', lines 24:0-28:1 -/ +@[reducible] +def U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo : + specs.traits.generic_impl.Foo Std.U64 := { + f := U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f +} + +/-- [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for hax_tests::specs::traits::generic_impl::Wrapper}::f]: + Source: 'src/specs/traits/generic_impl.rs', lines 31:4-33:5 -/ +def + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (self : specs.traits.generic_impl.Wrapper T) : + RustM Std.U64 + := do + FooInst.f self.inner + +/-- Trait implementation: [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for hax_tests::specs::traits::generic_impl::Wrapper}] + Source: 'src/specs/traits/generic_impl.rs', lines 30:0-34:1 -/ +@[reducible] +def specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) : + specs.traits.generic_impl.Foo (specs.traits.generic_impl.Wrapper T) := { + f := + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + FooInst +} + +/-- [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Sub for hax_tests::specs::traits::generic_impl::Wrapper}::s]: + Source: 'src/specs/traits/generic_impl.rs', lines 37:4-39:5 -/ +def + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implSub.s + {T : Type} (SubInst : specs.traits.generic_impl.Sub T) + (self : specs.traits.generic_impl.Wrapper T) : + RustM Std.U64 + := do + SubInst.s self.inner + +/-- Trait implementation: [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Sub for hax_tests::specs::traits::generic_impl::Wrapper}] + Source: 'src/specs/traits/generic_impl.rs', lines 36:0-40:1 -/ +@[reducible] +def specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implSub + {T : Type} (SubInst : specs.traits.generic_impl.Sub T) : + specs.traits.generic_impl.Sub (specs.traits.generic_impl.Wrapper T) := { + FooInst := + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo + SubInst.FooInst + s := + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implSub.s + SubInst +} + +/-- [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for (T, U)}::f]: + Source: 'src/specs/traits/generic_impl.rs', lines 43:4-45:5 -/ +def Pair.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + {T : Type} {U : Type} (FooInst : specs.traits.generic_impl.Foo T) (FooInst1 : + specs.traits.generic_impl.Foo U) (self : (T × U)) : + RustM Std.U64 + := do + let (t, _) := self + FooInst.f t + +/-- Trait implementation: [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for (T, U)}] + Source: 'src/specs/traits/generic_impl.rs', lines 42:0-46:1 -/ +@[reducible] +def Pair.Insts.Hax_testsSpecsTraitsGeneric_implFoo {T : Type} {U : Type} + (FooInst : specs.traits.generic_impl.Foo T) (FooInst1 : + specs.traits.generic_impl.Foo U) : specs.traits.generic_impl.Foo (T × U) + := { + f := Pair.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f FooInst FooInst1 +} + +/-- [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for hax_tests::specs::traits::generic_impl::Single}::f]: + Source: 'src/specs/traits/generic_impl.rs', lines 51:4-53:5 -/ +def + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (self : specs.traits.generic_impl.Single T) : + RustM Std.U64 + := do + FooInst.f self + +/-- Trait implementation: [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for hax_tests::specs::traits::generic_impl::Single}] + Source: 'src/specs/traits/generic_impl.rs', lines 50:0-54:1 -/ +@[reducible] +def specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) : + specs.traits.generic_impl.Foo (specs.traits.generic_impl.Single T) := { + f := + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + FooInst +} + +/-- [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Sub for hax_tests::specs::traits::generic_impl::Single}::s]: + Source: 'src/specs/traits/generic_impl.rs', lines 57:4-59:5 -/ +def + specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub.s + (self : specs.traits.generic_impl.Single Std.U64) : RustM Std.U64 := do + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo self + +/-- Trait implementation: [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Sub for hax_tests::specs::traits::generic_impl::Single}] + Source: 'src/specs/traits/generic_impl.rs', lines 56:0-60:1 -/ +@[reducible] +def + specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub + : specs.traits.generic_impl.Sub (specs.traits.generic_impl.Single Std.U64) + := { + FooInst := + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo + U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo + s := + specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub.s +} + +/-- [hax_tests::specs::traits::generic_impl::k]: + Source: 'src/specs/traits/generic_impl.rs', lines 63:0-65:1 -/ +def specs.traits.generic_impl.k + {T : Type} {U : Type} (FooInst : specs.traits.generic_impl.Foo T) (SubInst : + specs.traits.generic_impl.Sub U) (x : T) (y : U) : + RustM Std.U64 + := do + let i ← FooInst.f x + let i1 ← SubInst.s y + i + i1 + +/-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f]: + Source: 'src/specs/traits/impl_contract.rs', lines 16:4-18:5 -/ +def U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f + (self : Std.U32) : RustM Std.U32 := do + self + 1#u32 + +/-- Trait implementation: [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}] + Source: 'src/specs/traits/impl_contract.rs', lines 13:0-19:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo : + specs.traits.impl_contract.Foo Std.U32 := { + f := U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f +} + +/-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::G for u32}::g]: + Source: 'src/specs/traits/impl_contract.rs', lines 31:4-33:5 -/ +def U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g + (self : Std.U32) : RustM Std.U32 := do + let i ← self % 10#u32 + i + 1#u32 + +/-- Trait implementation: [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::G for u32}] + Source: 'src/specs/traits/impl_contract.rs', lines 28:0-34:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsImpl_contractG : specs.traits.impl_contract.G + Std.U32 := { + g := U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g +} + +/-- [hax_tests::specs::traits::method_generics::{impl hax_tests::specs::traits::method_generics::Bar for u32}::bar]: + Source: 'src/specs/traits/method_generics.rs', lines 19:4-21:5 -/ +def U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar.bar + (self : Std.U32) : RustM Std.U32 := do + ok 0#u32 + +/-- Trait implementation: [hax_tests::specs::traits::method_generics::{impl hax_tests::specs::traits::method_generics::Bar for u32}] + Source: 'src/specs/traits/method_generics.rs', lines 18:0-22:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar : + specs.traits.method_generics.Bar Std.U32 := { + bar := U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar.bar +} + +/-- [hax_tests::specs::traits::method_generics::{impl hax_tests::specs::traits::method_generics::Foo for u32}::f]: + Source: 'src/specs/traits/method_generics.rs', lines 25:4-27:5 -/ +def U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo.f + {U : Type} (BarInst : specs.traits.method_generics.Bar U) (self : Std.U32) + (u : U) : + RustM Std.U32 + := do + BarInst.bar u + +/-- Trait implementation: [hax_tests::specs::traits::method_generics::{impl hax_tests::specs::traits::method_generics::Foo for u32}] + Source: 'src/specs/traits/method_generics.rs', lines 24:0-28:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo : + specs.traits.method_generics.Foo Std.U32 := { + f := fun {U : Type} (BarInst : specs.traits.method_generics.Bar U) => + U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo.f BarInst +} + +/-- [hax_tests::specs::traits::mut_self::{impl hax_tests::specs::traits::mut_self::Counter for u32}::incr]: + Source: 'src/specs/traits/mut_self.rs', lines 19:4-21:5 -/ +def U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.incr + (self : Std.U32) : RustM Std.U32 := do + self + 1#u32 + +/-- [hax_tests::specs::traits::mut_self::{impl hax_tests::specs::traits::mut_self::Counter for u32}::get]: + Source: 'src/specs/traits/mut_self.rs', lines 15:4-17:5 -/ +def U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.get + (self : Std.U32) : RustM Std.U32 := do + ok self + +/-- Trait implementation: [hax_tests::specs::traits::mut_self::{impl hax_tests::specs::traits::mut_self::Counter for u32}] + Source: 'src/specs/traits/mut_self.rs', lines 14:0-22:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsMut_selfCounter : + specs.traits.mut_self.Counter Std.U32 := { + get := U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.get + incr := U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.incr +} + +/-- [hax_tests::specs::traits::supertraits::{impl hax_tests::specs::traits::supertraits::A for u8}::a]: + Source: 'src/specs/traits/supertraits.rs', lines 26:4-28:5 -/ +def U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a + (self : Std.U8) : RustM Std.Usize := do + ok 1#usize + +/-- Trait implementation: [hax_tests::specs::traits::supertraits::{impl hax_tests::specs::traits::supertraits::A for u8}] + Source: 'src/specs/traits/supertraits.rs', lines 25:0-29:1 -/ +@[reducible] +def U8.Insts.Hax_testsSpecsTraitsSupertraitsA : specs.traits.supertraits.A + Std.U8 := { + a := U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a +} + +/-- [hax_tests::specs::traits::supertraits::{impl hax_tests::specs::traits::supertraits::B for u8}::b]: + Source: 'src/specs/traits/supertraits.rs', lines 32:4-34:5 -/ +def U8.Insts.Hax_testsSpecsTraitsSupertraitsB.b + (self : Std.U8) : RustM Std.Usize := do + let i ← U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a self + i + 1#usize + +/-- Trait implementation: [hax_tests::specs::traits::supertraits::{impl hax_tests::specs::traits::supertraits::B for u8}] + Source: 'src/specs/traits/supertraits.rs', lines 31:0-35:1 -/ +@[reducible] +def U8.Insts.Hax_testsSpecsTraitsSupertraitsB : specs.traits.supertraits.B + Std.U8 := { + AInst := U8.Insts.Hax_testsSpecsTraitsSupertraitsA + b := U8.Insts.Hax_testsSpecsTraitsSupertraitsB.b +} + +/-- [hax_tests::specs::traits::supertraits::{impl hax_tests::specs::traits::supertraits::Cc for u8}::c]: + Source: 'src/specs/traits/supertraits.rs', lines 38:4-40:5 -/ +def U8.Insts.Hax_testsSpecsTraitsSupertraitsCc.c + (self : Std.U8) : RustM Std.Usize := do + U8.Insts.Hax_testsSpecsTraitsSupertraitsB.b self + +/-- Trait implementation: [hax_tests::specs::traits::supertraits::{impl hax_tests::specs::traits::supertraits::Cc for u8}] + Source: 'src/specs/traits/supertraits.rs', lines 37:0-41:1 -/ +@[reducible] +def U8.Insts.Hax_testsSpecsTraitsSupertraitsCc : specs.traits.supertraits.Cc + Std.U8 := { + BInst := U8.Insts.Hax_testsSpecsTraitsSupertraitsB + c := U8.Insts.Hax_testsSpecsTraitsSupertraitsCc.c +} + +/-- [hax_tests::specs::traits::supertraits::via_b]: + Source: 'src/specs/traits/supertraits.rs', lines 48:0-50:1 -/ +def specs.traits.supertraits.via_b + {T : Type} (BInst : specs.traits.supertraits.B T) (x : T) : + RustM Std.Usize + := do + let i ← BInst.b x + let i1 ← BInst.AInst.a x + i - i1 + +/-- [hax_tests::specs::traits::supertraits::via_u8]: + Source: 'src/specs/traits/supertraits.rs', lines 56:0-58:1 -/ +def specs.traits.supertraits.via_u8 (x : Std.U8) : RustM Std.Usize := do + let i ← U8.Insts.Hax_testsSpecsTraitsSupertraitsB.b x + let i1 ← U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a x + i - i1 + +/-- [hax_tests::specs::traits::trait_generics::{impl hax_tests::specs::traits::trait_generics::Conv for u32}::conv]: + Source: 'src/specs/traits/trait_generics.rs', lines 12:4-14:5 -/ +def U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8.conv + (self : Std.U32) (_t : Std.U8) : RustM Std.U32 := do + ok 0#u32 + +/-- Trait implementation: [hax_tests::specs::traits::trait_generics::{impl hax_tests::specs::traits::trait_generics::Conv for u32}] + Source: 'src/specs/traits/trait_generics.rs', lines 11:0-15:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8 : + specs.traits.trait_generics.Conv Std.U32 Std.U8 := { + conv := U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8.conv +} + +/-- [hax_tests::specs::traits::trait_generics::use_conv]: + Source: 'src/specs/traits/trait_generics.rs', lines 18:0-20:1 -/ +def specs.traits.trait_generics.use_conv + {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv C Std.U8) + (c : C) : + RustM Std.U32 + := do + ConvCU8Inst.conv c 0#u8 + +/-- [hax_tests::specs::traits::unannotated_sub::{impl hax_tests::specs::traits::unannotated_sub::A for u32}::a]: + Source: 'src/specs/traits/unannotated_sub.rs', lines 17:4-19:5 -/ +def U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.a + (self : Std.U32) : RustM Std.U32 := do + ok 1#u32 + +/-- Trait implementation: [hax_tests::specs::traits::unannotated_sub::{impl hax_tests::specs::traits::unannotated_sub::A for u32}] + Source: 'src/specs/traits/unannotated_sub.rs', lines 16:0-20:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsUnannotated_subA : + specs.traits.unannotated_sub.A Std.U32 := { + a := U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.a +} + +/-- [hax_tests::specs::traits::unannotated_sub::{impl hax_tests::specs::traits::unannotated_sub::B for u32}::b]: + Source: 'src/specs/traits/unannotated_sub.rs', lines 23:4-25:5 -/ +def U32.Insts.Hax_testsSpecsTraitsUnannotated_subB.b + (self : Std.U32) : RustM Std.U32 := do + ok 0#u32 + +/-- Trait implementation: [hax_tests::specs::traits::unannotated_sub::{impl hax_tests::specs::traits::unannotated_sub::B for u32}] + Source: 'src/specs/traits/unannotated_sub.rs', lines 22:0-26:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsUnannotated_subB : + specs.traits.unannotated_sub.B Std.U32 := { + AInst := U32.Insts.Hax_testsSpecsTraitsUnannotated_subA + b := U32.Insts.Hax_testsSpecsTraitsUnannotated_subB.b +} + end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean index 852860dfa9..1b11f418bf 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean @@ -46,6 +46,9 @@ theorem specs.contracts.returns_unit.spec.proof (x : Std.U32) : theorem specs.contracts.no_args.spec.proof : specs.contracts.no_args.spec := by sorry +theorem specs.contracts.zero_ret.spec.proof : specs.contracts.zero_ret.spec + := by sorry + theorem specs.contracts.block_in_requires.spec.proof (x : Std.U32) : specs.contracts.block_in_requires.spec x := by sorry @@ -126,6 +129,10 @@ theorem specs.mutable_borrows.swap_and_add.spec.proof (x : Std.U32) (y : Std.U32) : specs.mutable_borrows.swap_and_add.spec x y := by sorry +theorem specs.mutable_borrows.incr_ret.spec.proof (x : Std.U8) : + specs.mutable_borrows.incr_ret.spec x + := by sorry + theorem specs.mutable_borrows.read_shared.spec.proof (x : Std.U32) : specs.mutable_borrows.read_shared.spec x := by sorry @@ -203,4 +210,88 @@ theorem specs.generics.MyStruct.get.spec.proof {N : Std.Usize} (self : specs.generics.MyStruct N) : specs.generics.MyStruct.get.spec self := by sorry +theorem + specs.traits.basic.g.spec.proof {T : Type} (FooInst : specs.traits.basic.Foo + T) (x : T) : + specs.traits.basic.g.spec FooInst x + := by sorry + +theorem specs.traits.basic.h.spec.proof (x : Std.U64) : + specs.traits.basic.h.spec x + := by sorry + +theorem + specs.traits.supertraits.via_b.spec.proof {T : Type} (BInst : + specs.traits.supertraits.B T) + (x : T) : specs.traits.supertraits.via_b.spec BInst x + := by sorry + +theorem specs.traits.supertraits.via_u8.spec.proof (x : Std.U8) : + specs.traits.supertraits.via_u8.spec x + := by sorry + +theorem + specs.traits.diamond.via_b.spec.proof {T : Type} (BInst : + specs.traits.diamond.B T) (x : T) : + specs.traits.diamond.via_b.spec BInst x + := by sorry + +theorem + specs.traits.diamond.diamond.spec.proof {T : Type} (CInst : + specs.traits.diamond.C T) (x : T) : + specs.traits.diamond.diamond.spec CInst x + := by sorry + +theorem + specs.traits.generic_impl.k.spec.proof {T : Type} {U : Type} (FooInst : + specs.traits.generic_impl.Foo T) + (SubInst : + specs.traits.generic_impl.Sub U) + (x : T) (y : U) : specs.traits.generic_impl.k.spec FooInst SubInst x y + := by sorry + +theorem specs.traits.blanket_impl.show_generic.spec.proof {T : Type} + (x : T) : specs.traits.blanket_impl.show_generic.spec x + := by sorry + +theorem specs.traits.blanket_impl.show_u64.spec.proof (x : Std.U64) : + specs.traits.blanket_impl.show_u64.spec x + := by sorry + +theorem + specs.traits.assoc_type_bounds.first_bar.spec.proof {C : Type} {Clause0_Item + : Type} (ContainerInst : + specs.traits.assoc_type_bounds.Container + C Clause0_Item) + (c : C) : specs.traits.assoc_type_bounds.first_bar.spec ContainerInst c + := by sorry + +theorem + specs.traits.builtin_bound.dup.spec.proof {T : Type} (corecloneCloneInst : + core.clone.Clone T) (x : T) : + specs.traits.builtin_bound.dup.spec corecloneCloneInst x + := by sorry + +theorem + specs.traits.trait_generics.use_conv.spec.proof {C : Type} (ConvCU8Inst : + specs.traits.trait_generics.Conv + C Std.U8) (c : C) : + specs.traits.trait_generics.use_conv.spec ConvCU8Inst c + := by sorry + +theorem + specs.traits.default_methods.D.next.default.spec.proof {Self : Type} (DInst : + specs.traits.default_methods.D + Self) (self : Self) : + specs.traits.default_methods.D.next.default.spec DInst self + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec.proof + (self : Std.U32) : U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec self + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec.proof + (self : Std.U32) : U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec self + := by sorry + end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index d21c692896..e51cd5ec1f 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -106,8 +106,26 @@ def specs.contracts.no_args.spec : Prop := ⦃ ⇓ res => ⌜ (specs.contracts.no_args.post res).holds ⌝ ⦄ +/-- [hax_tests::specs::contracts::zero_ret::pre]: + Source: 'src/specs/contracts.rs', lines 33:0-33:17 -/ +@[reducible] def specs.contracts.zero_ret.pre : RustM Bool := do + ok true + +/-- [hax_tests::specs::contracts::zero_ret::post]: + Source: 'src/specs/contracts.rs', lines 34:0-34:22 -/ +@[reducible] +def specs.contracts.zero_ret.post (r : Std.U32) : RustM Bool := do + ok (r = 0#u32) + +def specs.contracts.zero_ret.spec : Prop := + (specs.contracts.zero_ret.pre).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.contracts.zero_ret + ⦃ ⇓ res => ⌜ (specs.contracts.zero_ret.post res).holds ⌝ ⦄ + + /-- [hax_tests::specs::contracts::block_in_requires::pre]: - Source: 'src/specs/contracts.rs', lines 32:0-32:42 -/ + Source: 'src/specs/contracts.rs', lines 40:0-40:42 -/ @[reducible] def specs.contracts.block_in_requires.pre (x : Std.U32) : RustM Bool := do ok (x > 10#u32) @@ -120,7 +138,7 @@ def specs.contracts.block_in_requires.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::returns_pair::post]: - Source: 'src/specs/contracts.rs', lines 38:0-38:37 -/ + Source: 'src/specs/contracts.rs', lines 46:0-46:37 -/ @[reducible] def specs.contracts.returns_pair.post (x : Std.U32) (p : (Std.U32 × Std.U32)) : RustM Bool := do @@ -136,7 +154,7 @@ def specs.contracts.returns_pair.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::returns_option::post]: - Source: 'src/specs/contracts.rs', lines 44:0-44:70 -/ + Source: 'src/specs/contracts.rs', lines 52:0-52:70 -/ @[reducible] def specs.contracts.returns_option.post (x : Std.U32) (result : core.option.Option Std.U32) : RustM Bool := do @@ -151,13 +169,13 @@ def specs.contracts.returns_option.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::returns_result::pre]: - Source: 'src/specs/contracts.rs', lines 50:0-50:20 -/ + Source: 'src/specs/contracts.rs', lines 58:0-58:20 -/ @[reducible] def specs.contracts.returns_result.pre (x : Std.U32) : RustM Bool := do ok (x < 100#u32) /-- [hax_tests::specs::contracts::returns_result::post]: - Source: 'src/specs/contracts.rs', lines 51:0-51:74 -/ + Source: 'src/specs/contracts.rs', lines 59:0-59:74 -/ @[reducible] def specs.contracts.returns_result.post (x : Std.U32) (result : core.result.Result Std.U32 Unit) : RustM Bool := do @@ -174,14 +192,14 @@ def specs.contracts.returns_result.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::may_panic::pre]: - Source: 'src/specs/contracts.rs', lines 57:0-57:19 -/ + Source: 'src/specs/contracts.rs', lines 65:0-65:19 -/ @[reducible] def specs.contracts.may_panic.pre (x : Std.U32) (y : Std.U32) : RustM Bool := do ok (y != 0#u32) /-- [hax_tests::specs::contracts::may_panic::post]: - Source: 'src/specs/contracts.rs', lines 58:0-58:32 -/ + Source: 'src/specs/contracts.rs', lines 66:0-66:32 -/ @[reducible] def specs.contracts.may_panic.post (x : Std.U32) (y : Std.U32) (result : Std.U32) : RustM Bool := do @@ -195,13 +213,13 @@ def specs.contracts.may_panic.spec (x : Std.U32) (y : Std.U32) : Prop := /-- [hax_tests::specs::contracts::explicit_panic::pre]: - Source: 'src/specs/contracts.rs', lines 64:0-64:19 -/ + Source: 'src/specs/contracts.rs', lines 72:0-72:19 -/ @[reducible] def specs.contracts.explicit_panic.pre (x : Std.U32) : RustM Bool := do ok (x < 10#u32) /-- [hax_tests::specs::contracts::explicit_panic::post]: - Source: 'src/specs/contracts.rs', lines 65:0-65:32 -/ + Source: 'src/specs/contracts.rs', lines 73:0-73:32 -/ @[reducible] def specs.contracts.explicit_panic.post (x : Std.U32) (result : Std.U32) : RustM Bool := do @@ -215,7 +233,7 @@ def specs.contracts.explicit_panic.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::implies_cond::pre]: - Source: 'src/specs/contracts.rs', lines 74:0-74:37 -/ + Source: 'src/specs/contracts.rs', lines 82:0-82:37 -/ @[reducible] def specs.contracts.implies_cond.pre (x : Std.U32) (y : Std.U32) : RustM hax_lib.prop.Prop := do @@ -224,7 +242,7 @@ def specs.contracts.implies_cond.pre hax_lib.prop.Prop.Insts.CoreConvertFromBool) (x >= 10#u32) (y = 0#u32) /-- [hax_tests::specs::contracts::implies_cond::post]: - Source: 'src/specs/contracts.rs', lines 75:0-75:50 -/ + Source: 'src/specs/contracts.rs', lines 83:0-83:50 -/ @[reducible] def specs.contracts.implies_cond.post (x : Std.U32) (y : Std.U32) (result : Std.U32) : @@ -242,22 +260,22 @@ def specs.contracts.implies_cond.spec (x : Std.U32) (y : Std.U32) : Prop := /-- [hax_tests::specs::contracts::quantifiers::pre]: - Source: 'src/specs/contracts.rs', lines 85:0-85:53 -/ + Source: 'src/specs/contracts.rs', lines 93:0-93:53 -/ @[reducible] def specs.contracts.quantifiers.pre (x : Std.U32) : RustM hax_lib.prop.Prop := do hax_lib.prop.forall (core.convert.Into.Blanket (core.convert.From.Blanket hax_lib.prop.Prop)) - specs.contracts.__18.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop x + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop x /-- [hax_tests::specs::contracts::quantifiers::post]: - Source: 'src/specs/contracts.rs', lines 86:0-86:49 -/ + Source: 'src/specs/contracts.rs', lines 94:0-94:49 -/ @[reducible] def specs.contracts.quantifiers.post (x : Std.U32) (result : Std.U32) : RustM hax_lib.prop.Prop := do hax_lib.prop.exists (core.convert.Into.Blanket hax_lib.prop.Prop.Insts.CoreConvertFromBool) - specs.contracts.__19.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool result def specs.contracts.quantifiers.spec (x : Std.U32) : Prop := @@ -268,7 +286,7 @@ def specs.contracts.quantifiers.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::int_bounds::pre]: - Source: 'src/specs/contracts.rs', lines 93:0-93:57 -/ + Source: 'src/specs/contracts.rs', lines 101:0-101:57 -/ @[reducible] def specs.contracts.int_bounds.pre (x : Std.U32) (y : Std.U32) : RustM Bool := do @@ -280,7 +298,7 @@ def specs.contracts.int_bounds.pre i3 /-- [hax_tests::specs::contracts::int_bounds::post]: - Source: 'src/specs/contracts.rs', lines 94:0-94:63 -/ + Source: 'src/specs/contracts.rs', lines 102:0-102:63 -/ @[reducible] def specs.contracts.int_bounds.post (x : Std.U32) (y : Std.U32) (result : Std.U32) : RustM Bool := do @@ -298,13 +316,13 @@ def specs.contracts.int_bounds.spec (x : Std.U32) (y : Std.U32) : Prop := /-- [hax_tests::specs::contracts::helper_in_requires::pre]: - Source: 'src/specs/contracts.rs', lines 104:0-104:24 -/ + Source: 'src/specs/contracts.rs', lines 112:0-112:24 -/ @[reducible] def specs.contracts.helper_in_requires.pre (x : Std.U32) : RustM Bool := do specs.contracts.is_small x /-- [hax_tests::specs::contracts::helper_in_requires::post]: - Source: 'src/specs/contracts.rs', lines 105:0-105:36 -/ + Source: 'src/specs/contracts.rs', lines 113:0-113:36 -/ @[reducible] def specs.contracts.helper_in_requires.post (x : Std.U32) (result : Std.U32) : RustM Bool := do @@ -320,13 +338,13 @@ def specs.contracts.helper_in_requires.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::calls_contracted::pre]: - Source: 'src/specs/contracts.rs', lines 111:0-111:19 -/ + Source: 'src/specs/contracts.rs', lines 119:0-119:19 -/ @[reducible] def specs.contracts.calls_contracted.pre (x : Std.U32) : RustM Bool := do ok (x < 10#u32) /-- [hax_tests::specs::contracts::calls_contracted::post]: - Source: 'src/specs/contracts.rs', lines 112:0-112:42 -/ + Source: 'src/specs/contracts.rs', lines 120:0-120:42 -/ @[reducible] def specs.contracts.calls_contracted.post (x : Std.U32) (result : Std.U32) : RustM Bool := do @@ -343,13 +361,13 @@ def specs.contracts.calls_contracted.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::contracts::recursive::pre]: - Source: 'src/specs/contracts.rs', lines 118:0-118:20 -/ + Source: 'src/specs/contracts.rs', lines 126:0-126:20 -/ @[reducible] def specs.contracts.recursive.pre (n : Std.U32) : RustM Bool := do ok (n < 100#u32) /-- [hax_tests::specs::contracts::recursive::post]: - Source: 'src/specs/contracts.rs', lines 119:0-119:32 -/ + Source: 'src/specs/contracts.rs', lines 127:0-127:32 -/ @[reducible] def specs.contracts.recursive.post (n : Std.U32) (result : Std.U32) : RustM Bool := do @@ -363,13 +381,13 @@ def specs.contracts.recursive.spec (n : Std.U32) : Prop := /-- [hax_tests::specs::contracts::with_loop::pre]: - Source: 'src/specs/contracts.rs', lines 130:0-130:20 -/ + Source: 'src/specs/contracts.rs', lines 138:0-138:20 -/ @[reducible] def specs.contracts.with_loop.pre (n : Std.U32) : RustM Bool := do ok (n < 100#u32) /-- [hax_tests::specs::contracts::with_loop::post]: - Source: 'src/specs/contracts.rs', lines 131:0-131:32 -/ + Source: 'src/specs/contracts.rs', lines 139:0-139:32 -/ @[reducible] def specs.contracts.with_loop.post (n : Std.U32) (result : Std.U32) : RustM Bool := do @@ -548,8 +566,32 @@ def specs.mutable_borrows.swap_and_add.spec (x : Std.U32) (y : Std.U32) ⌜ (specs.mutable_borrows.swap_and_add.post x y res).holds ⌝ ⦄ +/-- [hax_tests::specs::mutable_borrows::incr_ret::pre]: + Source: 'src/specs/mutable_borrows.rs', lines 31:0-31:21 -/ +@[reducible] +def specs.mutable_borrows.incr_ret.pre (x : Std.U8) : RustM Bool := do + ok (x < 100#u8) + +/-- [hax_tests::specs::mutable_borrows::incr_ret::post]: + Source: 'src/specs/mutable_borrows.rs', lines 32:0-32:46 -/ +@[reducible] +def specs.mutable_borrows.incr_ret.post + (x : Std.U8) (p : (Std.U32 × Std.U8)) : RustM Bool := do + let (r, x_future) := p + let i ← x + 1#u8 + if x_future = i + then ok (r = 7#u32) + else ok false + +def specs.mutable_borrows.incr_ret.spec (x : Std.U8) : Prop := + (specs.mutable_borrows.incr_ret.pre x).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.mutable_borrows.incr_ret x + ⦃ ⇓ res => ⌜ (specs.mutable_borrows.incr_ret.post x res).holds ⌝ ⦄ + + /-- [hax_tests::specs::mutable_borrows::read_shared::post]: - Source: 'src/specs/mutable_borrows.rs', lines 30:0-30:33 -/ + Source: 'src/specs/mutable_borrows.rs', lines 39:0-39:33 -/ @[reducible] def specs.mutable_borrows.read_shared.post (x : Std.U32) (result : Std.U32) : RustM Bool := do @@ -563,7 +605,7 @@ def specs.mutable_borrows.read_shared.spec (x : Std.U32) : Prop := /-- [hax_tests::specs::mutable_borrows::add_assign::pre]: - Source: 'src/specs/mutable_borrows.rs', lines 36:0-36:35 -/ + Source: 'src/specs/mutable_borrows.rs', lines 45:0-45:35 -/ @[reducible] def specs.mutable_borrows.add_assign.pre (x : Std.U32) (y : Std.U32) : RustM Bool := do @@ -572,7 +614,7 @@ def specs.mutable_borrows.add_assign.pre else ok false /-- [hax_tests::specs::mutable_borrows::add_assign::post]: - Source: 'src/specs/mutable_borrows.rs', lines 37:0-37:37 -/ + Source: 'src/specs/mutable_borrows.rs', lines 46:0-46:37 -/ @[reducible] def specs.mutable_borrows.add_assign.post (x : Std.U32) (y : Std.U32) (x_future : Std.U32) : RustM Bool := do @@ -817,14 +859,14 @@ def Tuple.Insts.Hax_testsSpecsArgumentsSize.len.spec (_ : Unit) : Prop := /-- [hax_tests::specs::mutable_borrows::{hax_tests::specs::mutable_borrows::Counter}::bump::pre]: - Source: 'src/specs/mutable_borrows.rs', lines 49:4-49:34 -/ + Source: 'src/specs/mutable_borrows.rs', lines 58:4-58:34 -/ @[reducible] def specs.mutable_borrows.Counter.bump.pre (self_ : specs.mutable_borrows.Counter) : RustM Bool := do ok (self_.count < 1000#u32) /-- [hax_tests::specs::mutable_borrows::{hax_tests::specs::mutable_borrows::Counter}::bump::post]: - Source: 'src/specs/mutable_borrows.rs', lines 50:4-50:56 -/ + Source: 'src/specs/mutable_borrows.rs', lines 59:4-59:56 -/ @[reducible] def specs.mutable_borrows.Counter.bump.post (self_ : specs.mutable_borrows.Counter) @@ -914,4 +956,315 @@ def specs.generics.MyStruct.get.spec {N : Std.Usize} specs.generics.MyStruct.get self ⦃ ⇓ res => ⌜ (specs.generics.MyStruct.get.post self res).holds ⌝ ⦄ + +/-- [hax_tests::specs::traits::basic::g::post]: + Source: 'src/specs/traits/basic.rs', lines 58:0-58:27 -/ +@[reducible] +def specs.traits.basic.g.post + {T : Type} (FooInst : specs.traits.basic.Foo T) (x : T) (res : Std.U64) : + RustM Bool + := do + ok (res <= 10#u64) + +def specs.traits.basic.g.spec {T : Type} (FooInst : specs.traits.basic.Foo T) + (x : T) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.basic.g FooInst x + ⦃ ⇓ res => ⌜ (specs.traits.basic.g.post FooInst x res).holds ⌝ ⦄ + + +/-- [hax_tests::specs::traits::basic::h::post]: + Source: 'src/specs/traits/basic.rs', lines 68:0-68:27 -/ +@[reducible] +def specs.traits.basic.h.post (x : Std.U64) (res : Std.U64) : RustM Bool := do + ok (res <= 10#u64) + +def specs.traits.basic.h.spec (x : Std.U64) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.basic.h x + ⦃ ⇓ res => ⌜ (specs.traits.basic.h.post x res).holds ⌝ ⦄ + + +/-- [hax_tests::specs::traits::supertraits::via_b::pre]: + Source: 'src/specs/traits/supertraits.rs', lines 46:0-46:24 -/ +@[reducible] +def specs.traits.supertraits.via_b.pre + {T : Type} (BInst : specs.traits.supertraits.B T) (x : T) : RustM Bool := do + let i ← BInst.AInst.a x + ok (i < 100#usize) + +/-- [hax_tests::specs::traits::supertraits::via_b::post]: + Source: 'src/specs/traits/supertraits.rs', lines 47:0-47:26 -/ +@[reducible] +def specs.traits.supertraits.via_b.post + {T : Type} (BInst : specs.traits.supertraits.B T) (x : T) (res : Std.Usize) : + RustM Bool + := do + ok (res >= 1#usize) + +def + specs.traits.supertraits.via_b.spec {T : Type} (BInst : + specs.traits.supertraits.B T) (x : T) + : Prop := + (specs.traits.supertraits.via_b.pre BInst x).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.traits.supertraits.via_b BInst x + ⦃ ⇓ res => + ⌜ (specs.traits.supertraits.via_b.post BInst x res).holds ⌝ ⦄ + + +/-- [hax_tests::specs::traits::supertraits::via_u8::pre]: + Source: 'src/specs/traits/supertraits.rs', lines 54:0-54:24 -/ +@[reducible] +def specs.traits.supertraits.via_u8.pre (x : Std.U8) : RustM Bool := do + let i ← U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a x + ok (i < 100#usize) + +/-- [hax_tests::specs::traits::supertraits::via_u8::post]: + Source: 'src/specs/traits/supertraits.rs', lines 55:0-55:26 -/ +@[reducible] +def specs.traits.supertraits.via_u8.post + (x : Std.U8) (res : Std.Usize) : RustM Bool := do + ok (res >= 1#usize) + +def specs.traits.supertraits.via_u8.spec (x : Std.U8) : Prop := + (specs.traits.supertraits.via_u8.pre x).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.traits.supertraits.via_u8 x + ⦃ ⇓ res => ⌜ (specs.traits.supertraits.via_u8.post x res).holds ⌝ ⦄ + + +/-- [hax_tests::specs::traits::diamond::via_b::post]: + Source: 'src/specs/traits/diamond.rs', lines 39:0-39:40 -/ +@[reducible] +def specs.traits.diamond.via_b.post + {T : Type} (BInst : specs.traits.diamond.B T) (x : T) (res : Std.Usize) : + RustM Bool + := do + if res >= 1#usize + then ok (res <= 100#usize) + else ok false + +def + specs.traits.diamond.via_b.spec {T : Type} (BInst : specs.traits.diamond.B T) + (x : T) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.diamond.via_b BInst x + ⦃ ⇓ res => ⌜ (specs.traits.diamond.via_b.post BInst x res).holds ⌝ + ⦄ + + +/-- [hax_tests::specs::traits::diamond::diamond::post]: + Source: 'src/specs/traits/diamond.rs', lines 46:0-46:26 -/ +@[reducible] +def specs.traits.diamond.diamond.post + {T : Type} (CInst : specs.traits.diamond.C T) (x : T) (res : Std.Usize) : + RustM Bool + := do + ok (res >= 2#usize) + +def + specs.traits.diamond.diamond.spec {T : Type} (CInst : specs.traits.diamond.C + T) (x : T) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.diamond.diamond CInst x + ⦃ ⇓ res => ⌜ (specs.traits.diamond.diamond.post CInst x res).holds ⌝ + ⦄ + + +/-- [hax_tests::specs::traits::generic_impl::k::post]: + Source: 'src/specs/traits/generic_impl.rs', lines 62:0-62:27 -/ +@[reducible] +def specs.traits.generic_impl.k.post + {T : Type} {U : Type} (FooInst : specs.traits.generic_impl.Foo T) (SubInst : + specs.traits.generic_impl.Sub U) (x : T) (y : U) (res : Std.U64) : + RustM Bool + := do + ok (res <= 20#u64) + +def + specs.traits.generic_impl.k.spec {T : Type} {U : Type} (FooInst : + specs.traits.generic_impl.Foo T) (SubInst : + specs.traits.generic_impl.Sub U) (x : T) + (y : U) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.generic_impl.k FooInst SubInst x y + ⦃ ⇓ res => + ⌜ (specs.traits.generic_impl.k.post FooInst SubInst x y res).holds ⌝ ⦄ + + +/-- [hax_tests::specs::traits::blanket_impl::show_generic::post]: + Source: 'src/specs/traits/blanket_impl.rs', lines 22:0-22:27 -/ +@[reducible] +def specs.traits.blanket_impl.show_generic.post + {T : Type} (x : T) (res : Std.U64) : RustM Bool := do + ok (res <= 20#u64) + +def specs.traits.blanket_impl.show_generic.spec {T : Type} (x : T) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.blanket_impl.show_generic x + ⦃ ⇓ res => + ⌜ (specs.traits.blanket_impl.show_generic.post x res).holds ⌝ ⦄ + + +/-- [hax_tests::specs::traits::blanket_impl::show_u64::post]: + Source: 'src/specs/traits/blanket_impl.rs', lines 28:0-28:27 -/ +@[reducible] +def specs.traits.blanket_impl.show_u64.post + (x : Std.U64) (res : Std.U64) : RustM Bool := do + ok (res <= 20#u64) + +def specs.traits.blanket_impl.show_u64.spec (x : Std.U64) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.blanket_impl.show_u64 x + ⦃ ⇓ res => ⌜ (specs.traits.blanket_impl.show_u64.post x res).holds ⌝ + ⦄ + + +/-- [hax_tests::specs::traits::assoc_type_bounds::first_bar::post]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 50:0-50:26 -/ +@[reducible] +def specs.traits.assoc_type_bounds.first_bar.post + {C : Type} {Clause0_Item : Type} (ContainerInst : + specs.traits.assoc_type_bounds.Container C Clause0_Item) (c : C) + (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + +def + specs.traits.assoc_type_bounds.first_bar.spec {C : Type} {Clause0_Item : + Type} (ContainerInst : + specs.traits.assoc_type_bounds.Container + C Clause0_Item) (c : C) + : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.assoc_type_bounds.first_bar ContainerInst c + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_type_bounds.first_bar.post ContainerInst c res).holds + ⌝ ⦄ + + +/-- [hax_tests::specs::traits::builtin_bound::dup::post]: + Source: 'src/specs/traits/builtin_bound.rs', lines 11:0-11:20 -/ +@[reducible] +def specs.traits.builtin_bound.dup.post + {T : Type} (corecloneCloneInst : core.clone.Clone T) (x : T) (p : (T × T)) : + RustM Bool + := do + ok true + +def + specs.traits.builtin_bound.dup.spec {T : Type} (corecloneCloneInst : + core.clone.Clone T) (x : T) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.builtin_bound.dup corecloneCloneInst x + ⦃ ⇓ res => + ⌜ (specs.traits.builtin_bound.dup.post corecloneCloneInst x res).holds ⌝ + ⦄ + + +/-- [hax_tests::specs::traits::trait_generics::use_conv::post]: + Source: 'src/specs/traits/trait_generics.rs', lines 17:0-17:26 -/ +@[reducible] +def specs.traits.trait_generics.use_conv.post + {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv C Std.U8) + (c : C) (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + +def + specs.traits.trait_generics.use_conv.spec {C : Type} (ConvCU8Inst : + specs.traits.trait_generics.Conv C + Std.U8) (c : C) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.trait_generics.use_conv ConvCU8Inst c + ⦃ ⇓ res => + ⌜ (specs.traits.trait_generics.use_conv.post ConvCU8Inst c res).holds ⌝ + ⦄ + + +/-- [hax_tests::specs::traits::default_methods::D::next::pre]: + Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.default_methods.D.next.pre + {Self_ : Type} (DInst : specs.traits.default_methods.D Self_) (self_ : Self_) + : + RustM Bool + := do + let i ← DInst.base self_ + ok (i < 100#u32) + +/-- [hax_tests::specs::traits::default_methods::D::next::post]: + Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.default_methods.D.next.post + {Self_ : Type} (DInst : specs.traits.default_methods.D Self_) (self_ : Self_) + (res : Std.U32) : + RustM Bool + := do + let i ← DInst.base self_ + ok (res > i) + +def + specs.traits.default_methods.D.next.default.spec {Self : Type} (DInst : + specs.traits.default_methods.D + Self) (self : Self) : Prop := + (specs.traits.default_methods.D.next.pre DInst self).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.traits.default_methods.D.next.default DInst self + ⦃ ⇓ res => + ⌜ (specs.traits.default_methods.D.next.post DInst self res).holds ⌝ ⦄ + + +/-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f::pre]: + Source: 'src/specs/traits/impl_contract.rs', lines 14:4-14:28 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.pre + (self_ : Std.U32) : RustM Bool := do + ok (self_ < 100#u32) + +/-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f::post]: + Source: 'src/specs/traits/impl_contract.rs', lines 15:4-15:38 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.post + (self_ : Std.U32) (res : Std.U32) : RustM Bool := do + let i ← self_ + 1#u32 + ok (res = i) + +def U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec (self : Std.U32) + : Prop := + (U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.pre self).holds → + ⦃ ⌜ True ⌝ ⦄ + U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f self + ⦃ ⇓ res => + ⌜ (U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.post self res).holds + ⌝ ⦄ + + +/-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::G for u32}::g::pre]: + Source: 'src/specs/traits/impl_contract.rs', lines 29:4-29:27 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.pre + (self_ : Std.U32) : RustM Bool := do + ok (self_ < 10#u32) + +/-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::G for u32}::g::post]: + Source: 'src/specs/traits/impl_contract.rs', lines 30:4-30:38 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.post + (self_ : Std.U32) (res : Std.U32) : RustM Bool := do + let i ← self_ + 1#u32 + ok (res = i) + +def U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec (self : Std.U32) + : Prop := + (U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.pre self).holds → + ⦃ ⌜ True ⌝ ⦄ + U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g self + ⦃ ⇓ res => + ⌜ (U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.post self res).holds ⌝ + ⦄ + end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index 820f06b7a2..37b923bc1a 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -42,15 +42,15 @@ inductive specs.arguments.Shape where | Dot : specs.arguments.Shape | Line : Std.U32 → specs.arguments.Shape -/-- [hax_tests::specs::contracts::_#18::requires::closure] - Source: 'src/specs/contracts.rs', lines 85:18-85:50 -/ +/-- [hax_tests::specs::contracts::_#20::requires::closure] + Source: 'src/specs/contracts.rs', lines 93:18-93:50 -/ @[reducible] -def specs.contracts.__18.requires.closure := Std.U32 +def specs.contracts.__20.requires.closure := Std.U32 -/-- [hax_tests::specs::contracts::_#19::ensures::closure] - Source: 'src/specs/contracts.rs', lines 86:26-86:46 -/ +/-- [hax_tests::specs::contracts::_#21::ensures::closure] + Source: 'src/specs/contracts.rs', lines 94:26-94:46 -/ @[reducible] -def specs.contracts.__19.ensures.closure := Std.U32 +def specs.contracts.__21.ensures.closure := Std.U32 /-- Trait declaration: [hax_tests::specs::generics::Val] Source: 'src/specs/generics.rs', lines 16:0-18:1 -/ @@ -80,9 +80,177 @@ structure specs.generics.Pair (T : Type) (N : Std.Usize) where fst : T /-- [hax_tests::specs::mutable_borrows::Counter] - Source: 'src/specs/mutable_borrows.rs', lines 42:0-44:1 + Source: 'src/specs/mutable_borrows.rs', lines 51:0-53:1 Visibility: public -/ structure specs.mutable_borrows.Counter where count : Std.U32 +/-- Trait declaration: [hax_tests::specs::traits::assoc_type_bounds::Bar] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 9:0-12:1 -/ +structure specs.traits.assoc_type_bounds.Bar (Self : Type) where + bar : Self → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::assoc_type_bounds::Container] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 15:0-20:1 -/ +structure specs.traits.assoc_type_bounds.Container (Self : Type) (Self_Item : + Type) where + BarInst : specs.traits.assoc_type_bounds.Bar Self_Item + first : Self → RustM Self_Item + +/-- [hax_tests::specs::traits::assoc_type_bounds::One] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 22:0-24:1 -/ +structure specs.traits.assoc_type_bounds.One where + x : Std.U32 + +/-- [hax_tests::specs::traits::assoc_type_bounds::Box1] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 40:0-40:18 -/ +@[reducible] +def specs.traits.assoc_type_bounds.Box1 (T : Type) := T + +/-- Trait declaration: [hax_tests::specs::traits::basic::Foo] + Source: 'src/specs/traits/basic.rs', lines 7:0-20:1 -/ +structure specs.traits.basic.Foo (Self : Type) where + f1 : Self → RustM Bool + f2 : Self → RustM Std.U64 + make : Std.U32 → RustM Self + zero : RustM Self + +/-- Trait declaration: [hax_tests::specs::traits::blanket_impl::Show] + Source: 'src/specs/traits/blanket_impl.rs', lines 10:0-13:1 -/ +structure specs.traits.blanket_impl.Show (Self : Type) where + «show» : Self → RustM Std.U64 + +/-- Trait declaration: [hax_tests::specs::traits::blanket_impl::Tag] + Source: 'src/specs/traits/blanket_impl.rs', lines 33:0-33:18 -/ +structure specs.traits.blanket_impl.Tag (Self : Type) where + ShowInst : specs.traits.blanket_impl.Show Self + +/-- Trait declaration: [hax_tests::specs::traits::builtin_bound::Dup] + Source: 'src/specs/traits/builtin_bound.rs', lines 17:0-20:1 -/ +structure specs.traits.builtin_bound.Dup (Self : Type) where + corecloneCloneInst : core.clone.Clone Self + dup : Self → RustM (Self × Self) + +/-- [hax_tests::specs::traits::builtin_bound::One] + Source: 'src/specs/traits/builtin_bound.rs', lines 29:0-29:11 -/ +@[reducible] +def specs.traits.builtin_bound.One := Unit + +/-- [hax_tests::specs::traits::builtin_bound::W] + Source: 'src/specs/traits/builtin_bound.rs', lines 44:0-46:1 -/ +structure specs.traits.builtin_bound.W (T : Type) where + x : T + +/-- Trait declaration: [hax_tests::specs::traits::default_methods::D] + Source: 'src/specs/traits/default_methods.rs', lines 7:0-15:1 -/ +structure specs.traits.default_methods.D (Self : Type) where + base : Self → RustM Std.U32 + next : Self → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::diamond::A] + Source: 'src/specs/traits/diamond.rs', lines 6:0-9:1 -/ +structure specs.traits.diamond.A (Self : Type) where + a : Self → RustM Std.Usize + +/-- Trait declaration: [hax_tests::specs::traits::diamond::B] + Source: 'src/specs/traits/diamond.rs', lines 11:0-13:1 -/ +structure specs.traits.diamond.B (Self : Type) where + AInst : specs.traits.diamond.A Self + b : Self → RustM Std.Usize + +/-- Trait declaration: [hax_tests::specs::traits::diamond::C] + Source: 'src/specs/traits/diamond.rs', lines 16:0-19:1 -/ +structure specs.traits.diamond.C (Self : Type) where + AInst : specs.traits.diamond.A Self + BInst : specs.traits.diamond.B Self + c : Self → RustM Std.Usize + +/-- Trait declaration: [hax_tests::specs::traits::generic_impl::Foo] + Source: 'src/specs/traits/generic_impl.rs', lines 9:0-12:1 -/ +structure specs.traits.generic_impl.Foo (Self : Type) where + f : Self → RustM Std.U64 + +/-- Trait declaration: [hax_tests::specs::traits::generic_impl::Sub] + Source: 'src/specs/traits/generic_impl.rs', lines 15:0-18:1 -/ +structure specs.traits.generic_impl.Sub (Self : Type) where + FooInst : specs.traits.generic_impl.Foo Self + s : Self → RustM Std.U64 + +/-- [hax_tests::specs::traits::generic_impl::Wrapper] + Source: 'src/specs/traits/generic_impl.rs', lines 20:0-22:1 -/ +structure specs.traits.generic_impl.Wrapper (T : Type) where + inner : T + +/-- [hax_tests::specs::traits::generic_impl::Single] + Source: 'src/specs/traits/generic_impl.rs', lines 48:0-48:20 -/ +@[reducible] +def specs.traits.generic_impl.Single (T : Type) := T + +/-- Trait declaration: [hax_tests::specs::traits::impl_contract::Foo] + Source: 'src/specs/traits/impl_contract.rs', lines 8:0-10:1 -/ +structure specs.traits.impl_contract.Foo (Self : Type) where + f : Self → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::impl_contract::G] + Source: 'src/specs/traits/impl_contract.rs', lines 22:0-25:1 -/ +structure specs.traits.impl_contract.G (Self : Type) where + g : Self → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::method_generics::Bar] + Source: 'src/specs/traits/method_generics.rs', lines 6:0-9:1 -/ +structure specs.traits.method_generics.Bar (Self : Type) where + bar : Self → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::method_generics::Foo] + Source: 'src/specs/traits/method_generics.rs', lines 12:0-16:1 -/ +structure specs.traits.method_generics.Foo (Self : Type) where + f : forall {U : Type} (BarInst : specs.traits.method_generics.Bar U), Self + → U → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::minimal::Foo] + Source: 'src/specs/traits/minimal.rs', lines 7:0-16:1 -/ +structure specs.traits.minimal.Foo (Self : Type) where + f : Self → Std.U32 → RustM Std.U32 + g : Self → RustM Std.U32 + h : Self → Std.U32 → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::mut_self::Counter] + Source: 'src/specs/traits/mut_self.rs', lines 6:0-12:1 -/ +structure specs.traits.mut_self.Counter (Self : Type) where + get : Self → RustM Std.U32 + incr : Self → RustM Self + +/-- Trait declaration: [hax_tests::specs::traits::supertraits::A] + Source: 'src/specs/traits/supertraits.rs', lines 7:0-10:1 -/ +structure specs.traits.supertraits.A (Self : Type) where + a : Self → RustM Std.Usize + +/-- Trait declaration: [hax_tests::specs::traits::supertraits::B] + Source: 'src/specs/traits/supertraits.rs', lines 13:0-17:1 -/ +structure specs.traits.supertraits.B (Self : Type) where + AInst : specs.traits.supertraits.A Self + b : Self → RustM Std.Usize + +/-- Trait declaration: [hax_tests::specs::traits::supertraits::Cc] + Source: 'src/specs/traits/supertraits.rs', lines 20:0-23:1 -/ +structure specs.traits.supertraits.Cc (Self : Type) where + BInst : specs.traits.supertraits.B Self + c : Self → RustM Std.Usize + +/-- Trait declaration: [hax_tests::specs::traits::trait_generics::Conv] + Source: 'src/specs/traits/trait_generics.rs', lines 6:0-9:1 -/ +structure specs.traits.trait_generics.Conv (Self : Type) (T : Type) where + conv : Self → T → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::unannotated_sub::A] + Source: 'src/specs/traits/unannotated_sub.rs', lines 7:0-10:1 -/ +structure specs.traits.unannotated_sub.A (Self : Type) where + a : Self → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::unannotated_sub::B] + Source: 'src/specs/traits/unannotated_sub.rs', lines 12:0-14:1 -/ +structure specs.traits.unannotated_sub.B (Self : Type) where + AInst : specs.traits.unannotated_sub.A Self + b : Self → RustM Std.U32 + end hax_tests diff --git a/tests/hax/src/specs/contracts.rs b/tests/hax/src/specs/contracts.rs index 9e99ecd7dc..6f84741365 100644 --- a/tests/hax/src/specs/contracts.rs +++ b/tests/hax/src/specs/contracts.rs @@ -28,6 +28,14 @@ fn no_args() { () } +// No arguments, non-unit return (the `requires(true)` also covers a +// precondition with no argument) +#[requires(true)] +#[ensures(|r| r == 0)] +fn zero_ret() -> u32 { + 0 +} + // Block expression (with a `let`) inside `requires` #[requires({ let bound = x; bound > 10 })] fn block_in_requires(x: u32) -> u32 { diff --git a/tests/hax/src/specs/mutable_borrows.rs b/tests/hax/src/specs/mutable_borrows.rs index 83d64adff7..96656f7e6d 100644 --- a/tests/hax/src/specs/mutable_borrows.rs +++ b/tests/hax/src/specs/mutable_borrows.rs @@ -26,6 +26,15 @@ fn swap_and_add(x: &mut u32, y: &mut u32) -> u32 { tmp_x + tmp_y } +// The result and the future value have different types: a wrong order +// of the `post` inputs doesn't typecheck. +#[requires(*x < 100)] +#[ensures(|r| *future(x) == *x + 1 && r == 7)] +fn incr_ret(x: &mut u8) -> u32 { + *x += 1; + 7 +} + // A shared borrow, read in the postcondition #[ensures(|result| result == *x)] fn read_shared(x: &u32) -> u32 { diff --git a/tests/hax/src/specs/traits.rs b/tests/hax/src/specs/traits.rs index 3d10ffa278..b19a3f0671 100644 --- a/tests/hax/src/specs/traits.rs +++ b/tests/hax/src/specs/traits.rs @@ -1 +1,15 @@ -// To be filled +// Trait-level specs: contracts on trait methods, and their impls. +mod minimal; +mod basic; +mod supertraits; +mod diamond; +mod generic_impl; +mod blanket_impl; +mod method_generics; +mod mut_self; +mod assoc_type_bounds; +mod default_methods; +mod builtin_bound; +mod unannotated_sub; +mod impl_contract; +mod trait_generics; diff --git a/tests/hax/src/specs/traits/assoc_type_bounds.rs b/tests/hax/src/specs/traits/assoc_type_bounds.rs new file mode 100644 index 0000000000..9ffd7c3d02 --- /dev/null +++ b/tests/hax/src/specs/traits/assoc_type_bounds.rs @@ -0,0 +1,53 @@ +// An associated type with a (non-recursive) trait bound. `first_bar` has a +// generic binder on the trait with the associated type; `Box1`'s generic +// impl sets the associated type to its parameter, whose bound is a clause. +// Its other clause, `T: Copy`, is a marker trait: no Lawful binder ([P17] 3). + +use hax_lib::*; + +#[hax_lib::attributes] +trait Bar { + #[ensures(|res| res < 10)] + fn bar(&self) -> u32; +} + +#[hax_lib::attributes] +trait Container { + type Item: Bar; + + #[ensures(|item| item.bar() < 10)] + fn first(&self) -> Self::Item; +} + +struct One { + x: u32, +} + +impl Bar for u32 { + fn bar(&self) -> u32 { + 0 + } +} + +impl Container for One { + type Item = u32; + + fn first(&self) -> u32 { + self.x + } +} + +struct Box1(T); + +impl Container for Box1 { + type Item = T; + + fn first(&self) -> T { + self.0 + } +} + +#[ensures(|res| res < 10)] +fn first_bar(c: &C) -> u32 { + c.first().bar() +} diff --git a/tests/hax/src/specs/traits/basic.rs b/tests/hax/src/specs/traits/basic.rs new file mode 100644 index 0000000000..461e27c552 --- /dev/null +++ b/tests/hax/src/specs/traits/basic.rs @@ -0,0 +1,71 @@ +// A trait, two impls, a generic caller and a concrete caller. `make` and +// `zero` are associated fns without `self` (`zero` is nullary). + +use hax_lib::*; + +#[hax_lib::attributes] +trait Foo { + #[ensures(|_| true)] + fn f1(&self) -> bool; + + #[requires(self.f1())] + #[ensures(|res| res <= 10)] + fn f2(&self) -> u64; + + #[ensures(|res| res.f1())] + fn make(x: u32) -> Self; + + #[ensures(|res| res.f1())] + fn zero() -> Self; +} + +impl Foo for u64 { + fn f1(&self) -> bool { + *self <= 10 + } + + fn f2(&self) -> u64 { + *self + } + + fn make(x: u32) -> u64 { + (x % 10) as u64 + } + + fn zero() -> u64 { + 0 + } +} + +impl Foo for u32 { + fn f1(&self) -> bool { + *self <= 10 + } + + fn f2(&self) -> u64 { + *self as u64 + } + + fn make(x: u32) -> u32 { + x % 10 + } + + fn zero() -> u32 { + 0 + } +} + +#[ensures(|res| res <= 10)] +fn g(x: T) -> u64 { + if x.f1() { + x.f2() + } else { + 0 + } +} + +// Concrete caller. +#[ensures(|res| res <= 10)] +fn h(x: u64) -> u64 { + g(x) +} diff --git a/tests/hax/src/specs/traits/blanket_impl.rs b/tests/hax/src/specs/traits/blanket_impl.rs new file mode 100644 index 0000000000..8df2e240ca --- /dev/null +++ b/tests/hax/src/specs/traits/blanket_impl.rs @@ -0,0 +1,35 @@ +// A blanket impl: `Show` for every type `T`, without any bound. Its Lawful +// obligation is generic over `T` and takes no Lawful binder (no impl clause); +// callers reach `Show` through the blanket impl applied to their own type. +// `Tag: Show` has a blanket impl with a clause: its `Show` parent is that +// clause. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Show { + #[ensures(|res| res <= 20)] + fn show(&self) -> u64; +} + +impl Show for T { + fn show(&self) -> u64 { + 7 + } +} + +// Generic caller: `Show` comes from the blanket impl at `T` (no clause). +#[ensures(|res| res <= 20)] +fn show_generic(x: &T) -> u64 { + x.show() +} + +// Concrete caller: `Show` comes from the blanket impl at `u64`. +#[ensures(|res| res <= 20)] +fn show_u64(x: u64) -> u64 { + x.show() +} + +trait Tag: Show {} + +impl Tag for T {} diff --git a/tests/hax/src/specs/traits/builtin_bound.rs b/tests/hax/src/specs/traits/builtin_bound.rs new file mode 100644 index 0000000000..a0cc544092 --- /dev/null +++ b/tests/hax/src/specs/traits/builtin_bound.rs @@ -0,0 +1,52 @@ +// A generic function bounded by a built-in trait, and a trait with a +// built-in supertrait. Local impls of foreign traits: derived `Clone` on a +// non-generic and on a generic struct, hand-written `Default`; the derived +// ones are the `Clone` parents of `Dup` impls. No `BuiltinOrAuto` parent +// ([P17] 1): built-in `Clone`/`Copy` refs (e.g. `Dup for (u32, u32)`) print +// `BuiltinClone`, which is not CoreModels' `Clone`; `Fn*` refs are not +// reachable (closures and fn items get impls, fn pointers are unsupported). + +use hax_lib::*; + +#[ensures(|_| true)] +fn dup(x: &T) -> (T, T) { + (x.clone(), x.clone()) +} + +#[hax_lib::attributes] +trait Dup: Clone { + #[ensures(|_| true)] + fn dup(&self) -> (Self, Self); +} + +impl Dup for u32 { + fn dup(&self) -> (u32, u32) { + (*self, *self) + } +} + +#[derive(Clone)] +struct One; + +impl Default for One { + fn default() -> Self { + One + } +} + +impl Dup for One { + fn dup(&self) -> (One, One) { + (self.clone(), self.clone()) + } +} + +#[derive(Clone)] +struct W { + x: T, +} + +impl Dup for W { + fn dup(&self) -> (W, W) { + (self.clone(), self.clone()) + } +} diff --git a/tests/hax/src/specs/traits/default_methods.rs b/tests/hax/src/specs/traits/default_methods.rs new file mode 100644 index 0000000000..e1ff7ce344 --- /dev/null +++ b/tests/hax/src/specs/traits/default_methods.rs @@ -0,0 +1,31 @@ +// An annotated provided method, overridden by one impl and not by the +// other. `base` is not annotated. + +use hax_lib::*; + +#[hax_lib::attributes] +trait D { + fn base(&self) -> u32; + + #[requires(self.base() < 100)] + #[ensures(|res| res > self.base())] + fn next(&self) -> u32 { + self.base() + 1 + } +} + +impl D for u32 { + fn base(&self) -> u32 { + *self + } + + fn next(&self) -> u32 { + *self + 2 + } +} + +impl D for u64 { + fn base(&self) -> u32 { + 0 + } +} diff --git a/tests/hax/src/specs/traits/diamond.rs b/tests/hax/src/specs/traits/diamond.rs new file mode 100644 index 0000000000..fb2f3d2428 --- /dev/null +++ b/tests/hax/src/specs/traits/diamond.rs @@ -0,0 +1,49 @@ +// `C: A + B` with `B: A`: `A` is reachable from `C` along two paths. + +use hax_lib::*; + +#[hax_lib::attributes] +trait A { + #[ensures(|res| res >= 1 && res <= 100)] + fn a(&self) -> usize; +} + +trait B: A { + fn b(&self) -> usize; +} + +#[hax_lib::attributes] +trait C: A + B { + #[ensures(|res| res == self.a())] + fn c(&self) -> usize; +} + +impl A for u8 { + fn a(&self) -> usize { + 1 + } +} + +impl B for u8 { + fn b(&self) -> usize { + 2 + } +} + +impl C for u8 { + fn c(&self) -> usize { + self.a() + } +} + +#[ensures(|res| res >= 1 && res <= 100)] +fn via_b(x: &T) -> usize { + x.a() +} + +// `x.a()` goes through `C`'s `A` clause, `via_b(x)` through `C`'s `B` +// clause and then `B`'s `A` clause. +#[ensures(|res| res >= 2)] +fn diamond(x: &T) -> usize { + x.a() + via_b(x) +} diff --git a/tests/hax/src/specs/traits/generic_impl.rs b/tests/hax/src/specs/traits/generic_impl.rs new file mode 100644 index 0000000000..cf44dc11ce --- /dev/null +++ b/tests/hax/src/specs/traits/generic_impl.rs @@ -0,0 +1,65 @@ +// Generic impls, including one of a subtrait whose parent impl is itself +// generic, one with two clauses (on a tuple), and a concrete impl whose +// parent impl is a generic impl applied to another impl (`Single`). +// `k` has two clauses on different traits. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Foo { + #[ensures(|res| res <= 10)] + fn f(&self) -> u64; +} + +#[hax_lib::attributes] +trait Sub: Foo { + #[ensures(|res| res == self.f())] + fn s(&self) -> u64; +} + +struct Wrapper { + inner: T, +} + +impl Foo for u64 { + fn f(&self) -> u64 { + 0 + } +} + +impl Foo for Wrapper { + fn f(&self) -> u64 { + self.inner.f() + } +} + +impl Sub for Wrapper { + fn s(&self) -> u64 { + self.inner.s() + } +} + +impl Foo for (T, U) { + fn f(&self) -> u64 { + self.0.f() + } +} + +struct Single(T); + +impl Foo for Single { + fn f(&self) -> u64 { + self.0.f() + } +} + +impl Sub for Single { + fn s(&self) -> u64 { + self.f() + } +} + +#[ensures(|res| res <= 20)] +fn k(x: &T, y: &U) -> u64 { + x.f() + y.s() +} diff --git a/tests/hax/src/specs/traits/impl_contract.rs b/tests/hax/src/specs/traits/impl_contract.rs new file mode 100644 index 0000000000..a0ac8af468 --- /dev/null +++ b/tests/hax/src/specs/traits/impl_contract.rs @@ -0,0 +1,34 @@ +// Impl-level contracts. On an unannotated trait (`Foo`): not supported +// yet, it emits a warning but still a standalone spec. On an annotated +// trait method (`G::g`): the trait-level contract gives the Lawful field, +// the impl-level one the warning and the standalone spec. + +use hax_lib::*; + +trait Foo { + fn f(&self) -> u32; +} + +#[hax_lib::attributes] +impl Foo for u32 { + #[requires(*self < 100)] + #[ensures(|res| res == *self + 1)] + fn f(&self) -> u32 { + *self + 1 + } +} + +#[hax_lib::attributes] +trait G { + #[ensures(|res| res > 0)] + fn g(&self) -> u32; +} + +#[hax_lib::attributes] +impl G for u32 { + #[requires(*self < 10)] + #[ensures(|res| res == *self + 1)] + fn g(&self) -> u32 { + *self % 10 + 1 + } +} diff --git a/tests/hax/src/specs/traits/method_generics.rs b/tests/hax/src/specs/traits/method_generics.rs new file mode 100644 index 0000000000..a1733e8030 --- /dev/null +++ b/tests/hax/src/specs/traits/method_generics.rs @@ -0,0 +1,28 @@ +// A trait method with its own generics and trait clause. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Bar { + #[ensures(|res| res < 10)] + fn bar(&self) -> u32; +} + +#[hax_lib::attributes] +trait Foo { + #[requires(u.bar() < 5)] + #[ensures(|res| res < 5)] + fn f(&self, u: &U) -> u32; +} + +impl Bar for u32 { + fn bar(&self) -> u32 { + 0 + } +} + +impl Foo for u32 { + fn f(&self, u: &U) -> u32 { + u.bar() + } +} diff --git a/tests/hax/src/specs/traits/minimal.rs b/tests/hax/src/specs/traits/minimal.rs new file mode 100644 index 0000000000..dd63bbc817 --- /dev/null +++ b/tests/hax/src/specs/traits/minimal.rs @@ -0,0 +1,16 @@ +// Just an annotated trait, no impl. `g` is not annotated, `h` only has a +// pre (its post defaults to `ok true`). + +use hax_lib::*; + +#[attributes] +trait Foo { + #[requires(x < 100)] + #[ensures(|res| res > x)] + fn f(&self, x: u32) -> u32; + + fn g(&self) -> u32; + + #[requires(x > 0)] + fn h(&self, x: u32) -> u32; +} diff --git a/tests/hax/src/specs/traits/mut_self.rs b/tests/hax/src/specs/traits/mut_self.rs new file mode 100644 index 0000000000..c644091c9b --- /dev/null +++ b/tests/hax/src/specs/traits/mut_self.rs @@ -0,0 +1,22 @@ +// An annotated `&mut self` method. `get` is not annotated. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Counter { + fn get(&self) -> u32; + + #[requires(self.get() < 100)] + #[ensures(|_| future(self).get() == self.get() + 1)] + fn incr(&mut self); +} + +impl Counter for u32 { + fn get(&self) -> u32 { + *self + } + + fn incr(&mut self) { + *self += 1 + } +} diff --git a/tests/hax/src/specs/traits/supertraits.rs b/tests/hax/src/specs/traits/supertraits.rs new file mode 100644 index 0000000000..c6017bc5b8 --- /dev/null +++ b/tests/hax/src/specs/traits/supertraits.rs @@ -0,0 +1,58 @@ +// `B: A`, both annotated. `B::b`'s contract reaches `A` through `self`. +// `Cc: B`: `Cc::c`'s contract reaches `A` through two parent projections. + +use hax_lib::*; + +#[hax_lib::attributes] +trait A { + #[ensures(|res| res >= 1)] + fn a(&self) -> usize; +} + +#[hax_lib::attributes] +trait B: A { + #[requires(self.a() < 100)] + #[ensures(|res| res > self.a())] + fn b(&self) -> usize; +} + +#[hax_lib::attributes] +trait Cc: B { + #[ensures(|res| res > self.a())] + fn c(&self) -> usize; +} + +impl A for u8 { + fn a(&self) -> usize { + 1 + } +} + +impl B for u8 { + fn b(&self) -> usize { + self.a() + 1 + } +} + +impl Cc for u8 { + fn c(&self) -> usize { + self.b() + } +} + +// Generic caller of both methods: `x.a()` goes through `B`'s `A` clause +// (`BInstLawful.AInstLawful.a_spec`), `x.b()` through `b_spec`, whose pre is +// this fn's pre. No underflow: `b`'s post says `x.b() > x.a()`. +#[requires(x.a() < 100)] +#[ensures(|res| res >= 1)] +fn via_b(x: &T) -> usize { + x.b() - x.a() +} + +// Concrete caller of both methods, on the `u8` impls (their `.Lawful` +// theorems). +#[requires(x.a() < 100)] +#[ensures(|res| res >= 1)] +fn via_u8(x: u8) -> usize { + x.b() - x.a() +} diff --git a/tests/hax/src/specs/traits/trait_generics.rs b/tests/hax/src/specs/traits/trait_generics.rs new file mode 100644 index 0000000000..5ad961c7c3 --- /dev/null +++ b/tests/hax/src/specs/traits/trait_generics.rs @@ -0,0 +1,20 @@ +// A trait with a generic parameter, a concrete impl and a generic caller. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Conv { + #[ensures(|res| res < 10)] + fn conv(&self, t: T) -> u32; +} + +impl Conv for u32 { + fn conv(&self, _t: u8) -> u32 { + 0 + } +} + +#[ensures(|res| res < 10)] +fn use_conv>(c: &C) -> u32 { + c.conv(0) +} diff --git a/tests/hax/src/specs/traits/unannotated_sub.rs b/tests/hax/src/specs/traits/unannotated_sub.rs new file mode 100644 index 0000000000..61642d12b1 --- /dev/null +++ b/tests/hax/src/specs/traits/unannotated_sub.rs @@ -0,0 +1,26 @@ +// A trait with no annotated method of its own, with an annotated +// supertrait: its `Lawful` only has the parent field. + +use hax_lib::*; + +#[hax_lib::attributes] +trait A { + #[ensures(|res| res > 0)] + fn a(&self) -> u32; +} + +trait B: A { + fn b(&self) -> u32; +} + +impl A for u32 { + fn a(&self) -> u32 { + 1 + } +} + +impl B for u32 { + fn b(&self) -> u32 { + 0 + } +} diff --git a/tests/lean/HaxSpecs/HaxSpecs.lean b/tests/lean/HaxSpecs/HaxSpecs.lean deleted file mode 100644 index cbc05829c8..0000000000 --- a/tests/lean/HaxSpecs/HaxSpecs.lean +++ /dev/null @@ -1,875 +0,0 @@ --- THIS FILE WAS AUTOMATICALLY GENERATED BY AENEAS --- [hax_specs] -import Aeneas -import Hax -open Aeneas Aeneas.Std RustM ControlFlow Error -open Std.Do -set_option linter.dupNamespace false -set_option linter.hashCommand false -set_option linter.unusedVariables false -set_option linter.style.whitespace false -set_option linter.style.setOption false -set_option linter.style.longLine false - -/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ -set_option maxHeartbeats 1000000 - -/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ -set_option maxRecDepth 2048 - -/- You can remove the following line by using the CLI option `-all-computable`: -/ -noncomputable section - -namespace hax_specs - -/-- [core::ops::arith::{impl core::ops::arith::Add<&'_0 u32, u32> for &'_1 u32}::add]: - Source: '/rustc/library/core/src/internal_macros.rs', lines 49:12-49:68 - Name pattern: [core::ops::arith::{core::ops::arith::Add<&'1 u32, &'0 u32, u32>}::add] - Visibility: public -/ -@[rust_fun - "core::ops::arith::{core::ops::arith::Add<&'1 u32, &'0 u32, u32>}::add"] -axiom Shared1U32.Insts.CoreOpsArithAddShared0U32U32.add - : Std.U32 → Std.U32 → RustM Std.U32 - -/-- [hax_specs::basic::only_requires]: - Source: 'src/lib.rs', lines 6:4-8:5 -/ -def basic.only_requires (x : Std.U32) : RustM Std.U32 := do - x + 1#u32 - -/-- [hax_specs::basic::only_ensures]: - Source: 'src/lib.rs', lines 11:4-13:5 -/ -def basic.only_ensures (x : Std.U32) : RustM Std.U32 := do - ok x - -/-- [hax_specs::basic::both]: - Source: 'src/lib.rs', lines 17:4-19:5 -/ -def basic.both (x : Std.U32) : RustM Std.U32 := do - x + 1#u32 - -/-- [hax_specs::basic::no_args]: - Source: 'src/lib.rs', lines 23:4-26:5 -/ -def basic.no_args : RustM Unit := do - ok () - -/-- [hax_specs::basic::returns_unit]: - Source: 'src/lib.rs', lines 31:4-31:30 -/ -def basic.returns_unit (x : Std.U32) : RustM Unit := do - ok () - -/-- [hax_specs::basic::block_in_requires]: - Source: 'src/lib.rs', lines 35:4-37:5 -/ -def basic.block_in_requires (x : Std.U32) : RustM Std.U32 := do - ok x - -/-- [hax_specs::basic::returns_pair]: - Source: 'src/lib.rs', lines 41:4-43:5 -/ -def basic.returns_pair (x : Std.U32) : RustM (Std.U32 × Std.U32) := do - ok (x, x) - -/-- [hax_specs::extra_args::generic]: - Source: 'src/lib.rs', lines 53:4-55:5 -/ -def extra_args.generic (N : Std.U32) (x : Std.U32) : RustM Std.U32 := do - N - x - -/-- Trait declaration: [hax_specs::extra_args::Val] - Source: 'src/lib.rs', lines 58:4-60:5 -/ -structure extra_args.Val (Self : Type) where - value : Self → RustM Std.U32 - -/-- [hax_specs::extra_args::{impl hax_specs::extra_args::Val for u32}::value]: - Source: 'src/lib.rs', lines 63:8-65:9 -/ -def U32.Insts.Hax_specsExtra_argsVal.value - (self : Std.U32) : RustM Std.U32 := do - ok self - -/-- Trait implementation: [hax_specs::extra_args::{impl hax_specs::extra_args::Val for u32}] - Source: 'src/lib.rs', lines 62:4-66:5 -/ -@[reducible] -def U32.Insts.Hax_specsExtra_argsVal : extra_args.Val Std.U32 := { - value := U32.Insts.Hax_specsExtra_argsVal.value -} - -/-- [hax_specs::extra_args::traits]: - Source: 'src/lib.rs', lines 70:4-72:5 -/ -def extra_args.traits - {T : Type} (ValInst : extra_args.Val T) (t : T) (x : Std.U32) : - RustM Std.U32 - := do - let i ← ValInst.value t - i + x - -/-- [hax_specs::future::incr]: - Source: 'src/lib.rs', lines 81:4-83:5 -/ -def future.incr (x : Std.U32) : RustM Std.U32 := do - x + 1#u32 - -/-- [hax_specs::future::incr_i]: - Source: 'src/lib.rs', lines 89:4-91:5 -/ -def future.incr_i - (x : Slice Std.U32) (i : Std.Usize) : RustM (Slice Std.U32) := do - let i1 ← Slice.index_usize x i - let i2 ← i1 + 1#u32 - Slice.update x i i2 - -/-- [hax_specs::future::swap_and_add]: - Source: 'src/lib.rs', lines 95:4-101:5 -/ -def future.swap_and_add - (x : Std.U32) (y : Std.U32) : RustM (Std.U32 × Std.U32 × Std.U32) := do - let i ← x + y - ok (i, y, x) - -/-- [hax_specs::const_generic_ty::MyStruct] - Source: 'src/lib.rs', lines 113:4-115:5 - Visibility: public -/ -structure const_generic_ty.MyStruct (N : Std.Usize) where - cap : Std.Usize - -/-- [hax_specs::const_generic_ty::{hax_specs::const_generic_ty::MyStruct}::build]: - Source: 'src/lib.rs', lines 123:8-125:9 - Visibility: public -/ -def const_generic_ty.MyStruct.build - (N : Std.Usize) (k : Std.Usize) : RustM (const_generic_ty.MyStruct N) := do - ok { cap := k } - -/-- [hax_specs::const_generic_ty::{hax_specs::const_generic_ty::MyStruct}::get]: - Source: 'src/lib.rs', lines 129:8-131:9 - Visibility: public -/ -def const_generic_ty.MyStruct.get - {N : Std.Usize} (self : const_generic_ty.MyStruct N) : RustM Std.Usize := do - ok self.cap - -/-- [hax_specs::implicit_generics::Pair] - Source: 'src/lib.rs', lines 139:4-141:5 - Visibility: public -/ -structure implicit_generics.Pair (T : Type) (N : Std.Usize) where - fst : T - -/-- [hax_specs::implicit_generics::nothing]: - Source: 'src/lib.rs', lines 147:4-149:5 -/ -def implicit_generics.nothing - (T : Type) (k : Std.Usize) : RustM (Option T) := do - ok none - -/-- [hax_specs::implicit_generics::of_fst]: - Source: 'src/lib.rs', lines 153:4-155:5 -/ -def implicit_generics.of_fst - {T : Type} (N : Std.Usize) (t : T) : RustM (implicit_generics.Pair T N) := do - ok { fst := t } - -/-- [hax_specs::implicit_generics::empty]: - Source: 'src/lib.rs', lines 159:4-161:5 -/ -def implicit_generics.empty - (T : Type) (N : Std.Usize) (k : Std.Usize) : - RustM (Option (implicit_generics.Pair T N)) - := do - ok none - -/-- [hax_specs::implicit_generics::from_default]: - Source: 'src/lib.rs', lines 167:4-169:5 -/ -def implicit_generics.from_default - {T : Type} (N : Std.Usize) (coredefaultDefaultInst : core.default.Default T) - (k : Std.Usize) : - RustM (implicit_generics.Pair T N) - := do - let t ← coredefaultDefaultInst.default - ok { fst := t } - -/-- Trait declaration: [hax_specs::unit_args::Size] - Source: 'src/lib.rs', lines 178:4-180:5 -/ -structure unit_args.Size (Self : Type) where - len : Self → RustM Std.Usize - -/-- [hax_specs::unit_args::{impl hax_specs::unit_args::Size for ()}::len]: - Source: 'src/lib.rs', lines 186:8-188:9 -/ -def Tuple.Insts.Hax_specsUnit_argsSize.len (_ : Unit) : RustM Std.Usize := do - ok 0#usize - -/-- Trait implementation: [hax_specs::unit_args::{impl hax_specs::unit_args::Size for ()}] - Source: 'src/lib.rs', lines 184:4-189:5 -/ -@[reducible] -def Tuple.Insts.Hax_specsUnit_argsSize : unit_args.Size Unit := { - len := Tuple.Insts.Hax_specsUnit_argsSize.len -} - -/-- [hax_specs::unit_args::named]: - Source: 'src/lib.rs', lines 192:4-194:5 -/ -def unit_args.named (_ : Unit) : RustM Std.Usize := do - ok 0#usize - -/-- [hax_specs::unit_args::before_other]: - Source: 'src/lib.rs', lines 199:4-201:5 -/ -def unit_args.before_other (_ : Unit) (y : Std.U32) : RustM Std.U32 := do - ok y - -/-- Trait declaration: [hax_specs::supertraits::A] - Source: 'src/lib.rs', lines 210:4-212:5 - Visibility: public -/ -structure supertraits.A (Self : Type) where - a : Self → RustM Std.Usize - -/-- Trait declaration: [hax_specs::supertraits::B] - Source: 'src/lib.rs', lines 215:4-223:5 - Visibility: public -/ -structure supertraits.B (Self : Type) where - AInst : supertraits.A Self - b : Self → RustM Std.Usize - provided : Self → RustM Std.Usize - -/-- [hax_specs::supertraits::B::provided]: - Source: 'src/lib.rs', lines 220:8-222:9 - Visibility: public -/ -@[trait_default] -def supertraits.B.provided.default - {Self : Type} (BInst : supertraits.B Self) (self : Self) : - RustM Std.Usize - := do - BInst.AInst.a self - -/-- Trait declaration: [hax_specs::supertraits::C] - Source: 'src/lib.rs', lines 227:4-232:5 - Visibility: public -/ -structure supertraits.C (Self : Type) where - BInst : supertraits.B Self - provided_c : Self → RustM Std.Usize - -/-- [hax_specs::supertraits::C::provided_c]: - Source: 'src/lib.rs', lines 229:8-231:9 - Visibility: public -/ -@[trait_default] -def supertraits.C.provided_c.default - {Self : Type} (CInst : supertraits.C Self) (self : Self) : - RustM Std.Usize - := do - CInst.BInst.AInst.a self - -/-- Trait declaration: [hax_specs::supertraits::G] - Source: 'src/lib.rs', lines 235:4-237:5 - Visibility: public -/ -structure supertraits.G (Self : Type) (T : Type) where - g : Self → RustM T - -/-- Trait declaration: [hax_specs::supertraits::H] - Source: 'src/lib.rs', lines 240:4-245:5 - Visibility: public -/ -structure supertraits.H (Self : Type) (T : Type) where - GInst : supertraits.G Self T - provided_h : Self → RustM T - -/-- [hax_specs::supertraits::H::provided_h]: - Source: 'src/lib.rs', lines 242:8-244:9 - Visibility: public -/ -@[trait_default] -def supertraits.H.provided_h.default - {Self : Type} {T : Type} (HInst : supertraits.H Self T) (self : Self) : - RustM T - := do - HInst.GInst.g self - -/-- [hax_specs::reserved_names::foo]: - Source: 'src/lib.rs', lines 255:4-257:5 - Visibility: public -/ -def reserved_names.foo (x : Std.U32) : RustM Std.U32 := do - x + 1#u32 - -/-- [hax_specs::reserved_names::foo::precondition]: - Source: 'src/lib.rs', lines 261:8-263:9 - Visibility: public -/ -def reserved_names.foo.precondition (x : Std.U32) : RustM Bool := do - ok (x < 100#u32) - -/-- [hax_specs::reserved_names::foo::spec::lemma]: - Source: 'src/lib.rs', lines 266:12-266:29 - Visibility: public -/ -def reserved_names.foo.spec.lemma : RustM Unit := do - ok () - -/-- [hax_specs::reserved_names::proof]: - Source: 'src/lib.rs', lines 271:4-271:21 - Visibility: public -/ -def reserved_names.proof : RustM Unit := do - ok () - -/-- [hax_specs::reserved_names::bar::pre]: - Source: 'src/lib.rs', lines 274:8-274:23 - Visibility: public -/ -def reserved_names.bar.pre : RustM Unit := do - ok () - - -/-- [hax_specs::basic::only_requires::pre]: - Source: 'src/lib.rs', lines 5:4-5:24 -/ -@[reducible] -def basic.only_requires.pre (x : Std.U32) : RustM Bool := do - ok (x < 100#u32) - -def basic.only_requires.spec (x : Std.U32) : Prop := - (basic.only_requires.pre x).holds → - ⦃ ⌜ True ⌝ ⦄ - basic.only_requires x - ⦃ ⇓ res => ⌜ True ⌝ ⦄ - - -/-- [hax_specs::basic::only_ensures::post]: - Source: 'src/lib.rs', lines 10:4-10:36 -/ -@[reducible] -def basic.only_ensures.post (x : Std.U32) (result : Std.U32) : RustM Bool := do - ok (result = x) - -def basic.only_ensures.spec (x : Std.U32) : Prop := - ⦃ ⌜ True ⌝ ⦄ - basic.only_ensures x - ⦃ ⇓ res => ⌜ (basic.only_ensures.post x res).holds ⌝ ⦄ - - -/-- [hax_specs::basic::both::pre]: - Source: 'src/lib.rs', lines 15:4-15:23 -/ -@[reducible] -def basic.both.pre (x : Std.U32) : RustM Bool := do - ok (x < 10#u32) - -/-- [hax_specs::basic::both::post]: - Source: 'src/lib.rs', lines 16:4-16:35 -/ -@[reducible] -def basic.both.post (x : Std.U32) (result : Std.U32) : RustM Bool := do - ok (result > x) - -def basic.both.spec (x : Std.U32) : Prop := - (basic.both.pre x).holds → - ⦃ ⌜ True ⌝ ⦄ - basic.both x - ⦃ ⇓ res => ⌜ (basic.both.post x res).holds ⌝ ⦄ - - -/-- [hax_specs::basic::returns_unit::pre]: - Source: 'src/lib.rs', lines 29:4-29:23 -/ -@[reducible] -def basic.returns_unit.pre (x : Std.U32) : RustM Bool := do - ok (x < 10#u32) - -/-- [hax_specs::basic::returns_unit::post]: - Source: 'src/lib.rs', lines 30:4-30:24 -/ -@[reducible] -def basic.returns_unit.post (x : Std.U32) (_ : Unit) : RustM Bool := do - ok true - -def basic.returns_unit.spec (x : Std.U32) : Prop := - (basic.returns_unit.pre x).holds → - ⦃ ⌜ True ⌝ ⦄ - basic.returns_unit x - ⦃ ⇓ res => ⌜ (basic.returns_unit.post x res).holds ⌝ ⦄ - - -/-- [hax_specs::basic::block_in_requires::pre]: - Source: 'src/lib.rs', lines 34:4-34:46 -/ -@[reducible] -def basic.block_in_requires.pre (x : Std.U32) : RustM Bool := do - ok (x > 10#u32) - -def basic.block_in_requires.spec (x : Std.U32) : Prop := - (basic.block_in_requires.pre x).holds → - ⦃ ⌜ True ⌝ ⦄ - basic.block_in_requires x - ⦃ ⇓ res => ⌜ True ⌝ ⦄ - - -/-- [hax_specs::basic::returns_pair::post]: - Source: 'src/lib.rs', lines 40:4-40:41 -/ -@[reducible] -def basic.returns_pair.post - (x : Std.U32) (p : (Std.U32 × Std.U32)) : RustM Bool := do - let (a, b) := p - if a = x - then ok (b = x) - else ok false - -def basic.returns_pair.spec (x : Std.U32) : Prop := - ⦃ ⌜ True ⌝ ⦄ - basic.returns_pair x - ⦃ ⇓ res => ⌜ (basic.returns_pair.post x res).holds ⌝ ⦄ - - -/-- [hax_specs::extra_args::generic::pre]: - Source: 'src/lib.rs', lines 51:4-51:31 -/ -@[reducible] -def extra_args.generic.pre (N : Std.U32) (x : Std.U32) : RustM Bool := do - if 0#u32 < x - then ok (x < N) - else ok false - -/-- [hax_specs::extra_args::generic::post]: - Source: 'src/lib.rs', lines 52:4-52:35 -/ -@[reducible] -def extra_args.generic.post - (N : Std.U32) (x : Std.U32) (result : Std.U32) : RustM Bool := do - ok (result < N) - -def extra_args.generic.spec (N : Std.U32) (x : Std.U32) : Prop := - (extra_args.generic.pre N x).holds → - ⦃ ⌜ True ⌝ ⦄ - extra_args.generic N x - ⦃ ⇓ res => ⌜ (extra_args.generic.post N x res).holds ⌝ ⦄ - - -/-- [hax_specs::extra_args::traits::pre]: - Source: 'src/lib.rs', lines 68:4-68:45 -/ -@[reducible] -def extra_args.traits.pre - {T : Type} (ValInst : extra_args.Val T) (t : T) (x : Std.U32) : - RustM Bool - := do - let i ← ValInst.value t - if i < 1000#u32 - then ok (x < 1000#u32) - else ok false - -/-- [hax_specs::extra_args::traits::post]: - Source: 'src/lib.rs', lines 69:4-69:38 -/ -@[reducible] -def extra_args.traits.post - {T : Type} (ValInst : extra_args.Val T) (t : T) (x : Std.U32) - (result : Std.U32) : - RustM Bool - := do - ok (result < 2000#u32) - -def extra_args.traits.spec {T : Type} (ValInst : extra_args.Val T) (t : T) - (x : Std.U32) : Prop := - (extra_args.traits.pre ValInst t x).holds → - ⦃ ⌜ True ⌝ ⦄ - extra_args.traits ValInst t x - ⦃ ⇓ res => ⌜ (extra_args.traits.post ValInst t x res).holds ⌝ ⦄ - - -/-- [hax_specs::future::incr::pre]: - Source: 'src/lib.rs', lines 79:4-79:26 -/ -@[reducible] -def future.incr.pre (x : Std.U32) : RustM Bool := do - ok (x < 1000#u32) - -/-- [hax_specs::future::incr::post]: - Source: 'src/lib.rs', lines 80:4-80:41 -/ -@[reducible] -def future.incr.post (x : Std.U32) (x_future : Std.U32) : RustM Bool := do - let i ← x + 1#u32 - ok (x_future = i) - -def future.incr.spec (x : Std.U32) : Prop := - (future.incr.pre x).holds → - ⦃ ⌜ True ⌝ ⦄ - future.incr x - ⦃ ⇓ res => ⌜ (future.incr.post x res).holds ⌝ ⦄ - - -/-- [hax_specs::future::incr_i::pre]: - Source: 'src/lib.rs', lines 85:4-85:28 -/ -@[reducible] -def future.incr_i.pre (x : Slice Std.U32) (i : Std.Usize) : RustM Bool := do - let i1 := Slice.len x - ok (i < i1) - -/-- [hax_specs::future::incr_i::post]: - Source: 'src/lib.rs', lines 86:4-88:31 -/ -@[reducible] -def future.incr_i.post - (x : Slice Std.U32) (i : Std.Usize) (x_future : Slice Std.U32) : - RustM Bool - := do - let i1 ← Slice.index_usize x_future i - let i2 ← Slice.index_usize x i - let i3 ← i2 + 1#u32 - ok (i1 = i3) - -def future.incr_i.spec (x : Slice Std.U32) (i : Std.Usize) : Prop := - (future.incr_i.pre x i).holds → - ⦃ ⌜ True ⌝ ⦄ - future.incr_i x i - ⦃ ⇓ res => ⌜ (future.incr_i.post x i res).holds ⌝ ⦄ - - -/-- [hax_specs::future::swap_and_add::pre]: - Source: 'src/lib.rs', lines 93:4-93:39 -/ -@[reducible] -def future.swap_and_add.pre (x : Std.U32) (y : Std.U32) : RustM Bool := do - if x < 1000#u32 - then ok (y < 1000#u32) - else ok false - -/-- [hax_specs::future::swap_and_add::post]: - Source: 'src/lib.rs', lines 94:4-94:73 -/ -@[reducible] -def future.swap_and_add.post - (x : Std.U32) (y : Std.U32) (t : (Std.U32 × Std.U32 × Std.U32)) : - RustM Bool - := do - let (x_future, y_future, r) := t - if y_future = x - then - if x_future = y - then - let i ← Shared1U32.Insts.CoreOpsArithAddShared0U32U32.add x y - ok (r = i) - else ok false - else ok false - -def future.swap_and_add.spec (x : Std.U32) (y : Std.U32) : Prop := - (future.swap_and_add.pre x y).holds → - ⦃ ⌜ True ⌝ ⦄ - future.swap_and_add x y - ⦃ ⇓ res => ⌜ (future.swap_and_add.post x y res).holds ⌝ ⦄ - - -/-- [hax_specs::implicit_generics::nothing::post]: - Source: 'src/lib.rs', lines 146:4-146:24 -/ -@[reducible] -def implicit_generics.nothing.post - {T : Type} (k : Std.Usize) (o : Option T) : RustM Bool := do - ok true - -def implicit_generics.nothing.spec (T : Type) (k : Std.Usize) : Prop := - ⦃ ⌜ True ⌝ ⦄ - implicit_generics.nothing T k - ⦃ ⇓ res => ⌜ (implicit_generics.nothing.post k res).holds ⌝ ⦄ - - -/-- [hax_specs::implicit_generics::of_fst::post]: - Source: 'src/lib.rs', lines 152:4-152:24 -/ -@[reducible] -def implicit_generics.of_fst.post - {T : Type} {N : Std.Usize} (t : T) (p : implicit_generics.Pair T N) : - RustM Bool - := do - ok true - -def implicit_generics.of_fst.spec {T : Type} (N : Std.Usize) (t : T) : Prop := - ⦃ ⌜ True ⌝ ⦄ - implicit_generics.of_fst N t - ⦃ ⇓ res => ⌜ (implicit_generics.of_fst.post t res).holds ⌝ ⦄ - - -/-- [hax_specs::implicit_generics::empty::post]: - Source: 'src/lib.rs', lines 158:4-158:24 -/ -@[reducible] -def implicit_generics.empty.post - {T : Type} {N : Std.Usize} (k : Std.Usize) - (o : Option (implicit_generics.Pair T N)) : - RustM Bool - := do - ok true - -def implicit_generics.empty.spec (T : Type) (N : Std.Usize) (k : Std.Usize) - : Prop := - ⦃ ⌜ True ⌝ ⦄ - implicit_generics.empty T N k - ⦃ ⇓ res => ⌜ (implicit_generics.empty.post k res).holds ⌝ ⦄ - - -/-- [hax_specs::implicit_generics::from_default::pre]: - Source: 'src/lib.rs', lines 165:4-165:24 -/ -@[reducible] -def implicit_generics.from_default.pre - {T : Type} (N : Std.Usize) (coredefaultDefaultInst : core.default.Default T) - (k : Std.Usize) : - RustM Bool - := do - ok (k < 100#usize) - -/-- [hax_specs::implicit_generics::from_default::post]: - Source: 'src/lib.rs', lines 166:4-166:24 -/ -@[reducible] -def implicit_generics.from_default.post - {T : Type} {N : Std.Usize} (coredefaultDefaultInst : core.default.Default T) - (k : Std.Usize) (p : implicit_generics.Pair T N) : - RustM Bool - := do - ok true - -def - implicit_generics.from_default.spec {T : Type} (N : Std.Usize) - (coredefaultDefaultInst : - core.default.Default T) (k : Std.Usize) - : Prop := - (implicit_generics.from_default.pre N coredefaultDefaultInst k).holds → - ⦃ ⌜ True ⌝ ⦄ - implicit_generics.from_default N coredefaultDefaultInst k - ⦃ ⇓ res => - ⌜ (implicit_generics.from_default.post coredefaultDefaultInst k res).holds - ⌝ ⦄ - - -/-- [hax_specs::unit_args::named::post]: - Source: 'src/lib.rs', lines 191:4-191:36 -/ -@[reducible] -def unit_args.named.post (_ : Unit) (result : Std.Usize) : RustM Bool := do - ok (result = 0#usize) - -def unit_args.named.spec (_ : Unit) : Prop := - ⦃ ⌜ True ⌝ ⦄ - unit_args.named () - ⦃ ⇓ res => ⌜ (unit_args.named.post () res).holds ⌝ ⦄ - - -/-- [hax_specs::unit_args::before_other::pre]: - Source: 'src/lib.rs', lines 197:4-197:24 -/ -@[reducible] -def unit_args.before_other.pre (_ : Unit) (y : Std.U32) : RustM Bool := do - ok (y < 100#u32) - -/-- [hax_specs::unit_args::before_other::post]: - Source: 'src/lib.rs', lines 198:4-198:36 -/ -@[reducible] -def unit_args.before_other.post - (_ : Unit) (y : Std.U32) (result : Std.U32) : RustM Bool := do - ok (result = y) - -def unit_args.before_other.spec (_ : Unit) (y : Std.U32) : Prop := - (unit_args.before_other.pre () y).holds → - ⦃ ⌜ True ⌝ ⦄ - unit_args.before_other () y - ⦃ ⇓ res => ⌜ (unit_args.before_other.post () y res).holds ⌝ ⦄ - - -/-- [hax_specs::reserved_names::foo::pre]: - Source: 'src/lib.rs', lines 253:4-253:24 -/ -@[reducible] -def reserved_names.foo.pre (x : Std.U32) : RustM Bool := do - ok (x < 100#u32) - -/-- [hax_specs::reserved_names::foo::post]: - Source: 'src/lib.rs', lines 254:4-254:40 -/ -@[reducible] -def reserved_names.foo.post (x : Std.U32) (result : Std.U32) : RustM Bool := do - let i ← x + 1#u32 - ok (result = i) - -def reserved_names.foo.spec (x : Std.U32) : Prop := - (reserved_names.foo.pre x).holds → - ⦃ ⌜ True ⌝ ⦄ - reserved_names.foo x - ⦃ ⇓ res => ⌜ (reserved_names.foo.post x res).holds ⌝ ⦄ - - -/-- [hax_specs::const_generic_ty::{hax_specs::const_generic_ty::MyStruct}::build::pre]: - Source: 'src/lib.rs', lines 121:8-121:28 -/ -@[reducible] -def const_generic_ty.MyStruct.build.pre - (N : Std.Usize) (k : Std.Usize) : RustM Bool := do - ok (k < 100#usize) - -/-- [hax_specs::const_generic_ty::{hax_specs::const_generic_ty::MyStruct}::build::post]: - Source: 'src/lib.rs', lines 122:8-122:28 -/ -@[reducible] -def const_generic_ty.MyStruct.build.post - {N : Std.Usize} (k : Std.Usize) (ms : const_generic_ty.MyStruct N) : - RustM Bool - := do - ok true - -def const_generic_ty.MyStruct.build.spec (N : Std.Usize) (k : Std.Usize) - : Prop := - (const_generic_ty.MyStruct.build.pre N k).holds → - ⦃ ⌜ True ⌝ ⦄ - const_generic_ty.MyStruct.build N k - ⦃ ⇓ res => ⌜ (const_generic_ty.MyStruct.build.post k res).holds ⌝ ⦄ - - -/-- [hax_specs::const_generic_ty::{hax_specs::const_generic_ty::MyStruct}::get::post]: - Source: 'src/lib.rs', lines 128:8-128:28 -/ -@[reducible] -def const_generic_ty.MyStruct.get.post - {N : Std.Usize} (self_ : const_generic_ty.MyStruct N) (i : Std.Usize) : - RustM Bool - := do - ok true - -def const_generic_ty.MyStruct.get.spec {N : Std.Usize} - (self : const_generic_ty.MyStruct N) : Prop := - ⦃ ⌜ True ⌝ ⦄ - const_generic_ty.MyStruct.get self - ⦃ ⇓ res => ⌜ (const_generic_ty.MyStruct.get.post self res).holds ⌝ - ⦄ - - -/-- [hax_specs::unit_args::{impl hax_specs::unit_args::Size for ()}::len::post]: - Source: 'src/lib.rs', lines 185:8-185:28 -/ -@[reducible] -def Tuple.Insts.Hax_specsUnit_argsSize.len.post - (_ : Unit) (i : Std.Usize) : RustM Bool := do - ok true - -def Tuple.Insts.Hax_specsUnit_argsSize.len.spec (_ : Unit) : Prop := - ⦃ ⌜ True ⌝ ⦄ - Tuple.Insts.Hax_specsUnit_argsSize.len () - ⦃ ⇓ res => - ⌜ (Tuple.Insts.Hax_specsUnit_argsSize.len.post () res).holds ⌝ ⦄ - - -/-- [hax_specs::supertraits::B::provided::pre]: - Source: 'src/lib.rs', lines 214:4-214:26 -/ -@[reducible] -def supertraits.B.provided.pre - {Self_ : Type} (AInst : supertraits.A Self_) (BInst : supertraits.B Self_) - (self_ : Self_) : - RustM Bool - := do - let i ← AInst.a self_ - ok (i < 100#usize) - -/-- [hax_specs::supertraits::B::provided::post]: - Source: 'src/lib.rs', lines 214:4-214:26 -/ -@[reducible] -def supertraits.B.provided.post - {Self_ : Type} (AInst : supertraits.A Self_) (BInst : supertraits.B Self_) - (self_ : Self_) (res : Std.Usize) : - RustM Bool - := do - let i ← AInst.a self_ - ok (res = i) - -def - supertraits.B.provided.default.spec {Self : Type} (BInst : supertraits.B - Self) (self : Self) : Prop := - (supertraits.B.provided.pre BInst.AInst BInst self).holds → - ⦃ ⌜ True ⌝ ⦄ - supertraits.B.provided.default BInst self - ⦃ ⇓ res => - ⌜ (supertraits.B.provided.post BInst.AInst BInst self res).holds ⌝ ⦄ - - -/-- [hax_specs::supertraits::C::provided_c::post]: - Source: 'src/lib.rs', lines 226:4-226:26 -/ -@[reducible] -def supertraits.C.provided_c.post - {Self_ : Type} (BInst : supertraits.B Self_) (CInst : supertraits.C Self_) - (self_ : Self_) (res : Std.Usize) : - RustM Bool - := do - let i ← BInst.AInst.a self_ - ok (res = i) - -def - supertraits.C.provided_c.default.spec {Self : Type} (CInst : supertraits.C - Self) (self : Self) : Prop := - ⦃ ⌜ True ⌝ ⦄ - supertraits.C.provided_c.default CInst self - ⦃ ⇓ res => - ⌜ (supertraits.C.provided_c.post CInst.BInst CInst self res).holds ⌝ ⦄ - - -/-- [hax_specs::supertraits::H::provided_h::post]: - Source: 'src/lib.rs', lines 239:4-239:26 -/ -@[reducible] -def supertraits.H.provided_h.post - {Self_ : Type} {T : Type} (GInst : supertraits.G Self_ T) (HInst : - supertraits.H Self_ T) (self_ : Self_) (t : T) : - RustM Bool - := do - ok true - -def - supertraits.H.provided_h.default.spec {Self : Type} {T : Type} (HInst : - supertraits.H Self T) (self : Self) - : Prop := - ⦃ ⌜ True ⌝ ⦄ - supertraits.H.provided_h.default HInst self - ⦃ ⇓ res => - ⌜ (supertraits.H.provided_h.post HInst.GInst HInst self res).holds ⌝ ⦄ - -theorem basic.only_requires.spec.proof (x : Std.U32) : - basic.only_requires.spec x - := by sorry - -theorem basic.only_ensures.spec.proof (x : Std.U32) : basic.only_ensures.spec x - := by sorry - -theorem basic.both.spec.proof (x : Std.U32) : basic.both.spec x := by sorry - -theorem basic.returns_unit.spec.proof (x : Std.U32) : basic.returns_unit.spec x - := by sorry - -theorem basic.block_in_requires.spec.proof (x : Std.U32) : - basic.block_in_requires.spec x - := by sorry - -theorem basic.returns_pair.spec.proof (x : Std.U32) : basic.returns_pair.spec x - := by sorry - -theorem extra_args.generic.spec.proof (N : Std.U32) (x : Std.U32) : - extra_args.generic.spec N x - := by sorry - -theorem extra_args.traits.spec.proof {T : Type} (ValInst : extra_args.Val T) - (t : T) (x : Std.U32) : extra_args.traits.spec ValInst t x - := by sorry - -theorem future.incr.spec.proof (x : Std.U32) : future.incr.spec x := by sorry - -theorem future.incr_i.spec.proof (x : Slice Std.U32) (i : Std.Usize) : - future.incr_i.spec x i - := by sorry - -theorem future.swap_and_add.spec.proof (x : Std.U32) (y : Std.U32) : - future.swap_and_add.spec x y - := by sorry - -theorem implicit_generics.nothing.spec.proof (T : Type) (k : Std.Usize) : - implicit_generics.nothing.spec T k - := by sorry - -theorem implicit_generics.of_fst.spec.proof {T : Type} (N : Std.Usize) - (t : T) : implicit_generics.of_fst.spec N t - := by sorry - -theorem implicit_generics.empty.spec.proof (T : Type) (N : Std.Usize) - (k : Std.Usize) : implicit_generics.empty.spec T N k - := by sorry - -theorem - implicit_generics.from_default.spec.proof {T : Type} (N : Std.Usize) - (coredefaultDefaultInst : - core.default.Default T) - (k : Std.Usize) : - implicit_generics.from_default.spec N coredefaultDefaultInst k - := by sorry - -theorem unit_args.named.spec.proof (_ : Unit) : unit_args.named.spec () - := by sorry - -theorem unit_args.before_other.spec.proof (_ : Unit) (y : Std.U32) : - unit_args.before_other.spec () y - := by sorry - -theorem reserved_names.foo.spec.proof (x : Std.U32) : reserved_names.foo.spec x - := by sorry - -theorem const_generic_ty.MyStruct.build.spec.proof (N : Std.Usize) - (k : Std.Usize) : const_generic_ty.MyStruct.build.spec N k - := by sorry - -theorem const_generic_ty.MyStruct.get.spec.proof {N : Std.Usize} - (self : const_generic_ty.MyStruct N) : - const_generic_ty.MyStruct.get.spec self - := by sorry - -theorem Tuple.Insts.Hax_specsUnit_argsSize.len.spec.proof (_ : Unit) : - Tuple.Insts.Hax_specsUnit_argsSize.len.spec () - := by sorry - -theorem - supertraits.B.provided.default.spec.proof {Self : Type} (BInst : - supertraits.B Self) (self : Self) : - supertraits.B.provided.default.spec BInst self - := by sorry - -theorem - supertraits.C.provided_c.default.spec.proof {Self : Type} (CInst : - supertraits.C Self) (self : Self) - : supertraits.C.provided_c.default.spec CInst self - := by sorry - -theorem - supertraits.H.provided_h.default.spec.proof {Self : Type} {T : Type} (HInst : - supertraits.H Self T) - (self : Self) : supertraits.H.provided_h.default.spec HInst self - := by sorry - -end hax_specs diff --git a/tests/src/hax_specs/Cargo.lock b/tests/src/hax_specs/Cargo.lock deleted file mode 100644 index 38d0643fad..0000000000 --- a/tests/src/hax_specs/Cargo.lock +++ /dev/null @@ -1,582 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "autocfg" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" - -[[package]] -name = "bitflags" -version = "2.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" - -[[package]] -name = "bumpalo" -version = "3.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "futures-core" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" - -[[package]] -name = "futures-task" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" - -[[package]] -name = "futures-util" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "slab", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasip2", - "wasip3", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - -[[package]] -name = "hax-lib" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e780db631bd4064c437fe76e3a8ea749a9307564f91bf3af7429502d12b3c7c0" -dependencies = [ - "hax-lib-macros", - "num-bigint", - "num-traits", -] - -[[package]] -name = "hax-lib-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16441cc9f5f9081d50f47346b0a46a0e99be08fd5439859093f81c72f24d6c5c" -dependencies = [ - "hax-lib-macros-types", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "hax-lib-macros-types" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31238c511c40fd6058d3a5d8856e6ef3245bc307a1878bcf84dca28c967750d" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "hax_specs" -version = "0.1.0" -dependencies = [ - "hax-lib", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown 0.17.1", - "serde", - "serde_core", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "js-sys" -version = "0.3.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" -dependencies = [ - "cfg-if", - "futures-util", - "wasm-bindgen", -] - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "log" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" - -[[package]] -name = "memchr" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "serde_json" -version = "1.0.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "uuid" -version = "1.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" -dependencies = [ - "getrandom", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wasip2" -version = "1.0.4+wasi-0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen 0.51.0", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.129" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.129" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.129" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 3.0.6", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.129" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" From c6dd0079d4bb108ac2b2874db13cb92a34246df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Thu, 8 Oct 2026 11:57:48 +0200 Subject: [PATCH 02/17] feat: have the [-specs] option require [-core-models-lib] --- src/Main.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Main.ml b/src/Main.ml index af0748e048..d413dc3b4b 100644 --- a/src/Main.ml +++ b/src/Main.ml @@ -139,7 +139,8 @@ let () = ( "-specs", Arg.Symbol (spec_config_options, set_spec_config), " Gather and emit specs from the given source. Available: " - ^ String.concat ", " spec_config_options ); + ^ String.concat ", " spec_config_options + ^ " (hax requires -core-models-lib)" ); ( "-emit-json", Arg.Set emit_json, " Emit a translation.json file alongside the Lean files (Lean only)" ); @@ -498,6 +499,8 @@ let () = fail_with_error "The -emit-json option is valid only for the Lean backend"; if Option.is_some !opt_spec_config && not (backend () = Lean) then fail_with_error "The -specs option is valid only for the Lean backend"; + if spec_config_is_hax () && not !core_models_lib then + fail_with_error "The -specs hax option requires the -core-models-lib option"; check_arg_implies !diagnose_detailed "-diagnose-detailed" !diagnose_micro_passes "-diagnose-micro-passes"; From acc9ef4a4348760d1e4cd2070f10a273f602c14a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Thu, 8 Oct 2026 11:58:23 +0200 Subject: [PATCH 03/17] feat-specs: extend haxspecs IR with trait specs and impl obligations --- src/extract/ExtractHaxSpecs.ml | 4 ++++ src/specs/HaxSpecs.ml | 42 ++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index d34a4f7e76..5cdaa0ca3f 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -213,6 +213,7 @@ let register_spec_names (ctx : ExtractBase.extraction_ctx) ctx conds in ExtractBase.ctx_add span (SpecId spec_id) spec ctx) + | TraitSpec _ -> (* Not produced yet *) ctx (** Same as {!register_spec_names}, for a proof obligation *) let register_obligation_names (ctx : ExtractBase.extraction_ctx) @@ -228,6 +229,7 @@ let register_obligation_names (ctx : ExtractBase.extraction_ctx) in ExtractBase.ctx_add parent.item_meta.span (ProofObligationId proof_id) proof ctx) + | ImplLawful _ -> (* Not produced yet *) ctx (** Emits the spec statement — the body of [def foo.spec … : Prop :=] (the [theorem foo.spec.proof … := by sorry] wrapper is the obligation, emitted @@ -362,6 +364,7 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) opt_span = F.pp_close_box fmt (); (* outer vbox *) F.pp_print_cut fmt ()) + | TraitSpec _ -> (* Not produced yet *) () (** Emit one [HaxSpecs.obligation] entry as the proof obligation that discharges a spec's statement of correctness: @@ -439,3 +442,4 @@ let emit_obligation ctx fmt (o : HaxSpecs.obligation) opt_span = F.pp_close_box fmt (); (* outer hvbox *) F.pp_print_cut fmt ()) + | ImplLawful _ -> (* Not produced yet *) () diff --git a/src/specs/HaxSpecs.ml b/src/specs/HaxSpecs.ml index 4e9a7a8ec1..a6a74cab3b 100644 --- a/src/specs/HaxSpecs.ml +++ b/src/specs/HaxSpecs.ml @@ -1,11 +1,16 @@ (** The Hax spec-objects Hax_lib macros allow for specs written directly in rust. This module - provides type definitions to represent such specs. Currently, it supports - only pre/post on standalone functions. *) + provides type definitions to represent such specs: pre/post on functions, + and trait contracts with the impl obligations they induce. *) (** Type for spec objects *) -type spec = FunctionSpec of function_spec [@@deriving show] +type spec = + | FunctionSpec of function_spec + | TraitSpec of trait_spec + (** The contract of a trait: its [X.Lawful] structure and the conditions + of its annotated methods *) +[@@deriving show] and function_spec = { fn : Pure.FunDeclId.id; @@ -14,8 +19,37 @@ and function_spec = { } [@@deriving show] +(** The contract of a local trait. The producer emits one per local trait, + possibly with no [methods] ([X.Lawful] then only has the parent fields, if + any). The parents, generics and method signatures are read from the + {!Pure.trait_decl}. *) +and trait_spec = { + trait_decl : Pure.TraitDeclId.id; + methods : method_spec list; (** The annotated methods, in declaration order *) +} +[@@deriving show] + +(** The contract of an annotated trait method (required or provided) *) +and method_spec = { + method_id : Pure.trait_method_id; + pre : Pure.fun_decl option; (** Precondition *) + post : Pure.fun_decl option; (** Postcondition *) +} +[@@deriving show] + (** Type for proof-obligation objects. *) -and obligation = FunctionContract of { spec : function_spec; proof : proof } +and obligation = + | FunctionContract of { spec : function_spec; proof : proof } + | ImplLawful of { + impl : Pure.TraitImplId.id; + spec : trait_spec option; + (** The contract of the implemented trait. [None] for a non-local + trait: its [Lawful] fields are only known on the Lean side, so the + obligation gets no field skeleton. *) + proof : proof; + } + (** [.Lawful : X.Lawful … ]: the impl satisfies the contract + of its trait *) [@@deriving show] (** Type for proof objects *) From 3df6306a678276986be7ecdf2d686c05c6fba95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Sun, 11 Oct 2026 21:44:12 +0200 Subject: [PATCH 04/17] feat-specs: extend hax-producer to catch trait contracts --- src/extract/ExtractHaxSpecs.ml | 148 ++++--- src/extract/ExtractHaxSpecs.mli | 21 +- src/extract/ExtractSpec.ml | 6 +- src/specs/HaxProducer.ml | 205 ++++++++-- .../HaxTests/Extraction/ProofObligations.lean | 7 - .../lean/HaxTests/Extraction/Specs.lean | 371 ++++++++++++++++-- 6 files changed, 619 insertions(+), 139 deletions(-) diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index 5cdaa0ca3f..37a15afde9 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -143,7 +143,8 @@ let emit_conditions ctx fmt ~pre ~post = (** {1 Names} The contract of [] generates [.pre], [.post], [.spec] and - [.spec.proof]. *) + [.spec.proof]. The contract of a method [] of a trait [] + generates [..pre] and [..post]. *) (** The registered name of [parent] *) let registered_fun_name (ctx : ExtractBase.extraction_ctx) @@ -152,34 +153,29 @@ let registered_fun_name (ctx : ExtractBase.extraction_ctx) (FunId (FromLlbc (FunId (FRegular parent.def_id), parent.loop_id))) ctx -(** [.]. The conditions of a default method - [..default] are [..pre] / [.post]: their - naming is left open for now. *) -let cond_name (ctx : ExtractBase.extraction_ctx) (parent : Pure.fun_decl) - (parent_name : string) (suffix : string) : string = - let base = - if ExtractBase.fun_source_is_trait_default ctx parent.src then - let default_suffix = "." ^ ExtractBase.trait_default_method_suffix in - match Filename.chop_suffix_opt ~suffix:default_suffix parent_name with - | Some base -> base - | None -> [%internal_error] parent.item_meta.span - else parent_name - in - base ^ "." ^ suffix +(** [.] *) +let cond_name (parent_name : string) (suffix : string) : string = + ExtractBuiltin.flatten_name [ parent_name; suffix ] -let spec_name (parent_name : string) : string = parent_name ^ ".spec" +let spec_name (parent_name : string) : string = + ExtractBuiltin.flatten_name [ parent_name; "spec" ] let proof_name (parent_name : string) : string = - spec_name parent_name ^ ".proof" + ExtractBuiltin.flatten_name [ spec_name parent_name; "proof" ] + +(** The names of the conditions [pre] and [post] of [parent_name] *) +let cond_names (parent_name : string) ~(pre : Pure.fun_decl option) + ~(post : Pure.fun_decl option) : (Pure.fun_decl * string) list = + let cond suffix (f : Pure.fun_decl option) = + Option.map (fun f -> (f, cond_name parent_name suffix)) f + in + List.filter_map Fun.id [ cond "pre" pre; cond "post" post ] (** The names of the conditions, spec and proof of [parent] *) -let generated_names ctx (parent : Pure.fun_decl) (parent_name : string) +let generated_names (parent_name : string) ({ pre; post; _ } : HaxSpecs.function_spec) : (Pure.fun_decl * string) list * string * string = - let cond suffix (f : Pure.fun_decl option) = - Option.map (fun f -> (f, cond_name ctx parent parent_name suffix)) f - in - ( List.filter_map Fun.id [ cond "pre" pre; cond "post" post ], + ( cond_names parent_name ~pre ~post, spec_name parent_name, proof_name parent_name ) @@ -190,30 +186,79 @@ let lookup_parent (ctx : ExtractBase.extraction_ctx) (fn : Pure.FunDeclId.id) : (fun (ft : TranslateCore.pure_fun_translation) -> ft.f) (Pure.FunDeclId.Map.find_opt fn ctx.trans_funs) +(** Register the names of conditions, under the ids of their fns *) +let register_conds span (conds : (Pure.fun_decl * string) list) + (ctx : ExtractBase.extraction_ctx) : ExtractBase.extraction_ctx = + List.fold_left + (fun ctx ((f : Pure.fun_decl), name) -> + ExtractBase.ctx_add span + (FunId (FromLlbc (FunId (FRegular f.def_id), None))) + name ctx) + ctx conds + +(** Warn that the contract of an untranslated item is dropped. We use the span + of the LLBC item [item_meta], if found, and [opt_span] otherwise. *) +let warn_untranslated (ctx : ExtractBase.extraction_ctx) opt_span + (item_meta : Types.item_meta option) (kind : string) (id : string) = + let span, name = + match item_meta with + | Some m -> (Some m.span, TranslateCore.name_to_string ctx.trans_ctx m.name) + | None -> (opt_span, id) + in + [%warn_opt_span] span + (Printf.sprintf + "hax-specs: dropping the contract of %s `%s`: the %s was not translated" + kind name kind) + (** Register the names of the conditions and of the spec. Must be called after - registering the crate items. *) + registering the crate items. Warns about the specs of untranslated items: + {!emit_spec} skips them. *) let register_spec_names (ctx : ExtractBase.extraction_ctx) - (spec_id : Spec.SpecId.id) (s : HaxSpecs.spec) : ExtractBase.extraction_ctx - = + (spec_id : Spec.SpecId.id) (s : HaxSpecs.spec) (opt_span : Meta.span option) + : ExtractBase.extraction_ctx = match s with | FunctionSpec fspec -> ( match lookup_parent ctx fspec.fn with - | None -> ctx + | None -> + warn_untranslated ctx opt_span + (Option.map + (fun (f : LlbcAst.fun_decl) -> f.item_meta) + (Pure.FunDeclId.Map.find_opt fspec.fn + ctx.trans_ctx.crate.fun_decls)) + "function" + (Pure.FunDeclId.to_string fspec.fn); + ctx | Some parent -> let span = parent.item_meta.span in let conds, spec, _ = - generated_names ctx parent (registered_fun_name ctx parent) fspec - in - let ctx = - List.fold_left - (fun ctx ((f : Pure.fun_decl), name) -> - ExtractBase.ctx_add span - (FunId (FromLlbc (FunId (FRegular f.def_id), None))) - name ctx) - ctx conds + generated_names (registered_fun_name ctx parent) fspec in + let ctx = register_conds span conds ctx in ExtractBase.ctx_add span (SpecId spec_id) spec ctx) - | TraitSpec _ -> (* Not produced yet *) ctx + | TraitSpec { trait_decl; methods } -> ( + match Pure.TraitDeclId.Map.find_opt trait_decl ctx.trans_trait_decls with + | None -> + warn_untranslated ctx opt_span + (Option.map + (fun (d : LlbcAst.trait_decl) -> d.item_meta) + (Pure.TraitDeclId.Map.find_opt trait_decl + ctx.trans_ctx.crate.trait_decls)) + "trait" + (Pure.TraitDeclId.to_string trait_decl); + ctx + | Some d -> + let span = d.item_meta.span in + let get id = ExtractBase.ctx_get_raw (Some span) id ctx in + let trait_name = get (TraitDeclId trait_decl) in + List.fold_left + (fun ctx ({ method_id; pre; post } : HaxSpecs.method_spec) -> + let method_name = get (TraitMethodId (trait_decl, method_id)) in + register_conds span + (cond_names + (ExtractBuiltin.flatten_name [ trait_name; method_name ]) + ~pre ~post) + ctx) + ctx methods) (** Same as {!register_spec_names}, for a proof obligation *) let register_obligation_names (ctx : ExtractBase.extraction_ctx) @@ -225,7 +270,7 @@ let register_obligation_names (ctx : ExtractBase.extraction_ctx) | None -> ctx | Some parent -> let _, _, proof = - generated_names ctx parent (registered_fun_name ctx parent) fspec + generated_names (registered_fun_name ctx parent) fspec in ExtractBase.ctx_add parent.item_meta.span (ProofObligationId proof_id) proof ctx) @@ -281,16 +326,12 @@ let emit_statement ctx fmt span (fn : Pure.FunDeclId.id) generics output_ty | Some post_fn -> emit_holds (arg_texprs @ [ res_texpr ]) post_fn))) (** Emit one [Spec.spec] entry *) -let emit_spec ctx fmt (s : HaxSpecs.spec) opt_span = +let emit_spec ctx fmt (s : HaxSpecs.spec) = let open ExtractBase in match s with | FunctionSpec { fn; pre; post } -> ( match Pure.FunDeclId.Map.find_opt fn ctx.trans_funs with - | None -> - [%warn_opt_span] opt_span - ("Trying to print a spec for an unknown function '" - ^ Pure.FunDeclId.to_string fn - ^ "'") + | None -> (* Reported by [register_spec_names] *) () | Some ft -> (* Register the pre/post conditions in the (local) context *) let reg f_opt ctx = @@ -364,7 +405,18 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) opt_span = F.pp_close_box fmt (); (* outer vbox *) F.pp_print_cut fmt ()) - | TraitSpec _ -> (* Not produced yet *) () + | TraitSpec { trait_decl; _ } + when not (Pure.TraitDeclId.Map.mem trait_decl ctx.trans_trait_decls) -> + (* Reported by [register_spec_names] *) () + | TraitSpec { methods; _ } -> + (* The conditions of the annotated methods *) + if methods <> [] then ( + (* Blank line before the entry. *) + F.pp_print_break fmt 0 0; + List.iter + (fun ({ pre; post; _ } : HaxSpecs.method_spec) -> + emit_conditions ctx fmt ~pre ~post) + methods) (** Emit one [HaxSpecs.obligation] entry as the proof obligation that discharges a spec's statement of correctness: @@ -373,16 +425,12 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) opt_span = ]} No attribute is emitted: registering the obligation with [mvcgen] (via [@[spec]]) is left to the user, who decides which specs to feed it. *) -let emit_obligation ctx fmt (o : HaxSpecs.obligation) opt_span = +let emit_obligation ctx fmt (o : HaxSpecs.obligation) = let open ExtractBase in match o with | FunctionContract { spec = { fn; _ }; proof } -> ( match Pure.FunDeclId.Map.find_opt fn ctx.trans_funs with - | None -> - [%warn_opt_span] opt_span - ("Trying to print a proof obligation for an unknown function '" - ^ Pure.FunDeclId.to_string fn - ^ "'") + | None -> (* Reported by [register_spec_names] *) () | Some ft -> let parent = ft.f in let span = parent.item_meta.span in diff --git a/src/extract/ExtractHaxSpecs.mli b/src/extract/ExtractHaxSpecs.mli index 0d4d9267eb..ff82e4b204 100644 --- a/src/extract/ExtractHaxSpecs.mli +++ b/src/extract/ExtractHaxSpecs.mli @@ -2,11 +2,13 @@ module F = Format -(** Registers the names generated for a spec (after the crate items) *) +(** Registers the names generated for a spec (after the crate items). The + [span option] is used for warnings *) val register_spec_names : ExtractBase.extraction_ctx -> Spec.SpecId.id -> HaxSpecs.spec -> + Meta.span option -> ExtractBase.extraction_ctx (** Registers the name of a proof obligation (after the crate items) *) @@ -16,19 +18,10 @@ val register_obligation_names : HaxSpecs.obligation -> ExtractBase.extraction_ctx -(** Emits one [HaxSpecs.spec] entry. The [span option] is used for errors *) +(** Emits one [HaxSpecs.spec] entry *) val emit_spec : - ExtractBase.extraction_ctx -> - F.formatter -> - HaxSpecs.spec -> - Meta.span option -> - unit + ExtractBase.extraction_ctx -> F.formatter -> HaxSpecs.spec -> unit -(** Emits one [HaxSpecs.obligation] entry. The [span option] is used for errors -*) +(** Emits one [HaxSpecs.obligation] entry *) val emit_obligation : - ExtractBase.extraction_ctx -> - F.formatter -> - HaxSpecs.obligation -> - Meta.span option -> - unit + ExtractBase.extraction_ctx -> F.formatter -> HaxSpecs.obligation -> unit diff --git a/src/extract/ExtractSpec.ml b/src/extract/ExtractSpec.ml index 90499e1ff9..dc779a79c5 100644 --- a/src/extract/ExtractSpec.ml +++ b/src/extract/ExtractSpec.ml @@ -7,12 +7,12 @@ module F = Format (** Emit one [Spec.spec] entry. *) let emit_spec ctx fmt (s : Spec.spec) = match s.kind with - | HaxSpec hs -> ExtractHaxSpecs.emit_spec ctx fmt hs s.span + | HaxSpec hs -> ExtractHaxSpecs.emit_spec ctx fmt hs (** Emit one [Spec.proof_obligation] entry. *) let emit_proof_obligation ctx fmt (o : Spec.proof_obligation) = match o.kind with - | HaxProof ho -> ExtractHaxSpecs.emit_obligation ctx fmt ho o.span + | HaxProof ho -> ExtractHaxSpecs.emit_obligation ctx fmt ho (** Register the names generated for the specs and proof obligations. Must be called after registering the crate items: clashes are reported as errors. *) @@ -22,7 +22,7 @@ let register_names (ctx : ExtractBase.extraction_ctx) : List.fold_left (fun ctx (s : Spec.spec) -> match s.kind with - | HaxSpec hs -> ExtractHaxSpecs.register_spec_names ctx s.id hs) + | HaxSpec hs -> ExtractHaxSpecs.register_spec_names ctx s.id hs s.span) ctx ctx.specs in List.fold_left diff --git a/src/specs/HaxProducer.ml b/src/specs/HaxProducer.ml index 6e0123ea54..6fc46e0637 100644 --- a/src/specs/HaxProducer.ml +++ b/src/specs/HaxProducer.ml @@ -12,9 +12,32 @@ open HaxAttributes let log = Logging.translate_log +(** The item contracts are attached to *) +type parent = Fun of Pure.fun_decl | Method of Pure.trait_method + +(** The name of [parent], for messages *) +let parent_name (ctx : TranslateCore.trans_ctx) : parent -> string = function + | Fun f -> f.name + | Method m -> TranslateCore.name_to_string ctx m.item_meta.name + +(** The LLBC name of [parent] *) +let parent_llbc_name : parent -> Types.name = function + | Fun f -> f.item_meta.name + | Method m -> m.item_meta.name + +(** The span of [parent] *) +let parent_span : parent -> Meta.span = function + | Fun f -> f.item_meta.span + | Method m -> m.item_meta.span + +(** The number of inputs of [parent] *) +let parent_arity : parent -> int = function + | Fun f -> List.length f.signature.inputs + | Method m -> List.length m.signature.inputs + (** Per-parent accumulator while scanning attributes. *) type assoc = { - parent : Pure.fun_decl; + parent : parent; requires_uid : string option; ensures_uid : string option; } @@ -23,11 +46,12 @@ let empty_assoc parent = { parent; requires_uid = None; ensures_uid = None } (** Update an accumulator with one [AssociatedItem]. Per design we accept at most one of each role per fn: extras are logged and ignored. *) -let update_assoc (role : hax_role) (uid : string) (a : assoc) : assoc = +let update_assoc (ctx : TranslateCore.trans_ctx) (role : hax_role) + (uid : string) (a : assoc) : assoc = let warn_extra side = [%lwarning Printf.sprintf "hax-specs: multiple #[%s] on fn `%s`; ignoring extras" - side a.parent.name] + side (parent_name ctx a.parent)] in match role with | Requires -> ( @@ -44,10 +68,19 @@ let update_assoc (role : hax_role) (uid : string) (a : assoc) : assoc = a) | Other_role -> a -(** Read a hax-annotated crate: emit one [FunctionSpec] per real fn that carries - [AssociatedItem] attribute(s), and strip the decoration fns whose bodies - have been folded into those specs. *) -let produce (_ctx : TranslateCore.trans_ctx) +(** The uids referenced by the [AssociatedItem]s among [attributes] *) +let associated_uids (attributes : Charon.Meta.attribute list) : string list = + List.filter_map + (fun a -> + match parse_attr a with + | Some (Associated_item { uid; _ }) -> Some uid + | _ -> None) + attributes + +(** Read a hax-annotated crate: emit one [TraitSpec] per local trait and one + [FunctionSpec] per real fn that carries [AssociatedItem] attribute(s), and + strip the decoration fns whose bodies have been folded into those specs. *) +let produce (ctx : TranslateCore.trans_ctx) (crate : TranslateCore.translated_crate) : TranslateCore.translated_crate = let _, fresh_spec_id = Spec.SpecId.fresh_stateful_generator () in let _, fresh_proof_id = Spec.ProofId.fresh_stateful_generator () in @@ -62,6 +95,13 @@ let produce (_ctx : TranslateCore.trans_ctx) List.iter (fun (ft : TranslateCore.pure_fun_translation) -> let f = ft.f in + (* The contracts of a default method are also on the trait's method + entry: we read them from there (pass 2) *) + let is_default = + match f.src with + | TraitDefaultFun _ -> true + | _ -> false + in List.iter (fun a -> match parse_attr a with @@ -69,21 +109,22 @@ let produce (_ctx : TranslateCore.trans_ctx) | Some (Uid uid) -> uid_map := Collections.StringMap.add uid f !uid_map; dec_set := Pure.FunDeclId.Set.add f.def_id !dec_set + | Some (Associated_item _) when is_default -> () | Some (Associated_item { role; uid }) -> let cur = match Pure.FunDeclId.Map.find_opt f.def_id !assoc_map with | Some a -> a - | None -> empty_assoc f + | None -> empty_assoc (Fun f) in assoc_map := Pure.FunDeclId.Map.add f.def_id - (update_assoc role uid cur) + (update_assoc ctx role uid cur) !assoc_map) f.item_meta.attr_info.attributes) crate.fun_decls; (* Pass 2: resolve uids to decoration fns and build [Spec.spec] / - [Spec.proof_obligation] entries. + [Spec.proof_obligation] entries, for the traits then for the fns. A decoration fn is reused as a proper function: we rename it to [::] and mark it [reducible], so the standard function @@ -93,22 +134,22 @@ let produce (_ctx : TranslateCore.trans_ctx) whole [Pure.fun_decl] is stashed in the spec (it is stripped from [crate.fun_decls] in pass 3, so it isn't also printed among the regular functions). *) - let rename_decoration (parent : Pure.fun_decl) (suffix : string) + let rename_decoration (parent : parent) (suffix : string) (dec : Pure.fun_decl) : Pure.fun_decl = let name = - parent.item_meta.name + parent_llbc_name parent @ [ Types.PeIdent (suffix, Pure.Disambiguator.zero) ] in let item_meta = { dec.item_meta with name } in { dec with item_meta; - name = parent.name ^ "." ^ suffix; + name = parent_name ctx parent ^ "." ^ suffix; backend_attributes = { reducible = true }; } in (* Resolve a decoration uid. Checks the arity. *) - let lookup_dec (parent : Pure.fun_decl) ~(suffix : string) ?(is_post = false) + let lookup_dec (parent : parent) ~(suffix : string) ?(is_post = false) (uid : string) : Pure.fun_decl option = match Collections.StringMap.find_opt uid !uid_map with | None -> @@ -116,13 +157,11 @@ let produce (_ctx : TranslateCore.trans_ctx) Printf.sprintf "hax-specs: fn `%s` references unknown decoration uid %s; skipping \ that side" - parent.name uid]; + (parent_name ctx parent) uid]; None | Some dec -> let decl = rename_decoration parent suffix dec in - let expected_arity = - List.length parent.signature.inputs + if is_post then 1 else 0 - in + let expected_arity = parent_arity parent + if is_post then 1 else 0 in let actual_arity = List.length decl.signature.inputs in if expected_arity = actual_arity then Some decl else begin @@ -130,7 +169,7 @@ let produce (_ctx : TranslateCore.trans_ctx) Printf.sprintf "hax-specs: argument count mismatch for `%s.%s` (takes %d, \ expected %d); dropping this condition" - parent.name suffix actual_arity expected_arity]; + (parent_name ctx parent) suffix actual_arity expected_arity]; None end in @@ -138,20 +177,68 @@ let produce (_ctx : TranslateCore.trans_ctx) | None -> "absent" | Some _ -> "present" in + (* Resolve the pre/post conditions of an accumulator *) + let lookup_conds (a : assoc) : Pure.fun_decl option * Pure.fun_decl option = + ( Option.bind a.requires_uid (lookup_dec a.parent ~suffix:"pre"), + Option.bind a.ensures_uid + (lookup_dec a.parent ~suffix:"post" ~is_post:true) ) + in + (* The contracts of the local traits, in the order of the declaration groups + (parents first). Every local trait gets one, even without annotated + methods. *) + let trait_decls = + Pure.TraitDeclId.Map.of_list + (List.map (fun (d : Pure.trait_decl) -> (d.def_id, d)) crate.trait_decls) + in + let method_spec (m : Pure.trait_method) : HaxSpecs.method_spec option = + let a = + List.fold_left + (fun a attr -> + match parse_attr attr with + | Some (Associated_item { role; uid }) -> update_assoc ctx role uid a + | _ -> a) + (empty_assoc (Method m)) m.item_meta.attr_info.attributes + in + match lookup_conds a with + | None, None -> None + | pre, post -> Some { method_id = m.method_id; pre; post } + in + let local_trait_decls = + List.concat_map + (fun (g : LlbcAst.declaration_group) -> + match g with + | TraitDeclGroup g -> + List.filter_map + (fun id -> + match Pure.TraitDeclId.Map.find_opt id trait_decls with + | Some (d : Pure.trait_decl) when d.item_meta.is_local -> Some d + | _ -> None) + (Charon.GAstUtils.g_declaration_group_to_list g) + | _ -> []) + (Option.get ctx.crate.declarations) + in + let trait_specs = + List.map + (fun (d : Pure.trait_decl) : Spec.spec -> + let methods = List.filter_map method_spec d.methods in + { + id = fresh_spec_id (); + span = Some d.item_meta.span; + kind = HaxSpec (TraitSpec { trait_decl = d.def_id; methods }); + }) + local_trait_decls + in + (* Build the spec (statement of correctness) and the proof obligation that discharges it, for one parent fn's accumulated [AssociatedItem]s. *) let build_entry (parent_id, a) : (Spec.spec * Spec.proof_obligation) option = - let pre = Option.bind a.requires_uid (lookup_dec a.parent ~suffix:"pre") in - let post = - Option.bind a.ensures_uid - (lookup_dec a.parent ~suffix:"post" ~is_post:true) - in + let pre, post = lookup_conds a in if Option.is_none pre && Option.is_none post then None else ( [%ltrace - Printf.sprintf "hax-specs: fn=%s pre=%s post=%s" a.parent.name - (shape pre) (shape post)]; - let span = Some a.parent.item_meta.span in + Printf.sprintf "hax-specs: fn=%s pre=%s post=%s" + (parent_name ctx a.parent) (shape pre) (shape post)]; + let span = Some (parent_span a.parent) in (* One [function_spec] payload, shared between the spec and the proof obligation that discharges it. *) let fspec : HaxSpecs.function_spec = { fn = parent_id; pre; post } in @@ -173,21 +260,75 @@ let produce (_ctx : TranslateCore.trans_ctx) |> List.split in - (* Pass 3: strip consumed decoration fns from [crate.fun_decls]. *) + (* Pass 3: strip the decoration fns from [crate.fun_decls]. Those that are + not consumed are reported: as a warning when no translated item refers to + them, in the log otherwise (unsupported role such as [decreases], extra + condition, argument count mismatch) *) + let referenced = + Collections.StringSet.of_list + (List.concat_map + (fun (ft : TranslateCore.pure_fun_translation) -> + associated_uids ft.f.item_meta.attr_info.attributes) + crate.fun_decls + @ List.concat_map + (fun (d : Pure.trait_decl) -> + List.concat_map + (fun (m : Pure.trait_method) -> + associated_uids m.item_meta.attr_info.attributes) + d.methods) + local_trait_decls) + in + (* The decorations stashed in the specs keep their [def_id] *) + let consumed = + let conds (s : Spec.spec) : Pure.fun_decl option list = + match s.kind with + | HaxSpec (FunctionSpec { pre; post; _ }) -> [ pre; post ] + | HaxSpec (TraitSpec { methods; _ }) -> + List.concat_map + (fun (m : HaxSpecs.method_spec) -> [ m.pre; m.post ]) + methods + in + Pure.FunDeclId.Set.of_list + (List.filter_map + (Option.map (fun (f : Pure.fun_decl) -> f.def_id)) + (List.concat_map conds (trait_specs @ new_specs))) + in + let report_dropped (dec : Pure.fun_decl) = + if not (Pure.FunDeclId.Set.mem dec.def_id consumed) then + List.iter + (fun a -> + match parse_attr a with + | Some (Uid uid) -> + let msg reason = + Printf.sprintf "hax-specs: dropping the hax decoration `%s`: %s" + dec.name reason + in + if Collections.StringSet.mem uid referenced then + [%lwarning msg "unsupported or invalid annotation"] + else + [%warn] dec.item_meta.span + (msg "it is attached to no translated item") + | _ -> ()) + dec.item_meta.attr_info.attributes + in let new_fun_decls = List.filter (fun (ft : TranslateCore.pure_fun_translation) -> - not (Pure.FunDeclId.Set.mem ft.f.def_id !dec_set)) + if Pure.FunDeclId.Set.mem ft.f.def_id !dec_set then ( + report_dropped ft.f; + false) + else true) crate.fun_decls in [%linfo - Printf.sprintf "hax-specs: produced %d FunctionSpec entries" - (List.length new_specs)]; + Printf.sprintf + "hax-specs: produced %d TraitSpec and %d FunctionSpec entries" + (List.length trait_specs) (List.length new_specs)]; { crate with fun_decls = new_fun_decls; - specs = crate.specs @ new_specs; + specs = crate.specs @ trait_specs @ new_specs; proof_obligations = crate.proof_obligations @ new_obligations; } diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean index 1b11f418bf..23067c2a1e 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean @@ -279,13 +279,6 @@ theorem specs.traits.trait_generics.use_conv.spec ConvCU8Inst c := by sorry -theorem - specs.traits.default_methods.D.next.default.spec.proof {Self : Type} (DInst : - specs.traits.default_methods.D - Self) (self : Self) : - specs.traits.default_methods.D.next.default.spec DInst self - := by sorry - theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec.proof (self : Std.U32) : U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec self := by sorry diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index e51cd5ec1f..941114cdd4 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -28,6 +28,344 @@ noncomputable section namespace hax_tests +/-- [hax_tests::specs::traits::assoc_type_bounds::Bar::bar::post]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 8:0-8:22 -/ +@[reducible] +def specs.traits.assoc_type_bounds.Bar.bar.post + {Self_ : Type} (BarInst : specs.traits.assoc_type_bounds.Bar Self_) + (self_ : Self_) (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + + +/-- [hax_tests::specs::traits::assoc_type_bounds::Container::first::post]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 14:0-14:22 -/ +@[reducible] +def specs.traits.assoc_type_bounds.Container.first.post + {Self_ : Type} {Clause0_Item : Type} (ContainerInst : + specs.traits.assoc_type_bounds.Container Self_ Clause0_Item) (self_ : Self_) + (item : Clause0_Item) : + RustM Bool + := do + let i ← ContainerInst.BarInst.bar item + ok (i < 10#u32) + + +/-- [hax_tests::specs::traits::basic::Foo::f1::post]: + Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.basic.Foo.f1.post + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) (self_ : Self_) + (b : Bool) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::basic::Foo::f2::pre]: + Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.basic.Foo.f2.pre + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) (self_ : Self_) : + RustM Bool + := do + FooInst.f1 self_ + +/-- [hax_tests::specs::traits::basic::Foo::f2::post]: + Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.basic.Foo.f2.post + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) (self_ : Self_) + (res : Std.U64) : + RustM Bool + := do + ok (res <= 10#u64) + +/-- [hax_tests::specs::traits::basic::Foo::make::post]: + Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.basic.Foo.make.post + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) (x : Std.U32) + (res : Self_) : + RustM Bool + := do + FooInst.f1 res + +/-- [hax_tests::specs::traits::basic::Foo::zero::post]: + Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.basic.Foo.zero.post + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) (res : Self_) : + RustM Bool + := do + FooInst.f1 res + + +/-- [hax_tests::specs::traits::blanket_impl::Show::show::post]: + Source: 'src/specs/traits/blanket_impl.rs', lines 9:0-9:22 -/ +@[reducible] +def specs.traits.blanket_impl.Show.show.post + {Self_ : Type} (ShowInst : specs.traits.blanket_impl.Show Self_) + (self_ : Self_) (res : Std.U64) : + RustM Bool + := do + ok (res <= 20#u64) + + +/-- [hax_tests::specs::traits::builtin_bound::Dup::dup::post]: + Source: 'src/specs/traits/builtin_bound.rs', lines 16:0-16:22 -/ +@[reducible] +def specs.traits.builtin_bound.Dup.dup.post + {Self_ : Type} (corecloneCloneInst : core.clone.Clone Self_) (DupInst : + specs.traits.builtin_bound.Dup Self_) (self_ : Self_) (p : (Self_ × Self_)) + : + RustM Bool + := do + ok true + + +/-- [hax_tests::specs::traits::default_methods::D::next::pre]: + Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.default_methods.D.next.pre + {Self_ : Type} (DInst : specs.traits.default_methods.D Self_) (self_ : Self_) + : + RustM Bool + := do + let i ← DInst.base self_ + ok (i < 100#u32) + +/-- [hax_tests::specs::traits::default_methods::D::next::post]: + Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.default_methods.D.next.post + {Self_ : Type} (DInst : specs.traits.default_methods.D Self_) (self_ : Self_) + (res : Std.U32) : + RustM Bool + := do + let i ← DInst.base self_ + ok (res > i) + + +/-- [hax_tests::specs::traits::diamond::A::a::post]: + Source: 'src/specs/traits/diamond.rs', lines 5:0-5:22 -/ +@[reducible] +def specs.traits.diamond.A.a.post + {Self_ : Type} (AInst : specs.traits.diamond.A Self_) (self_ : Self_) + (res : Std.Usize) : + RustM Bool + := do + if res >= 1#usize + then ok (res <= 100#usize) + else ok false + + +/-- [hax_tests::specs::traits::diamond::C::c::post]: + Source: 'src/specs/traits/diamond.rs', lines 15:0-15:22 -/ +@[reducible] +def specs.traits.diamond.C.c.post + {Self_ : Type} (AInst : specs.traits.diamond.A Self_) (BInst : + specs.traits.diamond.B Self_) (CInst : specs.traits.diamond.C Self_) + (self_ : Self_) (res : Std.Usize) : + RustM Bool + := do + let i ← AInst.a self_ + ok (res = i) + + +/-- [hax_tests::specs::traits::generic_impl::Foo::f::post]: + Source: 'src/specs/traits/generic_impl.rs', lines 8:0-8:22 -/ +@[reducible] +def specs.traits.generic_impl.Foo.f.post + {Self_ : Type} (FooInst : specs.traits.generic_impl.Foo Self_) + (self_ : Self_) (res : Std.U64) : + RustM Bool + := do + ok (res <= 10#u64) + + +/-- [hax_tests::specs::traits::generic_impl::Sub::s::post]: + Source: 'src/specs/traits/generic_impl.rs', lines 14:0-14:22 -/ +@[reducible] +def specs.traits.generic_impl.Sub.s.post + {Self_ : Type} (FooInst : specs.traits.generic_impl.Foo Self_) (SubInst : + specs.traits.generic_impl.Sub Self_) (self_ : Self_) (res : Std.U64) : + RustM Bool + := do + let i ← FooInst.f self_ + ok (res = i) + + +/-- [hax_tests::specs::traits::impl_contract::G::g::post]: + Source: 'src/specs/traits/impl_contract.rs', lines 21:0-21:22 -/ +@[reducible] +def specs.traits.impl_contract.G.g.post + {Self_ : Type} (GInst : specs.traits.impl_contract.G Self_) (self_ : Self_) + (res : Std.U32) : + RustM Bool + := do + ok (res > 0#u32) + + +/-- [hax_tests::specs::traits::method_generics::Bar::bar::post]: + Source: 'src/specs/traits/method_generics.rs', lines 5:0-5:22 -/ +@[reducible] +def specs.traits.method_generics.Bar.bar.post + {Self_ : Type} (BarInst : specs.traits.method_generics.Bar Self_) + (self_ : Self_) (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + + +/-- [hax_tests::specs::traits::method_generics::Foo::f::pre]: + Source: 'src/specs/traits/method_generics.rs', lines 11:0-11:22 -/ +@[reducible] +def specs.traits.method_generics.Foo.f.pre + {Self_ : Type} {U : Type} (BarInst : specs.traits.method_generics.Bar U) + (FooInst : specs.traits.method_generics.Foo Self_) (self_ : Self_) + (u : U) : + RustM Bool + := do + let i ← BarInst.bar u + ok (i < 5#u32) + +/-- [hax_tests::specs::traits::method_generics::Foo::f::post]: + Source: 'src/specs/traits/method_generics.rs', lines 11:0-11:22 -/ +@[reducible] +def specs.traits.method_generics.Foo.f.post + {Self_ : Type} {U : Type} (BarInst : specs.traits.method_generics.Bar U) + (FooInst : specs.traits.method_generics.Foo Self_) (self_ : Self_) + (u : U) (res : Std.U32) : + RustM Bool + := do + ok (res < 5#u32) + + +/-- [hax_tests::specs::traits::minimal::Foo::f::pre]: + Source: 'src/specs/traits/minimal.rs', lines 6:0-6:13 -/ +@[reducible] +def specs.traits.minimal.Foo.f.pre + {Self_ : Type} (FooInst : specs.traits.minimal.Foo Self_) (self_ : Self_) + (x : Std.U32) : + RustM Bool + := do + ok (x < 100#u32) + +/-- [hax_tests::specs::traits::minimal::Foo::f::post]: + Source: 'src/specs/traits/minimal.rs', lines 6:0-6:13 -/ +@[reducible] +def specs.traits.minimal.Foo.f.post + {Self_ : Type} (FooInst : specs.traits.minimal.Foo Self_) (self_ : Self_) + (x : Std.U32) (res : Std.U32) : + RustM Bool + := do + ok (res > x) + +/-- [hax_tests::specs::traits::minimal::Foo::h::pre]: + Source: 'src/specs/traits/minimal.rs', lines 6:0-6:13 -/ +@[reducible] +def specs.traits.minimal.Foo.h.pre + {Self_ : Type} (FooInst : specs.traits.minimal.Foo Self_) (self_ : Self_) + (x : Std.U32) : + RustM Bool + := do + ok (x > 0#u32) + + +/-- [hax_tests::specs::traits::mut_self::Counter::incr::pre]: + Source: 'src/specs/traits/mut_self.rs', lines 5:0-5:22 -/ +@[reducible] +def specs.traits.mut_self.Counter.incr.pre + {Self_ : Type} (CounterInst : specs.traits.mut_self.Counter Self_) + (self_ : Self_) : + RustM Bool + := do + let i ← CounterInst.get self_ + ok (i < 100#u32) + +/-- [hax_tests::specs::traits::mut_self::Counter::incr::post]: + Source: 'src/specs/traits/mut_self.rs', lines 5:0-5:22 -/ +@[reducible] +def specs.traits.mut_self.Counter.incr.post + {Self_ : Type} (CounterInst : specs.traits.mut_self.Counter Self_) + (self_ : Self_) (self__future : Self_) : + RustM Bool + := do + let i ← CounterInst.get self__future + let i1 ← CounterInst.get self_ + let i2 ← i1 + 1#u32 + ok (i = i2) + + +/-- [hax_tests::specs::traits::supertraits::A::a::post]: + Source: 'src/specs/traits/supertraits.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.supertraits.A.a.post + {Self_ : Type} (AInst : specs.traits.supertraits.A Self_) (self_ : Self_) + (res : Std.Usize) : + RustM Bool + := do + ok (res >= 1#usize) + + +/-- [hax_tests::specs::traits::supertraits::B::b::pre]: + Source: 'src/specs/traits/supertraits.rs', lines 12:0-12:22 -/ +@[reducible] +def specs.traits.supertraits.B.b.pre + {Self_ : Type} (AInst : specs.traits.supertraits.A Self_) (BInst : + specs.traits.supertraits.B Self_) (self_ : Self_) : + RustM Bool + := do + let i ← AInst.a self_ + ok (i < 100#usize) + +/-- [hax_tests::specs::traits::supertraits::B::b::post]: + Source: 'src/specs/traits/supertraits.rs', lines 12:0-12:22 -/ +@[reducible] +def specs.traits.supertraits.B.b.post + {Self_ : Type} (AInst : specs.traits.supertraits.A Self_) (BInst : + specs.traits.supertraits.B Self_) (self_ : Self_) (res : Std.Usize) : + RustM Bool + := do + let i ← AInst.a self_ + ok (res > i) + + +/-- [hax_tests::specs::traits::supertraits::Cc::c::post]: + Source: 'src/specs/traits/supertraits.rs', lines 19:0-19:22 -/ +@[reducible] +def specs.traits.supertraits.Cc.c.post + {Self_ : Type} (BInst : specs.traits.supertraits.B Self_) (CcInst : + specs.traits.supertraits.Cc Self_) (self_ : Self_) (res : Std.Usize) : + RustM Bool + := do + let i ← BInst.AInst.a self_ + ok (res > i) + + +/-- [hax_tests::specs::traits::trait_generics::Conv::conv::post]: + Source: 'src/specs/traits/trait_generics.rs', lines 5:0-5:22 -/ +@[reducible] +def specs.traits.trait_generics.Conv.conv.post + {Self_ : Type} {T : Type} (ConvInst : specs.traits.trait_generics.Conv Self_ + T) (self_ : Self_) (t : T) (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + + +/-- [hax_tests::specs::traits::unannotated_sub::A::a::post]: + Source: 'src/specs/traits/unannotated_sub.rs', lines 6:0-6:22 -/ +@[reducible] +def specs.traits.unannotated_sub.A.a.post + {Self_ : Type} (AInst : specs.traits.unannotated_sub.A Self_) (self_ : Self_) + (res : Std.U32) : + RustM Bool + := do + ok (res > 0#u32) + + /-- [hax_tests::specs::contracts::only_requires::pre]: Source: 'src/specs/contracts.rs', lines 3:0-3:20 -/ @[reducible] @@ -1185,39 +1523,6 @@ def ⦄ -/-- [hax_tests::specs::traits::default_methods::D::next::pre]: - Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ -@[reducible] -def specs.traits.default_methods.D.next.pre - {Self_ : Type} (DInst : specs.traits.default_methods.D Self_) (self_ : Self_) - : - RustM Bool - := do - let i ← DInst.base self_ - ok (i < 100#u32) - -/-- [hax_tests::specs::traits::default_methods::D::next::post]: - Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ -@[reducible] -def specs.traits.default_methods.D.next.post - {Self_ : Type} (DInst : specs.traits.default_methods.D Self_) (self_ : Self_) - (res : Std.U32) : - RustM Bool - := do - let i ← DInst.base self_ - ok (res > i) - -def - specs.traits.default_methods.D.next.default.spec {Self : Type} (DInst : - specs.traits.default_methods.D - Self) (self : Self) : Prop := - (specs.traits.default_methods.D.next.pre DInst self).holds → - ⦃ ⌜ True ⌝ ⦄ - specs.traits.default_methods.D.next.default DInst self - ⦃ ⇓ res => - ⌜ (specs.traits.default_methods.D.next.post DInst self res).holds ⌝ ⦄ - - /-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f::pre]: Source: 'src/specs/traits/impl_contract.rs', lines 14:4-14:28 -/ @[reducible] From 062709309e7981c4d2a75437bdab044e42203b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Tue, 13 Oct 2026 09:48:23 +0200 Subject: [PATCH 05/17] feat-specs: synthesize missing pre/post --- src/specs/HaxProducer.ml | 162 +++++++++- .../lean/HaxTests/Extraction/Specs.lean | 297 ++++++++++++++++++ .../lean/HaxTests/Extraction/Types.lean | 18 ++ tests/hax/src/specs/traits.rs | 1 + tests/hax/src/specs/traits/synthesized.rs | 41 +++ 5 files changed, 509 insertions(+), 10 deletions(-) create mode 100644 tests/hax/src/specs/traits/synthesized.rs diff --git a/src/specs/HaxProducer.ml b/src/specs/HaxProducer.ml index 6fc46e0637..5c712a05f2 100644 --- a/src/specs/HaxProducer.ml +++ b/src/specs/HaxProducer.ml @@ -45,13 +45,13 @@ type assoc = { let empty_assoc parent = { parent; requires_uid = None; ensures_uid = None } (** Update an accumulator with one [AssociatedItem]. Per design we accept at - most one of each role per fn: extras are logged and ignored. *) + most one of each role per item: extras are logged and ignored. *) let update_assoc (ctx : TranslateCore.trans_ctx) (role : hax_role) (uid : string) (a : assoc) : assoc = let warn_extra side = [%lwarning - Printf.sprintf "hax-specs: multiple #[%s] on fn `%s`; ignoring extras" - side (parent_name ctx a.parent)] + Printf.sprintf "hax-specs: multiple #[%s] on `%s`; ignoring extras" side + (parent_name ctx a.parent)] in match role with | Requires -> ( @@ -155,7 +155,7 @@ let produce (ctx : TranslateCore.trans_ctx) | None -> [%lwarning Printf.sprintf - "hax-specs: fn `%s` references unknown decoration uid %s; skipping \ + "hax-specs: `%s` references unknown decoration uid %s; skipping \ that side" (parent_name ctx parent) uid]; None @@ -183,6 +183,108 @@ let produce (ctx : TranslateCore.trans_ctx) Option.bind a.ensures_uid (lookup_dec a.parent ~suffix:"post" ~is_post:true) ) in + (* The conditions of the trait methods that hax has no annotation for are + synthesized as [ok true]. They get fresh ids, after those of the crate. *) + let _, fresh_fun_id = + Pure.FunDeclId.mk_stateful_generator + (match Pure.FunDeclId.Map.max_binding_opt ctx.crate.fun_decls with + | None -> Pure.FunDeclId.generator_zero + | Some (id, _) -> Pure.FunDeclId.generator_from_incr_id id) + in + (* The condition [.] with the given [inputs] and body [ok true]. + The rest is taken from the other condition [dec]. *) + let synthesize_cond (m : Pure.trait_method) (suffix : string) + (dec : Pure.fun_decl) (inputs : Pure.tpat list) : Pure.fun_decl = + let span = m.item_meta.span in + let sg = dec.signature in + let input_tys = List.map (fun (p : Pure.tpat) -> p.ty) inputs in + let explicit_info = PureUtils.compute_explicit_info sg.generics input_tys in + let signature = + { + sg with + inputs = input_tys; + explicit_info; + known_from_trait_refs = + PureUtils.compute_known_info explicit_info sg.generics; + } + in + let body : Pure.fun_body = + { inputs; body = PureUtils.mk_result_ok_texpr span PureUtils.mk_true } + in + rename_decoration (Method m) suffix + { + dec with + def_id = fresh_fun_id (); + item_meta = + { + dec.item_meta with + span; + attr_info = { dec.item_meta.attr_info with attributes = [] }; + }; + signature; + body = Some body; + } + in + (* The inputs of a condition *) + let cond_inputs (m : Pure.trait_method) (dec : Pure.fun_decl) : Pure.tpat list + = + match dec.body with + | Some b -> b.inputs + | None -> + [%craise] m.item_meta.span + ("hax-specs: cannot synthesize the missing condition of `" + ^ parent_name ctx (Method m) ^ "`: the other one has no body") + in + (* The output type of the method [m] of [d], in the generics of its + condition [dec]. The type parameters of the decoration fns are those of + the trait then those of the method, as in the flattened signature of the + method. *) + let method_output_ty (d : Pure.trait_decl) (m : Pure.trait_method) + (dec : Pure.fun_decl) : Pure.ty = + let span = m.item_meta.span in + let name = parent_name ctx (Method m) in + let llbc_decl = Pure.TraitDeclId.Map.find d.def_id ctx.crate.trait_decls in + let sg = + (SymbolicToPureTypes.translate_flat_trait_method_sigs ctx llbc_decl + m.method_id + (Pure.TraitMethodId.Map.find m.method_id llbc_decl.methods)) + .sg + in + let params = sg.generics in + let args = PureUtils.generic_args_of_params dec.signature.generics in + [%cassert] span + (List.length params.types = List.length args.types + && List.length params.const_generics = List.length args.const_generics) + ("Internal error: the generics of the conditions of `" ^ name + ^ "` don't match those of the trait and the method"); + let unsupported () = + [%craise] span + ("hax-specs: cannot synthesize the postcondition of `" ^ name + ^ "`: trait instances in its output type are not supported yet") + in + let subst : PureUtils.subst = + { + ty_subst = PureUtils.make_type_subst params.types args.types; + cg_subst = + PureUtils.make_const_generic_subst params.const_generics + args.const_generics; + tr_subst = (fun _ -> unsupported ()); + tr_self = Self (* Unused: see [visit_Self] *); + } + in + let visitor = + object + inherit [_] PureUtils.subst_visitor + method! visit_Self _ = unsupported () + end + in + let output = + if sg.fwd_info.effect_info.can_fail then + PureUtils.unwrap_result_ty span sg.output + else sg.output + in + visitor#visit_ty subst output + in (* The contracts of the local traits, in the order of the declaration groups (parents first). Every local trait gets one, even without annotated methods. *) @@ -190,7 +292,8 @@ let produce (ctx : TranslateCore.trans_ctx) Pure.TraitDeclId.Map.of_list (List.map (fun (d : Pure.trait_decl) -> (d.def_id, d)) crate.trait_decls) in - let method_spec (m : Pure.trait_method) : HaxSpecs.method_spec option = + let method_spec (d : Pure.trait_decl) (m : Pure.trait_method) : + HaxSpecs.method_spec option = let a = List.fold_left (fun a attr -> @@ -199,9 +302,44 @@ let produce (ctx : TranslateCore.trans_ctx) | _ -> a) (empty_assoc (Method m)) m.item_meta.attr_info.attributes in + let spec pre post : HaxSpecs.method_spec option = + Some { method_id = m.method_id; pre = Some pre; post = Some post } + in + let warn_drop reason = + [%warn] m.item_meta.span + ("hax-specs: dropping the contract of trait method `" + ^ parent_name ctx (Method m) ^ "`: " ^ reason); + None + in + (* Only the conditions without annotation are synthesized: if an annotated + one was dropped (see [lookup_dec]), so is the whole contract of [m] *) + let dropped uid cond = Option.is_some uid && Option.is_none cond in match lookup_conds a with - | None, None -> None - | pre, post -> Some { method_id = m.method_id; pre; post } + | pre, _ when dropped a.requires_uid pre -> + warn_drop "its #[requires] is invalid" + | _, post when dropped a.ensures_uid post -> + warn_drop "its #[ensures] is invalid" + | pre, post -> ( + (* A failure to synthesize a condition only drops the contract of [m] *) + try + match (pre, post) with + | None, None -> None + | Some pre, Some post -> spec pre post + | None, Some post -> + (* The inputs of [post] but the result *) + let inputs = + fst (Collections.List.pop_last (cond_inputs m post)) + in + spec (synthesize_cond m "pre" post inputs) post + | Some pre, None -> + let ty = method_output_ty d m pre in + let res : Pure.tpat = + { pat = PBound ({ basename = Some "res"; ty }, None); ty } + in + let inputs = cond_inputs m pre @ [ res ] in + spec pre (synthesize_cond m "post" pre inputs) + with Errors.CFailure _ -> + warn_drop "a missing condition could not be synthesized") in let local_trait_decls = List.concat_map @@ -220,7 +358,7 @@ let produce (ctx : TranslateCore.trans_ctx) let trait_specs = List.map (fun (d : Pure.trait_decl) : Spec.spec -> - let methods = List.filter_map method_spec d.methods in + let methods = List.filter_map (method_spec d) d.methods in { id = fresh_spec_id (); span = Some d.item_meta.span; @@ -263,7 +401,8 @@ let produce (ctx : TranslateCore.trans_ctx) (* Pass 3: strip the decoration fns from [crate.fun_decls]. Those that are not consumed are reported: as a warning when no translated item refers to them, in the log otherwise (unsupported role such as [decreases], extra - condition, argument count mismatch) *) + condition, argument count mismatch, valid condition of a trait method + whose contract was dropped) *) let referenced = Collections.StringSet.of_list (List.concat_map @@ -304,7 +443,10 @@ let produce (ctx : TranslateCore.trans_ctx) dec.name reason in if Collections.StringSet.mem uid referenced then - [%lwarning msg "unsupported or invalid annotation"] + [%lwarning + msg + "unsupported or invalid annotation, or part of a dropped \ + contract"] else [%warn] dec.item_meta.span (msg "it is attached to no translated item") diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index 941114cdd4..dd46657cba 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -28,6 +28,16 @@ noncomputable section namespace hax_tests +/-- [hax_tests::specs::traits::assoc_type_bounds::Bar::bar::pre]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 11:4-11:25 -/ +@[reducible] +def specs.traits.assoc_type_bounds.Bar.bar.pre + {Self_ : Type} (BarInst : specs.traits.assoc_type_bounds.Bar Self_) + (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::assoc_type_bounds::Bar::bar::post]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 8:0-8:22 -/ @[reducible] @@ -39,6 +49,17 @@ def specs.traits.assoc_type_bounds.Bar.bar.post ok (res < 10#u32) +/-- [hax_tests::specs::traits::assoc_type_bounds::Container::first::pre]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 19:4-19:34 -/ +@[reducible] +def specs.traits.assoc_type_bounds.Container.first.pre + {Self_ : Type} {Clause0_Item : Type} (ContainerInst : + specs.traits.assoc_type_bounds.Container Self_ Clause0_Item) (self_ : Self_) + : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::assoc_type_bounds::Container::first::post]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 14:0-14:22 -/ @[reducible] @@ -52,6 +73,15 @@ def specs.traits.assoc_type_bounds.Container.first.post ok (i < 10#u32) +/-- [hax_tests::specs::traits::basic::Foo::f1::pre]: + Source: 'src/specs/traits/basic.rs', lines 9:4-9:25 -/ +@[reducible] +def specs.traits.basic.Foo.f1.pre + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::basic::Foo::f1::post]: Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ @[reducible] @@ -81,6 +111,15 @@ def specs.traits.basic.Foo.f2.post := do ok (res <= 10#u64) +/-- [hax_tests::specs::traits::basic::Foo::make::pre]: + Source: 'src/specs/traits/basic.rs', lines 16:4-16:28 -/ +@[reducible] +def specs.traits.basic.Foo.make.pre + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) (x : Std.U32) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::basic::Foo::make::post]: Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ @[reducible] @@ -91,6 +130,13 @@ def specs.traits.basic.Foo.make.post := do FooInst.f1 res +/-- [hax_tests::specs::traits::basic::Foo::zero::pre]: + Source: 'src/specs/traits/basic.rs', lines 19:4-19:22 -/ +@[reducible] +def specs.traits.basic.Foo.zero.pre + {Self_ : Type} (FooInst : specs.traits.basic.Foo Self_) : RustM Bool := do + ok true + /-- [hax_tests::specs::traits::basic::Foo::zero::post]: Source: 'src/specs/traits/basic.rs', lines 6:0-6:22 -/ @[reducible] @@ -101,6 +147,16 @@ def specs.traits.basic.Foo.zero.post FooInst.f1 res +/-- [hax_tests::specs::traits::blanket_impl::Show::show::pre]: + Source: 'src/specs/traits/blanket_impl.rs', lines 12:4-12:26 -/ +@[reducible] +def specs.traits.blanket_impl.Show.show.pre + {Self_ : Type} (ShowInst : specs.traits.blanket_impl.Show Self_) + (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::blanket_impl::Show::show::post]: Source: 'src/specs/traits/blanket_impl.rs', lines 9:0-9:22 -/ @[reducible] @@ -112,6 +168,16 @@ def specs.traits.blanket_impl.Show.show.post ok (res <= 20#u64) +/-- [hax_tests::specs::traits::builtin_bound::Dup::dup::pre]: + Source: 'src/specs/traits/builtin_bound.rs', lines 19:4-19:34 -/ +@[reducible] +def specs.traits.builtin_bound.Dup.dup.pre + {Self_ : Type} (corecloneCloneInst : core.clone.Clone Self_) (DupInst : + specs.traits.builtin_bound.Dup Self_) (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::builtin_bound::Dup::dup::post]: Source: 'src/specs/traits/builtin_bound.rs', lines 16:0-16:22 -/ @[reducible] @@ -147,6 +213,15 @@ def specs.traits.default_methods.D.next.post ok (res > i) +/-- [hax_tests::specs::traits::diamond::A::a::pre]: + Source: 'src/specs/traits/diamond.rs', lines 8:4-8:25 -/ +@[reducible] +def specs.traits.diamond.A.a.pre + {Self_ : Type} (AInst : specs.traits.diamond.A Self_) (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::diamond::A::a::post]: Source: 'src/specs/traits/diamond.rs', lines 5:0-5:22 -/ @[reducible] @@ -160,6 +235,17 @@ def specs.traits.diamond.A.a.post else ok false +/-- [hax_tests::specs::traits::diamond::C::c::pre]: + Source: 'src/specs/traits/diamond.rs', lines 18:4-18:25 -/ +@[reducible] +def specs.traits.diamond.C.c.pre + {Self_ : Type} (AInst : specs.traits.diamond.A Self_) (BInst : + specs.traits.diamond.B Self_) (CInst : specs.traits.diamond.C Self_) + (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::diamond::C::c::post]: Source: 'src/specs/traits/diamond.rs', lines 15:0-15:22 -/ @[reducible] @@ -173,6 +259,16 @@ def specs.traits.diamond.C.c.post ok (res = i) +/-- [hax_tests::specs::traits::generic_impl::Foo::f::pre]: + Source: 'src/specs/traits/generic_impl.rs', lines 11:4-11:23 -/ +@[reducible] +def specs.traits.generic_impl.Foo.f.pre + {Self_ : Type} (FooInst : specs.traits.generic_impl.Foo Self_) + (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::generic_impl::Foo::f::post]: Source: 'src/specs/traits/generic_impl.rs', lines 8:0-8:22 -/ @[reducible] @@ -184,6 +280,16 @@ def specs.traits.generic_impl.Foo.f.post ok (res <= 10#u64) +/-- [hax_tests::specs::traits::generic_impl::Sub::s::pre]: + Source: 'src/specs/traits/generic_impl.rs', lines 17:4-17:23 -/ +@[reducible] +def specs.traits.generic_impl.Sub.s.pre + {Self_ : Type} (FooInst : specs.traits.generic_impl.Foo Self_) (SubInst : + specs.traits.generic_impl.Sub Self_) (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::generic_impl::Sub::s::post]: Source: 'src/specs/traits/generic_impl.rs', lines 14:0-14:22 -/ @[reducible] @@ -196,6 +302,15 @@ def specs.traits.generic_impl.Sub.s.post ok (res = i) +/-- [hax_tests::specs::traits::impl_contract::G::g::pre]: + Source: 'src/specs/traits/impl_contract.rs', lines 24:4-24:23 -/ +@[reducible] +def specs.traits.impl_contract.G.g.pre + {Self_ : Type} (GInst : specs.traits.impl_contract.G Self_) (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::impl_contract::G::g::post]: Source: 'src/specs/traits/impl_contract.rs', lines 21:0-21:22 -/ @[reducible] @@ -207,6 +322,16 @@ def specs.traits.impl_contract.G.g.post ok (res > 0#u32) +/-- [hax_tests::specs::traits::method_generics::Bar::bar::pre]: + Source: 'src/specs/traits/method_generics.rs', lines 8:4-8:25 -/ +@[reducible] +def specs.traits.method_generics.Bar.bar.pre + {Self_ : Type} (BarInst : specs.traits.method_generics.Bar Self_) + (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::method_generics::Bar::bar::post]: Source: 'src/specs/traits/method_generics.rs', lines 5:0-5:22 -/ @[reducible] @@ -272,6 +397,16 @@ def specs.traits.minimal.Foo.h.pre := do ok (x > 0#u32) +/-- [hax_tests::specs::traits::minimal::Foo::h::post]: + Source: 'src/specs/traits/minimal.rs', lines 15:4-15:31 -/ +@[reducible] +def specs.traits.minimal.Foo.h.post + {Self_ : Type} (FooInst : specs.traits.minimal.Foo Self_) (self_ : Self_) + (x : Std.U32) (res : Std.U32) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::mut_self::Counter::incr::pre]: Source: 'src/specs/traits/mut_self.rs', lines 5:0-5:22 -/ @@ -298,6 +433,15 @@ def specs.traits.mut_self.Counter.incr.post ok (i = i2) +/-- [hax_tests::specs::traits::supertraits::A::a::pre]: + Source: 'src/specs/traits/supertraits.rs', lines 9:4-9:25 -/ +@[reducible] +def specs.traits.supertraits.A.a.pre + {Self_ : Type} (AInst : specs.traits.supertraits.A Self_) (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::supertraits::A::a::post]: Source: 'src/specs/traits/supertraits.rs', lines 6:0-6:22 -/ @[reducible] @@ -332,6 +476,16 @@ def specs.traits.supertraits.B.b.post ok (res > i) +/-- [hax_tests::specs::traits::supertraits::Cc::c::pre]: + Source: 'src/specs/traits/supertraits.rs', lines 22:4-22:25 -/ +@[reducible] +def specs.traits.supertraits.Cc.c.pre + {Self_ : Type} (BInst : specs.traits.supertraits.B Self_) (CcInst : + specs.traits.supertraits.Cc Self_) (self_ : Self_) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::supertraits::Cc::c::post]: Source: 'src/specs/traits/supertraits.rs', lines 19:0-19:22 -/ @[reducible] @@ -344,6 +498,139 @@ def specs.traits.supertraits.Cc.c.post ok (res > i) +/-- [hax_tests::specs::traits::synthesized::Gen::pick::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 11:4-11:30 -/ +@[reducible] +def specs.traits.synthesized.Gen.pick.pre + {Self_ : Type} (U : Type) (GenInst : specs.traits.synthesized.Gen Self_) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Gen::pick::post]: + Source: 'src/specs/traits/synthesized.rs', lines 7:0-7:22 -/ +@[reducible] +def specs.traits.synthesized.Gen.pick.post + {Self_ : Type} {U : Type} (GenInst : specs.traits.synthesized.Gen Self_) + (o : core.option.Option U) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Gen::id::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 7:0-7:22 -/ +@[reducible] +def specs.traits.synthesized.Gen.id.pre + {Self_ : Type} {U : Type} (GenInst : specs.traits.synthesized.Gen Self_) + (self_ : Self_) (u : U) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Gen::id::post]: + Source: 'src/specs/traits/synthesized.rs', lines 15:4-15:31 -/ +@[reducible] +def specs.traits.synthesized.Gen.id.post + {Self_ : Type} {U : Type} (GenInst : specs.traits.synthesized.Gen Self_) + (self_ : Self_) (u : U) (res : U) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Gen::add::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 7:0-7:22 -/ +@[reducible] +def specs.traits.synthesized.Gen.add.pre + {Self_ : Type} (GenInst : specs.traits.synthesized.Gen Self_) (self_ : Self_) + (x : Std.U32) : + RustM Bool + := do + ok (x < 100#u32) + +/-- [hax_tests::specs::traits::synthesized::Gen::add::post]: + Source: 'src/specs/traits/synthesized.rs', lines 19:4-19:37 -/ +@[reducible] +def specs.traits.synthesized.Gen.add.post + {Self_ : Type} (GenInst : specs.traits.synthesized.Gen Self_) (self_ : Self_) + (x : Std.U32) (res : (Std.U32 × Self_)) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Gen::arr::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 7:0-7:22 -/ +@[reducible] +def specs.traits.synthesized.Gen.arr.pre + {Self_ : Type} (N : Std.Usize) (GenInst : specs.traits.synthesized.Gen Self_) + (self_ : Self_) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Gen::arr::post]: + Source: 'src/specs/traits/synthesized.rs', lines 23:4-23:46 -/ +@[reducible] +def specs.traits.synthesized.Gen.arr.post + {Self_ : Type} {N : Std.Usize} (GenInst : specs.traits.synthesized.Gen Self_) + (self_ : Self_) (res : Array Std.U32 N) : + RustM Bool + := do + ok true + + +/-- [hax_tests::specs::traits::synthesized::Tg::get::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 27:0-27:22 -/ +@[reducible] +def specs.traits.synthesized.Tg.get.pre + {Self_ : Type} {T : Type} (TgInst : specs.traits.synthesized.Tg Self_ T) + (self_ : Self_) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Tg::get::post]: + Source: 'src/specs/traits/synthesized.rs', lines 30:4-30:23 -/ +@[reducible] +def specs.traits.synthesized.Tg.get.post + {Self_ : Type} {T : Type} (TgInst : specs.traits.synthesized.Tg Self_ T) + (self_ : Self_) (res : T) : + RustM Bool + := do + ok true + + +/-- [hax_tests::specs::traits::synthesized::Assoc::item::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 35:0-35:22 -/ +@[reducible] +def specs.traits.synthesized.Assoc.item.pre + {Self_ : Type} {Clause0_Item : Type} (AssocInst : + specs.traits.synthesized.Assoc Self_ Clause0_Item) (self_ : Self_) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Assoc::item::post]: + Source: 'src/specs/traits/synthesized.rs', lines 40:4-40:33 -/ +@[reducible] +def specs.traits.synthesized.Assoc.item.post + {Self_ : Type} {Clause0_Item : Type} (AssocInst : + specs.traits.synthesized.Assoc Self_ Clause0_Item) (self_ : Self_) + (res : Clause0_Item) : + RustM Bool + := do + ok true + + +/-- [hax_tests::specs::traits::trait_generics::Conv::conv::pre]: + Source: 'src/specs/traits/trait_generics.rs', lines 8:4-8:32 -/ +@[reducible] +def specs.traits.trait_generics.Conv.conv.pre + {Self_ : Type} {T : Type} (ConvInst : specs.traits.trait_generics.Conv Self_ + T) (self_ : Self_) (t : T) : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::trait_generics::Conv::conv::post]: Source: 'src/specs/traits/trait_generics.rs', lines 5:0-5:22 -/ @[reducible] @@ -355,6 +642,16 @@ def specs.traits.trait_generics.Conv.conv.post ok (res < 10#u32) +/-- [hax_tests::specs::traits::unannotated_sub::A::a::pre]: + Source: 'src/specs/traits/unannotated_sub.rs', lines 9:4-9:23 -/ +@[reducible] +def specs.traits.unannotated_sub.A.a.pre + {Self_ : Type} (AInst : specs.traits.unannotated_sub.A Self_) (self_ : Self_) + : + RustM Bool + := do + ok true + /-- [hax_tests::specs::traits::unannotated_sub::A::a::post]: Source: 'src/specs/traits/unannotated_sub.rs', lines 6:0-6:22 -/ @[reducible] diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index 37b923bc1a..25cd03e8b4 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -237,6 +237,24 @@ structure specs.traits.supertraits.Cc (Self : Type) where BInst : specs.traits.supertraits.B Self c : Self → RustM Std.Usize +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Gen] + Source: 'src/specs/traits/synthesized.rs', lines 8:0-24:1 -/ +structure specs.traits.synthesized.Gen (Self : Type) where + pick : forall (U : Type), RustM (core.option.Option U) + id : forall {U : Type}, Self → U → RustM U + add : Self → Std.U32 → RustM (Std.U32 × Self) + arr : forall (N : Std.Usize), Self → RustM (Array Std.U32 N) + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Tg] + Source: 'src/specs/traits/synthesized.rs', lines 28:0-31:1 -/ +structure specs.traits.synthesized.Tg (Self : Type) (T : Type) where + get : Self → RustM T + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Assoc] + Source: 'src/specs/traits/synthesized.rs', lines 36:0-41:1 -/ +structure specs.traits.synthesized.Assoc (Self : Type) (Self_Item : Type) where + item : Self → RustM Self_Item + /-- Trait declaration: [hax_tests::specs::traits::trait_generics::Conv] Source: 'src/specs/traits/trait_generics.rs', lines 6:0-9:1 -/ structure specs.traits.trait_generics.Conv (Self : Type) (T : Type) where diff --git a/tests/hax/src/specs/traits.rs b/tests/hax/src/specs/traits.rs index b19a3f0671..03d52db4b0 100644 --- a/tests/hax/src/specs/traits.rs +++ b/tests/hax/src/specs/traits.rs @@ -13,3 +13,4 @@ mod builtin_bound; mod unannotated_sub; mod impl_contract; mod trait_generics; +mod synthesized; diff --git a/tests/hax/src/specs/traits/synthesized.rs b/tests/hax/src/specs/traits/synthesized.rs new file mode 100644 index 0000000000..02be5dbd71 --- /dev/null +++ b/tests/hax/src/specs/traits/synthesized.rs @@ -0,0 +1,41 @@ +// Annotated traits with one condition per method, no impl: the other +// condition is synthesized as `ok true`. The result type of a synthesized post +// is rewritten into the generics of the decoration fns. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Gen { + // Post only: `U` is only in the result, explicit in the synthesized pre + #[ensures(|_| true)] + fn pick() -> Option; + + // A method type parameter in the result + #[requires(true)] + fn id(&self, u: U) -> U; + + // `&mut self`: the back value is in the result + #[requires(x < 100)] + fn add(&mut self, x: u32) -> u32; + + // A const generic in the result + #[requires(true)] + fn arr(&self) -> [u32; N]; +} + +// A trait type parameter in the result, after `Self_` +#[hax_lib::attributes] +trait Tg { + #[requires(true)] + fn get(&self) -> T; +} + +// An associated type in the result: `Self_Item` in the trait, `Clause0_Item` +// in the decoration fns +#[hax_lib::attributes] +trait Assoc { + type Item; + + #[requires(true)] + fn item(&self) -> Self::Item; +} From e50f53d3edbbe4fd00ed38d68d3744176f930df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Wed, 14 Oct 2026 10:53:05 +0200 Subject: [PATCH 06/17] feat-specs: emit lawful structures --- src/extract/ExtractHaxSpecs.ml | 426 +++++++++++++--- tests/hax/hax.toml | 3 + .../HaxTests/Assumptions/MissingCore.lean | 30 ++ .../lean/HaxTests/Extraction/Funs.lean | 1 + .../Extraction/FunsExternal_Template.lean | 27 -- .../HaxTests/Extraction/ProofObligations.lean | 1 + .../lean/HaxTests/Extraction/Specs.lean | 457 ++++++++++++++---- .../lean/HaxTests/Extraction/Types.lean | 1 + 8 files changed, 772 insertions(+), 174 deletions(-) create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean delete mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/FunsExternal_Template.lean diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index 37a15afde9..04ff07a32f 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -24,7 +24,19 @@ module Helpers = struct (** Wrap [k] in a Hoare-triple postcondition delimiter [⦃ … ⦄]. *) let emit_wp (fmt : F.formatter) (k : unit -> unit) : unit = - Extract.emit_delim fmt "⦃" k "⦄" + Extract.emit_delim ~add_spaces:false fmt "⦃ " k " ⦄" + + (** Emit a binder [( : )], with [k] printing [] *) + let emit_binder fmt (name : string) (k : unit -> unit) = + F.pp_print_space fmt (); + F.pp_open_hovbox fmt 0; + F.pp_print_string fmt ("(" ^ name); + F.pp_print_space fmt (); + F.pp_print_string fmt ":"; + F.pp_print_space fmt (); + k (); + F.pp_print_string fmt ")"; + F.pp_close_box fmt () (** Emit [ ] — an application head applied to its generic and value arguments (caller controls the surrounding box). This is @@ -57,45 +69,94 @@ module Helpers = struct | None -> [%internal_error] span) inputs + (** The arguments of a method with signature [sg], as fresh variables + registered in [ctx], named after the inputs of the precondition [pre]. *) + let method_args span (ctx : ExtractBase.extraction_ctx) fresh_fvar_id + (sg : Pure.fun_sig) (pre : Pure.fun_decl option) : + ExtractBase.extraction_ctx * Pure.texpr list = + let inputs = + Option.fold ~none:[] + ~some:(fun (b : Pure.fun_body) -> b.inputs) + (Option.bind pre (fun (f : Pure.fun_decl) -> f.body)) + in + let name i = + match Option.bind (List.nth_opt inputs i) PureUtils.as_opt_pat_bound with + | Some ({ basename = Some n; _ }, _) -> n + | _ -> "_" + in + List.fold_left_map + (fun ctx (i, ty) -> + let id = fresh_fvar_id () in + let ctx, _ = ExtractBase.ctx_add_var span (name i) id ctx in + (ctx, ({ e = FVar id; ty } : Pure.texpr))) + ctx + (List.mapi (fun i ty -> (i, ty)) sg.inputs) + + (** The instance of the parent clause [c] of the trait [d], from the instance + [tr] of [d]: the generics of [c] are instantiated for [tr] *) + let parent_ref (d : Pure.trait_decl) (tr : Pure.trait_ref) + (c : Pure.trait_param) : Pure.trait_ref = + let subst = + PureUtils.make_subst_from_generics_for_trait d.generics tr.trait_id + tr.trait_decl_ref.decl_generics + in + { + trait_id = ParentClause (tr.trait_id, d.def_id, c.clause_id); + trait_decl_ref = + { + trait_decl_id = c.trait_id; + decl_generics = PureUtils.generic_args_substitute subst c.generics; + }; + } + (** The generics to pass to a pre/post condition [cond], from the [generics] of the function it describes. The types and const generics match, but the trait clauses may not: for [trait B: A], the conditions of a method of [B] have clauses [Self_: A] and [Self_: B], while the method only has [Self: B]. We look up each clause of [cond] among the trait refs of - [generics] and their parent clauses. *) + [generics] and their parent clauses. The clauses of [cond] are written in + its own type and const generic parameters, while [generics] may use other + variables (e.g., those of a trait and its method): we substitute them with + the types and const generics of [generics] before the lookup. *) let cond_generics span (ctx : ExtractBase.extraction_ctx) (generics : Pure.generic_args) (cond : Pure.fun_decl) : Pure.generic_args = let rec with_parents (tr : Pure.trait_ref) : Pure.trait_ref list = - let decl_ref = tr.trait_decl_ref in match - Pure.TraitDeclId.Map.find_opt decl_ref.trait_decl_id + Pure.TraitDeclId.Map.find_opt tr.trait_decl_ref.trait_decl_id ctx.trans_trait_decls with | None -> [ tr ] | Some d -> - let subst = - PureUtils.make_subst_from_generics_for_trait d.generics tr.trait_id - decl_ref.decl_generics - in - let parent (c : Pure.trait_param) : Pure.trait_ref = - { - trait_id = ParentClause (tr.trait_id, d.def_id, c.clause_id); - trait_decl_ref = - { - trait_decl_id = c.trait_id; - decl_generics = - PureUtils.generic_args_substitute subst c.generics; - }; - } - in tr - :: List.concat_map (fun c -> with_parents (parent c)) d.parent_clauses + :: List.concat_map + (fun c -> with_parents (parent_ref d tr c)) + d.parent_clauses in let available = List.concat_map with_parents generics.trait_refs in + let params = cond.signature.generics in + [%cassert] span + (List.length params.types = List.length generics.types + && List.length params.const_generics = List.length generics.const_generics + ) + ("Internal error: the generics of the condition `" ^ cond.name + ^ "` don't match those it is applied to"); + let subst : PureUtils.subst = + { + ty_subst = PureUtils.make_type_subst params.types generics.types; + cg_subst = + PureUtils.make_const_generic_subst params.const_generics + generics.const_generics; + tr_subst = (fun id -> Clause (Free id)); + tr_self = Self; + } + in let find (c : Pure.trait_param) : Pure.trait_ref = let decl_ref : Pure.trait_decl_ref = - { trait_decl_id = c.trait_id; decl_generics = c.generics } + { + trait_decl_id = c.trait_id; + decl_generics = PureUtils.generic_args_substitute subst c.generics; + } in match List.find_opt @@ -113,6 +174,31 @@ module Helpers = struct trait_refs = List.map find cond.signature.generics.trait_clauses; } + (** The generics of a method of the trait [d] with signature [sg], from the + instance [self_ref] of [d]: those of the trait, then those of the method, + as the conditions of the method take them. *) + let method_generics (d : Pure.trait_decl) (self_ref : Pure.trait_ref) + (sg : Pure.fun_sig) : Pure.generic_args = + let trait_args = PureUtils.generic_args_of_params d.generics in + (* The de Bruijn indices of the method generics are not reliable (see + {!ExtractBase.origin_from_de_bruijn_var}): we reset them, so that + {!cond_generics} can compare the trait refs *) + let reset = + object + inherit [_] Pure.map_ty + method! visit_de_bruijn_id _ _ = 0 + end + in + let method_args = + PureUtils.bound_generic_args_of_params + (reset#visit_generic_params () sg.generics) + in + { + types = trait_args.types @ method_args.types; + const_generics = trait_args.const_generics @ method_args.const_generics; + trait_refs = (self_ref :: trait_args.trait_refs) @ method_args.trait_refs; + } + (** Emit [( ).holds] for a fn [f]. *) let emit_holds span ctx fmt generics args (f : Pure.fun_decl) = let generics = cond_generics span ctx generics f in @@ -123,6 +209,22 @@ module Helpers = struct f.signature.output; F.pp_print_string fmt ").holds"; F.pp_close_box fmt () + + (** Register the pre/post conditions in the (local) context *) + let add_conditions (ctx : ExtractBase.extraction_ctx) ~pre ~post = + let reg f_opt (ctx : ExtractBase.extraction_ctx) = + let some (f : Pure.fun_decl) = + let trans : TranslateCore.pure_fun_translation = + { f; loops = []; bodies = [] } + in + { + ctx with + trans_funs = Pure.FunDeclId.Map.add f.def_id trans ctx.trans_funs; + } + in + Option.fold ~some ~none:ctx f_opt + in + ctx |> reg pre |> reg post end open Helpers @@ -144,7 +246,8 @@ let emit_conditions ctx fmt ~pre ~post = The contract of [] generates [.pre], [.post], [.spec] and [.spec.proof]. The contract of a method [] of a trait [] - generates [..pre] and [..post]. *) + generates [..pre] and [..post]. Every trait [] + generates [.Lawful]. *) (** The registered name of [parent] *) let registered_fun_name (ctx : ExtractBase.extraction_ctx) @@ -163,6 +266,9 @@ let spec_name (parent_name : string) : string = let proof_name (parent_name : string) : string = ExtractBuiltin.flatten_name [ spec_name parent_name; "proof" ] +let lawful_name (trait_name : string) : string = + ExtractBuiltin.flatten_name [ trait_name; "Lawful" ] + (** The names of the conditions [pre] and [post] of [parent_name] *) let cond_names (parent_name : string) ~(pre : Pure.fun_decl option) ~(post : Pure.fun_decl option) : (Pure.fun_decl * string) list = @@ -250,6 +356,10 @@ let register_spec_names (ctx : ExtractBase.extraction_ctx) let span = d.item_meta.span in let get id = ExtractBase.ctx_get_raw (Some span) id ctx in let trait_name = get (TraitDeclId trait_decl) in + let ctx = + ExtractBase.ctx_add span (SpecId spec_id) (lawful_name trait_name) + ctx + in List.fold_left (fun ctx ({ method_id; pre; post } : HaxSpecs.method_spec) -> let method_name = get (TraitMethodId (trait_decl, method_id)) in @@ -284,8 +394,10 @@ let register_obligation_names (ctx : ExtractBase.extraction_ctx) ⦃ ⌜ True ⌝ ⦄ foo args ⦃ ⇓ res => ⌜ (foo.post args res).holds ⌝ ⦄ - ]} *) -let emit_statement ctx fmt span (fn : Pure.FunDeclId.id) generics output_ty + ]} + [head] is the function applied ([foo]), and [generics] the generics from + which those of the conditions are computed. *) +let emit_statement ctx fmt span (head : Pure.texpr) generics output_ty arg_texprs res_id ~(pre : Pure.fun_decl option) ~(post : Pure.fun_decl option) = let open ExtractBase in @@ -293,7 +405,7 @@ let emit_statement ctx fmt span (fn : Pure.FunDeclId.id) generics output_ty let ctx, res_name = ctx_add_var span "res" res_id ctx in let res_texpr : Pure.texpr = { e = FVar res_id; ty = output_ty } in let emit_holds = emit_holds span ctx fmt generics in - let emit_pure k = Extract.emit_delim fmt "⌜" k "⌝" in + let emit_pure k = Extract.emit_delim ~add_spaces:false fmt "⌜ " k " ⌝" in (* Optional pre-hypothesis: [(.pre ).holds →]. *) (match pre with @@ -310,7 +422,6 @@ let emit_statement ctx fmt span (fn : Pure.FunDeclId.id) generics output_ty (* The real function application [ ], via the standard printer. *) line fmt (fun () -> - let head = fun_head fn generics output_ty in Extract.extract_App span ctx fmt ~inside:false ~inside_do:false head arg_texprs output_ty); @@ -319,12 +430,228 @@ let emit_statement ctx fmt span (fn : Pure.FunDeclId.id) generics output_ty line fmt (fun () -> emit_wp fmt (fun () -> emit_words fmt [ "⇓"; res_name; "=>" ]; - F.pp_print_space fmt (); + F.pp_print_break fmt 1 ctx.indent_incr; emit_pure (fun () -> match post with | None -> F.pp_print_string fmt "True" | Some post_fn -> emit_holds (arg_texprs @ [ res_texpr ]) post_fn))) +(** {1 Lawful structures} *) + +(** The instance an [X.Lawful] structure is about, for the trait [d]: a fresh + clause [Inst : ] registered in [ctx] (where the parameters of + [d] must be registered), its name and a reference to it. It is named like + the clause [Self_: ] of the conditions, as + {!ExtractBase.ctx_compute_trait_clause_basename} does for Lean. *) +let lawful_instance span (ctx : ExtractBase.extraction_ctx) + (d : Pure.trait_decl) : + ExtractBase.extraction_ctx * Pure.trait_param * string * Pure.trait_ref = + let clause : Pure.trait_param = + { + (* The clause ids are positions *) + clause_id = + Pure.TraitClauseId.of_int (List.length d.generics.trait_clauses); + trait_id = d.def_id; + generics = PureUtils.generic_args_of_params d.generics; + } + in + let basename = + String.concat "" + (TranslateCore.trait_name_with_generics_to_simple_name ctx.trans_ctx + ~prefix:(Some (fst (Collections.List.pop_last d.item_meta.name))) + d.item_meta.name d.llbc_generics + (Charon.TypesUtils.generic_args_of_params (Some span) d.llbc_generics)) + ^ "Inst" + in + let ctx, name = + ExtractBase.ctx_add_local_trait_clause span Item basename clause.clause_id + ctx + in + let tr = + match + (PureUtils.generic_args_of_params + { PureUtils.empty_generic_params with trait_clauses = [ clause ] }) + .trait_refs + with + | [ tr ] -> tr + | _ -> [%internal_error] span + in + (ctx, clause, name, tr) + +(** Emit [.Lawful ]: the Lawful structure of the trait [tr] is an + instance of, applied to it *) +let emit_lawful_type span (ctx : ExtractBase.extraction_ctx) fmt + (tr : Pure.trait_ref) = + let decl_ref = tr.trait_decl_ref in + let name = + ExtractBase.ctx_get_raw (Some span) (TraitDeclId decl_ref.trait_decl_id) ctx + in + F.pp_print_string fmt (ExtractBase.escape_name (lawful_name name)); + (* The arguments, as for the trait (see {!ExtractTypes.extract_trait_decl_ref}) *) + let explicit = + Option.map + (fun (d : Pure.trait_decl) -> d.explicit_info) + (Pure.TraitDeclId.Map.find_opt decl_ref.trait_decl_id + ctx.trans_trait_decls) + in + ExtractTypes.extract_generic_args span ctx fmt Pure.TypeDeclId.Set.empty + ~explicit + { decl_ref.decl_generics with trait_refs = [] }; + F.pp_print_space fmt (); + ExtractTypes.extract_trait_ref span ctx fmt Pure.TypeDeclId.Set.empty + ~inside:true tr + +(** Emit the binders of the trait clauses [clauses] (bound at [origin]), each + followed by its Lawful binder: + [( : ) (Lawful : .Lawful )] *) +let emit_lawful_clause_binders span (ctx : ExtractBase.extraction_ctx) fmt + (origin : ExtractBase.generic_origin) (clauses : Pure.trait_param list) = + let args = + (match origin with + | Item -> PureUtils.generic_args_of_params + | Method -> PureUtils.bound_generic_args_of_params) + { PureUtils.empty_generic_params with trait_clauses = clauses } + in + List.iter2 + (fun (c : Pure.trait_param) tr -> + let name = + ExtractBase.ctx_get_local_trait_clause span origin c.clause_id ctx + in + emit_binder fmt name (fun () -> + ExtractTypes.extract_trait_clause_type span ctx fmt + Pure.TypeDeclId.Set.empty c); + emit_binder fmt (name ^ "Lawful") (fun () -> + emit_lawful_type span ctx fmt tr)) + clauses args.trait_refs + +(** Emit the [Lawful] structure of the trait [d], whose annotated methods are + [methods]: one field per parent clause of the trait, then one per annotated + method. The arguments of the methods are named as in their conditions. *) +let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt + (d : Pure.trait_decl) (methods : HaxSpecs.method_spec list) = + let open ExtractBase in + let span = d.item_meta.span in + let no_params_tys = Pure.TypeDeclId.Set.empty in + let ctx, type_params, cg_params, trait_clauses = + ctx_add_generic_params span d.item_meta.name Item d.llbc_generics d.generics + ctx + in + let ctx, self_clause, self_name, self_ref = lawful_instance span ctx d in + (* Link the structure to the trait declaration *) + ExtractTypes.extract_comment_with_span ctx fmt + [ + "Lawful structure of trait: [" ^ name_to_string ctx d.item_meta.name ^ "]"; + ] + None span; + F.pp_print_break fmt 0 0; + F.pp_open_vbox fmt ctx.indent_incr; + (* [structure .Lawful (Inst : ) : Prop where] *) + F.pp_open_hovbox fmt ctx.indent_incr; + F.pp_print_string fmt "structure"; + F.pp_print_space fmt (); + F.pp_print_string fmt + (escape_name + (lawful_name (ctx_get_raw (Some span) (TraitDeclId d.def_id) ctx))); + ExtractTypes.extract_generic_params span ctx fmt no_params_tys Item + { + d.generics with + trait_clauses = d.generics.trait_clauses @ [ self_clause ]; + } + (Some d.explicit_info) type_params cg_params + (trait_clauses @ [ self_name ]); + F.pp_print_space fmt (); + F.pp_print_string fmt ":"; + F.pp_print_space fmt (); + F.pp_print_string fmt "Prop"; + if d.parent_clauses <> [] || methods <> [] then ( + F.pp_print_space fmt (); + F.pp_print_string fmt "where"); + F.pp_close_box fmt (); + (* The parents: [

Lawful :

.Lawful Inst.

] *) + List.iter + (fun (c : Pure.trait_param) -> + let name = + ctx_get_raw (Some span) + (TraitParentClauseId (d.def_id, c.clause_id)) + ctx + in + Extract.extract_trait_decl_item ctx fmt + (escape_name (name ^ "Lawful")) + (fun () -> + F.pp_print_space fmt (); + emit_lawful_type span ctx fmt (parent_ref d self_ref c))) + d.parent_clauses; + (* The annotated methods: [_spec : ] *) + List.iter + (fun ({ method_id; pre; post } : HaxSpecs.method_spec) -> + let m = + match + List.find_opt + (fun (m : Pure.trait_method) -> m.method_id = method_id) + d.methods + with + | Some m -> m + | None -> [%internal_error] span + in + let sg = m.signature in + let ctx, type_params, cg_params, clause_names = + ctx_add_generic_params span m.item_meta.name Method sg.llbc_generics + sg.generics ctx + in + (* The names of the Lawful binders of the clauses *) + let ctx = + ctx_reserve_names (List.map (fun n -> n ^ "Lawful") clause_names) ctx + in + let ctx = add_conditions ctx ~pre ~post in + let _, fresh_fvar_id = Pure.FVarId.fresh_stateful_generator () in + let ctx, args = method_args span ctx fresh_fvar_id sg pre in + F.pp_print_space fmt (); + F.pp_open_vbox fmt ctx.indent_incr; + F.pp_open_hovbox fmt ctx.indent_incr; + F.pp_print_string fmt + (escape_name + (ctx_get_raw (Some span) (TraitMethodId (d.def_id, method_id)) ctx + ^ "_spec")); + ExtractTypes.extract_generic_params span ctx fmt no_params_tys Method + { sg.generics with trait_clauses = [] } + (Some sg.explicit_info) type_params cg_params []; + emit_lawful_clause_binders span ctx fmt Method sg.generics.trait_clauses; + List.iter + (fun (a : Pure.texpr) -> + emit_binder fmt + (ctx_get_var span (PureUtils.as_fvar span a) ctx) + (fun () -> + ExtractTypes.extract_ty span ctx fmt no_params_tys ~inside:false + a.ty)) + args; + F.pp_print_space fmt (); + F.pp_print_string fmt ":"; + F.pp_close_box fmt (); + let head : Pure.texpr = + { + e = + Qualif + { + id = + FunOrOp + (Fun (FromLlbc (TraitMethod (self_ref, method_id), None))); + generics = PureUtils.bound_generic_args_of_params sg.generics; + }; + ty = sg.output; + } + in + let output = + if sg.fwd_info.effect_info.can_fail then + PureUtils.unwrap_result_ty span sg.output + else sg.output + in + emit_statement ctx fmt span head + (method_generics d self_ref sg) + output args (fresh_fvar_id ()) ~pre ~post; + F.pp_close_box fmt ()) + methods; + F.pp_close_box fmt () + (** Emit one [Spec.spec] entry *) let emit_spec ctx fmt (s : HaxSpecs.spec) = let open ExtractBase in @@ -333,21 +660,7 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) = match Pure.FunDeclId.Map.find_opt fn ctx.trans_funs with | None -> (* Reported by [register_spec_names] *) () | Some ft -> - (* Register the pre/post conditions in the (local) context *) - let reg f_opt ctx = - let some (f : Pure.fun_decl) = - let trans : TranslateCore.pure_fun_translation = - { f; loops = []; bodies = [] } - in - { - ctx with - trans_funs = - Pure.FunDeclId.Map.add f.def_id trans ctx.trans_funs; - } - in - Option.fold ~some ~none:ctx f_opt - in - let ctx = ctx |> reg pre |> reg post in + let ctx = add_conditions ctx ~pre ~post in let parent = ft.f in let span = parent.item_meta.span in let sg = parent.signature in @@ -373,9 +686,7 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) = (* Fresh result-var id, from the body generator so it can't clash. *) let res_id = fresh_fvar_id () in - (* Blank line before the entry. *) - F.pp_print_break fmt 0 0; - + (* The leading break of the conditions separates the entry *) emit_conditions ctx fmt ~pre ~post; (* Spec definition header: [def .spec : Prop :=] *) @@ -398,8 +709,9 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) = F.pp_close_box fmt (); (* Statement shape (the def body). *) - emit_statement ctx fmt span fn generics sg.output arg_texprs res_id - ~pre ~post; + emit_statement ctx fmt span + (fun_head fn generics sg.output) + generics sg.output arg_texprs res_id ~pre ~post; F.pp_close_box fmt (); (* inner vbox *) F.pp_close_box fmt (); @@ -408,15 +720,19 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) = | TraitSpec { trait_decl; _ } when not (Pure.TraitDeclId.Map.mem trait_decl ctx.trans_trait_decls) -> (* Reported by [register_spec_names] *) () - | TraitSpec { methods; _ } -> + | TraitSpec { trait_decl; methods } -> (* The conditions of the annotated methods *) - if methods <> [] then ( - (* Blank line before the entry. *) - F.pp_print_break fmt 0 0; - List.iter - (fun ({ pre; post; _ } : HaxSpecs.method_spec) -> - emit_conditions ctx fmt ~pre ~post) - methods) + List.iter + (fun ({ pre; post; _ } : HaxSpecs.method_spec) -> + emit_conditions ctx fmt ~pre ~post) + methods; + (* Blank line before the structure. *) + F.pp_print_break fmt 0 0; + emit_lawful_structure ctx fmt + (Pure.TraitDeclId.Map.find trait_decl ctx.trans_trait_decls) + methods; + (* New line after the structure. *) + F.pp_print_break fmt 0 0 (** Emit one [HaxSpecs.obligation] entry as the proof obligation that discharges a spec's statement of correctness: diff --git a/tests/hax/hax.toml b/tests/hax/hax.toml index 8055874532..daf053d0d5 100644 --- a/tests/hax/hax.toml +++ b/tests/hax/hax.toml @@ -14,3 +14,6 @@ charon = { path = "../../charon/bin/charon" } # `proofs/hax-tests/lean`. [scenario.hax-tests] backend = "lean" +# Imports the stubs of the core `Lawful` structures the generated specs refer +# to, until the CoreModels library provides them, into every generated file. +aeneas-args = ["-extra-includes", "HaxTests.Assumptions.MissingCore"] diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean new file mode 100644 index 0000000000..f2fdd535ab --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean @@ -0,0 +1,30 @@ +-- Stubs for the `Lawful` structures of hax's core models (`CoreModels`), which +-- the generated specs refer to (e.g. the `Lawful` field of a `Clone` parent). +-- Kept here until the CoreModels library provides them. Imported into every +-- generated file through Aeneas' `-extra-includes` (see `tests/hax/hax.toml`), +-- so it must not import any `HaxTests` module. +import Aeneas +import CoreModels +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +set_option linter.dupNamespace false +set_option linter.unusedVariables false + +namespace CoreModels + +-- The actual fields are to be decided with the library. +structure core.clone.Clone.Lawful (Self : Type) + (CloneInst : core.clone.Clone Self) : Prop where + +theorem core.U32.Insts.CoreCloneClone.Lawful : + core.clone.Clone.Lawful Std.U32 core.U32.Insts.CoreCloneClone := ⟨⟩ + +structure core.default.Default.Lawful (Self : Type) + (DefaultInst : core.default.Default Self) : Prop where + +-- `Copy` has no method; its parent `Clone` would give a +-- `corecloneCloneInstLawful` field, omitted like the fields of `Clone.Lawful`. +structure core.marker.Copy.Lawful (Self : Type) + (CopyInst : core.marker.Copy Self) : Prop where + +end CoreModels diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean index 69ec46fdbf..bd78646230 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean @@ -4,6 +4,7 @@ import Aeneas import CoreModels import HaxTests.Extraction.Types import HaxTests.Extraction.FunsExternal +import HaxTests.Assumptions.MissingCore open CoreModels Aeneas open Aeneas.Std hiding namespace core alloc open RustM ControlFlow Error diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/FunsExternal_Template.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/FunsExternal_Template.lean deleted file mode 100644 index 9068172a8d..0000000000 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/FunsExternal_Template.lean +++ /dev/null @@ -1,27 +0,0 @@ --- THIS FILE WAS AUTOMATICALLY GENERATED BY AENEAS --- [hax_tests]: external functions. --- This is a template file: hax seeded HaxTests/Assumptions/FunsExternal.lean --- from it, and that copy is yours to fill in. This file is regenerated on --- every extraction; diff it against your Assumptions file to see what the --- extraction now requires. -import Aeneas -import CoreModels -import HaxTests.Extraction.Types -open CoreModels Aeneas -open Aeneas.Std hiding namespace core alloc -open RustM ControlFlow Error -open Std.Do -set_option linter.dupNamespace false -set_option linter.hashCommand false -set_option linter.unusedVariables false -set_option linter.style.whitespace false -set_option linter.style.setOption false -set_option linter.style.longLine false - -/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ -set_option maxHeartbeats 1000000 - -/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ -set_option maxRecDepth 2048 -open hax_tests - diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean index 23067c2a1e..393f74f2a7 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean @@ -5,6 +5,7 @@ import CoreModels import HaxTests.Extraction.Types import HaxTests.Extraction.Funs import HaxTests.Extraction.Specs +import HaxTests.Assumptions.MissingCore open CoreModels Aeneas open Aeneas.Std hiding namespace core alloc open RustM ControlFlow Error diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index dd46657cba..147fe40b86 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -5,6 +5,7 @@ import CoreModels import Hax import HaxTests.Extraction.Types import HaxTests.Extraction.Funs +import HaxTests.Assumptions.MissingCore open CoreModels Aeneas open Aeneas.Std hiding namespace core alloc open RustM ControlFlow Error @@ -27,6 +28,20 @@ noncomputable section namespace hax_tests +/-- Lawful structure of trait: [hax_tests::specs::arguments::Size] + Source: 'src/specs/arguments.rs', lines 5:0-7:1 -/ +structure specs.arguments.Size.Lawful (Self : Type) (SizeInst : + specs.arguments.Size Self) : Prop + +/-- Lawful structure of trait: [hax_tests::specs::generics::Val] + Source: 'src/specs/generics.rs', lines 16:0-18:1 -/ +structure specs.generics.Val.Lawful (Self : Type) (ValInst : specs.generics.Val + Self) : Prop + +/-- Lawful structure of trait: [hax_tests::specs::generics::Producer] + Source: 'src/specs/generics.rs', lines 55:0-58:1 -/ +structure specs.generics.Producer.Lawful (Self : Type) (Self_Out : Type) + (ProducerInst : specs.generics.Producer Self Self_Out) : Prop /-- [hax_tests::specs::traits::assoc_type_bounds::Bar::bar::pre]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 11:4-11:25 -/ @@ -48,6 +63,16 @@ def specs.traits.assoc_type_bounds.Bar.bar.post := do ok (res < 10#u32) +/-- Lawful structure of trait: [hax_tests::specs::traits::assoc_type_bounds::Bar] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 9:0-12:1 -/ +structure specs.traits.assoc_type_bounds.Bar.Lawful (Self : Type) (BarInst : + specs.traits.assoc_type_bounds.Bar Self) : Prop where + bar_spec (self_ : Self) : + (specs.traits.assoc_type_bounds.Bar.bar.pre BarInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + BarInst.bar self_ + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_type_bounds.Bar.bar.post BarInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::assoc_type_bounds::Container::first::pre]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 19:4-19:34 -/ @@ -72,6 +97,21 @@ def specs.traits.assoc_type_bounds.Container.first.post let i ← ContainerInst.BarInst.bar item ok (i < 10#u32) +/-- Lawful structure of trait: [hax_tests::specs::traits::assoc_type_bounds::Container] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 15:0-20:1 -/ +structure specs.traits.assoc_type_bounds.Container.Lawful (Self : Type) + (Self_Item : Type) (ContainerInst : specs.traits.assoc_type_bounds.Container + Self Self_Item) : Prop where + BarInstLawful : specs.traits.assoc_type_bounds.Bar.Lawful Self_Item + ContainerInst.BarInst + first_spec (self_ : Self) : + (specs.traits.assoc_type_bounds.Container.first.pre ContainerInst + self_).holds → + ⦃ ⌜ True ⌝ ⦄ + ContainerInst.first self_ + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_type_bounds.Container.first.post ContainerInst + self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::basic::Foo::f1::pre]: Source: 'src/specs/traits/basic.rs', lines 9:4-9:25 -/ @@ -146,6 +186,34 @@ def specs.traits.basic.Foo.zero.post := do FooInst.f1 res +/-- Lawful structure of trait: [hax_tests::specs::traits::basic::Foo] + Source: 'src/specs/traits/basic.rs', lines 7:0-20:1 -/ +structure specs.traits.basic.Foo.Lawful (Self : Type) (FooInst : + specs.traits.basic.Foo Self) : Prop where + f1_spec (self_ : Self) : + (specs.traits.basic.Foo.f1.pre FooInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.f1 self_ + ⦃ ⇓ res => + ⌜ (specs.traits.basic.Foo.f1.post FooInst self_ res).holds ⌝ ⦄ + f2_spec (self_ : Self) : + (specs.traits.basic.Foo.f2.pre FooInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.f2 self_ + ⦃ ⇓ res => + ⌜ (specs.traits.basic.Foo.f2.post FooInst self_ res).holds ⌝ ⦄ + make_spec (x : Std.U32) : + (specs.traits.basic.Foo.make.pre FooInst x).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.make x + ⦃ ⇓ res => + ⌜ (specs.traits.basic.Foo.make.post FooInst x res).holds ⌝ ⦄ + zero_spec : + (specs.traits.basic.Foo.zero.pre FooInst).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.zero + ⦃ ⇓ res => + ⌜ (specs.traits.basic.Foo.zero.post FooInst res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::blanket_impl::Show::show::pre]: Source: 'src/specs/traits/blanket_impl.rs', lines 12:4-12:26 -/ @@ -167,6 +235,22 @@ def specs.traits.blanket_impl.Show.show.post := do ok (res <= 20#u64) +/-- Lawful structure of trait: [hax_tests::specs::traits::blanket_impl::Show] + Source: 'src/specs/traits/blanket_impl.rs', lines 10:0-13:1 -/ +structure specs.traits.blanket_impl.Show.Lawful (Self : Type) (ShowInst : + specs.traits.blanket_impl.Show Self) : Prop where + show_spec (self_ : Self) : + (specs.traits.blanket_impl.Show.show.pre ShowInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + ShowInst.«show» self_ + ⦃ ⇓ res => + ⌜ (specs.traits.blanket_impl.Show.show.post ShowInst self_ res).holds ⌝ ⦄ + +/-- Lawful structure of trait: [hax_tests::specs::traits::blanket_impl::Tag] + Source: 'src/specs/traits/blanket_impl.rs', lines 33:0-33:18 -/ +structure specs.traits.blanket_impl.Tag.Lawful (Self : Type) (TagInst : + specs.traits.blanket_impl.Tag Self) : Prop where + ShowInstLawful : specs.traits.blanket_impl.Show.Lawful Self TagInst.ShowInst /-- [hax_tests::specs::traits::builtin_bound::Dup::dup::pre]: Source: 'src/specs/traits/builtin_bound.rs', lines 19:4-19:34 -/ @@ -189,6 +273,20 @@ def specs.traits.builtin_bound.Dup.dup.post := do ok true +/-- Lawful structure of trait: [hax_tests::specs::traits::builtin_bound::Dup] + Source: 'src/specs/traits/builtin_bound.rs', lines 17:0-20:1 -/ +structure specs.traits.builtin_bound.Dup.Lawful (Self : Type) (DupInst : + specs.traits.builtin_bound.Dup Self) : Prop where + corecloneCloneInstLawful : core.clone.Clone.Lawful Self + DupInst.corecloneCloneInst + dup_spec (self_ : Self) : + (specs.traits.builtin_bound.Dup.dup.pre DupInst.corecloneCloneInst DupInst + self_).holds → + ⦃ ⌜ True ⌝ ⦄ + DupInst.dup self_ + ⦃ ⇓ res => + ⌜ (specs.traits.builtin_bound.Dup.dup.post DupInst.corecloneCloneInst + DupInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::default_methods::D::next::pre]: Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ @@ -212,6 +310,16 @@ def specs.traits.default_methods.D.next.post let i ← DInst.base self_ ok (res > i) +/-- Lawful structure of trait: [hax_tests::specs::traits::default_methods::D] + Source: 'src/specs/traits/default_methods.rs', lines 7:0-15:1 -/ +structure specs.traits.default_methods.D.Lawful (Self : Type) (DInst : + specs.traits.default_methods.D Self) : Prop where + next_spec (self_ : Self) : + (specs.traits.default_methods.D.next.pre DInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + DInst.next self_ + ⦃ ⇓ res => + ⌜ (specs.traits.default_methods.D.next.post DInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::diamond::A::a::pre]: Source: 'src/specs/traits/diamond.rs', lines 8:4-8:25 -/ @@ -234,6 +342,22 @@ def specs.traits.diamond.A.a.post then ok (res <= 100#usize) else ok false +/-- Lawful structure of trait: [hax_tests::specs::traits::diamond::A] + Source: 'src/specs/traits/diamond.rs', lines 6:0-9:1 -/ +structure specs.traits.diamond.A.Lawful (Self : Type) (AInst : + specs.traits.diamond.A Self) : Prop where + a_spec (self_ : Self) : + (specs.traits.diamond.A.a.pre AInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + AInst.a self_ + ⦃ ⇓ res => + ⌜ (specs.traits.diamond.A.a.post AInst self_ res).holds ⌝ ⦄ + +/-- Lawful structure of trait: [hax_tests::specs::traits::diamond::B] + Source: 'src/specs/traits/diamond.rs', lines 11:0-13:1 -/ +structure specs.traits.diamond.B.Lawful (Self : Type) (BInst : + specs.traits.diamond.B Self) : Prop where + AInstLawful : specs.traits.diamond.A.Lawful Self BInst.AInst /-- [hax_tests::specs::traits::diamond::C::c::pre]: Source: 'src/specs/traits/diamond.rs', lines 18:4-18:25 -/ @@ -258,6 +382,20 @@ def specs.traits.diamond.C.c.post let i ← AInst.a self_ ok (res = i) +/-- Lawful structure of trait: [hax_tests::specs::traits::diamond::C] + Source: 'src/specs/traits/diamond.rs', lines 16:0-19:1 -/ +structure specs.traits.diamond.C.Lawful (Self : Type) (CInst : + specs.traits.diamond.C Self) : Prop where + AInstLawful : specs.traits.diamond.A.Lawful Self CInst.AInst + BInstLawful : specs.traits.diamond.B.Lawful Self CInst.BInst + c_spec (self_ : Self) : + (specs.traits.diamond.C.c.pre CInst.AInst CInst.BInst CInst self_).holds + → + ⦃ ⌜ True ⌝ ⦄ + CInst.c self_ + ⦃ ⇓ res => + ⌜ (specs.traits.diamond.C.c.post CInst.AInst CInst.BInst CInst self_ + res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::generic_impl::Foo::f::pre]: Source: 'src/specs/traits/generic_impl.rs', lines 11:4-11:23 -/ @@ -279,6 +417,16 @@ def specs.traits.generic_impl.Foo.f.post := do ok (res <= 10#u64) +/-- Lawful structure of trait: [hax_tests::specs::traits::generic_impl::Foo] + Source: 'src/specs/traits/generic_impl.rs', lines 9:0-12:1 -/ +structure specs.traits.generic_impl.Foo.Lawful (Self : Type) (FooInst : + specs.traits.generic_impl.Foo Self) : Prop where + f_spec (self_ : Self) : + (specs.traits.generic_impl.Foo.f.pre FooInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.f self_ + ⦃ ⇓ res => + ⌜ (specs.traits.generic_impl.Foo.f.post FooInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::generic_impl::Sub::s::pre]: Source: 'src/specs/traits/generic_impl.rs', lines 17:4-17:23 -/ @@ -301,6 +449,24 @@ def specs.traits.generic_impl.Sub.s.post let i ← FooInst.f self_ ok (res = i) +/-- Lawful structure of trait: [hax_tests::specs::traits::generic_impl::Sub] + Source: 'src/specs/traits/generic_impl.rs', lines 15:0-18:1 -/ +structure specs.traits.generic_impl.Sub.Lawful (Self : Type) (SubInst : + specs.traits.generic_impl.Sub Self) : Prop where + FooInstLawful : specs.traits.generic_impl.Foo.Lawful Self SubInst.FooInst + s_spec (self_ : Self) : + (specs.traits.generic_impl.Sub.s.pre SubInst.FooInst SubInst self_).holds + → + ⦃ ⌜ True ⌝ ⦄ + SubInst.s self_ + ⦃ ⇓ res => + ⌜ (specs.traits.generic_impl.Sub.s.post SubInst.FooInst SubInst self_ + res).holds ⌝ ⦄ + +/-- Lawful structure of trait: [hax_tests::specs::traits::impl_contract::Foo] + Source: 'src/specs/traits/impl_contract.rs', lines 8:0-10:1 -/ +structure specs.traits.impl_contract.Foo.Lawful (Self : Type) (FooInst : + specs.traits.impl_contract.Foo Self) : Prop /-- [hax_tests::specs::traits::impl_contract::G::g::pre]: Source: 'src/specs/traits/impl_contract.rs', lines 24:4-24:23 -/ @@ -321,6 +487,16 @@ def specs.traits.impl_contract.G.g.post := do ok (res > 0#u32) +/-- Lawful structure of trait: [hax_tests::specs::traits::impl_contract::G] + Source: 'src/specs/traits/impl_contract.rs', lines 22:0-25:1 -/ +structure specs.traits.impl_contract.G.Lawful (Self : Type) (GInst : + specs.traits.impl_contract.G Self) : Prop where + g_spec (self_ : Self) : + (specs.traits.impl_contract.G.g.pre GInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + GInst.g self_ + ⦃ ⇓ res => + ⌜ (specs.traits.impl_contract.G.g.post GInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::method_generics::Bar::bar::pre]: Source: 'src/specs/traits/method_generics.rs', lines 8:4-8:25 -/ @@ -342,6 +518,16 @@ def specs.traits.method_generics.Bar.bar.post := do ok (res < 10#u32) +/-- Lawful structure of trait: [hax_tests::specs::traits::method_generics::Bar] + Source: 'src/specs/traits/method_generics.rs', lines 6:0-9:1 -/ +structure specs.traits.method_generics.Bar.Lawful (Self : Type) (BarInst : + specs.traits.method_generics.Bar Self) : Prop where + bar_spec (self_ : Self) : + (specs.traits.method_generics.Bar.bar.pre BarInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + BarInst.bar self_ + ⦃ ⇓ res => + ⌜ (specs.traits.method_generics.Bar.bar.post BarInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::method_generics::Foo::f::pre]: Source: 'src/specs/traits/method_generics.rs', lines 11:0-11:22 -/ @@ -366,6 +552,19 @@ def specs.traits.method_generics.Foo.f.post := do ok (res < 5#u32) +/-- Lawful structure of trait: [hax_tests::specs::traits::method_generics::Foo] + Source: 'src/specs/traits/method_generics.rs', lines 12:0-16:1 -/ +structure specs.traits.method_generics.Foo.Lawful (Self : Type) (FooInst : + specs.traits.method_generics.Foo Self) : Prop where + f_spec {U : Type} (BarInst : specs.traits.method_generics.Bar U) + (BarInstLawful : specs.traits.method_generics.Bar.Lawful U BarInst) + (self_ : Self) (u : U) : + (specs.traits.method_generics.Foo.f.pre BarInst FooInst self_ u).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.f BarInst self_ u + ⦃ ⇓ res => + ⌜ (specs.traits.method_generics.Foo.f.post BarInst FooInst self_ u + res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::minimal::Foo::f::pre]: Source: 'src/specs/traits/minimal.rs', lines 6:0-6:13 -/ @@ -407,6 +606,22 @@ def specs.traits.minimal.Foo.h.post := do ok true +/-- Lawful structure of trait: [hax_tests::specs::traits::minimal::Foo] + Source: 'src/specs/traits/minimal.rs', lines 7:0-16:1 -/ +structure specs.traits.minimal.Foo.Lawful (Self : Type) (FooInst : + specs.traits.minimal.Foo Self) : Prop where + f_spec (self_ : Self) (x : Std.U32) : + (specs.traits.minimal.Foo.f.pre FooInst self_ x).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.f self_ x + ⦃ ⇓ res => + ⌜ (specs.traits.minimal.Foo.f.post FooInst self_ x res).holds ⌝ ⦄ + h_spec (self_ : Self) (x : Std.U32) : + (specs.traits.minimal.Foo.h.pre FooInst self_ x).holds → + ⦃ ⌜ True ⌝ ⦄ + FooInst.h self_ x + ⦃ ⇓ res => + ⌜ (specs.traits.minimal.Foo.h.post FooInst self_ x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::mut_self::Counter::incr::pre]: Source: 'src/specs/traits/mut_self.rs', lines 5:0-5:22 -/ @@ -432,6 +647,16 @@ def specs.traits.mut_self.Counter.incr.post let i2 ← i1 + 1#u32 ok (i = i2) +/-- Lawful structure of trait: [hax_tests::specs::traits::mut_self::Counter] + Source: 'src/specs/traits/mut_self.rs', lines 6:0-12:1 -/ +structure specs.traits.mut_self.Counter.Lawful (Self : Type) (CounterInst : + specs.traits.mut_self.Counter Self) : Prop where + incr_spec (self_ : Self) : + (specs.traits.mut_self.Counter.incr.pre CounterInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + CounterInst.incr self_ + ⦃ ⇓ res => + ⌜ (specs.traits.mut_self.Counter.incr.post CounterInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::supertraits::A::a::pre]: Source: 'src/specs/traits/supertraits.rs', lines 9:4-9:25 -/ @@ -452,6 +677,16 @@ def specs.traits.supertraits.A.a.post := do ok (res >= 1#usize) +/-- Lawful structure of trait: [hax_tests::specs::traits::supertraits::A] + Source: 'src/specs/traits/supertraits.rs', lines 7:0-10:1 -/ +structure specs.traits.supertraits.A.Lawful (Self : Type) (AInst : + specs.traits.supertraits.A Self) : Prop where + a_spec (self_ : Self) : + (specs.traits.supertraits.A.a.pre AInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + AInst.a self_ + ⦃ ⇓ res => + ⌜ (specs.traits.supertraits.A.a.post AInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::supertraits::B::b::pre]: Source: 'src/specs/traits/supertraits.rs', lines 12:0-12:22 -/ @@ -475,6 +710,17 @@ def specs.traits.supertraits.B.b.post let i ← AInst.a self_ ok (res > i) +/-- Lawful structure of trait: [hax_tests::specs::traits::supertraits::B] + Source: 'src/specs/traits/supertraits.rs', lines 13:0-17:1 -/ +structure specs.traits.supertraits.B.Lawful (Self : Type) (BInst : + specs.traits.supertraits.B Self) : Prop where + AInstLawful : specs.traits.supertraits.A.Lawful Self BInst.AInst + b_spec (self_ : Self) : + (specs.traits.supertraits.B.b.pre BInst.AInst BInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + BInst.b self_ + ⦃ ⇓ res => + ⌜ (specs.traits.supertraits.B.b.post BInst.AInst BInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::supertraits::Cc::c::pre]: Source: 'src/specs/traits/supertraits.rs', lines 22:4-22:25 -/ @@ -497,6 +743,18 @@ def specs.traits.supertraits.Cc.c.post let i ← BInst.AInst.a self_ ok (res > i) +/-- Lawful structure of trait: [hax_tests::specs::traits::supertraits::Cc] + Source: 'src/specs/traits/supertraits.rs', lines 20:0-23:1 -/ +structure specs.traits.supertraits.Cc.Lawful (Self : Type) (CcInst : + specs.traits.supertraits.Cc Self) : Prop where + BInstLawful : specs.traits.supertraits.B.Lawful Self CcInst.BInst + c_spec (self_ : Self) : + (specs.traits.supertraits.Cc.c.pre CcInst.BInst CcInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + CcInst.c self_ + ⦃ ⇓ res => + ⌜ (specs.traits.supertraits.Cc.c.post CcInst.BInst CcInst self_ + res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::synthesized::Gen::pick::pre]: Source: 'src/specs/traits/synthesized.rs', lines 11:4-11:30 -/ @@ -577,6 +835,34 @@ def specs.traits.synthesized.Gen.arr.post := do ok true +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Gen] + Source: 'src/specs/traits/synthesized.rs', lines 8:0-24:1 -/ +structure specs.traits.synthesized.Gen.Lawful (Self : Type) (GenInst : + specs.traits.synthesized.Gen Self) : Prop where + pick_spec (U : Type) : + (specs.traits.synthesized.Gen.pick.pre U GenInst).holds → + ⦃ ⌜ True ⌝ ⦄ + GenInst.pick U + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Gen.pick.post GenInst res).holds ⌝ ⦄ + id_spec {U : Type} (self_ : Self) (u : U) : + (specs.traits.synthesized.Gen.id.pre GenInst self_ u).holds → + ⦃ ⌜ True ⌝ ⦄ + GenInst.id self_ u + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Gen.id.post GenInst self_ u res).holds ⌝ ⦄ + add_spec (self_ : Self) (x : Std.U32) : + (specs.traits.synthesized.Gen.add.pre GenInst self_ x).holds → + ⦃ ⌜ True ⌝ ⦄ + GenInst.add self_ x + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Gen.add.post GenInst self_ x res).holds ⌝ ⦄ + arr_spec (N : Std.Usize) (self_ : Self) : + (specs.traits.synthesized.Gen.arr.pre N GenInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + GenInst.arr N self_ + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Gen.arr.post GenInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::synthesized::Tg::get::pre]: Source: 'src/specs/traits/synthesized.rs', lines 27:0-27:22 -/ @@ -598,6 +884,16 @@ def specs.traits.synthesized.Tg.get.post := do ok true +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Tg] + Source: 'src/specs/traits/synthesized.rs', lines 28:0-31:1 -/ +structure specs.traits.synthesized.Tg.Lawful (Self : Type) (T : Type) (TgInst : + specs.traits.synthesized.Tg Self T) : Prop where + get_spec (self_ : Self) : + (specs.traits.synthesized.Tg.get.pre TgInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + TgInst.get self_ + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Tg.get.post TgInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::synthesized::Assoc::item::pre]: Source: 'src/specs/traits/synthesized.rs', lines 35:0-35:22 -/ @@ -620,6 +916,17 @@ def specs.traits.synthesized.Assoc.item.post := do ok true +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Assoc] + Source: 'src/specs/traits/synthesized.rs', lines 36:0-41:1 -/ +structure specs.traits.synthesized.Assoc.Lawful (Self : Type) (Self_Item : + Type) (AssocInst : specs.traits.synthesized.Assoc Self Self_Item) : Prop + where + item_spec (self_ : Self) : + (specs.traits.synthesized.Assoc.item.pre AssocInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + AssocInst.item self_ + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Assoc.item.post AssocInst self_ res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::trait_generics::Conv::conv::pre]: Source: 'src/specs/traits/trait_generics.rs', lines 8:4-8:32 -/ @@ -641,6 +948,17 @@ def specs.traits.trait_generics.Conv.conv.post := do ok (res < 10#u32) +/-- Lawful structure of trait: [hax_tests::specs::traits::trait_generics::Conv] + Source: 'src/specs/traits/trait_generics.rs', lines 6:0-9:1 -/ +structure specs.traits.trait_generics.Conv.Lawful (Self : Type) (T : Type) + (ConvInst : specs.traits.trait_generics.Conv Self T) : Prop where + conv_spec (self_ : Self) (t : T) : + (specs.traits.trait_generics.Conv.conv.pre ConvInst self_ t).holds → + ⦃ ⌜ True ⌝ ⦄ + ConvInst.conv self_ t + ⦃ ⇓ res => + ⌜ (specs.traits.trait_generics.Conv.conv.post ConvInst self_ t + res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::unannotated_sub::A::a::pre]: Source: 'src/specs/traits/unannotated_sub.rs', lines 9:4-9:23 -/ @@ -662,6 +980,22 @@ def specs.traits.unannotated_sub.A.a.post := do ok (res > 0#u32) +/-- Lawful structure of trait: [hax_tests::specs::traits::unannotated_sub::A] + Source: 'src/specs/traits/unannotated_sub.rs', lines 7:0-10:1 -/ +structure specs.traits.unannotated_sub.A.Lawful (Self : Type) (AInst : + specs.traits.unannotated_sub.A Self) : Prop where + a_spec (self_ : Self) : + (specs.traits.unannotated_sub.A.a.pre AInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + AInst.a self_ + ⦃ ⇓ res => + ⌜ (specs.traits.unannotated_sub.A.a.post AInst self_ res).holds ⌝ ⦄ + +/-- Lawful structure of trait: [hax_tests::specs::traits::unannotated_sub::B] + Source: 'src/specs/traits/unannotated_sub.rs', lines 12:0-14:1 -/ +structure specs.traits.unannotated_sub.B.Lawful (Self : Type) (BInst : + specs.traits.unannotated_sub.B Self) : Prop where + AInstLawful : specs.traits.unannotated_sub.A.Lawful Self BInst.AInst /-- [hax_tests::specs::contracts::only_requires::pre]: Source: 'src/specs/contracts.rs', lines 3:0-3:20 -/ @@ -675,7 +1009,6 @@ def specs.contracts.only_requires.spec (x : Std.U32) : Prop := specs.contracts.only_requires x ⦃ ⇓ res => ⌜ True ⌝ ⦄ - /-- [hax_tests::specs::contracts::only_ensures::post]: Source: 'src/specs/contracts.rs', lines 8:0-8:32 -/ @[reducible] @@ -688,7 +1021,6 @@ def specs.contracts.only_ensures.spec (x : Std.U32) : Prop := specs.contracts.only_ensures x ⦃ ⇓ res => ⌜ (specs.contracts.only_ensures.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::both::pre]: Source: 'src/specs/contracts.rs', lines 13:0-13:19 -/ @[reducible] @@ -708,7 +1040,6 @@ def specs.contracts.both.spec (x : Std.U32) : Prop := specs.contracts.both x ⦃ ⇓ res => ⌜ (specs.contracts.both.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::returns_unit::pre]: Source: 'src/specs/contracts.rs', lines 20:0-20:19 -/ @[reducible] @@ -728,7 +1059,6 @@ def specs.contracts.returns_unit.spec (x : Std.U32) : Prop := specs.contracts.returns_unit x ⦃ ⇓ res => ⌜ (specs.contracts.returns_unit.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::no_args::post]: Source: 'src/specs/contracts.rs', lines 25:0-25:20 -/ @[reducible] @@ -740,7 +1070,6 @@ def specs.contracts.no_args.spec : Prop := specs.contracts.no_args ⦃ ⇓ res => ⌜ (specs.contracts.no_args.post res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::zero_ret::pre]: Source: 'src/specs/contracts.rs', lines 33:0-33:17 -/ @[reducible] def specs.contracts.zero_ret.pre : RustM Bool := do @@ -758,7 +1087,6 @@ def specs.contracts.zero_ret.spec : Prop := specs.contracts.zero_ret ⦃ ⇓ res => ⌜ (specs.contracts.zero_ret.post res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::block_in_requires::pre]: Source: 'src/specs/contracts.rs', lines 40:0-40:42 -/ @[reducible] @@ -771,7 +1099,6 @@ def specs.contracts.block_in_requires.spec (x : Std.U32) : Prop := specs.contracts.block_in_requires x ⦃ ⇓ res => ⌜ True ⌝ ⦄ - /-- [hax_tests::specs::contracts::returns_pair::post]: Source: 'src/specs/contracts.rs', lines 46:0-46:37 -/ @[reducible] @@ -787,7 +1114,6 @@ def specs.contracts.returns_pair.spec (x : Std.U32) : Prop := specs.contracts.returns_pair x ⦃ ⇓ res => ⌜ (specs.contracts.returns_pair.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::returns_option::post]: Source: 'src/specs/contracts.rs', lines 52:0-52:70 -/ @[reducible] @@ -802,7 +1128,6 @@ def specs.contracts.returns_option.spec (x : Std.U32) : Prop := specs.contracts.returns_option x ⦃ ⇓ res => ⌜ (specs.contracts.returns_option.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::returns_result::pre]: Source: 'src/specs/contracts.rs', lines 58:0-58:20 -/ @[reducible] @@ -825,7 +1150,6 @@ def specs.contracts.returns_result.spec (x : Std.U32) : Prop := specs.contracts.returns_result x ⦃ ⇓ res => ⌜ (specs.contracts.returns_result.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::may_panic::pre]: Source: 'src/specs/contracts.rs', lines 65:0-65:19 -/ @[reducible] @@ -846,7 +1170,6 @@ def specs.contracts.may_panic.spec (x : Std.U32) (y : Std.U32) : Prop := specs.contracts.may_panic x y ⦃ ⇓ res => ⌜ (specs.contracts.may_panic.post x y res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::explicit_panic::pre]: Source: 'src/specs/contracts.rs', lines 72:0-72:19 -/ @[reducible] @@ -866,7 +1189,6 @@ def specs.contracts.explicit_panic.spec (x : Std.U32) : Prop := specs.contracts.explicit_panic x ⦃ ⇓ res => ⌜ (specs.contracts.explicit_panic.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::implies_cond::pre]: Source: 'src/specs/contracts.rs', lines 82:0-82:37 -/ @[reducible] @@ -893,7 +1215,6 @@ def specs.contracts.implies_cond.spec (x : Std.U32) (y : Std.U32) : Prop := specs.contracts.implies_cond x y ⦃ ⇓ res => ⌜ (specs.contracts.implies_cond.post x y res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::quantifiers::pre]: Source: 'src/specs/contracts.rs', lines 93:0-93:53 -/ @[reducible] @@ -919,7 +1240,6 @@ def specs.contracts.quantifiers.spec (x : Std.U32) : Prop := specs.contracts.quantifiers x ⦃ ⇓ res => ⌜ (specs.contracts.quantifiers.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::int_bounds::pre]: Source: 'src/specs/contracts.rs', lines 101:0-101:57 -/ @[reducible] @@ -949,7 +1269,6 @@ def specs.contracts.int_bounds.spec (x : Std.U32) (y : Std.U32) : Prop := specs.contracts.int_bounds x y ⦃ ⇓ res => ⌜ (specs.contracts.int_bounds.post x y res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::helper_in_requires::pre]: Source: 'src/specs/contracts.rs', lines 112:0-112:24 -/ @[reducible] @@ -968,9 +1287,8 @@ def specs.contracts.helper_in_requires.spec (x : Std.U32) : Prop := (specs.contracts.helper_in_requires.pre x).holds → ⦃ ⌜ True ⌝ ⦄ specs.contracts.helper_in_requires x - ⦃ ⇓ res => ⌜ (specs.contracts.helper_in_requires.post x res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.contracts.helper_in_requires.post x res).holds ⌝ ⦄ /-- [hax_tests::specs::contracts::calls_contracted::pre]: Source: 'src/specs/contracts.rs', lines 119:0-119:19 -/ @@ -991,9 +1309,8 @@ def specs.contracts.calls_contracted.spec (x : Std.U32) : Prop := (specs.contracts.calls_contracted.pre x).holds → ⦃ ⌜ True ⌝ ⦄ specs.contracts.calls_contracted x - ⦃ ⇓ res => ⌜ (specs.contracts.calls_contracted.post x res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.contracts.calls_contracted.post x res).holds ⌝ ⦄ /-- [hax_tests::specs::contracts::recursive::pre]: Source: 'src/specs/contracts.rs', lines 126:0-126:20 -/ @@ -1014,7 +1331,6 @@ def specs.contracts.recursive.spec (n : Std.U32) : Prop := specs.contracts.recursive n ⦃ ⇓ res => ⌜ (specs.contracts.recursive.post n res).holds ⌝ ⦄ - /-- [hax_tests::specs::contracts::with_loop::pre]: Source: 'src/specs/contracts.rs', lines 138:0-138:20 -/ @[reducible] @@ -1034,7 +1350,6 @@ def specs.contracts.with_loop.spec (n : Std.U32) : Prop := specs.contracts.with_loop n ⦃ ⇓ res => ⌜ (specs.contracts.with_loop.post n res).holds ⌝ ⦄ - /-- [hax_tests::specs::arguments::named::post]: Source: 'src/specs/arguments.rs', lines 18:0-18:32 -/ @[reducible] @@ -1047,7 +1362,6 @@ def specs.arguments.named.spec (_ : Unit) : Prop := specs.arguments.named () ⦃ ⇓ res => ⌜ (specs.arguments.named.post () res).holds ⌝ ⦄ - /-- [hax_tests::specs::arguments::before_other::pre]: Source: 'src/specs/arguments.rs', lines 24:0-24:20 -/ @[reducible] @@ -1068,7 +1382,6 @@ def specs.arguments.before_other.spec (_ : Unit) (y : Std.U32) : Prop := specs.arguments.before_other () y ⦃ ⇓ res => ⌜ (specs.arguments.before_other.post () y res).holds ⌝ ⦄ - /-- [hax_tests::specs::arguments::sum_fields::pre]: Source: 'src/specs/arguments.rs', lines 36:0-36:35 -/ @[reducible] @@ -1092,7 +1405,6 @@ def specs.arguments.sum_fields.spec (p : specs.arguments.Point) : Prop := specs.arguments.sum_fields p ⦃ ⇓ res => ⌜ (specs.arguments.sum_fields.post p res).holds ⌝ ⦄ - /-- [hax_tests::specs::arguments::shape_len::pre]: Source: 'src/specs/arguments.rs', lines 48:0-48:70 -/ @[reducible] @@ -1115,7 +1427,6 @@ def specs.arguments.shape_len.spec (s : specs.arguments.Shape) : Prop := specs.arguments.shape_len s ⦃ ⇓ res => ⌜ (specs.arguments.shape_len.post s res).holds ⌝ ⦄ - /-- [hax_tests::specs::mutable_borrows::incr::pre]: Source: 'src/specs/mutable_borrows.rs', lines 3:0-3:22 -/ @[reducible] @@ -1136,7 +1447,6 @@ def specs.mutable_borrows.incr.spec (x : Std.U32) : Prop := specs.mutable_borrows.incr x ⦃ ⇓ res => ⌜ (specs.mutable_borrows.incr.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::mutable_borrows::incr_i::pre]: Source: 'src/specs/mutable_borrows.rs', lines 9:0-9:43 -/ @[reducible] @@ -1167,7 +1477,6 @@ def specs.mutable_borrows.incr_i.spec (x : Slice Std.U32) (i : Std.Usize) specs.mutable_borrows.incr_i x i ⦃ ⇓ res => ⌜ (specs.mutable_borrows.incr_i.post x i res).holds ⌝ ⦄ - /-- [hax_tests::specs::mutable_borrows::swap_and_add::pre]: Source: 'src/specs/mutable_borrows.rs', lines 17:0-17:35 -/ @[reducible] @@ -1198,8 +1507,7 @@ def specs.mutable_borrows.swap_and_add.spec (x : Std.U32) (y : Std.U32) ⦃ ⌜ True ⌝ ⦄ specs.mutable_borrows.swap_and_add x y ⦃ ⇓ res => - ⌜ (specs.mutable_borrows.swap_and_add.post x y res).holds ⌝ ⦄ - + ⌜ (specs.mutable_borrows.swap_and_add.post x y res).holds ⌝ ⦄ /-- [hax_tests::specs::mutable_borrows::incr_ret::pre]: Source: 'src/specs/mutable_borrows.rs', lines 31:0-31:21 -/ @@ -1224,7 +1532,6 @@ def specs.mutable_borrows.incr_ret.spec (x : Std.U8) : Prop := specs.mutable_borrows.incr_ret x ⦃ ⇓ res => ⌜ (specs.mutable_borrows.incr_ret.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::mutable_borrows::read_shared::post]: Source: 'src/specs/mutable_borrows.rs', lines 39:0-39:33 -/ @[reducible] @@ -1235,9 +1542,8 @@ def specs.mutable_borrows.read_shared.post def specs.mutable_borrows.read_shared.spec (x : Std.U32) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.mutable_borrows.read_shared x - ⦃ ⇓ res => ⌜ (specs.mutable_borrows.read_shared.post x res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.mutable_borrows.read_shared.post x res).holds ⌝ ⦄ /-- [hax_tests::specs::mutable_borrows::add_assign::pre]: Source: 'src/specs/mutable_borrows.rs', lines 45:0-45:35 -/ @@ -1260,9 +1566,8 @@ def specs.mutable_borrows.add_assign.spec (x : Std.U32) (y : Std.U32) : Prop := (specs.mutable_borrows.add_assign.pre x y).holds → ⦃ ⌜ True ⌝ ⦄ specs.mutable_borrows.add_assign x y - ⦃ ⇓ res => ⌜ (specs.mutable_borrows.add_assign.post x y res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.mutable_borrows.add_assign.post x y res).holds ⌝ ⦄ /-- [hax_tests::specs::generics::generic::pre]: Source: 'src/specs/generics.rs', lines 9:0-9:27 -/ @@ -1285,7 +1590,6 @@ def specs.generics.generic.spec (N : Std.U32) (x : Std.U32) : Prop := specs.generics.generic N x ⦃ ⇓ res => ⌜ (specs.generics.generic.post N x res).holds ⌝ ⦄ - /-- [hax_tests::specs::generics::trait_clause::pre]: Source: 'src/specs/generics.rs', lines 26:0-26:41 -/ @[reducible] @@ -1315,8 +1619,7 @@ def ⦃ ⌜ True ⌝ ⦄ specs.generics.trait_clause ValInst t x ⦃ ⇓ res => - ⌜ (specs.generics.trait_clause.post ValInst t x res).holds ⌝ ⦄ - + ⌜ (specs.generics.trait_clause.post ValInst t x res).holds ⌝ ⦄ /-- [hax_tests::specs::generics::where_clause::pre]: Source: 'src/specs/generics.rs', lines 33:0-33:29 -/ @@ -1341,9 +1644,8 @@ def (specs.generics.where_clause.pre ValInst t).holds → ⦃ ⌜ True ⌝ ⦄ specs.generics.where_clause ValInst t - ⦃ ⇓ res => ⌜ (specs.generics.where_clause.post ValInst t res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.generics.where_clause.post ValInst t res).holds ⌝ ⦄ /-- [hax_tests::specs::generics::assoc_type::pre]: Source: 'src/specs/generics.rs', lines 61:0-61:29 -/ @@ -1373,8 +1675,7 @@ def ⦃ ⌜ True ⌝ ⦄ specs.generics.assoc_type ProducerPU32Inst p ⦃ ⇓ res => - ⌜ (specs.generics.assoc_type.post ProducerPU32Inst p res).holds ⌝ ⦄ - + ⌜ (specs.generics.assoc_type.post ProducerPU32Inst p res).holds ⌝ ⦄ /-- [hax_tests::specs::generics::array_index::pre]: Source: 'src/specs/generics.rs', lines 68:0-68:18 -/ @@ -1400,7 +1701,6 @@ def specs.generics.array_index.spec {N : Std.Usize} (x : Array Std.U32 N) specs.generics.array_index x i ⦃ ⇓ res => ⌜ (specs.generics.array_index.post x i res).holds ⌝ ⦄ - /-- [hax_tests::specs::generics::nothing::post]: Source: 'src/specs/generics.rs', lines 100:0-100:20 -/ @[reducible] @@ -1413,7 +1713,6 @@ def specs.generics.nothing.spec (T : Type) (k : Std.Usize) : Prop := specs.generics.nothing T k ⦃ ⇓ res => ⌜ (specs.generics.nothing.post k res).holds ⌝ ⦄ - /-- [hax_tests::specs::generics::nothing_no_args::post]: Source: 'src/specs/generics.rs', lines 106:0-106:20 -/ @[reducible] @@ -1426,7 +1725,6 @@ def specs.generics.nothing_no_args.spec (T : Type) : Prop := specs.generics.nothing_no_args T ⦃ ⇓ res => ⌜ (specs.generics.nothing_no_args.post res).holds ⌝ ⦄ - /-- [hax_tests::specs::generics::of_fst::post]: Source: 'src/specs/generics.rs', lines 112:0-112:20 -/ @[reducible] @@ -1441,7 +1739,6 @@ def specs.generics.of_fst.spec {T : Type} (N : Std.Usize) (t : T) : Prop := specs.generics.of_fst N t ⦃ ⇓ res => ⌜ (specs.generics.of_fst.post t res).holds ⌝ ⦄ - /-- [hax_tests::specs::generics::empty::post]: Source: 'src/specs/generics.rs', lines 118:0-118:20 -/ @[reducible] @@ -1458,7 +1755,6 @@ def specs.generics.empty.spec (T : Type) (N : Std.Usize) (k : Std.Usize) specs.generics.empty T N k ⦃ ⇓ res => ⌜ (specs.generics.empty.post k res).holds ⌝ ⦄ - /-- [hax_tests::specs::naming::foo::pre]: Source: 'src/specs/naming.rs', lines 5:0-5:20 -/ @[reducible] @@ -1478,7 +1774,6 @@ def specs.naming.foo.spec (x : Std.U32) : Prop := specs.naming.foo x ⦃ ⇓ res => ⌜ (specs.naming.foo.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::arguments::{impl hax_tests::specs::arguments::Size for ()}::len::post]: Source: 'src/specs/arguments.rs', lines 12:4-12:24 -/ @[reducible] @@ -1490,8 +1785,7 @@ def Tuple.Insts.Hax_testsSpecsArgumentsSize.len.spec (_ : Unit) : Prop := ⦃ ⌜ True ⌝ ⦄ Tuple.Insts.Hax_testsSpecsArgumentsSize.len () ⦃ ⇓ res => - ⌜ (Tuple.Insts.Hax_testsSpecsArgumentsSize.len.post () res).holds ⌝ ⦄ - + ⌜ (Tuple.Insts.Hax_testsSpecsArgumentsSize.len.post () res).holds ⌝ ⦄ /-- [hax_tests::specs::mutable_borrows::{hax_tests::specs::mutable_borrows::Counter}::bump::pre]: Source: 'src/specs/mutable_borrows.rs', lines 58:4-58:34 -/ @@ -1517,8 +1811,7 @@ def specs.mutable_borrows.Counter.bump.spec ⦃ ⌜ True ⌝ ⦄ specs.mutable_borrows.Counter.bump self ⦃ ⇓ res => - ⌜ (specs.mutable_borrows.Counter.bump.post self res).holds ⌝ ⦄ - + ⌜ (specs.mutable_borrows.Counter.bump.post self res).holds ⌝ ⦄ /-- [hax_tests::specs::generics::{hax_tests::specs::generics::Wrapper}::inner_value::pre]: Source: 'src/specs/generics.rs', lines 48:4-48:36 -/ @@ -1549,8 +1842,7 @@ def ⦃ ⌜ True ⌝ ⦄ specs.generics.Wrapper.inner_value ValInst self ⦃ ⇓ res => - ⌜ (specs.generics.Wrapper.inner_value.post ValInst self res).holds ⌝ ⦄ - + ⌜ (specs.generics.Wrapper.inner_value.post ValInst self res).holds ⌝ ⦄ /-- [hax_tests::specs::generics::{hax_tests::specs::generics::MyStruct}::build::pre]: Source: 'src/specs/generics.rs', lines 82:4-82:24 -/ @@ -1575,7 +1867,6 @@ def specs.generics.MyStruct.build.spec (N : Std.Usize) (k : Std.Usize) specs.generics.MyStruct.build N k ⦃ ⇓ res => ⌜ (specs.generics.MyStruct.build.post k res).holds ⌝ ⦄ - /-- [hax_tests::specs::generics::{hax_tests::specs::generics::MyStruct}::get::post]: Source: 'src/specs/generics.rs', lines 89:4-89:24 -/ @[reducible] @@ -1591,7 +1882,6 @@ def specs.generics.MyStruct.get.spec {N : Std.Usize} specs.generics.MyStruct.get self ⦃ ⇓ res => ⌜ (specs.generics.MyStruct.get.post self res).holds ⌝ ⦄ - /-- [hax_tests::specs::traits::basic::g::post]: Source: 'src/specs/traits/basic.rs', lines 58:0-58:27 -/ @[reducible] @@ -1607,7 +1897,6 @@ def specs.traits.basic.g.spec {T : Type} (FooInst : specs.traits.basic.Foo T) specs.traits.basic.g FooInst x ⦃ ⇓ res => ⌜ (specs.traits.basic.g.post FooInst x res).holds ⌝ ⦄ - /-- [hax_tests::specs::traits::basic::h::post]: Source: 'src/specs/traits/basic.rs', lines 68:0-68:27 -/ @[reducible] @@ -1619,7 +1908,6 @@ def specs.traits.basic.h.spec (x : Std.U64) : Prop := specs.traits.basic.h x ⦃ ⇓ res => ⌜ (specs.traits.basic.h.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::traits::supertraits::via_b::pre]: Source: 'src/specs/traits/supertraits.rs', lines 46:0-46:24 -/ @[reducible] @@ -1645,8 +1933,7 @@ def ⦃ ⌜ True ⌝ ⦄ specs.traits.supertraits.via_b BInst x ⦃ ⇓ res => - ⌜ (specs.traits.supertraits.via_b.post BInst x res).holds ⌝ ⦄ - + ⌜ (specs.traits.supertraits.via_b.post BInst x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::supertraits::via_u8::pre]: Source: 'src/specs/traits/supertraits.rs', lines 54:0-54:24 -/ @@ -1668,7 +1955,6 @@ def specs.traits.supertraits.via_u8.spec (x : Std.U8) : Prop := specs.traits.supertraits.via_u8 x ⦃ ⇓ res => ⌜ (specs.traits.supertraits.via_u8.post x res).holds ⌝ ⦄ - /-- [hax_tests::specs::traits::diamond::via_b::post]: Source: 'src/specs/traits/diamond.rs', lines 39:0-39:40 -/ @[reducible] @@ -1685,9 +1971,8 @@ def (x : T) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.diamond.via_b BInst x - ⦃ ⇓ res => ⌜ (specs.traits.diamond.via_b.post BInst x res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.traits.diamond.via_b.post BInst x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::diamond::diamond::post]: Source: 'src/specs/traits/diamond.rs', lines 46:0-46:26 -/ @@ -1703,9 +1988,8 @@ def T) (x : T) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.diamond.diamond CInst x - ⦃ ⇓ res => ⌜ (specs.traits.diamond.diamond.post CInst x res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.traits.diamond.diamond.post CInst x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::generic_impl::k::post]: Source: 'src/specs/traits/generic_impl.rs', lines 62:0-62:27 -/ @@ -1725,8 +2009,7 @@ def ⦃ ⌜ True ⌝ ⦄ specs.traits.generic_impl.k FooInst SubInst x y ⦃ ⇓ res => - ⌜ (specs.traits.generic_impl.k.post FooInst SubInst x y res).holds ⌝ ⦄ - + ⌜ (specs.traits.generic_impl.k.post FooInst SubInst x y res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::blanket_impl::show_generic::post]: Source: 'src/specs/traits/blanket_impl.rs', lines 22:0-22:27 -/ @@ -1739,8 +2022,7 @@ def specs.traits.blanket_impl.show_generic.spec {T : Type} (x : T) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.blanket_impl.show_generic x ⦃ ⇓ res => - ⌜ (specs.traits.blanket_impl.show_generic.post x res).holds ⌝ ⦄ - + ⌜ (specs.traits.blanket_impl.show_generic.post x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::blanket_impl::show_u64::post]: Source: 'src/specs/traits/blanket_impl.rs', lines 28:0-28:27 -/ @@ -1752,9 +2034,8 @@ def specs.traits.blanket_impl.show_u64.post def specs.traits.blanket_impl.show_u64.spec (x : Std.U64) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.blanket_impl.show_u64 x - ⦃ ⇓ res => ⌜ (specs.traits.blanket_impl.show_u64.post x res).holds ⌝ - ⦄ - + ⦃ ⇓ res => + ⌜ (specs.traits.blanket_impl.show_u64.post x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::assoc_type_bounds::first_bar::post]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 50:0-50:26 -/ @@ -1776,9 +2057,8 @@ def ⦃ ⌜ True ⌝ ⦄ specs.traits.assoc_type_bounds.first_bar ContainerInst c ⦃ ⇓ res => - ⌜ (specs.traits.assoc_type_bounds.first_bar.post ContainerInst c res).holds - ⌝ ⦄ - + ⌜ (specs.traits.assoc_type_bounds.first_bar.post ContainerInst c + res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::builtin_bound::dup::post]: Source: 'src/specs/traits/builtin_bound.rs', lines 11:0-11:20 -/ @@ -1795,9 +2075,7 @@ def ⦃ ⌜ True ⌝ ⦄ specs.traits.builtin_bound.dup corecloneCloneInst x ⦃ ⇓ res => - ⌜ (specs.traits.builtin_bound.dup.post corecloneCloneInst x res).holds ⌝ - ⦄ - + ⌜ (specs.traits.builtin_bound.dup.post corecloneCloneInst x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::trait_generics::use_conv::post]: Source: 'src/specs/traits/trait_generics.rs', lines 17:0-17:26 -/ @@ -1816,9 +2094,7 @@ def ⦃ ⌜ True ⌝ ⦄ specs.traits.trait_generics.use_conv ConvCU8Inst c ⦃ ⇓ res => - ⌜ (specs.traits.trait_generics.use_conv.post ConvCU8Inst c res).holds ⌝ - ⦄ - + ⌜ (specs.traits.trait_generics.use_conv.post ConvCU8Inst c res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f::pre]: Source: 'src/specs/traits/impl_contract.rs', lines 14:4-14:28 -/ @@ -1841,9 +2117,7 @@ def U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec (self : Std.U32) ⦃ ⌜ True ⌝ ⦄ U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f self ⦃ ⇓ res => - ⌜ (U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.post self res).holds - ⌝ ⦄ - + ⌜ (U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.post self res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::G for u32}::g::pre]: Source: 'src/specs/traits/impl_contract.rs', lines 29:4-29:27 -/ @@ -1866,7 +2140,6 @@ def U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec (self : Std.U32) ⦃ ⌜ True ⌝ ⦄ U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g self ⦃ ⇓ res => - ⌜ (U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.post self res).holds ⌝ - ⦄ + ⌜ (U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.post self res).holds ⌝ ⦄ end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index 25cd03e8b4..a281541927 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -3,6 +3,7 @@ import Aeneas import CoreModels import HaxTests.Extraction.TypesExternal +import HaxTests.Assumptions.MissingCore open CoreModels Aeneas open Aeneas.Std hiding namespace core alloc open RustM ControlFlow Error From c63a74b96651ae536f6c228f206abf78a8fdbb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Wed, 14 Oct 2026 11:23:24 +0200 Subject: [PATCH 07/17] feat-specs: check for name clash + warn for impl-level specs --- src/extract/ExtractHaxSpecs.ml | 30 +++++++++++++++++++ src/specs/HaxProducer.ml | 11 +++++++ .../lean/HaxTests/Extraction/Specs.lean | 5 ++++ .../lean/HaxTests/Extraction/Types.lean | 6 ++++ tests/hax/src/specs/naming.rs | 6 ++++ tests/hax/src/specs/traits/impl_contract.rs | 6 ++-- 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index 04ff07a32f..58f68170db 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -316,6 +316,35 @@ let warn_untranslated (ctx : ExtractBase.extraction_ctx) opt_span "hax-specs: dropping the contract of %s `%s`: the %s was not translated" kind name kind) +(** Report a clash between [.Lawful] and the projection of a field of the + trait structure [d] (parent clause, associated item or method) named + [Lawful]: field names are registered without collision checks (see + {!ExtractBase.allow_collisions}). *) +let check_lawful_field_clash span (ctx : ExtractBase.extraction_ctx) + (spec_id : Spec.SpecId.id) (d : Pure.trait_decl) : unit = + let open ExtractBase in + let get id = ctx_get_raw (Some span) id ctx in + let trait_name = get (TraitDeclId d.def_id) in + let lawful = lawful_name trait_name in + let fields = + List.map + (fun (c : Pure.trait_param) -> + TraitParentClauseId (d.def_id, c.clause_id)) + d.parent_clauses + @ List.map (fun (id, _, _) -> TraitConstId (d.def_id, id)) d.consts + @ List.map (fun (id, _) -> TraitTypeId (d.def_id, id)) d.types + @ List.map + (fun (m : Pure.trait_method) -> TraitMethodId (d.def_id, m.method_id)) + d.methods + in + List.iter + (fun id -> + if ExtractBuiltin.flatten_name [ trait_name; get id ] = lawful then + report_name_collision + (fun id -> id_to_string (Some span) id ctx) + (id, Some span) (SpecId spec_id) (Some span) lawful) + fields + (** Register the names of the conditions and of the spec. Must be called after registering the crate items. Warns about the specs of untranslated items: {!emit_spec} skips them. *) @@ -356,6 +385,7 @@ let register_spec_names (ctx : ExtractBase.extraction_ctx) let span = d.item_meta.span in let get id = ExtractBase.ctx_get_raw (Some span) id ctx in let trait_name = get (TraitDeclId trait_decl) in + check_lawful_field_clash span ctx spec_id d; let ctx = ExtractBase.ctx_add span (SpecId spec_id) (lawful_name trait_name) ctx diff --git a/src/specs/HaxProducer.ml b/src/specs/HaxProducer.ml index 5c712a05f2..e4cf1b9ad8 100644 --- a/src/specs/HaxProducer.ml +++ b/src/specs/HaxProducer.ml @@ -376,6 +376,17 @@ let produce (ctx : TranslateCore.trans_ctx) [%ltrace Printf.sprintf "hax-specs: fn=%s pre=%s post=%s" (parent_name ctx a.parent) (shape pre) (shape post)]; + (* The contract of a trait impl method is checked against its body by its + own spec, the trait-level one by the Lawful obligation of the impl: + nothing relates them *) + (match a.parent with + | Fun { src = TraitImplFun _; _ } -> + [%lwarning + Printf.sprintf + "hax-specs: the contract of `%s` is checked as a standalone spec \ + only; it is independent of the trait-level contract" + (parent_name ctx a.parent)] + | _ -> ()); let span = Some (parent_span a.parent) in (* One [function_spec] payload, shared between the spec and the proof obligation that discharges it. *) diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index 147fe40b86..9ac7fd5fea 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -43,6 +43,11 @@ structure specs.generics.Val.Lawful (Self : Type) (ValInst : specs.generics.Val structure specs.generics.Producer.Lawful (Self : Type) (Self_Out : Type) (ProducerInst : specs.generics.Producer Self Self_Out) : Prop +/-- Lawful structure of trait: [hax_tests::specs::naming::Qux] + Source: 'src/specs/naming.rs', lines 31:0-33:1 -/ +structure specs.naming.Qux.Lawful (Self : Type) (QuxInst : specs.naming.Qux + Self) : Prop + /-- [hax_tests::specs::traits::assoc_type_bounds::Bar::bar::pre]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 11:4-11:25 -/ @[reducible] diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index a281541927..c384e789a8 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -86,6 +86,12 @@ structure specs.generics.Pair (T : Type) (N : Std.Usize) where structure specs.mutable_borrows.Counter where count : Std.U32 +/-- Trait declaration: [hax_tests::specs::naming::Qux] + Source: 'src/specs/naming.rs', lines 31:0-33:1 + Visibility: public -/ +structure specs.naming.Qux (Self : Type) where + lawful : Self → RustM Std.U32 + /-- Trait declaration: [hax_tests::specs::traits::assoc_type_bounds::Bar] Source: 'src/specs/traits/assoc_type_bounds.rs', lines 9:0-12:1 -/ structure specs.traits.assoc_type_bounds.Bar (Self : Type) where diff --git a/tests/hax/src/specs/naming.rs b/tests/hax/src/specs/naming.rs index a6771caf09..f8ae49fdf6 100644 --- a/tests/hax/src/specs/naming.rs +++ b/tests/hax/src/specs/naming.rs @@ -25,3 +25,9 @@ pub fn proof() {} pub mod bar { pub fn pre() {} } + +// No clash: the check against `Qux.Lawful` is case-sensitive, so the field +// `Qux.lawful` is fine. +pub trait Qux { + fn lawful(&self) -> u32; +} diff --git a/tests/hax/src/specs/traits/impl_contract.rs b/tests/hax/src/specs/traits/impl_contract.rs index a0ac8af468..163a73175f 100644 --- a/tests/hax/src/specs/traits/impl_contract.rs +++ b/tests/hax/src/specs/traits/impl_contract.rs @@ -1,7 +1,7 @@ -// Impl-level contracts. On an unannotated trait (`Foo`): not supported -// yet, it emits a warning but still a standalone spec. On an annotated +// Impl-level contracts: checked as standalone specs only, with a warning. +// On an unannotated trait (`Foo`): only the standalone spec. On an annotated // trait method (`G::g`): the trait-level contract gives the Lawful field, -// the impl-level one the warning and the standalone spec. +// the impl-level one the warning and the independent standalone spec. use hax_lib::*; From 38dcc06e042ca14071bff30a11bbbacd37f32854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Wed, 14 Oct 2026 13:27:22 +0200 Subject: [PATCH 08/17] feat-specs: add lawful hypothesis to specs --- src/extract/ExtractHaxSpecs.ml | 58 ++++++++++++---- .../lean/HaxTests/Extraction/Funs.lean | 9 +++ .../HaxTests/Extraction/ProofObligations.lean | 66 ++++++++++++++----- .../lean/HaxTests/Extraction/Specs.lean | 52 +++++++++++---- .../Verification/ProofObligations.lean | 23 +++++-- tests/hax/src/specs/naming.rs | 13 ++++ 6 files changed, 171 insertions(+), 50 deletions(-) diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index 58f68170db..6af65f1e30 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -269,6 +269,10 @@ let proof_name (parent_name : string) : string = let lawful_name (trait_name : string) : string = ExtractBuiltin.flatten_name [ trait_name; "Lawful" ] +(** [Lawful]: the name of the Lawful binder (or parent field) of the + clause [clause_name] *) +let lawful_binder_name (clause_name : string) : string = clause_name ^ "Lawful" + (** The names of the conditions [pre] and [post] of [parent_name] *) let cond_names (parent_name : string) ~(pre : Pure.fun_decl option) ~(post : Pure.fun_decl option) : (Pure.fun_decl * string) list = @@ -550,7 +554,7 @@ let emit_lawful_clause_binders span (ctx : ExtractBase.extraction_ctx) fmt emit_binder fmt name (fun () -> ExtractTypes.extract_trait_clause_type span ctx fmt Pure.TypeDeclId.Set.empty c); - emit_binder fmt (name ^ "Lawful") (fun () -> + emit_binder fmt (lawful_binder_name name) (fun () -> emit_lawful_type span ctx fmt tr)) clauses args.trait_refs @@ -606,7 +610,7 @@ let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt ctx in Extract.extract_trait_decl_item ctx fmt - (escape_name (name ^ "Lawful")) + (escape_name (lawful_binder_name name)) (fun () -> F.pp_print_space fmt (); emit_lawful_type span ctx fmt (parent_ref d self_ref c))) @@ -630,7 +634,7 @@ let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt in (* The names of the Lawful binders of the clauses *) let ctx = - ctx_reserve_names (List.map (fun n -> n ^ "Lawful") clause_names) ctx + ctx_reserve_names (List.map lawful_binder_name clause_names) ctx in let ctx = add_conditions ctx ~pre ~post in let _, fresh_fvar_id = Pure.FVarId.fresh_stateful_generator () in @@ -682,6 +686,32 @@ let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt methods; F.pp_close_box fmt () +(** Emit the binders of the function [f]: its generic and value parameters, then + the Lawful binders of its trait clauses. Return the context with the + parameters registered, and the names of the Lawful binders. *) +let emit_fun_binders (ctx : ExtractBase.extraction_ctx) fmt (f : Pure.fun_decl) + = + let open ExtractBase in + let span = f.item_meta.span in + let sg = f.signature in + (* Reserve the Lawful names, so that no parameter takes them. The clause + names are those [extract_fun_parameters] computes: they end with [Inst] + (and an index), so the reserved names cannot change them. *) + let _, _, _, clause_names = + ctx_add_generic_params span f.item_meta.name Item sg.llbc_generics + sg.generics ctx + in + let lawful_names = List.map lawful_binder_name clause_names in + let ctx = ctx_reserve_names lawful_names ctx in + let space = ref false in + let _, ctx, _ = Extract.extract_fun_parameters space ctx fmt f in + List.iter2 + (fun name tr -> + emit_binder fmt name (fun () -> emit_lawful_type span ctx fmt tr)) + lawful_names (PureUtils.generic_args_of_params sg.generics).trait_refs; + ExtractTypes.insert_req_space fmt space; + (ctx, lawful_names) + (** Emit one [Spec.spec] entry *) let emit_spec ctx fmt (s : HaxSpecs.spec) = let open ExtractBase in @@ -731,10 +761,7 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) = | None -> ()); F.pp_print_string fmt (escape_name (spec_name (registered_fun_name ctx parent))); - (* Generic + value binders via the standard param extractor. *) - let space = ref false in - let _, ctx, _ = Extract.extract_fun_parameters space ctx fmt parent in - ExtractTypes.insert_req_space fmt space; + let ctx, _ = emit_fun_binders ctx fmt parent in F.pp_print_string fmt ": Prop :="; F.pp_close_box fmt (); @@ -767,9 +794,10 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) = (** Emit one [HaxSpecs.obligation] entry as the proof obligation that discharges a spec's statement of correctness: {[ - theorem foo.spec.proof args : foo.spec args := by sorry + theorem foo.spec.proof args lawfuls : foo.spec args lawfuls := by sorry ]} - No attribute is emitted: registering the obligation with [mvcgen] (via + where [lawfuls] are the Lawful binders of the trait clauses of [foo]. No + attribute is emitted: registering the obligation with [mvcgen] (via [@[spec]]) is left to the user, who decides which specs to feed it. *) let emit_obligation ctx fmt (o : HaxSpecs.obligation) = let open ExtractBase in @@ -817,17 +845,19 @@ let emit_obligation ctx fmt (o : HaxSpecs.obligation) = F.pp_print_string fmt "theorem"; F.pp_print_space fmt (); F.pp_print_string fmt (escape_name (proof_name parent_name)); - (* Generic + value binders via the standard param extractor. *) - let space = ref false in - let _, ctx, _ = Extract.extract_fun_parameters space ctx fmt parent in - ExtractTypes.insert_req_space fmt space; + let ctx, lawful_names = emit_fun_binders ctx fmt parent in F.pp_print_string fmt ":"; F.pp_print_space fmt (); (* The statement of correctness, in its own box: - [.spec ]. *) + [.spec ]. *) F.pp_open_hovbox fmt 0; emit_app span ctx fmt explicit generics arg_texprs (escape_name (spec_name parent_name)); + List.iter + (fun name -> + F.pp_print_space fmt (); + F.pp_print_string fmt name) + lawful_names; F.pp_close_box fmt (); F.pp_close_box fmt (); (* statement hovbox *) diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean index bd78646230..ebd3c0816a 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean @@ -525,6 +525,15 @@ def specs.naming.proof : RustM Unit := do def specs.naming.bar.pre : RustM Unit := do ok () +/-- [hax_tests::specs::naming::lawful_binder::f]: + Source: 'src/specs/naming.rs', lines 43:4-45:5 + Visibility: public -/ +def specs.naming.lawful_binder.f + {T : Type} (QuxInst : specs.naming.Qux T) (QuxInstLawful : T) (x : Std.U32) : + RustM Std.U32 + := do + ok x + /-- [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Bar for u32}::bar]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 27:4-29:5 -/ def U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.bar diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean index 393f74f2a7..c51b7ef294 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean @@ -149,19 +149,24 @@ theorem specs.generics.generic.spec.proof (N : Std.U32) (x : Std.U32) : theorem specs.generics.trait_clause.spec.proof {T : Type} (ValInst : specs.generics.Val T) (t : T) - (x : Std.U32) : specs.generics.trait_clause.spec ValInst t x + (x : Std.U32) (ValInstLawful : specs.generics.Val.Lawful T ValInst) : + specs.generics.trait_clause.spec ValInst t x ValInstLawful := by sorry theorem specs.generics.where_clause.spec.proof {T : Type} (ValInst : - specs.generics.Val T) (t : T) : - specs.generics.where_clause.spec ValInst t + specs.generics.Val T) (t : T) + (ValInstLawful : specs.generics.Val.Lawful T ValInst) : + specs.generics.where_clause.spec ValInst t ValInstLawful := by sorry theorem specs.generics.assoc_type.spec.proof {P : Type} (ProducerPU32Inst : specs.generics.Producer P Std.U32) - (p : P) : specs.generics.assoc_type.spec ProducerPU32Inst p + (p : P) + (ProducerPU32InstLawful : specs.generics.Producer.Lawful P Std.U32 + ProducerPU32Inst) : + specs.generics.assoc_type.spec ProducerPU32Inst p ProducerPU32InstLawful := by sorry theorem specs.generics.array_index.spec.proof {N : Std.Usize} @@ -199,8 +204,9 @@ theorem specs.mutable_borrows.Counter.bump.spec.proof theorem specs.generics.Wrapper.inner_value.spec.proof {T : Type} (ValInst : specs.generics.Val T) - (self : specs.generics.Wrapper T) : - specs.generics.Wrapper.inner_value.spec ValInst self + (self : specs.generics.Wrapper T) + (ValInstLawful : specs.generics.Val.Lawful T ValInst) : + specs.generics.Wrapper.inner_value.spec ValInst self ValInstLawful := by sorry theorem specs.generics.MyStruct.build.spec.proof (N : Std.Usize) @@ -213,8 +219,9 @@ theorem specs.generics.MyStruct.get.spec.proof {N : Std.Usize} theorem specs.traits.basic.g.spec.proof {T : Type} (FooInst : specs.traits.basic.Foo - T) (x : T) : - specs.traits.basic.g.spec FooInst x + T) (x : T) + (FooInstLawful : specs.traits.basic.Foo.Lawful T FooInst) : + specs.traits.basic.g.spec FooInst x FooInstLawful := by sorry theorem specs.traits.basic.h.spec.proof (x : Std.U64) : @@ -224,7 +231,8 @@ theorem specs.traits.basic.h.spec.proof (x : Std.U64) : theorem specs.traits.supertraits.via_b.spec.proof {T : Type} (BInst : specs.traits.supertraits.B T) - (x : T) : specs.traits.supertraits.via_b.spec BInst x + (x : T) (BInstLawful : specs.traits.supertraits.B.Lawful T BInst) : + specs.traits.supertraits.via_b.spec BInst x BInstLawful := by sorry theorem specs.traits.supertraits.via_u8.spec.proof (x : Std.U8) : @@ -233,14 +241,16 @@ theorem specs.traits.supertraits.via_u8.spec.proof (x : Std.U8) : theorem specs.traits.diamond.via_b.spec.proof {T : Type} (BInst : - specs.traits.diamond.B T) (x : T) : - specs.traits.diamond.via_b.spec BInst x + specs.traits.diamond.B T) (x : T) + (BInstLawful : specs.traits.diamond.B.Lawful T BInst) : + specs.traits.diamond.via_b.spec BInst x BInstLawful := by sorry theorem specs.traits.diamond.diamond.spec.proof {T : Type} (CInst : - specs.traits.diamond.C T) (x : T) : - specs.traits.diamond.diamond.spec CInst x + specs.traits.diamond.C T) (x : T) + (CInstLawful : specs.traits.diamond.C.Lawful T CInst) : + specs.traits.diamond.diamond.spec CInst x CInstLawful := by sorry theorem @@ -248,7 +258,11 @@ theorem specs.traits.generic_impl.Foo T) (SubInst : specs.traits.generic_impl.Sub U) - (x : T) (y : U) : specs.traits.generic_impl.k.spec FooInst SubInst x y + (x : T) (y : U) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) + (SubInstLawful : specs.traits.generic_impl.Sub.Lawful U SubInst) : + specs.traits.generic_impl.k.spec FooInst SubInst x y FooInstLawful + SubInstLawful := by sorry theorem specs.traits.blanket_impl.show_generic.spec.proof {T : Type} @@ -264,20 +278,36 @@ theorem : Type} (ContainerInst : specs.traits.assoc_type_bounds.Container C Clause0_Item) - (c : C) : specs.traits.assoc_type_bounds.first_bar.spec ContainerInst c + (c : C) + (ContainerInstLawful : specs.traits.assoc_type_bounds.Container.Lawful C + Clause0_Item ContainerInst) : + specs.traits.assoc_type_bounds.first_bar.spec ContainerInst c + ContainerInstLawful := by sorry theorem specs.traits.builtin_bound.dup.spec.proof {T : Type} (corecloneCloneInst : - core.clone.Clone T) (x : T) : + core.clone.Clone T) (x : T) + (corecloneCloneInstLawful : core.clone.Clone.Lawful T corecloneCloneInst) : specs.traits.builtin_bound.dup.spec corecloneCloneInst x + corecloneCloneInstLawful := by sorry theorem specs.traits.trait_generics.use_conv.spec.proof {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv - C Std.U8) (c : C) : - specs.traits.trait_generics.use_conv.spec ConvCU8Inst c + C Std.U8) (c : C) + (ConvCU8InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U8 + ConvCU8Inst) : + specs.traits.trait_generics.use_conv.spec ConvCU8Inst c ConvCU8InstLawful + := by sorry + +theorem + specs.naming.lawful_binder.f.spec.proof {T : Type} (QuxInst : + specs.naming.Qux T) + (QuxInstLawful1 : T) (x : Std.U32) + (QuxInstLawful : specs.naming.Qux.Lawful T QuxInst) : + specs.naming.lawful_binder.f.spec QuxInst QuxInstLawful1 x QuxInstLawful := by sorry theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec.proof diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index 9ac7fd5fea..190dae1f0d 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -1619,7 +1619,8 @@ def specs.generics.trait_clause.post def specs.generics.trait_clause.spec {T : Type} (ValInst : specs.generics.Val T) - (t : T) (x : Std.U32) : Prop := + (t : T) (x : Std.U32) (ValInstLawful : specs.generics.Val.Lawful T ValInst) + : Prop := (specs.generics.trait_clause.pre ValInst t x).holds → ⦃ ⌜ True ⌝ ⦄ specs.generics.trait_clause ValInst t x @@ -1645,7 +1646,7 @@ def specs.generics.where_clause.post def specs.generics.where_clause.spec {T : Type} (ValInst : specs.generics.Val T) - (t : T) : Prop := + (t : T) (ValInstLawful : specs.generics.Val.Lawful T ValInst) : Prop := (specs.generics.where_clause.pre ValInst t).holds → ⦃ ⌜ True ⌝ ⦄ specs.generics.where_clause ValInst t @@ -1675,7 +1676,8 @@ def specs.generics.assoc_type.post def specs.generics.assoc_type.spec {P : Type} (ProducerPU32Inst : specs.generics.Producer P Std.U32) (p : P) - : Prop := + (ProducerPU32InstLawful : specs.generics.Producer.Lawful P Std.U32 + ProducerPU32Inst) : Prop := (specs.generics.assoc_type.pre ProducerPU32Inst p).holds → ⦃ ⌜ True ⌝ ⦄ specs.generics.assoc_type ProducerPU32Inst p @@ -1842,7 +1844,8 @@ def specs.generics.Wrapper.inner_value.post def specs.generics.Wrapper.inner_value.spec {T : Type} (ValInst : specs.generics.Val T) - (self : specs.generics.Wrapper T) : Prop := + (self : specs.generics.Wrapper T) + (ValInstLawful : specs.generics.Val.Lawful T ValInst) : Prop := (specs.generics.Wrapper.inner_value.pre ValInst self).holds → ⦃ ⌜ True ⌝ ⦄ specs.generics.Wrapper.inner_value ValInst self @@ -1897,7 +1900,7 @@ def specs.traits.basic.g.post ok (res <= 10#u64) def specs.traits.basic.g.spec {T : Type} (FooInst : specs.traits.basic.Foo T) - (x : T) : Prop := + (x : T) (FooInstLawful : specs.traits.basic.Foo.Lawful T FooInst) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.basic.g FooInst x ⦃ ⇓ res => ⌜ (specs.traits.basic.g.post FooInst x res).holds ⌝ ⦄ @@ -1933,7 +1936,7 @@ def specs.traits.supertraits.via_b.post def specs.traits.supertraits.via_b.spec {T : Type} (BInst : specs.traits.supertraits.B T) (x : T) - : Prop := + (BInstLawful : specs.traits.supertraits.B.Lawful T BInst) : Prop := (specs.traits.supertraits.via_b.pre BInst x).holds → ⦃ ⌜ True ⌝ ⦄ specs.traits.supertraits.via_b BInst x @@ -1973,7 +1976,7 @@ def specs.traits.diamond.via_b.post def specs.traits.diamond.via_b.spec {T : Type} (BInst : specs.traits.diamond.B T) - (x : T) : Prop := + (x : T) (BInstLawful : specs.traits.diamond.B.Lawful T BInst) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.diamond.via_b BInst x ⦃ ⇓ res => @@ -1990,7 +1993,8 @@ def specs.traits.diamond.diamond.post def specs.traits.diamond.diamond.spec {T : Type} (CInst : specs.traits.diamond.C - T) (x : T) : Prop := + T) (x : T) + (CInstLawful : specs.traits.diamond.C.Lawful T CInst) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.diamond.diamond CInst x ⦃ ⇓ res => @@ -2010,7 +2014,8 @@ def specs.traits.generic_impl.k.spec {T : Type} {U : Type} (FooInst : specs.traits.generic_impl.Foo T) (SubInst : specs.traits.generic_impl.Sub U) (x : T) - (y : U) : Prop := + (y : U) (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) + (SubInstLawful : specs.traits.generic_impl.Sub.Lawful U SubInst) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.generic_impl.k FooInst SubInst x y ⦃ ⇓ res => @@ -2058,7 +2063,8 @@ def Type} (ContainerInst : specs.traits.assoc_type_bounds.Container C Clause0_Item) (c : C) - : Prop := + (ContainerInstLawful : specs.traits.assoc_type_bounds.Container.Lawful C + Clause0_Item ContainerInst) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.assoc_type_bounds.first_bar ContainerInst c ⦃ ⇓ res => @@ -2076,7 +2082,9 @@ def specs.traits.builtin_bound.dup.post def specs.traits.builtin_bound.dup.spec {T : Type} (corecloneCloneInst : - core.clone.Clone T) (x : T) : Prop := + core.clone.Clone T) (x : T) + (corecloneCloneInstLawful : core.clone.Clone.Lawful T corecloneCloneInst) + : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.builtin_bound.dup corecloneCloneInst x ⦃ ⇓ res => @@ -2095,12 +2103,32 @@ def specs.traits.trait_generics.use_conv.post def specs.traits.trait_generics.use_conv.spec {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv C - Std.U8) (c : C) : Prop := + Std.U8) (c : C) + (ConvCU8InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U8 + ConvCU8Inst) : Prop := ⦃ ⌜ True ⌝ ⦄ specs.traits.trait_generics.use_conv ConvCU8Inst c ⦃ ⇓ res => ⌜ (specs.traits.trait_generics.use_conv.post ConvCU8Inst c res).holds ⌝ ⦄ +/-- [hax_tests::specs::naming::lawful_binder::f::post]: + Source: 'src/specs/naming.rs', lines 42:4-42:36 -/ +@[reducible] +def specs.naming.lawful_binder.f.post + {T : Type} (QuxInst : specs.naming.Qux T) (QuxInstLawful : T) (x : Std.U32) + (result : Std.U32) : + RustM Bool + := do + ok (result = x) + +def specs.naming.lawful_binder.f.spec {T : Type} (QuxInst : specs.naming.Qux T) + (QuxInstLawful1 : T) (x : Std.U32) + (QuxInstLawful : specs.naming.Qux.Lawful T QuxInst) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.naming.lawful_binder.f QuxInst QuxInstLawful1 x + ⦃ ⇓ res => + ⌜ (specs.naming.lawful_binder.f.post QuxInst QuxInstLawful1 x res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f::pre]: Source: 'src/specs/traits/impl_contract.rs', lines 14:4-14:28 -/ @[reducible] diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean index a490cbc278..cf3dc0d08c 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean @@ -112,7 +112,8 @@ theorem specs.generics.generic.spec.proof (N : Std.U32) (x : Std.U32) : theorem specs.generics.trait_clause.spec.proof {T : Type} (ValInst : specs.generics.Val T) - (t : T) (x : Std.U32) : specs.generics.trait_clause.spec ValInst t x := by + (t : T) (x : Std.U32) (ValInstLawful : specs.generics.Val.Lawful T ValInst) : + specs.generics.trait_clause.spec ValInst t x ValInstLawful := by unfold specs.generics.trait_clause.spec specs.generics.trait_clause specs.generics.trait_clause.pre simp only [bind_assoc_eq, bind_tc_ok, RustM.holds_bind_iff, forall_exists_index, and_imp] intros @@ -123,7 +124,8 @@ theorem specs.generics.trait_clause.spec.proof {T : Type} (ValInst : theorem specs.generics.where_clause.spec.proof {T : Type} (ValInst : specs.generics.Val T) - (t : T) : specs.generics.where_clause.spec ValInst t := by + (t : T) (ValInstLawful : specs.generics.Val.Lawful T ValInst) : + specs.generics.where_clause.spec ValInst t ValInstLawful := by unfold specs.generics.where_clause.spec specs.generics.where_clause specs.generics.where_clause.pre simp only [bind_assoc_eq, bind_tc_ok, RustM.holds_bind_iff, forall_exists_index, and_imp] intros @@ -220,6 +222,14 @@ theorem specs.naming.foo.spec.proof (x : Std.U32) : specs.naming.foo.spec x · scalar_tac · scalar_tac +theorem specs.naming.lawful_binder.f.spec.proof {T : Type} (QuxInst : specs.naming.Qux T) + (QuxInstLawful1 : T) (x : Std.U32) (QuxInstLawful : specs.naming.Qux.Lawful T QuxInst) : + specs.naming.lawful_binder.f.spec QuxInst QuxInstLawful1 x QuxInstLawful + := by + unfold specs.naming.lawful_binder.f.spec specs.naming.lawful_binder.f + hax_mvcgen [specs.naming.lawful_binder.f.post] + simp + theorem specs.generics.MyStruct.build.spec.proof (N : Std.Usize) (k : Std.Usize) : specs.generics.MyStruct.build.spec N k := by @@ -375,8 +385,9 @@ theorem specs.arguments.shape_len.spec.proof theorem specs.generics.assoc_type.spec.proof {P : Type} (ProducerPU32Inst : specs.generics.Producer P - Std.U32) (p : P) : - specs.generics.assoc_type.spec ProducerPU32Inst p := by + Std.U32) (p : P) + (ProducerPU32InstLawful : specs.generics.Producer.Lawful P Std.U32 ProducerPU32Inst) : + specs.generics.assoc_type.spec ProducerPU32Inst p ProducerPU32InstLawful := by unfold specs.generics.assoc_type.spec specs.generics.assoc_type specs.generics.assoc_type.pre simp only [bind_assoc_eq, bind_tc_ok, RustM.holds_bind_iff, forall_exists_index, and_imp] intros @@ -409,8 +420,8 @@ theorem specs.mutable_borrows.Counter.bump.spec.proof (self : specs.mutable_borr theorem specs.generics.Wrapper.inner_value.spec.proof {T : Type} (ValInst : specs.generics.Val T) - (self : specs.generics.Wrapper T) : - specs.generics.Wrapper.inner_value.spec ValInst self := by + (self : specs.generics.Wrapper T) (ValInstLawful : specs.generics.Val.Lawful T ValInst) : + specs.generics.Wrapper.inner_value.spec ValInst self ValInstLawful := by unfold specs.generics.Wrapper.inner_value.spec specs.generics.Wrapper.inner_value specs.generics.Wrapper.inner_value.pre simp only [bind_assoc_eq, bind_tc_ok, RustM.holds_bind_iff, forall_exists_index, and_imp] intros diff --git a/tests/hax/src/specs/naming.rs b/tests/hax/src/specs/naming.rs index f8ae49fdf6..6d8fdc6d7c 100644 --- a/tests/hax/src/specs/naming.rs +++ b/tests/hax/src/specs/naming.rs @@ -31,3 +31,16 @@ pub mod bar { pub trait Qux { fn lawful(&self) -> u32; } + +// No clash: an argument named like the Lawful binder `QuxInstLawful` of the +// trait clause `QuxInst` becomes `QuxInstLawful1` in the spec. +pub mod lawful_binder { + #![allow(non_snake_case)] + use super::Qux; + use hax_lib::*; + + #[ensures(|result| result == x)] + pub fn f(QuxInstLawful: T, x: u32) -> u32 { + x + } +} From 3e0c538bb4d09b6395f95a3c65a0ca8a514a8805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Wed, 14 Oct 2026 14:47:39 +0200 Subject: [PATCH 09/17] feat-specs: emit impl-obligations of lawfulness --- src/extract/ExtractHaxSpecs.ml | 181 +++++++++--- src/specs/HaxProducer.ml | 53 +++- src/specs/HaxSpecs.ml | 3 +- .../HaxTests/Assumptions/MissingCore.lean | 16 ++ .../lean/HaxTests/Extraction/Funs.lean | 21 ++ .../HaxTests/Extraction/ProofObligations.lean | 270 ++++++++++++++++++ .../lean/HaxTests/Extraction/Types.lean | 6 + tests/hax/src/specs/naming.rs | 15 + 8 files changed, 524 insertions(+), 41 deletions(-) diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index 6af65f1e30..07c5ee7671 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -225,6 +225,22 @@ module Helpers = struct Option.fold ~some ~none:ctx f_opt in ctx |> reg pre |> reg post + + (** The ids of the fields of the trait structure [d]: parent clauses, + associated constants and types, and methods *) + let trait_field_ids (d : Pure.trait_decl) : ExtractBase.id list = + List.map + (fun (c : Pure.trait_param) -> + ExtractBase.TraitParentClauseId (d.def_id, c.clause_id)) + d.parent_clauses + @ List.map + (fun (id, _, _) -> ExtractBase.TraitConstId (d.def_id, id)) + d.consts + @ List.map (fun (id, _) -> ExtractBase.TraitTypeId (d.def_id, id)) d.types + @ List.map + (fun (m : Pure.trait_method) -> + ExtractBase.TraitMethodId (d.def_id, m.method_id)) + d.methods end open Helpers @@ -247,7 +263,8 @@ let emit_conditions ctx fmt ~pre ~post = The contract of [] generates [.pre], [.post], [.spec] and [.spec.proof]. The contract of a method [] of a trait [] generates [..pre] and [..post]. Every trait [] - generates [.Lawful]. *) + generates [.Lawful], and every local trait impl [] the theorem + [.Lawful]. *) (** The registered name of [parent] *) let registered_fun_name (ctx : ExtractBase.extraction_ctx) @@ -306,9 +323,11 @@ let register_conds span (conds : (Pure.fun_decl * string) list) name ctx) ctx conds -(** Warn that the contract of an untranslated item is dropped. We use the span - of the LLBC item [item_meta], if found, and [opt_span] otherwise. *) -let warn_untranslated (ctx : ExtractBase.extraction_ctx) opt_span +(** Warn that [dropped] (by default, the contract) of an untranslated item is + dropped. We use the span of the LLBC item [item_meta], if found, and + [opt_span] otherwise. *) +let warn_untranslated ?(dropped = "the contract") + (ctx : ExtractBase.extraction_ctx) opt_span (item_meta : Types.item_meta option) (kind : string) (id : string) = let span, name = match item_meta with @@ -317,7 +336,7 @@ let warn_untranslated (ctx : ExtractBase.extraction_ctx) opt_span in [%warn_opt_span] span (Printf.sprintf - "hax-specs: dropping the contract of %s `%s`: the %s was not translated" + "hax-specs: dropping %s of %s `%s`: the %s was not translated" dropped kind name kind) (** Report a clash between [.Lawful] and the projection of a field of the @@ -330,24 +349,13 @@ let check_lawful_field_clash span (ctx : ExtractBase.extraction_ctx) let get id = ctx_get_raw (Some span) id ctx in let trait_name = get (TraitDeclId d.def_id) in let lawful = lawful_name trait_name in - let fields = - List.map - (fun (c : Pure.trait_param) -> - TraitParentClauseId (d.def_id, c.clause_id)) - d.parent_clauses - @ List.map (fun (id, _, _) -> TraitConstId (d.def_id, id)) d.consts - @ List.map (fun (id, _) -> TraitTypeId (d.def_id, id)) d.types - @ List.map - (fun (m : Pure.trait_method) -> TraitMethodId (d.def_id, m.method_id)) - d.methods - in List.iter (fun id -> if ExtractBuiltin.flatten_name [ trait_name; get id ] = lawful then report_name_collision (fun id -> id_to_string (Some span) id ctx) (id, Some span) (SpecId spec_id) (Some span) lawful) - fields + (trait_field_ids d) (** Register the names of the conditions and of the spec. Must be called after registering the crate items. Warns about the specs of untranslated items: @@ -418,7 +426,23 @@ let register_obligation_names (ctx : ExtractBase.extraction_ctx) in ExtractBase.ctx_add parent.item_meta.span (ProofObligationId proof_id) proof ctx) - | ImplLawful _ -> (* Not produced yet *) ctx + | ImplLawful { impl; _ } -> ( + match Pure.TraitImplId.Map.find_opt impl ctx.trans_trait_impls with + | None -> + warn_untranslated ~dropped:"the Lawful obligation" ctx None + (Option.map + (fun (i : LlbcAst.trait_impl) -> i.item_meta) + (Pure.TraitImplId.Map.find_opt impl + ctx.trans_ctx.crate.trait_impls)) + "trait impl" + (Pure.TraitImplId.to_string impl); + ctx + | Some i -> + let span = i.item_meta.span in + ExtractBase.ctx_add span (ProofObligationId proof_id) + (lawful_name + (ExtractBase.ctx_get_raw (Some span) (TraitImplId impl) ctx)) + ctx) (** Emits the spec statement — the body of [def foo.spec … : Prop :=] (the [theorem foo.spec.proof … := by sorry] wrapper is the obligation, emitted @@ -686,32 +710,75 @@ let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt methods; F.pp_close_box fmt () -(** Emit the binders of the function [f]: its generic and value parameters, then - the Lawful binders of its trait clauses. Return the context with the - parameters registered, and the names of the Lawful binders. *) -let emit_fun_binders (ctx : ExtractBase.extraction_ctx) fmt (f : Pure.fun_decl) - = +(** Emit the binders of an item [name] with generics [generics]: [emit_params] + emits its parameters and registers them, then we emit the Lawful binders of + its trait clauses. Return the context with the parameters registered, and + the names of the Lawful binders. *) +let emit_binders_with_lawfuls span (ctx : ExtractBase.extraction_ctx) fmt + (name : Types.name) (llbc_generics : Types.generic_params) + (generics : Pure.generic_params) + (emit_params : ExtractBase.extraction_ctx -> ExtractBase.extraction_ctx) = let open ExtractBase in - let span = f.item_meta.span in - let sg = f.signature in (* Reserve the Lawful names, so that no parameter takes them. The clause - names are those [extract_fun_parameters] computes: they end with [Inst] - (and an index), so the reserved names cannot change them. *) + names are those [emit_params] computes: they end with [Inst] (and an + index), so the reserved names cannot change them. *) let _, _, _, clause_names = - ctx_add_generic_params span f.item_meta.name Item sg.llbc_generics - sg.generics ctx + ctx_add_generic_params span name Item llbc_generics generics ctx in let lawful_names = List.map lawful_binder_name clause_names in - let ctx = ctx_reserve_names lawful_names ctx in - let space = ref false in - let _, ctx, _ = Extract.extract_fun_parameters space ctx fmt f in + let ctx = emit_params (ctx_reserve_names lawful_names ctx) in List.iter2 (fun name tr -> emit_binder fmt name (fun () -> emit_lawful_type span ctx fmt tr)) - lawful_names (PureUtils.generic_args_of_params sg.generics).trait_refs; + lawful_names (PureUtils.generic_args_of_params generics).trait_refs; + (ctx, lawful_names) + +(** Emit the binders of the function [f]: its generic and value parameters, then + the Lawful binders of its trait clauses. Return the context with the + parameters registered, and the names of the Lawful binders. *) +let emit_fun_binders (ctx : ExtractBase.extraction_ctx) fmt (f : Pure.fun_decl) + = + let sg = f.signature in + let space = ref false in + let ctx, lawful_names = + emit_binders_with_lawfuls f.item_meta.span ctx fmt f.item_meta.name + sg.llbc_generics sg.generics (fun ctx -> + let _, ctx, _ = Extract.extract_fun_parameters space ctx fmt f in + ctx) + in ExtractTypes.insert_req_space fmt space; (ctx, lawful_names) +(** Emit the binders of the trait impl [impl]: its generic parameters, named as + in its definition (see {!Extract.extract_trait_impl}), then the Lawful + binders of its trait clauses. Return the context with the parameters + registered. *) +let emit_impl_binders (ctx : ExtractBase.extraction_ctx) fmt + (impl : Pure.trait_impl) = + let open ExtractBase in + let span = impl.item_meta.span in + let d = + Pure.TraitDeclId.Map.find impl.impl_trait.trait_decl_id + ctx.trans_trait_decls + in + (* Reserve the field names of the trait, as [extract_trait_impl] does *) + let ctx = + ctx_reserve_names + (List.map (fun id -> ctx_get (Some span) id ctx) (trait_field_ids d)) + ctx + in + fst + (emit_binders_with_lawfuls span ctx fmt impl.item_meta.name + impl.llbc_generics impl.generics (fun ctx -> + let ctx, type_params, cg_params, trait_clauses = + ctx_add_generic_params span impl.item_meta.name Item + impl.llbc_generics impl.generics ctx + in + ExtractTypes.extract_generic_params span ctx fmt + Pure.TypeDeclId.Set.empty Item impl.generics + (Some impl.explicit_info) type_params cg_params trait_clauses; + ctx)) + (** Emit one [Spec.spec] entry *) let emit_spec ctx fmt (s : HaxSpecs.spec) = let open ExtractBase in @@ -796,8 +863,13 @@ let emit_spec ctx fmt (s : HaxSpecs.spec) = {[ theorem foo.spec.proof args lawfuls : foo.spec args lawfuls := by sorry ]} - where [lawfuls] are the Lawful binders of the trait clauses of [foo]. No - attribute is emitted: registering the obligation with [mvcgen] (via + where [lawfuls] are the Lawful binders of the trait clauses of [foo], or the + theorem that a trait impl satisfies the contract of its trait: + {[ + theorem .Lawful params lawfuls : X.Lawful args ( params) + := by sorry + ]} + No attribute is emitted: registering the obligation with [mvcgen] (via [@[spec]]) is left to the user, who decides which specs to feed it. *) let emit_obligation ctx fmt (o : HaxSpecs.obligation) = let open ExtractBase in @@ -866,4 +938,41 @@ let emit_obligation ctx fmt (o : HaxSpecs.obligation) = F.pp_close_box fmt (); (* outer hvbox *) F.pp_print_cut fmt ()) - | ImplLawful _ -> (* Not produced yet *) () + | ImplLawful { impl; proof; _ } -> ( + match Pure.TraitImplId.Map.find_opt impl ctx.trans_trait_impls with + | None -> (* Reported by [register_obligation_names] *) () + | Some impl -> + let span = impl.item_meta.span in + (* Blank line before the entry. *) + F.pp_print_break fmt 0 0; + (* Same box layout as above *) + F.pp_open_hvbox fmt ctx.indent_incr; + (* The theorem statement: [theorem .Lawful binders : ]. *) + F.pp_open_hovbox fmt ctx.indent_incr; + F.pp_print_string fmt "theorem"; + F.pp_print_space fmt (); + F.pp_print_string fmt + (escape_name + (lawful_name + (ctx_get_raw (Some span) (TraitImplId impl.def_id) ctx))); + let ctx = emit_impl_binders ctx fmt impl in + F.pp_print_space fmt (); + F.pp_print_string fmt ":"; + F.pp_print_space fmt (); + (* [.Lawful ( )] *) + F.pp_open_hovbox fmt 0; + emit_lawful_type span ctx fmt + { + trait_id = + TraitImpl + (impl.def_id, PureUtils.generic_args_of_params impl.generics); + trait_decl_ref = impl.impl_trait; + }; + F.pp_close_box fmt (); + F.pp_close_box fmt (); + (* statement hovbox *) + F.pp_print_space fmt (); + emit_proof fmt proof; + F.pp_close_box fmt (); + (* outer hvbox *) + F.pp_print_cut fmt ()) diff --git a/src/specs/HaxProducer.ml b/src/specs/HaxProducer.ml index e4cf1b9ad8..2d62d2df17 100644 --- a/src/specs/HaxProducer.ml +++ b/src/specs/HaxProducer.ml @@ -366,6 +366,50 @@ let produce (ctx : TranslateCore.trans_ctx) }) local_trait_decls in + (* The Lawful obligations of the local trait impls, in the order of the + declaration groups (dependencies first), with the contract of the + implemented trait if it is local *) + let trait_impls = + Pure.TraitImplId.Map.of_list + (List.map (fun (i : Pure.trait_impl) -> (i.def_id, i)) crate.trait_impls) + in + let trait_spec (id : Pure.TraitDeclId.id) : HaxSpecs.trait_spec option = + List.find_map + (fun (s : Spec.spec) -> + match s with + | { kind = HaxSpec (TraitSpec ts); _ } when ts.trait_decl = id -> + Some ts + | _ -> None) + trait_specs + in + let impl_obligations = + List.concat_map + (fun (g : LlbcAst.declaration_group) -> + match g with + | TraitImplGroup g -> + List.filter_map + (fun id -> + match Pure.TraitImplId.Map.find_opt id trait_impls with + | Some (i : Pure.trait_impl) when i.item_meta.is_local -> + Some + ({ + id = fresh_proof_id (); + span = Some i.item_meta.span; + kind = + HaxProof + (ImplLawful + { + impl = i.def_id; + spec = trait_spec i.impl_trait.trait_decl_id; + proof = Admitted; + }); + } + : Spec.proof_obligation) + | _ -> None) + (Charon.GAstUtils.g_declaration_group_to_list g) + | _ -> []) + (Option.get ctx.crate.declarations) + in (* Build the spec (statement of correctness) and the proof obligation that discharges it, for one parent fn's accumulated [AssociatedItem]s. *) @@ -476,12 +520,15 @@ let produce (ctx : TranslateCore.trans_ctx) [%linfo Printf.sprintf - "hax-specs: produced %d TraitSpec and %d FunctionSpec entries" - (List.length trait_specs) (List.length new_specs)]; + "hax-specs: produced %d TraitSpec, %d FunctionSpec and %d ImplLawful \ + entries" + (List.length trait_specs) (List.length new_specs) + (List.length impl_obligations)]; { crate with fun_decls = new_fun_decls; specs = crate.specs @ trait_specs @ new_specs; - proof_obligations = crate.proof_obligations @ new_obligations; + proof_obligations = + crate.proof_obligations @ impl_obligations @ new_obligations; } diff --git a/src/specs/HaxSpecs.ml b/src/specs/HaxSpecs.ml index a6a74cab3b..851b2d14c2 100644 --- a/src/specs/HaxSpecs.ml +++ b/src/specs/HaxSpecs.ml @@ -44,8 +44,7 @@ and obligation = impl : Pure.TraitImplId.id; spec : trait_spec option; (** The contract of the implemented trait. [None] for a non-local - trait: its [Lawful] fields are only known on the Lean side, so the - obligation gets no field skeleton. *) + trait. *) proof : proof; } (** [.Lawful : X.Lawful … ]: the impl satisfies the contract diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean index f2fdd535ab..91af26553c 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean @@ -27,4 +27,20 @@ structure core.default.Default.Lawful (Self : Type) structure core.marker.Copy.Lawful (Self : Type) (CopyInst : core.marker.Copy Self) : Prop where +-- The closure traits, implemented by the closures of hax decorations. The +-- parent fields (`FnOnceInstLawful`, `FnMutInstLawful`) are omitted like that +-- of `Copy.Lawful`. +structure core.ops.function.FnOnce.Lawful (Self : Type) (Args : Type) + (Self_Output : Type) + (FnOnceInst : core.ops.function.FnOnce Self Args Self_Output) : Prop where + +structure core.ops.function.FnMut.Lawful (Self : Type) (Args : Type) + (Self_Clause0_Output : Type) + (FnMutInst : core.ops.function.FnMut Self Args Self_Clause0_Output) : + Prop where + +structure core.ops.function.Fn.Lawful (Self : Type) (Args : Type) + (Self_Clause0_Output : Type) + (FnInst : core.ops.function.Fn Self Args Self_Clause0_Output) : Prop where + end CoreModels diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean index ebd3c0816a..09c8677b68 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean @@ -534,6 +534,27 @@ def specs.naming.lawful_binder.f := do ok x +/-- [hax_tests::specs::naming::lawful_impl_binder::{impl hax_tests::specs::naming::Qux for hax_tests::specs::naming::lawful_impl_binder::Wrap}::lawful]: + Source: 'src/specs/naming.rs', lines 57:8-59:9 + Visibility: public -/ +def specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux.lawful + {QuxInstLawful : Type} (QuxInst : specs.naming.Qux QuxInstLawful) + (self : specs.naming.lawful_impl_binder.Wrap QuxInstLawful) : + RustM Std.U32 + := do + QuxInst.lawful self + +/-- Trait implementation: [hax_tests::specs::naming::lawful_impl_binder::{impl hax_tests::specs::naming::Qux for hax_tests::specs::naming::lawful_impl_binder::Wrap}] + Source: 'src/specs/naming.rs', lines 56:4-60:5 -/ +@[reducible] +def specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux + {QuxInstLawful : Type} (QuxInst : specs.naming.Qux QuxInstLawful) : + specs.naming.Qux (specs.naming.lawful_impl_binder.Wrap QuxInstLawful) := { + lawful := + specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux.lawful + QuxInst +} + /-- [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Bar for u32}::bar]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 27:4-29:5 -/ def U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.bar diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean index c51b7ef294..6986434292 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean @@ -28,6 +28,276 @@ noncomputable section namespace hax_tests +theorem Tuple.Insts.Hax_testsSpecsArgumentsSize.Lawful : + specs.arguments.Size.Lawful Unit Tuple.Insts.Hax_testsSpecsArgumentsSize + := by sorry + +theorem + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop.Lawful + : + core.ops.function.FnOnce.Lawful specs.contracts.__20.requires.closure Std.U32 + hax_lib.prop.Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop + := by sorry + +theorem + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.Lawful + : + core.ops.function.FnMut.Lawful specs.contracts.__20.requires.closure Std.U32 + hax_lib.prop.Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop + := by sorry + +theorem + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.Lawful + : + core.ops.function.Fn.Lawful specs.contracts.__20.requires.closure Std.U32 + hax_lib.prop.Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop + := by sorry + +theorem + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool.Lawful + : + core.ops.function.FnOnce.Lawful specs.contracts.__21.ensures.closure Std.U32 + Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool + := by sorry + +theorem + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.Lawful + : + core.ops.function.FnMut.Lawful specs.contracts.__21.ensures.closure Std.U32 + Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool + := by sorry + +theorem + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.Lawful + : + core.ops.function.Fn.Lawful specs.contracts.__21.ensures.closure Std.U32 Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool + := by sorry + +theorem U32.Insts.Hax_testsSpecsGenericsVal.Lawful : + specs.generics.Val.Lawful Std.U32 U32.Insts.Hax_testsSpecsGenericsVal + := by sorry + +theorem + specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux.Lawful + {QuxInstLawful1 : Type} (QuxInst : specs.naming.Qux QuxInstLawful1) + (QuxInstLawful : specs.naming.Qux.Lawful QuxInstLawful1 QuxInst) : + specs.naming.Qux.Lawful (specs.naming.lawful_impl_binder.Wrap QuxInstLawful1) + (specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux QuxInst) + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.Lawful : + specs.traits.assoc_type_bounds.Bar.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar + := by sorry + +theorem + specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32.Lawful + : + specs.traits.assoc_type_bounds.Container.Lawful + specs.traits.assoc_type_bounds.One Std.U32 + specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32 + := by sorry + +theorem + specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer.Lawful + {T : Type} (BarInst1 : specs.traits.assoc_type_bounds.Bar T) + (coremarkerCopyInst : core.marker.Copy T) + (BarInst1Lawful : specs.traits.assoc_type_bounds.Bar.Lawful T BarInst1) + (coremarkerCopyInstLawful : core.marker.Copy.Lawful T coremarkerCopyInst) : + specs.traits.assoc_type_bounds.Container.Lawful + (specs.traits.assoc_type_bounds.Box1 T) T + (specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer + BarInst1 coremarkerCopyInst) + := by sorry + +theorem U64.Insts.Hax_testsSpecsTraitsBasicFoo.Lawful : + specs.traits.basic.Foo.Lawful Std.U64 U64.Insts.Hax_testsSpecsTraitsBasicFoo + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsBasicFoo.Lawful : + specs.traits.basic.Foo.Lawful Std.U32 U32.Insts.Hax_testsSpecsTraitsBasicFoo + := by sorry + +theorem specs.traits.blanket_impl.Show.Blanket.Lawful (T : Type) : + specs.traits.blanket_impl.Show.Lawful T + (specs.traits.blanket_impl.Show.Blanket T) + := by sorry + +theorem specs.traits.blanket_impl.Tag.Blanket.Lawful {T : Type} (ShowInst1 : + specs.traits.blanket_impl.Show T) + (ShowInst1Lawful : specs.traits.blanket_impl.Show.Lawful T ShowInst1) : + specs.traits.blanket_impl.Tag.Lawful T (specs.traits.blanket_impl.Tag.Blanket + ShowInst1) + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.Lawful : + specs.traits.builtin_bound.Dup.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup + := by sorry + +theorem specs.traits.builtin_bound.One.Insts.CoreCloneClone.Lawful : + core.clone.Clone.Lawful specs.traits.builtin_bound.One + specs.traits.builtin_bound.One.Insts.CoreCloneClone + := by sorry + +theorem specs.traits.builtin_bound.One.Insts.CoreDefaultDefault.Lawful : + core.default.Default.Lawful specs.traits.builtin_bound.One + specs.traits.builtin_bound.One.Insts.CoreDefaultDefault + := by sorry + +theorem + specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.Lawful + : + specs.traits.builtin_bound.Dup.Lawful specs.traits.builtin_bound.One + specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup + := by sorry + +theorem specs.traits.builtin_bound.W.Insts.CoreCloneClone.Lawful {T : Type} + (corecloneCloneInst : core.clone.Clone T) + (corecloneCloneInstLawful : core.clone.Clone.Lawful T corecloneCloneInst) : + core.clone.Clone.Lawful (specs.traits.builtin_bound.W T) + (specs.traits.builtin_bound.W.Insts.CoreCloneClone corecloneCloneInst) + := by sorry + +theorem + specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.Lawful + : + specs.traits.builtin_bound.Dup.Lawful (specs.traits.builtin_bound.W Std.U32) + specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.Lawful : + specs.traits.default_methods.D.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsDefault_methodsD + := by sorry + +theorem U64.Insts.Hax_testsSpecsTraitsDefault_methodsD.Lawful : + specs.traits.default_methods.D.Lawful Std.U64 + U64.Insts.Hax_testsSpecsTraitsDefault_methodsD + := by sorry + +theorem U8.Insts.Hax_testsSpecsTraitsDiamondA.Lawful : + specs.traits.diamond.A.Lawful Std.U8 U8.Insts.Hax_testsSpecsTraitsDiamondA + := by sorry + +theorem U8.Insts.Hax_testsSpecsTraitsDiamondB.Lawful : + specs.traits.diamond.B.Lawful Std.U8 U8.Insts.Hax_testsSpecsTraitsDiamondB + := by sorry + +theorem U8.Insts.Hax_testsSpecsTraitsDiamondC.Lawful : + specs.traits.diamond.C.Lawful Std.U8 U8.Insts.Hax_testsSpecsTraitsDiamondC + := by sorry + +theorem U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful : + specs.traits.generic_impl.Foo.Lawful Std.U64 + U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo + := by sorry + +theorem + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : + specs.traits.generic_impl.Foo.Lawful (specs.traits.generic_impl.Wrapper T) + (specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo + FooInst) + := by sorry + +theorem + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implSub.Lawful + {T : Type} (SubInst : specs.traits.generic_impl.Sub T) + (SubInstLawful : specs.traits.generic_impl.Sub.Lawful T SubInst) : + specs.traits.generic_impl.Sub.Lawful (specs.traits.generic_impl.Wrapper T) + (specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implSub + SubInst) + := by sorry + +theorem Pair.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful {T : Type} {U : + Type} (FooInst : specs.traits.generic_impl.Foo T) (FooInst1 : + specs.traits.generic_impl.Foo U) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) + (FooInst1Lawful : specs.traits.generic_impl.Foo.Lawful U FooInst1) : + specs.traits.generic_impl.Foo.Lawful (T × U) + (Pair.Insts.Hax_testsSpecsTraitsGeneric_implFoo FooInst FooInst1) + := by sorry + +theorem + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : + specs.traits.generic_impl.Foo.Lawful (specs.traits.generic_impl.Single T) + (specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo + FooInst) + := by sorry + +theorem + specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub.Lawful + : + specs.traits.generic_impl.Sub.Lawful (specs.traits.generic_impl.Single + Std.U64) + specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.Lawful : + specs.traits.impl_contract.Foo.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractG.Lawful : + specs.traits.impl_contract.G.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsImpl_contractG + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar.Lawful : + specs.traits.method_generics.Bar.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo.Lawful : + specs.traits.method_generics.Foo.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.Lawful : + specs.traits.mut_self.Counter.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsMut_selfCounter + := by sorry + +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsA.Lawful : + specs.traits.supertraits.A.Lawful Std.U8 + U8.Insts.Hax_testsSpecsTraitsSupertraitsA + := by sorry + +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsB.Lawful : + specs.traits.supertraits.B.Lawful Std.U8 + U8.Insts.Hax_testsSpecsTraitsSupertraitsB + := by sorry + +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsCc.Lawful : + specs.traits.supertraits.Cc.Lawful Std.U8 + U8.Insts.Hax_testsSpecsTraitsSupertraitsCc + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8.Lawful : + specs.traits.trait_generics.Conv.Lawful Std.U32 Std.U8 + U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8 + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.Lawful : + specs.traits.unannotated_sub.A.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsUnannotated_subA + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsUnannotated_subB.Lawful : + specs.traits.unannotated_sub.B.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsUnannotated_subB + := by sorry + theorem specs.contracts.only_requires.spec.proof (x : Std.U32) : specs.contracts.only_requires.spec x := by sorry diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index c384e789a8..fce113d28d 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -92,6 +92,12 @@ structure specs.mutable_borrows.Counter where structure specs.naming.Qux (Self : Type) where lawful : Self → RustM Std.U32 +/-- [hax_tests::specs::naming::lawful_impl_binder::Wrap] + Source: 'src/specs/naming.rs', lines 54:4-54:26 + Visibility: public -/ +@[reducible] +def specs.naming.lawful_impl_binder.Wrap (T : Type) := T + /-- Trait declaration: [hax_tests::specs::traits::assoc_type_bounds::Bar] Source: 'src/specs/traits/assoc_type_bounds.rs', lines 9:0-12:1 -/ structure specs.traits.assoc_type_bounds.Bar (Self : Type) where diff --git a/tests/hax/src/specs/naming.rs b/tests/hax/src/specs/naming.rs index 6d8fdc6d7c..4383ec812a 100644 --- a/tests/hax/src/specs/naming.rs +++ b/tests/hax/src/specs/naming.rs @@ -44,3 +44,18 @@ pub mod lawful_binder { x } } + +// No clash: a type parameter named like the Lawful binder `QuxInstLawful` of +// the impl clause `QuxInst` becomes `QuxInstLawful1` in the impl theorem +// `….Lawful` (but not in the impl definition). +pub mod lawful_impl_binder { + use super::Qux; + + pub struct Wrap(T); + + impl Qux for Wrap { + fn lawful(&self) -> u32 { + self.0.lawful() + } + } +} From a4f8423870e029f3912676114884db0a97faf6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Wed, 14 Oct 2026 16:20:12 +0200 Subject: [PATCH 10/17] proofs: add proofs for trait level specs --- .../HaxTests/Assumptions/MissingCore.lean | 24 +++- .../lean/HaxTests/Verification/Lemmas.lean | 27 ++++ .../Verification/ProofObligations.lean | 94 +++++++++++++ .../Verification/Traits/AssocTypeBounds.lean | 92 +++++++++++++ .../HaxTests/Verification/Traits/Basic.lean | 96 +++++++++++++ .../Verification/Traits/BlanketImpl.lean | 64 +++++++++ .../Verification/Traits/BuiltinBound.lean | 106 ++++++++++++++ .../Verification/Traits/DefaultMethods.lean | 52 +++++++ .../HaxTests/Verification/Traits/Diamond.lean | 84 ++++++++++++ .../Verification/Traits/GenericImpl.lean | 129 ++++++++++++++++++ .../Verification/Traits/ImplContract.lean | 67 +++++++++ .../Verification/Traits/MethodGenerics.lean | 50 +++++++ .../HaxTests/Verification/Traits/MutSelf.lean | 45 ++++++ .../Verification/Traits/Supertraits.lean | 91 ++++++++++++ .../Verification/Traits/TraitGenerics.lean | 54 ++++++++ .../Verification/Traits/UnannotatedSub.lean | 45 ++++++ 16 files changed, 1117 insertions(+), 3 deletions(-) create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Basic.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BlanketImpl.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BuiltinBound.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/DefaultMethods.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Diamond.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ImplContract.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MethodGenerics.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MutSelf.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Supertraits.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/UnannotatedSub.lean diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean index 91af26553c..39695eb88a 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Assumptions/MissingCore.lean @@ -7,23 +7,41 @@ import Aeneas import CoreModels open CoreModels Aeneas open Aeneas.Std hiding namespace core alloc +open Std.Do set_option linter.dupNamespace false set_option linter.unusedVariables false +set_option mvcgen.warning false namespace CoreModels --- The actual fields are to be decided with the library. +/- The actual fields are to be decided with the library; until then, only the + one field the generated obligations need. + + `clone_spec`: `clone` does not fail (no panic, no divergence), and nothing + more (the result is unconstrained). Why needed: a function with a `T: Clone` + bound that calls `clone` (e.g. `specs::traits::builtin_bound::dup`) cannot + prove a `⇓` (total-correctness) postcondition otherwise; with an empty + structure, `dup.spec.proof` is false (counter-example with a panicking + `clone`: `tests/hax/mockup/builtin_bound_proofs.lean`). Why valid: derived + and core `clone`s do not fail; for any impl, the field is a proof obligation + (each impl's `Lawful` theorem), not an axiom, so a panicking or looping impl + simply cannot be shown Lawful. It assumes nothing about arbitrary impls; + the models only abstract away stack overflow and allocation failure (which + Rust reports by aborting, not by a recoverable error). -/ structure core.clone.Clone.Lawful (Self : Type) (CloneInst : core.clone.Clone Self) : Prop where + clone_spec (x : Self) : ⦃ ⌜ True ⌝ ⦄ CloneInst.clone x ⦃ ⇓ _ => ⌜ True ⌝ ⦄ theorem core.U32.Insts.CoreCloneClone.Lawful : - core.clone.Clone.Lawful Std.U32 core.U32.Insts.CoreCloneClone := ⟨⟩ + core.clone.Clone.Lawful Std.U32 core.U32.Insts.CoreCloneClone where + clone_spec x := by + mvcgen [core.U32.Insts.CoreCloneClone.clone] structure core.default.Default.Lawful (Self : Type) (DefaultInst : core.default.Default Self) : Prop where -- `Copy` has no method; its parent `Clone` would give a --- `corecloneCloneInstLawful` field, omitted like the fields of `Clone.Lawful`. +-- `corecloneCloneInstLawful` field, omitted until the library decides the fields. structure core.marker.Copy.Lawful (Self : Type) (CopyInst : core.marker.Copy Self) : Prop where diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Lemmas.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Lemmas.lean index 543745ec39..ecfdeab239 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Lemmas.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Lemmas.lean @@ -45,6 +45,33 @@ theorem Aeneas.Std.RustM.holds_bind_iff {α : Type} {m : RustM α} {f : α → R · rintro ⟨_, rfl, _⟩ simpa +/-- A `RustM Bool` contract leg (the `.pre`/`.post` defs of trait methods) used +as a `RustM Prop` is coerced as `do let a ← x; pure (a = true)`, whose simp normal +form is `(· = true) <$> x`; nothing in Aeneas/Hax simplifies its `.holds`. It holds +iff the leg evaluates to `ok true`. -/ +@[simp] theorem Aeneas.Std.RustM.holds_bool (x : RustM Bool) : + ((fun a => a = true) <$> x : RustM Prop).holds ↔ x = ok true := by + cases x + · simp [RustM.holds, Triple, WP.wp, PredTrans.apply, Functor.map, pure] + · simp [RustM.holds, Triple, WP.wp, PredTrans.apply, Functor.map] + · simp [RustM.holds, Triple, WP.wp, PredTrans.apply, Functor.map] + +/-- `(pure p).holds` is `p` (nothing in Aeneas/Hax simplifies it). Not `@[simp]`: +as a simp lemma it changes what `simp_all` does to the hypotheses of existing +proofs (e.g. `specs.generics.trait_clause.spec.proof` loses its precondition); +pass it explicitly, `simp [RustM.holds_pure]`. -/ +theorem Aeneas.Std.RustM.holds_pure (p : Prop) : (pure p : RustM Prop).holds ↔ p := by + simp [RustM.holds, Triple, WP.wp, PredTrans.apply, pure] + +/- Bridges between Aeneas specs and `Std.Do` triples, already in Aeneas +(`Aeneas/Std/WP.lean`), to use rather than restating them: +- `Aeneas.Std.WP.spec_to_mvcgen`: an Aeneas `spec` (`m ⦃ r => P r ⦄`, the + `step`/`step*` world) gives `⦃ ⌜ True ⌝ ⦄ m ⦃ ⇓ r => ⌜ P r ⌝ ⦄`, the shape of + the `Lawful` fields; +- `Aeneas.Std.WP.triple_iff_exists_ok`: such a total-correctness triple is + `∃ a, m = .ok a ∧ P a`; the `Lawful` fields do not state `m = ok res`, this + recovers it on the consuming side. -/ + open Lean Elab Command in /-- `register_closure_specs ns` marks `@[spec]` the `call`/`call_mut`/`call_once` methods of every closure extracted under the namespace `ns`, so that `hax_mvcgen` diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean index cf3dc0d08c..7bb55b4343 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean @@ -6,6 +6,19 @@ import HaxTests.Extraction.Types import HaxTests.Extraction.Funs import HaxTests.Extraction.Specs import HaxTests.Verification.Lemmas +import HaxTests.Verification.Traits.AssocTypeBounds +import HaxTests.Verification.Traits.Basic +import HaxTests.Verification.Traits.BlanketImpl +import HaxTests.Verification.Traits.BuiltinBound +import HaxTests.Verification.Traits.DefaultMethods +import HaxTests.Verification.Traits.Diamond +import HaxTests.Verification.Traits.GenericImpl +import HaxTests.Verification.Traits.ImplContract +import HaxTests.Verification.Traits.MethodGenerics +import HaxTests.Verification.Traits.MutSelf +import HaxTests.Verification.Traits.Supertraits +import HaxTests.Verification.Traits.TraitGenerics +import HaxTests.Verification.Traits.UnannotatedSub open CoreModels Aeneas open Aeneas.Std hiding namespace core alloc open RustM ControlFlow Error @@ -31,6 +44,73 @@ register_closure_specs hax_tests namespace hax_tests +/- Lawfulness of the impls of the non-trait test modules. Their `Lawful` +structures have no field: the traits have no annotated method, and the +`Fn*` stubs of `Assumptions/MissingCore.lean` are empty. -/ + +theorem Tuple.Insts.Hax_testsSpecsArgumentsSize.Lawful : + specs.arguments.Size.Lawful Unit Tuple.Insts.Hax_testsSpecsArgumentsSize + := ⟨⟩ + +theorem + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop.Lawful + : + core.ops.function.FnOnce.Lawful specs.contracts.__20.requires.closure Std.U32 + hax_lib.prop.Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnOnceTupleU32Prop + := ⟨⟩ + +theorem + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop.Lawful + : + core.ops.function.FnMut.Lawful specs.contracts.__20.requires.closure Std.U32 + hax_lib.prop.Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnMutTupleU32Prop + := ⟨⟩ + +theorem + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop.Lawful + : + core.ops.function.Fn.Lawful specs.contracts.__20.requires.closure Std.U32 + hax_lib.prop.Prop + specs.contracts.__20.requires.closure.Insts.CoreOpsFunctionFnTupleU32Prop + := ⟨⟩ + +theorem + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool.Lawful + : + core.ops.function.FnOnce.Lawful specs.contracts.__21.ensures.closure Std.U32 + Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnOnceTupleU32Bool + := ⟨⟩ + +theorem + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool.Lawful + : + core.ops.function.FnMut.Lawful specs.contracts.__21.ensures.closure Std.U32 + Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnMutTupleU32Bool + := ⟨⟩ + +theorem + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool.Lawful + : + core.ops.function.Fn.Lawful specs.contracts.__21.ensures.closure Std.U32 Bool + specs.contracts.__21.ensures.closure.Insts.CoreOpsFunctionFnTupleU32Bool + := ⟨⟩ + +theorem U32.Insts.Hax_testsSpecsGenericsVal.Lawful : + specs.generics.Val.Lawful Std.U32 U32.Insts.Hax_testsSpecsGenericsVal + := ⟨⟩ + +theorem + specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux.Lawful + {QuxInstLawful1 : Type} (QuxInst : specs.naming.Qux QuxInstLawful1) + (QuxInstLawful : specs.naming.Qux.Lawful QuxInstLawful1 QuxInst) : + specs.naming.Qux.Lawful (specs.naming.lawful_impl_binder.Wrap QuxInstLawful1) + (specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux QuxInst) + := ⟨⟩ + theorem specs.contracts.only_requires.spec.proof (x : Std.U32) : specs.contracts.only_requires.spec x := by @@ -54,6 +134,11 @@ theorem specs.contracts.no_args.spec.proof : specs.contracts.no_args.spec := by unfold specs.contracts.no_args.spec specs.contracts.no_args hax_mvcgen +theorem specs.contracts.zero_ret.spec.proof : specs.contracts.zero_ret.spec + := by + unfold specs.contracts.zero_ret.spec specs.contracts.zero_ret + hax_mvcgen + theorem specs.contracts.returns_unit.spec.proof (x : Std.U32) : specs.contracts.returns_unit.spec x := by unfold specs.contracts.returns_unit.spec specs.contracts.returns_unit @@ -168,6 +253,15 @@ theorem specs.mutable_borrows.swap_and_add.spec.proof (x : Std.U32) (y : Std.U32 · scalar_tac · scalar_tac +theorem specs.mutable_borrows.incr_ret.spec.proof (x : Std.U8) : + specs.mutable_borrows.incr_ret.spec x + := by + unfold specs.mutable_borrows.incr_ret.spec specs.mutable_borrows.incr_ret + hax_mvcgen + · agrind + · agrind + · agrind + theorem specs.mutable_borrows.read_shared.spec.proof (x : Std.U32) : specs.mutable_borrows.read_shared.spec x := by diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean new file mode 100644 index 0000000000..e7223d5628 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean @@ -0,0 +1,92 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::assoc_type_bounds`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.Lawful : + specs.traits.assoc_type_bounds.Bar.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar + where + bar_spec := by + intro self _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.bar] + +theorem + specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32.Lawful + : + specs.traits.assoc_type_bounds.Container.Lawful + specs.traits.assoc_type_bounds.One Std.U32 + specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32 + where + BarInstLawful := U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.Lawful + first_spec := by + intro self _ + -- the post calls `bar` on the result, through the impl's `BarInst` + mvcgen [specs.traits.assoc_type_bounds.One.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainerU32.first, + U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.bar] + +theorem + specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer.Lawful + {T : Type} (BarInst1 : specs.traits.assoc_type_bounds.Bar T) + (coremarkerCopyInst : core.marker.Copy T) + (BarInst1Lawful : specs.traits.assoc_type_bounds.Bar.Lawful T BarInst1) + (coremarkerCopyInstLawful : core.marker.Copy.Lawful T coremarkerCopyInst) : + specs.traits.assoc_type_bounds.Container.Lawful + (specs.traits.assoc_type_bounds.Box1 T) T + (specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer + BarInst1 coremarkerCopyInst) + where + BarInstLawful := BarInst1Lawful + first_spec := by + intro self hpre + /- `first` is the identity on `Box1 T = T`, and the post calls + `BarInst1.bar` on it: evaluate it once through `BarInst1Lawful`. -/ + obtain ⟨i, hb, hi⟩ := + Aeneas.Std.WP.triple_iff_exists_ok.1 (BarInst1Lawful.bar_spec self hpre) + mvcgen [specs.traits.assoc_type_bounds.Box1.Insts.Hax_testsSpecsTraitsAssoc_type_boundsContainer.first] + simpa [hb] using hi + +theorem + specs.traits.assoc_type_bounds.first_bar.spec.proof {C : Type} {Clause0_Item + : Type} (ContainerInst : + specs.traits.assoc_type_bounds.Container + C Clause0_Item) + (c : C) + (ContainerInstLawful : specs.traits.assoc_type_bounds.Container.Lawful C + Clause0_Item ContainerInst) : + specs.traits.assoc_type_bounds.first_bar.spec ContainerInst c + ContainerInstLawful + := by + unfold specs.traits.assoc_type_bounds.first_bar.spec specs.traits.assoc_type_bounds.first_bar + have h1 := ContainerInstLawful.first_spec + have h2 := ContainerInstLawful.BarInstLawful.bar_spec + -- `Bar.bar.post` and `first_bar.post` are both `ok (res < 10#u32)`: defeq + mvcgen [h1, h2] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Basic.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Basic.lean new file mode 100644 index 0000000000..a0b0b58ddc --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Basic.lean @@ -0,0 +1,96 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::basic`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U64.Insts.Hax_testsSpecsTraitsBasicFoo.Lawful : + specs.traits.basic.Foo.Lawful Std.U64 U64.Insts.Hax_testsSpecsTraitsBasicFoo + where + f1_spec := by + intro self _ + mvcgen [U64.Insts.Hax_testsSpecsTraitsBasicFoo.f1] + f2_spec := by + intro self hpre + mvcgen [U64.Insts.Hax_testsSpecsTraitsBasicFoo.f2] + make_spec := by + intro x _ + apply Aeneas.Std.WP.spec_to_mvcgen + simp [U64.Insts.Hax_testsSpecsTraitsBasicFoo.make] + step* + simp [specs.traits.basic.Foo.make.post, U64.Insts.Hax_testsSpecsTraitsBasicFoo.f1] + scalar_tac + zero_spec := by + intro _ + mvcgen [U64.Insts.Hax_testsSpecsTraitsBasicFoo.zero, U64.Insts.Hax_testsSpecsTraitsBasicFoo.f1] + +theorem U32.Insts.Hax_testsSpecsTraitsBasicFoo.Lawful : + specs.traits.basic.Foo.Lawful Std.U32 U32.Insts.Hax_testsSpecsTraitsBasicFoo + where + f1_spec := by + intro self _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsBasicFoo.f1] + f2_spec := by + intro self hpre + mvcgen [U32.Insts.Hax_testsSpecsTraitsBasicFoo.f2] + make_spec := by + intro x _ + apply Aeneas.Std.WP.spec_to_mvcgen + simp [U32.Insts.Hax_testsSpecsTraitsBasicFoo.make] + step* + simp [specs.traits.basic.Foo.make.post, U32.Insts.Hax_testsSpecsTraitsBasicFoo.f1] + scalar_tac + zero_spec := by + intro _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsBasicFoo.zero, U32.Insts.Hax_testsSpecsTraitsBasicFoo.f1] + +theorem + specs.traits.basic.g.spec.proof {T : Type} (FooInst : specs.traits.basic.Foo + T) (x : T) + (FooInstLawful : specs.traits.basic.Foo.Lawful T FooInst) : + specs.traits.basic.g.spec FooInst x FooInstLawful + := by + unfold specs.traits.basic.g.spec specs.traits.basic.g + /- `mvcgen [FooInstLawful.f2_spec]` cannot resolve a local projection: go through `have`. -/ + have h2 := FooInstLawful.f2_spec + /- `f2`'s pre re-runs `f1 x`: pin its value with the equality recovered from `f1_spec`. -/ + obtain ⟨b, hf1, -⟩ := (Aeneas.Std.WP.triple_iff_exists_ok).1 (FooInstLawful.f1_spec x (by simp)) + mvcgen [hf1, h2] + -- `else` branch: `0 <= 10` + simp [specs.traits.basic.g.post] + +theorem specs.traits.basic.h.spec.proof (x : Std.U64) : + specs.traits.basic.h.spec x + := by + unfold specs.traits.basic.h.spec specs.traits.basic.h + have hg := specs.traits.basic.g.spec.proof U64.Insts.Hax_testsSpecsTraitsBasicFoo x + U64.Insts.Hax_testsSpecsTraitsBasicFoo.Lawful + unfold specs.traits.basic.g.spec at hg + mvcgen [hg] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BlanketImpl.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BlanketImpl.lean new file mode 100644 index 0000000000..e8c623a535 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BlanketImpl.lean @@ -0,0 +1,64 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::blanket_impl`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem specs.traits.blanket_impl.Show.Blanket.Lawful (T : Type) : + specs.traits.blanket_impl.Show.Lawful T + (specs.traits.blanket_impl.Show.Blanket T) + where + show_spec := by + intro self _ + mvcgen [specs.traits.blanket_impl.Show.Blanket.show] + +theorem specs.traits.blanket_impl.Tag.Blanket.Lawful {T : Type} (ShowInst1 : + specs.traits.blanket_impl.Show T) + (ShowInst1Lawful : specs.traits.blanket_impl.Show.Lawful T ShowInst1) : + specs.traits.blanket_impl.Tag.Lawful T (specs.traits.blanket_impl.Tag.Blanket + ShowInst1) + := ⟨ShowInst1Lawful⟩ + +theorem specs.traits.blanket_impl.show_generic.spec.proof {T : Type} + (x : T) : specs.traits.blanket_impl.show_generic.spec x + := by + unfold specs.traits.blanket_impl.show_generic.spec + specs.traits.blanket_impl.show_generic + -- `Show` comes from `Show.Blanket T`: use its Lawful term. + have hs := (specs.traits.blanket_impl.Show.Blanket.Lawful T).show_spec + mvcgen [hs] + +theorem specs.traits.blanket_impl.show_u64.spec.proof (x : Std.U64) : + specs.traits.blanket_impl.show_u64.spec x + := by + unfold specs.traits.blanket_impl.show_u64.spec specs.traits.blanket_impl.show_u64 + -- `Show` comes from `Show.Blanket Std.U64`: use the blanket theorem at `Std.U64`. + have hs := (specs.traits.blanket_impl.Show.Blanket.Lawful Std.U64).show_spec + mvcgen [hs] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BuiltinBound.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BuiltinBound.lean new file mode 100644 index 0000000000..2eb912f571 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/BuiltinBound.lean @@ -0,0 +1,106 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::builtin_bound`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.Lawful : + specs.traits.builtin_bound.Dup.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup + where + corecloneCloneInstLawful := core.U32.Insts.CoreCloneClone.Lawful + dup_spec := by + intro self _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup] + +theorem specs.traits.builtin_bound.One.Insts.CoreCloneClone.Lawful : + core.clone.Clone.Lawful specs.traits.builtin_bound.One + specs.traits.builtin_bound.One.Insts.CoreCloneClone + where + clone_spec x := by + mvcgen [specs.traits.builtin_bound.One.Insts.CoreCloneClone.clone] + +theorem specs.traits.builtin_bound.One.Insts.CoreDefaultDefault.Lawful : + core.default.Default.Lawful specs.traits.builtin_bound.One + specs.traits.builtin_bound.One.Insts.CoreDefaultDefault + := ⟨⟩ + +theorem + specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.Lawful + : + specs.traits.builtin_bound.Dup.Lawful specs.traits.builtin_bound.One + specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup + where + corecloneCloneInstLawful := + specs.traits.builtin_bound.One.Insts.CoreCloneClone.Lawful + dup_spec := by + intro self _ + mvcgen [specs.traits.builtin_bound.One.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup, + specs.traits.builtin_bound.One.Insts.CoreCloneClone.clone] + +theorem specs.traits.builtin_bound.W.Insts.CoreCloneClone.Lawful {T : Type} + (corecloneCloneInst : core.clone.Clone T) + (corecloneCloneInstLawful : core.clone.Clone.Lawful T corecloneCloneInst) : + core.clone.Clone.Lawful (specs.traits.builtin_bound.W T) + (specs.traits.builtin_bound.W.Insts.CoreCloneClone corecloneCloneInst) + where + clone_spec w := by + -- `W`'s derived `clone` clones the field: use the inner `clone_spec` + have h := corecloneCloneInstLawful.clone_spec + mvcgen [specs.traits.builtin_bound.W.Insts.CoreCloneClone.clone, h] + +theorem + specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.Lawful + : + specs.traits.builtin_bound.Dup.Lawful (specs.traits.builtin_bound.W Std.U32) + specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup + where + corecloneCloneInstLawful := + specs.traits.builtin_bound.W.Insts.CoreCloneClone.Lawful + core.U32.Insts.CoreCloneClone core.U32.Insts.CoreCloneClone.Lawful + dup_spec := by + intro self _ + -- reuse the `Clone.Lawful` proof of `W U32` rather than unfolding both `clone` layers + have h := (specs.traits.builtin_bound.W.Insts.CoreCloneClone.Lawful + core.U32.Insts.CoreCloneClone core.U32.Insts.CoreCloneClone.Lawful).clone_spec + mvcgen [specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup, h] + +theorem + specs.traits.builtin_bound.dup.spec.proof {T : Type} (corecloneCloneInst : + core.clone.Clone T) (x : T) + (corecloneCloneInstLawful : core.clone.Clone.Lawful T corecloneCloneInst) : + specs.traits.builtin_bound.dup.spec corecloneCloneInst x + corecloneCloneInstLawful + := by + unfold specs.traits.builtin_bound.dup.spec specs.traits.builtin_bound.dup + -- `clone` cannot fail by the `Clone.Lawful` hypothesis + obtain ⟨a, ha, -⟩ := Aeneas.Std.WP.triple_iff_exists_ok.1 (corecloneCloneInstLawful.clone_spec x) + rw [ha] + hax_mvcgen [specs.traits.builtin_bound.dup.post] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/DefaultMethods.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/DefaultMethods.lean new file mode 100644 index 0000000000..3f13b6f221 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/DefaultMethods.lean @@ -0,0 +1,52 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::default_methods`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.Lawful : + specs.traits.default_methods.D.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsDefault_methodsD + where + next_spec := by + intro self hpre + simp [U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.base] at hpre + mvcgen [U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.next] + · simp [U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.base] + agrind + · agrind + +theorem U64.Insts.Hax_testsSpecsTraitsDefault_methodsD.Lawful : + specs.traits.default_methods.D.Lawful Std.U64 + U64.Insts.Hax_testsSpecsTraitsDefault_methodsD + where + next_spec := by + intro self _ + mvcgen [specs.traits.default_methods.D.next.default] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Diamond.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Diamond.lean new file mode 100644 index 0000000000..61a05c8f76 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Diamond.lean @@ -0,0 +1,84 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::diamond`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U8.Insts.Hax_testsSpecsTraitsDiamondA.Lawful : + specs.traits.diamond.A.Lawful Std.U8 U8.Insts.Hax_testsSpecsTraitsDiamondA + where + a_spec := by + intro self _ + mvcgen [U8.Insts.Hax_testsSpecsTraitsDiamondA.a] + +theorem U8.Insts.Hax_testsSpecsTraitsDiamondB.Lawful : + specs.traits.diamond.B.Lawful Std.U8 U8.Insts.Hax_testsSpecsTraitsDiamondB + := ⟨U8.Insts.Hax_testsSpecsTraitsDiamondA.Lawful⟩ + +theorem U8.Insts.Hax_testsSpecsTraitsDiamondC.Lawful : + specs.traits.diamond.C.Lawful Std.U8 U8.Insts.Hax_testsSpecsTraitsDiamondC + where + AInstLawful := U8.Insts.Hax_testsSpecsTraitsDiamondA.Lawful + BInstLawful := U8.Insts.Hax_testsSpecsTraitsDiamondB.Lawful + c_spec := by + intro self _ + mvcgen [U8.Insts.Hax_testsSpecsTraitsDiamondC.c, U8.Insts.Hax_testsSpecsTraitsDiamondA.a] + +theorem + specs.traits.diamond.via_b.spec.proof {T : Type} (BInst : + specs.traits.diamond.B T) (x : T) + (BInstLawful : specs.traits.diamond.B.Lawful T BInst) : + specs.traits.diamond.via_b.spec BInst x BInstLawful + := by + unfold specs.traits.diamond.via_b.spec specs.traits.diamond.via_b + have ha := BInstLawful.AInstLawful.a_spec + mvcgen [ha] + +theorem + specs.traits.diamond.diamond.spec.proof {T : Type} (CInst : + specs.traits.diamond.C T) (x : T) + (CInstLawful : specs.traits.diamond.C.Lawful T CInst) : + specs.traits.diamond.diamond.spec CInst x CInstLawful + := by + unfold specs.traits.diamond.diamond.spec specs.traits.diamond.diamond + /- Modular: `x.a()` goes through `CInst.AInst` (paired with + `CInstLawful.AInstLawful`), `via_b x` through `CInst.BInst` (paired with + `CInstLawful.BInstLawful`, via `via_b`'s spec, without unfolding `via_b`). -/ + obtain ⟨a, ha, hapost⟩ := Aeneas.Std.WP.triple_iff_exists_ok.1 (CInstLawful.AInstLawful.a_spec x (by simp)) + have hvb := specs.traits.diamond.via_b.spec.proof CInst.BInst x CInstLawful.BInstLawful + unfold specs.traits.diamond.via_b.spec at hvb + obtain ⟨b, hb, hbpost⟩ := Aeneas.Std.WP.triple_iff_exists_ok.1 hvb + simp [specs.traits.diamond.A.a.post] at hapost + simp [specs.traits.diamond.via_b.post] at hbpost + mvcgen [ha, hb] + · simp [specs.traits.diamond.diamond.post] + agrind + · -- no overflow: both summands are ≤ 100 + agrind + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean new file mode 100644 index 0000000000..7f8ca11492 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean @@ -0,0 +1,129 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::generic_impl`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful : + specs.traits.generic_impl.Foo.Lawful Std.U64 + U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo + where + f_spec := by + intro self _ + mvcgen [U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f] + +theorem + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : + specs.traits.generic_impl.Foo.Lawful (specs.traits.generic_impl.Wrapper T) + (specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo + FooInst) + where + f_spec self hpre := FooInstLawful.f_spec self.inner hpre + +theorem + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implSub.Lawful + {T : Type} (SubInst : specs.traits.generic_impl.Sub T) + (SubInstLawful : specs.traits.generic_impl.Sub.Lawful T SubInst) : + specs.traits.generic_impl.Sub.Lawful (specs.traits.generic_impl.Wrapper T) + (specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implSub + SubInst) + where + FooInstLawful := + specs.traits.generic_impl.Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful + SubInst.FooInst SubInstLawful.FooInstLawful + s_spec self hpre := SubInstLawful.s_spec self.inner hpre + +theorem Pair.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful {T : Type} {U : + Type} (FooInst : specs.traits.generic_impl.Foo T) (FooInst1 : + specs.traits.generic_impl.Foo U) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) + (FooInst1Lawful : specs.traits.generic_impl.Foo.Lawful U FooInst1) : + specs.traits.generic_impl.Foo.Lawful (T × U) + (Pair.Insts.Hax_testsSpecsTraitsGeneric_implFoo FooInst FooInst1) + where + f_spec := by + intro self hpre + obtain ⟨t, u⟩ := self + exact FooInstLawful.f_spec t hpre + +theorem + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : + specs.traits.generic_impl.Foo.Lawful (specs.traits.generic_impl.Single T) + (specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo + FooInst) + where + f_spec self hpre := FooInstLawful.f_spec self hpre + +theorem + specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub.Lawful + : + specs.traits.generic_impl.Sub.Lawful (specs.traits.generic_impl.Single + Std.U64) + specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub + where + FooInstLawful := + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful + U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo + U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful + s_spec := by + intro self _ + mvcgen [specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub.s, + specs.traits.generic_impl.Single.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f, + U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f] + +theorem + specs.traits.generic_impl.k.spec.proof {T : Type} {U : Type} (FooInst : + specs.traits.generic_impl.Foo T) + (SubInst : + specs.traits.generic_impl.Sub U) + (x : T) (y : U) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) + (SubInstLawful : specs.traits.generic_impl.Sub.Lawful U SubInst) : + specs.traits.generic_impl.k.spec FooInst SubInst x y FooInstLawful + SubInstLawful + := by + unfold specs.traits.generic_impl.k.spec specs.traits.generic_impl.k + have h1 := FooInstLawful.f_spec + have h2 := SubInstLawful.s_spec + /- `s`'s post is `res = SubInst.FooInst.f y`: evaluate the parent's `f` on + `y` once, through the parent Lawful field. -/ + obtain ⟨i, hfy, hi⟩ := Aeneas.Std.WP.triple_iff_exists_ok.1 + (SubInstLawful.FooInstLawful.f_spec y (by simp)) + mvcgen [h1, h2] + · -- `f x <= 10` and `s y = f y <= 10` + simp [hfy] at * + agrind + · -- no overflow: the sum is at most 20 + simp [hfy] at * + agrind + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ImplContract.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ImplContract.lean new file mode 100644 index 0000000000..12723b6836 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ImplContract.lean @@ -0,0 +1,67 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::impl_contract`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.Lawful : + specs.traits.impl_contract.Foo.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo + := ⟨⟩ + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractG.Lawful : + specs.traits.impl_contract.G.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsImpl_contractG + where + g_spec := by + intro self _ + /- `self % 10 + 1` cannot overflow and is positive, whatever `self`: the + trait-level contract holds without the impl-level `requires`. -/ + mvcgen [U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g] + · agrind + · agrind + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec.proof + (self : Std.U32) : U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec self + := by + unfold U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f + hax_mvcgen + · agrind + · agrind + · agrind + +theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec.proof + (self : Std.U32) : U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec self + := by + unfold U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g + hax_mvcgen + · agrind + · agrind + · agrind + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MethodGenerics.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MethodGenerics.lean new file mode 100644 index 0000000000..a40a25df7f --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MethodGenerics.lean @@ -0,0 +1,50 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::method_generics`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar.Lawful : + specs.traits.method_generics.Bar.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar + where + bar_spec := by + intro self _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsMethod_genericsBar.bar] + +theorem U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo.Lawful : + specs.traits.method_generics.Foo.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo + where + f_spec := by + intro U BarInst _ self u hpre + cases hb : BarInst.bar u <;> simp [specs.traits.method_generics.Foo.f.pre, hb] at hpre + mvcgen [U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo.f, hb] + simp [hpre] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MutSelf.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MutSelf.lean new file mode 100644 index 0000000000..75d23dac5b --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/MutSelf.lean @@ -0,0 +1,45 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::mut_self`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.Lawful : + specs.traits.mut_self.Counter.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsMut_selfCounter + where + incr_spec := by + intro self hpre + simp [U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.get] at hpre + -- `self + 1` does not overflow under the precondition. + obtain ⟨r, hr, -⟩ := + WP.spec_imp_exists (U32.add_bv_spec (x := self) (y := 1#u32) (by scalar_tac)) + mvcgen [U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.incr, hr] + simp [U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.get, hr] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Supertraits.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Supertraits.lean new file mode 100644 index 0000000000..90e10de060 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Supertraits.lean @@ -0,0 +1,91 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::supertraits`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsA.Lawful : + specs.traits.supertraits.A.Lawful Std.U8 + U8.Insts.Hax_testsSpecsTraitsSupertraitsA + where + a_spec := by + intro self _ + mvcgen [U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a] + +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsB.Lawful : + specs.traits.supertraits.B.Lawful Std.U8 + U8.Insts.Hax_testsSpecsTraitsSupertraitsB + where + AInstLawful := U8.Insts.Hax_testsSpecsTraitsSupertraitsA.Lawful + b_spec := by + intro self _ + apply Aeneas.Std.WP.spec_to_mvcgen + simp [U8.Insts.Hax_testsSpecsTraitsSupertraitsB.b, U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a] + step* + +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsCc.Lawful : + specs.traits.supertraits.Cc.Lawful Std.U8 + U8.Insts.Hax_testsSpecsTraitsSupertraitsCc + where + BInstLawful := U8.Insts.Hax_testsSpecsTraitsSupertraitsB.Lawful + c_spec := by + /- `c = b = a + 1 = 2`; the post reaches `a` through + `CcInst.BInst.AInst = U8.Insts.Hax_testsSpecsTraitsSupertraitsA`. -/ + intro self _ + apply Aeneas.Std.WP.spec_to_mvcgen + simp [U8.Insts.Hax_testsSpecsTraitsSupertraitsCc.c, U8.Insts.Hax_testsSpecsTraitsSupertraitsB.b, U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a] + step* + +theorem + specs.traits.supertraits.via_b.spec.proof {T : Type} (BInst : + specs.traits.supertraits.B T) + (x : T) (BInstLawful : specs.traits.supertraits.B.Lawful T BInst) : + specs.traits.supertraits.via_b.spec BInst x BInstLawful + := by + unfold specs.traits.supertraits.via_b.spec specs.traits.supertraits.via_b + intro hpre + /- `x.a()` (and the pre) through `BInstLawful.AInstLawful.a_spec`, `x.b()` through + `BInstLawful.b_spec`, whose pre (`a x < 100`) is `via_b`'s pre and whose post + (`b x > a x`) rules out the underflow. -/ + obtain ⟨a, ha, -⟩ := Aeneas.Std.WP.triple_iff_exists_ok.1 (BInstLawful.AInstLawful.a_spec x (by simp)) + simp [ha, specs.traits.supertraits.via_b.pre] at hpre + obtain ⟨b, hb, hgt⟩ := Aeneas.Std.WP.triple_iff_exists_ok.1 (BInstLawful.b_spec x (by simpa [ha] using hpre)) + simp [ha] at hgt + mvcgen [ha, hb] + · simp [specs.traits.supertraits.via_b.post] + agrind + · -- no underflow: `b x > a x` + agrind + +theorem specs.traits.supertraits.via_u8.spec.proof (x : Std.U8) : + specs.traits.supertraits.via_u8.spec x + := by + /- `via_u8` is `via_b` at the `u8` impls. -/ + exact specs.traits.supertraits.via_b.spec.proof _ x U8.Insts.Hax_testsSpecsTraitsSupertraitsB.Lawful + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean new file mode 100644 index 0000000000..9993581f25 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean @@ -0,0 +1,54 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::trait_generics`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8.Lawful : + specs.traits.trait_generics.Conv.Lawful Std.U32 Std.U8 + U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8 + where + conv_spec := by + intro self t _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8.conv] + +theorem + specs.traits.trait_generics.use_conv.spec.proof {C : Type} (ConvCU8Inst : + specs.traits.trait_generics.Conv + C Std.U8) (c : C) + (ConvCU8InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U8 + ConvCU8Inst) : + specs.traits.trait_generics.use_conv.spec ConvCU8Inst c ConvCU8InstLawful + := by + unfold specs.traits.trait_generics.use_conv.spec + specs.traits.trait_generics.use_conv + -- The Lawful binder gives `conv`'s contract at `T := Std.U8`. + have hc := ConvCU8InstLawful.conv_spec + mvcgen [hc] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/UnannotatedSub.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/UnannotatedSub.lean new file mode 100644 index 0000000000..bc80725b7a --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/UnannotatedSub.lean @@ -0,0 +1,45 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::unannotated_sub`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.Lawful : + specs.traits.unannotated_sub.A.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsUnannotated_subA + where + a_spec := by + intro self _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.a] + +theorem U32.Insts.Hax_testsSpecsTraitsUnannotated_subB.Lawful : + specs.traits.unannotated_sub.B.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsUnannotated_subB + := ⟨U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.Lawful⟩ + +end hax_tests From a4fa2b9aee65b8af6acff7c25d5171e0bca79d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Thu, 15 Oct 2026 18:34:17 +0200 Subject: [PATCH 11/17] docs: add documentation for hax-specs --- CLAUDE.md | 1 + documentation/README.md | 1 + documentation/hax-specs.md | 291 ++++++++++++++++++++++++++++++ documentation/proof-strategies.md | 4 + tests/README.md | 40 ++-- 5 files changed, 326 insertions(+), 11 deletions(-) create mode 100644 documentation/hax-specs.md diff --git a/CLAUDE.md b/CLAUDE.md index 923580e0e1..569c89ff76 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,5 +27,6 @@ Copilot) and `.claude/skills/` (for Claude Code). **Always edit files in - `documentation/proof-strategies.md` — Proof strategies (step, loops, decomposition, specs) - `documentation/tactics-reference.md` — All tactics with docstrings and examples - `documentation/crypto-verification.md` — Crypto verification guide (ML-KEM/Kyber patterns) +- `documentation/hax-specs.md` — `-specs hax`: specs, `Lawful` structures and obligations from `hax_lib` contracts - `documentation/tips-and-tricks.md` — Pitfalls, tips, and tricks - `documentation/glossary.md` — Glossary of Aeneas-specific terms diff --git a/documentation/README.md b/documentation/README.md index 2c06593938..8f5e101936 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -8,6 +8,7 @@ Aeneas translates Rust programs to into pure functional programs (primarily Lean - [Tactics Reference](tactics-reference.md) — All tactics with docstrings and examples - [Tips, Tricks & Pitfalls](tips-and-tricks.md) — Common pitfalls and how to avoid them - [Crypto Verification](crypto-verification.md) — Verifying cryptographic code +- [hax Specs](hax-specs.md) — Lean specs and proof obligations from `hax_lib` contracts (`-specs hax`) - [Glossary](glossary.md) — Aeneas-specific terms For AI agent instructions see the [skills/](skills/) folder. \ No newline at end of file diff --git a/documentation/hax-specs.md b/documentation/hax-specs.md new file mode 100644 index 0000000000..a93ae62d9f --- /dev/null +++ b/documentation/hax-specs.md @@ -0,0 +1,291 @@ +# Specs from Rust, via hax annotations (`-specs hax`) + +## High-level documentation + +When Aeneas is invoked with `-specs hax` (Lean backend only) it reads the +contracts written with [`hax_lib`](https://github.com/cryspen/hax) annotations +in the Rust code and emits them as Lean statements of correctness, together with +the proof obligations stating that the code meets them. + +### Overview + +There are several kinds of rust-written specs: + +* *Function level specs*: `#[requires(..)]` / `#[ensures(\|res\|..)]` on a + function. Those generate specification functions`.pre`, `.post`, a + statement of correctness `.spec`, and the obligation `.spec.proof` +* *Trait level specs*: every trait gets a *companion* structure `.Lawful` + that registers the specifications attached to methods and constants. Every + implementation generates a corresponding obligation of lawfulness. + * If no annotation is written, the companion structure is empty. + * `#[requires(..)]` / `#[ensures(\|res\|..)]` on the methods of trait + generate specification functions `..pre`, `..post`, + and add a field `_spec` to the companion structure `.Lawful`. +* *Impl level specs*: trait-level specifications can be *refined* (weaker + pre-condition and stronger post) for each implementation. Such specifications, + written with `#[requires(..)]` / `#[ensures(\|res\|..)]`, generate standalone + contracts. For now, the trait-level and impl-level specs are not linked. + +At most one `#[requires]` and one `#[ensures]` are used per item. Other hax +annotations (e.g. `decreases`) are dropped. + +### File structure + +With `-split-files`, the specs go to `Specs.lean` and the obligations to +`ProofObligations.lean` (which imports `Specs`). Without `-split-files`, both +go at the end of the single output file. + +`Specs.lean` contains, in order: +1. For each local trait (parents first): the `.pre`/`.post` of its annotated + methods, then `.Lawful`. +2. For each contracted function: `.pre`, `.post`, then `.spec`. + +`ProofObligations.lean` contains, in order: +1. `.Lawful` for each local trait impl (dependencies first). +2. `.spec.proof` for each contracted function. + +### Function contracts + +```rust +#[requires(x < 10)] +#[ensures(|result| result > x)] +fn both(x: u32) -> u32 { x + 1 } +``` + +```lean +-- Specs.lean +@[reducible] +def both.pre (x : Std.U32) : RustM Bool := do + ok (x < 10#u32) + +@[reducible] +def both.post + (x : Std.U32) (result : Std.U32) : RustM Bool := do + ok (result > x) + +def both.spec (x : Std.U32) : Prop := + (specs.contracts.both.pre x).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.contracts.both x + ⦃ ⇓ res => ⌜ (specs.contracts.both.post x res).holds ⌝ ⦄ +``` + +```lean +-- ProofObligations.lean +theorem both.spec.proof (x : Std.U32) : + specs.contracts.both.spec x + := by sorry +``` + +- The conditions are the hax decoration functions, translated like any function: + `RustM Bool` (or `RustM hax_lib.prop.Prop` for `hax_lib::prop` + conditions). The postcondition takes the result as its last argument. +- Without `#[requires]` the spec has no hypothesis; without `#[ensures]` its + postcondition is `⌜ True ⌝`. +- `.spec` is a total-correctness triple (`⇓`): the function must not panic or + diverge. + +### Trait contracts and `X.Lawful` + +```rust +#[hax_lib::attributes] +trait A { + #[ensures(|res| res >= 1)] + fn a(&self) -> usize; +} + +#[hax_lib::attributes] +trait B: A { + #[requires(self.a() < 100)] + #[ensures(|res| res > self.a())] + fn b(&self) -> usize; +} + +impl B for Foo { ... } +``` + +```lean +-- Specs.lean +structure B.Lawful + (Self : Type) + (BInst : specs.traits.supertraits.B Self) : Prop where + + -- supertrait lawfulness + AInstLawful : specs.traits.supertraits.A.Lawful Self BInst.AInst + + -- method spec + b_spec (self_ : Self) : + (specs.traits.supertraits.B.b.pre BInst.AInst BInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + BInst.b self_ + ⦃ ⇓ res => + ⌜ (specs.traits.supertraits.B.b.post BInst.AInst BInst self_ res).holds ⌝ ⦄ +``` + +```lean +-- ProofObligations.lean +theorem Foo.Insts.BLawful : specs.traits.supertraits.B.Lawful U32 := by sorry +``` + +One lawful instances per parent clause `

InstLawful : P.Lawful … +Inst.

Inst`, one spec per annotated method `_spec`. A trait with no +annotated method and no parent still gets an empty structure. Each +implementation gets a corresponding proof obligation. + +#### Foreign traits + +`X.Lawful` is only generated for local traits. For a foreign trait the generated +code refers to `X.Lawful` as if it existed, so a Lean library must provide it, +following the same conventions. + + +## Details + +### Diagnostics + +All messages start with `hax-specs:`. Warnings marked *(span)* point at the Rust +source when it is known and become errors with `-warnings-as-errors`; the others +are logged at warning level. + +* ``multiple #[requires] on `f`; ignoring extras`` (or `#[ensures]`) : More + than one condition of a kind on an item: the first one is used. +* ``` `f` references unknown decoration uid …; skipping that side ``` : The + decoration function of a condition is not in the LLBC. +* ``argument count mismatch for `f.pre` (takes N, expected M); dropping this + condition`` : The condition does not take the arguments of the function (plus + the result, for a post). +* ``dropping the contract of trait method `m`: its #[requires] is invalid`` (or + `#[ensures]`) *(span)* : A condition of a trait method was dropped: the whole + method contract is dropped. +* ``the contract of `m` is checked as a standalone spec only; it is independent + of the trait-level contract`` Contract on a method of a trait impl. +* ``dropping the hax decoration `d`: it is attached to no translated item`` + *(span)* No item refers to this decoration function. +* ``dropping the hax decoration `d`: unsupported or invalid annotation, or part + of a dropped contract`` A decoration that was not used (e.g. `decreases`, an + extra or dropped condition). +* ``dropping the contract of function `f`: the function was not translated`` + *(span)* The annotated function failed to translate. Same for a trait (``the + contract of trait `X` ``) and a trait impl (``the Lawful obligation of trait + impl `I` ``). + +Name clashes between the generated names (`.pre`, `.post`, `.spec`, +`.spec.proof`, `.Lawful`) and the names of the crate items are errors (`Name +clash detected: …`). This includes a trait field (parent clause, associated +constant or type, or method) whose projection would be named `.Lawful`, +e.g. an associated type `Lawful`; the check is case-sensitive (a method `lawful` +is fine). + +### Limitations + +- **No `@[spec]` registration.** The obligations are plain theorems: `mvcgen` + does not use them automatically. A caller unfolds the callee's `.spec` or + passes the theorem explicitly (see below). +- **Impl-level contracts**: see [Inputs](#inputs). +- **`ProofObligations.lean` is a template**: every proof is `sorry`, and it is + overwritten on each extraction. Copy the obligations to a handwritten file to + prove them. Nothing checks the copy against the template: after a + re-extraction, compare the two (the theorems live in `namespace `, as + in the generated files). +- **Built-in instances**: an instance that Charon resolves as built-in + (`BuiltinOrAuto`, e.g. `Clone` for a tuple) is printed as `BuiltinClone …`, + not as a `CoreModels` instance, so no `Lawful` theorem exists for it (e.g. to + fill the `Clone` parent field of an impl of `Dup: Clone` for a tuple). +- **Dropped trait-method contracts** (with a warning, see + [Diagnostics](#diagnostics)): when the generics of the conditions match those + of the trait and the method ambiguously (e.g. a supertrait with an associated + type, plus several method type parameters with the same bound that no input + distinguishes), and when a postcondition must be synthesized for a method + whose output type mentions a trait instance. + +### Proving the obligations + +The examples below are adapted from the hax test suite +(`tests/hax/proofs/hax-tests/lean/HaxTests/Verification/`). + +**Function specs.** Unfold the spec and the function, then run `hax_mvcgen` +(from hax's Lean library) or `mvcgen`: + +```lean +theorem specs.contracts.both.spec.proof (x : Std.U32) : specs.contracts.both.spec x := by + unfold specs.contracts.both.spec specs.contracts.both + hax_mvcgen + · simp; scalar_tac + · scalar_tac +``` + +**Using a Lawful hypothesis.** `mvcgen [L.m_spec]` does not accept a projection +of a local hypothesis: bind it with `have` first. To learn that a method call +returns (e.g. because a condition calls it again), use +`Aeneas.Std.WP.triple_iff_exists_ok`, which turns a `⇓` triple into `∃ a, x = +.ok a ∧ P a`: + +```lean +theorem specs.traits.basic.g.spec.proof … := by + unfold specs.traits.basic.g.spec specs.traits.basic.g + have h2 := FooInstLawful.f2_spec + obtain ⟨b, hf1, -⟩ := (Aeneas.Std.WP.triple_iff_exists_ok).1 (FooInstLawful.f1_spec x (by simp)) + mvcgen [hf1, h2] + simp [specs.traits.basic.g.post] +``` + +Parent contracts are reached through the parent fields, +e.g. `BInstLawful.AInstLawful.a_spec`. + +**Concrete callers.** A caller at a concrete impl uses the `.Lawful` theorem of +the impl. Either instantiate the callee's proof and unfold it, or reuse a +generic proof directly when the function is the same code at a concrete type: + +```lean +theorem specs.traits.basic.h.spec.proof (x : Std.U64) : specs.traits.basic.h.spec x := by + unfold specs.traits.basic.h.spec specs.traits.basic.h + have hg := specs.traits.basic.g.spec.proof U64.Insts.Hax_testsSpecsTraitsBasicFoo x + U64.Insts.Hax_testsSpecsTraitsBasicFoo.Lawful + unfold specs.traits.basic.g.spec at hg + mvcgen [hg] + +theorem specs.traits.supertraits.via_u8.spec.proof (x : Std.U8) : + specs.traits.supertraits.via_u8.spec x := + specs.traits.supertraits.via_b.spec.proof _ x U8.Insts.Hax_testsSpecsTraitsSupertraitsB.Lawful +``` + +A generic caller passes its own Lawful binders instead, or their parent fields +for a parent instance (e.g. `… SubInst.FooInst SubInstLawful.FooInstLawful`, in +`Verification/Traits/GenericImpl.lean`). A foreign bound at a concrete type +takes the theorem of the core impl +(e.g. `core.U32.Insts.CoreCloneClone.Lawful`). + +**Impl obligations.** Prove `.Lawful` with `where` (one tactic block per +field) or an anonymous constructor (`⟨⟩` for an empty structure). Fill the +parent fields with the theorems of the parent impls, and, for generic impls, +with the Lawful binders: + +```lean +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsB.Lawful : + specs.traits.supertraits.B.Lawful Std.U8 U8.Insts.Hax_testsSpecsTraitsSupertraitsB + where + AInstLawful := U8.Insts.Hax_testsSpecsTraitsSupertraitsA.Lawful + b_spec := by + intro self _ + apply Aeneas.Std.WP.spec_to_mvcgen + simp [U8.Insts.Hax_testsSpecsTraitsSupertraitsB.b, U8.Insts.Hax_testsSpecsTraitsSupertraitsA.a] + step* + +theorem …Wrapper.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful {T : Type} + (FooInst : …) (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : … + where + f_spec self hpre := FooInstLawful.f_spec self.inner hpre +``` + +`Aeneas.Std.WP.spec_to_mvcgen` turns the `⦃ ⌜ True ⌝ ⦄ x ⦃ ⇓ r => ⌜ Q r ⌝ ⦄` +goal of a field into the Aeneas `spec` form, so that `step*` can be used. + +**`.holds` of `RustM Bool` conditions.** A trait-method condition used as a +proposition appears as `((fun a => a = true) <$> x).holds`, which neither Aeneas +nor Hax simplifies yet. The test suite proves a simp lemma for it in +`HaxTests/Verification/Lemmas.lean`: + +```lean +@[simp] theorem Aeneas.Std.RustM.holds_bool (x : RustM Bool) : + ((fun a => a = true) <$> x : RustM Prop).holds ↔ x = ok true +``` diff --git a/documentation/proof-strategies.md b/documentation/proof-strategies.md index 44d678ba1f..e61b9eef79 100644 --- a/documentation/proof-strategies.md +++ b/documentation/proof-strategies.md @@ -229,6 +229,10 @@ This technique makes large proofs tractable by breaking them into manageable pie grep -r "@\[progress\]" . --include="*.lean" ``` +5. **`hax_lib` contracts:** with `-specs hax`, the contracts of the Rust code + are stated in `Specs.lean` and proved by hand; the proofs are not registered + for `step`/`mvcgen` (see [hax-specs.md](hax-specs.md)) + ### When to write a new spec: - The function is Aeneas-generated and has no existing spec diff --git a/tests/README.md b/tests/README.md index d9a79b5f03..2a021ce7dd 100644 --- a/tests/README.md +++ b/tests/README.md @@ -16,7 +16,7 @@ Running the test suite has two parts: `charon` and `aeneas` to generate the backend-specific outputs. - We check that the generated output is valid code by parsing it and type-checking it with the relevant verifier (Lean, Coq, F*, etc.), and replay the hand-written proofs which use it as - a dependency. This is done by running `make verify` in the project root. + a dependency. This is done by running `make verify` in the project root. To generate the output of a single test, run `make test-`, e.g. `make test-loops.rs` or `make test-betree`. To verify the output for a single backend, run `make verify-` inside the @@ -40,12 +40,12 @@ on it confidently. ## hax tests -`tests/hax/` is a crate (on `hax-lib` 0.4.2) that is extracted the way -[hax](https://github.com/cryspen/hax) users extract them: through `cargo hax extract`, which runs -the proof scenario `hax-tests` of `tests/hax/hax.toml` and drives charon and aeneas. hax is pointed -at the binaries of this checkout (`bin/aeneas`, `charon/bin/charon`) by the same `hax.toml`. The -extracted Lean code lives in `tests/hax/proofs/hax-tests/lean/` (Lean package `HaxTests`), next to -the Lake project that builds it and the handwritten proofs, and is committed. +`tests/hax/` is a crate that is extracted the way [hax](https://github.com/cryspen/hax) users +extract them: through `cargo hax extract`, which runs the proof scenario `hax-tests` of +`tests/hax/hax.toml` and drives charon and aeneas. hax is pointed at the binaries of this checkout +(`bin/aeneas`, `charon/bin/charon`) by the same `hax.toml`. The extracted Lean code lives in +`tests/hax/proofs/hax-tests/lean/` (Lean package `HaxTests`), next to the Lake project that builds +it and the handwritten proofs, and is committed. These tests are not run by `make test`. Run them with a checkout of hax and the matching `cargo hax` on your `PATH`: @@ -54,10 +54,28 @@ on your `PATH`: make test-hax HAX_DIR=../hax ``` -This regenerates the outputs, with the crate using the `hax-lib` of `HAX_DIR`, then builds them -with the Lake project `tests/hax/proofs/hax-tests/lean/lakefile.toml`, against the aeneas Lean -library of this checkout and the hax Lean library of `HAX_DIR`. `HAX_DIR` itself is not modified (except for Lake's build -directory). `make extract-hax` and `make verify-hax` run the two steps separately. +This regenerates the outputs, with the crate using the `hax-lib` of `HAX_DIR`, then builds them with +the Lake project `tests/hax/proofs/hax-tests/lean/lakefile.toml`, against the aeneas Lean library of +this checkout and the hax Lean library of `HAX_DIR`. `HAX_DIR` itself is not modified (except for +Lake's build directory). `make extract-hax` and `make verify-hax` run the two steps separately. + +The Lean package `HaxTests` is laid out as follows (see also +[`documentation/hax-specs.md`](../documentation/hax-specs.md)): +- `HaxTests/Extraction/*`: generated by the extraction, and committed. `ProofObligations.lean` is the + generated template of the proof obligations (with `sorry`): it is not built by `make verify-hax`. +- `HaxTests/Verification/ProofObligations.lean` and `HaxTests/Verification/Traits/.lean`: + the handwritten proofs of the obligations. `make verify-hax` builds them and the extracted specs + (the roots of the `HaxTestsChecks` library of `lakefile.toml`, with everything they import). +- `HaxTests/Verification/Lemmas.lean` and `HaxTests/Verification/MissingCore.lean`: helper lemmas + for these proofs, and lemmas about `CoreModels` missing upstream. +- `HaxTests/Assumptions/MissingCore.lean`: stubs of the `Lawful` structures of `CoreModels` traits, + until `CoreModels` provides them. Imported into every file Aeneas generates by + `aeneas-args = ["-extra-includes", "HaxTests.Assumptions.MissingCore"]` in `tests/hax/hax.toml`, + so it must not import any other `HaxTests` module. +- `HaxTests/Assumptions/FunsExternal.lean` and `TypesExternal.lean`: the models of external + definitions. hax seeds each one, if absent, from the `Extraction/*External_Template.lean` file + Aeneas generates, then never modifies it; `Extraction/FunsExternal.lean` and + `TypesExternal.lean` are hax shims importing them. In CI, the `hax-tests` job of `.github/workflows/hax-main.yml` runs them with hax `main`, or with the branch named by a `hax-branch: ` line in the pull request description. It fails if the From 5d600b861c42f161f6fefe89e83e3db2ddd7ed25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Fri, 23 Oct 2026 14:36:41 +0200 Subject: [PATCH 12/17] test: more tests for associated consts --- .../lean/HaxTests/Extraction/Funs.lean | 60 ++++ .../HaxTests/Extraction/ProofObligations.lean | 32 ++ .../lean/HaxTests/Extraction/Specs.lean | 310 ++++++++++++++++++ .../lean/HaxTests/Extraction/Types.lean | 52 +++ .../Verification/ProofObligations.lean | 12 + .../Verification/Traits/AssocConsts.lean | 73 +++++ tests/hax/src/specs/contracts.rs | 16 + tests/hax/src/specs/generics.rs | 8 + tests/hax/src/specs/traits.rs | 1 + tests/hax/src/specs/traits/assoc_consts.rs | 51 +++ tests/hax/src/specs/traits/synthesized.rs | 117 +++++++ 11 files changed, 732 insertions(+) create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocConsts.lean create mode 100644 tests/hax/src/specs/traits/assoc_consts.rs diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean index 09c8677b68..47debdf4e5 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean @@ -447,6 +447,15 @@ def specs.generics.from_default let t ← coredefaultDefaultInst.default ok { fst := t } +/-- [hax_tests::specs::generics::first]: + Source: 'src/specs/generics.rs', lines 134:0-136:1 -/ +def specs.generics.first + {T : Type} {V : Type} (HolderVOptionInst : specs.generics.Holder V + (core.option.Option T)) (v : V) : + RustM Std.U32 + := do + ok 0#u32 + /-- [hax_tests::specs::mutable_borrows::incr]: Source: 'src/specs/mutable_borrows.rs', lines 5:0-7:1 -/ def specs.mutable_borrows.incr (x : Std.U32) : RustM Std.U32 := do @@ -555,6 +564,57 @@ def specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux QuxInst } +/-- [hax_tests::specs::traits::assoc_consts::Bounded::MIN] + Source: 'src/specs/traits/assoc_consts.rs', lines 13:4-13:23 -/ +@[global_simps, irreducible, trait_default] +def specs.traits.assoc_consts.Bounded.MIN.default (Self : Type) : Std.U32 := + 0#u32 + +/-- [hax_tests::specs::traits::assoc_consts::{impl hax_tests::specs::traits::assoc_consts::Bounded for u32}::clamp]: + Source: 'src/specs/traits/assoc_consts.rs', lines 27:4-29:5 -/ +def U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp + (self : Std.U32) (x : Std.U32) : RustM Std.U32 := do + ok x + +/-- [hax_tests::specs::traits::assoc_consts::{impl hax_tests::specs::traits::assoc_consts::Bounded for u32}::MAX] + Source: 'src/specs/traits/assoc_consts.rs', lines 22:4-22:25 -/ +@[global_simps, irreducible] +def U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.MAX : Std.U32 := 100#u32 + +/-- Trait implementation: [hax_tests::specs::traits::assoc_consts::{impl hax_tests::specs::traits::assoc_consts::Bounded for u32}] + Source: 'src/specs/traits/assoc_consts.rs', lines 21:0-30:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded : + specs.traits.assoc_consts.Bounded Std.U32 := { + MAX := ok U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.MAX + MIN := ok (specs.traits.assoc_consts.Bounded.MIN.default Std.U32) + clamp := U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp +} + +/-- [hax_tests::specs::traits::assoc_consts::{impl hax_tests::specs::traits::assoc_consts::Scaled for u32}::scale]: + Source: 'src/specs/traits/assoc_consts.rs', lines 41:4-43:5 -/ +def U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled.scale + (self : Std.U32) (x : Std.U32) : RustM Std.U32 := do + ok x + +/-- Trait implementation: [hax_tests::specs::traits::assoc_consts::{impl hax_tests::specs::traits::assoc_consts::Scaled for u32}] + Source: 'src/specs/traits/assoc_consts.rs', lines 40:0-44:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled : + specs.traits.assoc_consts.Scaled Std.U32 := { + BoundedInst := U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded + scale := U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled.scale +} + +/-- [hax_tests::specs::traits::assoc_consts::use_clamp]: + Source: 'src/specs/traits/assoc_consts.rs', lines 49:0-51:1 -/ +def specs.traits.assoc_consts.use_clamp + {T : Type} (BoundedInst : specs.traits.assoc_consts.Bounded T) (t : T) + (x : Std.U32) : + RustM Std.U32 + := do + BoundedInst.clamp t x + /-- [hax_tests::specs::traits::assoc_type_bounds::{impl hax_tests::specs::traits::assoc_type_bounds::Bar for u32}::bar]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 27:4-29:5 -/ def U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.bar diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean index 6986434292..e3e1024e14 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean @@ -91,6 +91,16 @@ theorem (specs.naming.lawful_impl_binder.Wrap.Insts.Hax_testsSpecsNamingQux QuxInst) := by sorry +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.Lawful : + specs.traits.assoc_consts.Bounded.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled.Lawful : + specs.traits.assoc_consts.Scaled.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled + := by sorry + theorem U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar.Lawful : specs.traits.assoc_type_bounds.Bar.Lawful Std.U32 U32.Insts.Hax_testsSpecsTraitsAssoc_type_boundsBar @@ -459,6 +469,15 @@ theorem specs.generics.empty.spec.proof (T : Type) (N : Std.Usize) (k : Std.Usize) : specs.generics.empty.spec T N k := by sorry +theorem + specs.generics.first.spec.proof {T : Type} {V : Type} (HolderVOptionInst : + specs.generics.Holder V (core.option.Option + T)) (v : V) + (HolderVOptionInstLawful : specs.generics.Holder.Lawful V (core.option.Option + T) HolderVOptionInst) : + specs.generics.first.spec HolderVOptionInst v HolderVOptionInstLawful + := by sorry + theorem specs.naming.foo.spec.proof (x : Std.U32) : specs.naming.foo.spec x := by sorry @@ -572,6 +591,14 @@ theorem specs.traits.trait_generics.use_conv.spec ConvCU8Inst c ConvCU8InstLawful := by sorry +theorem + specs.traits.assoc_consts.use_clamp.spec.proof {T : Type} (BoundedInst : + specs.traits.assoc_consts.Bounded + T) (t : T) (x : Std.U32) + (BoundedInstLawful : specs.traits.assoc_consts.Bounded.Lawful T BoundedInst) + : specs.traits.assoc_consts.use_clamp.spec BoundedInst t x BoundedInstLawful + := by sorry + theorem specs.naming.lawful_binder.f.spec.proof {T : Type} (QuxInst : specs.naming.Qux T) @@ -588,4 +615,9 @@ theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec.proof (self : Std.U32) : U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec self := by sorry +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.spec.proof + (self : Std.U32) (x : Std.U32) : + U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.spec self x + := by sorry + end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index 190dae1f0d..765891ef49 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -43,11 +43,92 @@ structure specs.generics.Val.Lawful (Self : Type) (ValInst : specs.generics.Val structure specs.generics.Producer.Lawful (Self : Type) (Self_Out : Type) (ProducerInst : specs.generics.Producer Self Self_Out) : Prop +/-- Lawful structure of trait: [hax_tests::specs::generics::Holder] + Source: 'src/specs/generics.rs', lines 131:0-131:18 -/ +structure specs.generics.Holder.Lawful (Self : Type) (T : Type) (HolderInst : + specs.generics.Holder Self T) : Prop + /-- Lawful structure of trait: [hax_tests::specs::naming::Qux] Source: 'src/specs/naming.rs', lines 31:0-33:1 -/ structure specs.naming.Qux.Lawful (Self : Type) (QuxInst : specs.naming.Qux Self) : Prop +/-- [hax_tests::specs::traits::assoc_consts::Bounded::clamp::pre]: + Source: 'src/specs/traits/assoc_consts.rs', lines 8:0-8:22 -/ +@[reducible] +def specs.traits.assoc_consts.Bounded.clamp.pre + {Self_ : Type} (BoundedInst : specs.traits.assoc_consts.Bounded Self_) + (self_ : Self_) (x : Std.U32) : + RustM Bool + := do + let i ← BoundedInst.MAX + ok (x < i) + +/-- [hax_tests::specs::traits::assoc_consts::Bounded::clamp::post]: + Source: 'src/specs/traits/assoc_consts.rs', lines 8:0-8:22 -/ +@[reducible] +def specs.traits.assoc_consts.Bounded.clamp.post + {Self_ : Type} (BoundedInst : specs.traits.assoc_consts.Bounded Self_) + (self_ : Self_) (x : Std.U32) (r : Std.U32) : + RustM Bool + := do + let i ← BoundedInst.MAX + ok (r <= i) + +/-- Lawful structure of trait: [hax_tests::specs::traits::assoc_consts::Bounded] + Source: 'src/specs/traits/assoc_consts.rs', lines 9:0-18:1 -/ +structure specs.traits.assoc_consts.Bounded.Lawful (Self : Type) (BoundedInst : + specs.traits.assoc_consts.Bounded Self) : Prop where + clamp_spec (self_ : Self) (x : Std.U32) : + (specs.traits.assoc_consts.Bounded.clamp.pre BoundedInst self_ x).holds → + ⦃ ⌜ True ⌝ ⦄ + BoundedInst.clamp self_ x + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_consts.Bounded.clamp.post BoundedInst self_ x + res).holds ⌝ ⦄ + +/-- [hax_tests::specs::traits::assoc_consts::Scaled::scale::pre]: + Source: 'src/specs/traits/assoc_consts.rs', lines 33:0-33:22 -/ +@[reducible] +def specs.traits.assoc_consts.Scaled.scale.pre + {Self_ : Type} (BoundedInst : specs.traits.assoc_consts.Bounded Self_) + (ScaledInst : specs.traits.assoc_consts.Scaled Self_) (self_ : Self_) + (x : Std.U32) : + RustM Bool + := do + let i ← BoundedInst.MIN + if i <= x + then let i1 ← BoundedInst.MAX + ok (x <= i1) + else ok false + +/-- [hax_tests::specs::traits::assoc_consts::Scaled::scale::post]: + Source: 'src/specs/traits/assoc_consts.rs', lines 33:0-33:22 -/ +@[reducible] +def specs.traits.assoc_consts.Scaled.scale.post + {Self_ : Type} (BoundedInst : specs.traits.assoc_consts.Bounded Self_) + (ScaledInst : specs.traits.assoc_consts.Scaled Self_) (self_ : Self_) + (x : Std.U32) (r : Std.U32) : + RustM Bool + := do + let i ← BoundedInst.MAX + ok (r <= i) + +/-- Lawful structure of trait: [hax_tests::specs::traits::assoc_consts::Scaled] + Source: 'src/specs/traits/assoc_consts.rs', lines 34:0-38:1 -/ +structure specs.traits.assoc_consts.Scaled.Lawful (Self : Type) (ScaledInst : + specs.traits.assoc_consts.Scaled Self) : Prop where + BoundedInstLawful : specs.traits.assoc_consts.Bounded.Lawful Self + ScaledInst.BoundedInst + scale_spec (self_ : Self) (x : Std.U32) : + (specs.traits.assoc_consts.Scaled.scale.pre ScaledInst.BoundedInst + ScaledInst self_ x).holds → + ⦃ ⌜ True ⌝ ⦄ + ScaledInst.scale self_ x + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_consts.Scaled.scale.post ScaledInst.BoundedInst + ScaledInst self_ x res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::assoc_type_bounds::Bar::bar::pre]: Source: 'src/specs/traits/assoc_type_bounds.rs', lines 11:4-11:25 -/ @[reducible] @@ -933,6 +1014,165 @@ structure specs.traits.synthesized.Assoc.Lawful (Self : Type) (Self_Item : ⦃ ⇓ res => ⌜ (specs.traits.synthesized.Assoc.item.post AssocInst self_ res).holds ⌝ ⦄ +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::K] + Source: 'src/specs/traits/synthesized.rs', lines 43:0-45:1 -/ +structure specs.traits.synthesized.K.Lawful (Self : Type) (KInst : + specs.traits.synthesized.K Self) : Prop + +/-- [hax_tests::specs::traits::synthesized::Sym::g::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 49:0-49:22 -/ +@[reducible] +def specs.traits.synthesized.Sym.g.pre + {Self_ : Type} {U : Type} (KInst : specs.traits.synthesized.K U) (KInst1 : + specs.traits.synthesized.K Self_) (SymInst : specs.traits.synthesized.Sym + Self_) (x : Std.U32) : + RustM Bool + := do + let i ← KInst.k + if x < i + then ok (i < 10#u32) + else ok false + +/-- [hax_tests::specs::traits::synthesized::Sym::g::post]: + Source: 'src/specs/traits/synthesized.rs', lines 52:4-52:30 -/ +@[reducible] +def specs.traits.synthesized.Sym.g.post + {Self_ : Type} {U : Type} (KInst : specs.traits.synthesized.K U) (KInst1 : + specs.traits.synthesized.K Self_) (SymInst : specs.traits.synthesized.Sym + Self_) (x : Std.U32) (res : Std.U32) : + RustM Bool + := do + ok true + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Sym] + Source: 'src/specs/traits/synthesized.rs', lines 50:0-53:1 -/ +structure specs.traits.synthesized.Sym.Lawful (Self : Type) (SymInst : + specs.traits.synthesized.Sym Self) : Prop where + KInstLawful : specs.traits.synthesized.K.Lawful Self SymInst.KInst + g_spec {U : Type} (KInst : specs.traits.synthesized.K U) + (KInstLawful : specs.traits.synthesized.K.Lawful U KInst) (x : Std.U32) : + (specs.traits.synthesized.Sym.g.pre KInst SymInst.KInst SymInst x).holds + → + ⦃ ⌜ True ⌝ ⦄ + SymInst.g KInst x + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Sym.g.post KInst SymInst.KInst SymInst x + res).holds ⌝ ⦄ + +/-- [hax_tests::specs::traits::synthesized::Nested::m::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 56:0-56:22 -/ +@[reducible] +def specs.traits.synthesized.Nested.m.pre + {Self_ : Type} {V : Type} {U : Type} (TgUOptionInst : + specs.traits.synthesized.Tg U (core.option.Option V)) (NestedInst : + specs.traits.synthesized.Nested Self_) (self_ : Self_) (u : U) (v : Std.U32) + : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Nested::m::post]: + Source: 'src/specs/traits/synthesized.rs', lines 59:4-59:58 -/ +@[reducible] +def specs.traits.synthesized.Nested.m.post + {Self_ : Type} {V : Type} {U : Type} (TgUOptionInst : + specs.traits.synthesized.Tg U (core.option.Option V)) (NestedInst : + specs.traits.synthesized.Nested Self_) (self_ : Self_) (u : U) (v : Std.U32) + (res : Std.U32) : + RustM Bool + := do + ok true + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Nested] + Source: 'src/specs/traits/synthesized.rs', lines 57:0-60:1 -/ +structure specs.traits.synthesized.Nested.Lawful (Self : Type) (NestedInst : + specs.traits.synthesized.Nested Self) : Prop where + m_spec {V : Type} {U : Type} + (TgPOptionInst : specs.traits.synthesized.Tg U (core.option.Option V)) + (TgPOptionInstLawful : specs.traits.synthesized.Tg.Lawful U + (core.option.Option V) TgPOptionInst) (self_ : Self) (u : U) (v : Std.U32) + : + (specs.traits.synthesized.Nested.m.pre TgPOptionInst NestedInst self_ u + v).holds → + ⦃ ⌜ True ⌝ ⦄ + NestedInst.m TgPOptionInst self_ u v + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Nested.m.post TgPOptionInst NestedInst + self_ u v res).holds ⌝ ⦄ + +/-- [hax_tests::specs::traits::synthesized::Many::m::pre]: + Source: 'src/specs/traits/synthesized.rs', lines 63:0-63:22 -/ +@[reducible] +def specs.traits.synthesized.Many.m.pre + {Self_ : Type} {A : Type} {B : Type} {C : Type} {D : Type} {E : Type} {F : + Type} {G : Type} {H : Type} (corecloneCloneInst : core.clone.Clone A) + (corecloneCloneInst1 : core.clone.Clone B) (corecloneCloneInst2 : + core.clone.Clone C) (corecloneCloneInst3 : core.clone.Clone D) + (corecloneCloneInst4 : core.clone.Clone E) (corecloneCloneInst5 : + core.clone.Clone F) (corecloneCloneInst6 : core.clone.Clone G) + (corecloneCloneInst7 : core.clone.Clone H) (corecloneCloneInst8 : + core.clone.Clone Self_) (ManyInst : specs.traits.synthesized.Many Self_) + (self_ : Self_) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::synthesized::Many::m::post]: + Source: 'src/specs/traits/synthesized.rs', lines 66:4-68:13 -/ +@[reducible] +def specs.traits.synthesized.Many.m.post + {Self_ : Type} {A : Type} {B : Type} {C : Type} {D : Type} {E : Type} {F : + Type} {G : Type} {H : Type} (corecloneCloneInst : core.clone.Clone A) + (corecloneCloneInst1 : core.clone.Clone B) (corecloneCloneInst2 : + core.clone.Clone C) (corecloneCloneInst3 : core.clone.Clone D) + (corecloneCloneInst4 : core.clone.Clone E) (corecloneCloneInst5 : + core.clone.Clone F) (corecloneCloneInst6 : core.clone.Clone G) + (corecloneCloneInst7 : core.clone.Clone H) (corecloneCloneInst8 : + core.clone.Clone Self_) (ManyInst : specs.traits.synthesized.Many Self_) + (self_ : Self_) (res : Std.U32) : + RustM Bool + := do + ok true + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Many] + Source: 'src/specs/traits/synthesized.rs', lines 64:0-69:1 -/ +structure specs.traits.synthesized.Many.Lawful (Self : Type) (ManyInst : + specs.traits.synthesized.Many Self) : Prop where + corecloneCloneInstLawful : core.clone.Clone.Lawful Self + ManyInst.corecloneCloneInst + m_spec {A : Type} {B : Type} {C : Type} {D : Type} {E : Type} {F : Type} {G : + Type} {H : Type} (corecloneCloneInst : core.clone.Clone A) + (corecloneCloneInstLawful : core.clone.Clone.Lawful A corecloneCloneInst) + (corecloneCloneInst1 : core.clone.Clone B) + (corecloneCloneInst1Lawful : core.clone.Clone.Lawful B corecloneCloneInst1) + (corecloneCloneInst2 : core.clone.Clone C) + (corecloneCloneInst2Lawful : core.clone.Clone.Lawful C corecloneCloneInst2) + (corecloneCloneInst3 : core.clone.Clone D) + (corecloneCloneInst3Lawful : core.clone.Clone.Lawful D corecloneCloneInst3) + (corecloneCloneInst4 : core.clone.Clone E) + (corecloneCloneInst4Lawful : core.clone.Clone.Lawful E corecloneCloneInst4) + (corecloneCloneInst5 : core.clone.Clone F) + (corecloneCloneInst5Lawful : core.clone.Clone.Lawful F corecloneCloneInst5) + (corecloneCloneInst6 : core.clone.Clone G) + (corecloneCloneInst6Lawful : core.clone.Clone.Lawful G corecloneCloneInst6) + (corecloneCloneInst7 : core.clone.Clone H) + (corecloneCloneInst7Lawful : core.clone.Clone.Lawful H corecloneCloneInst7) + (self_ : Self) : + (specs.traits.synthesized.Many.m.pre corecloneCloneInst corecloneCloneInst1 + corecloneCloneInst2 corecloneCloneInst3 corecloneCloneInst4 + corecloneCloneInst5 corecloneCloneInst6 corecloneCloneInst7 + ManyInst.corecloneCloneInst ManyInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + ManyInst.m corecloneCloneInst corecloneCloneInst1 corecloneCloneInst2 + corecloneCloneInst3 corecloneCloneInst4 corecloneCloneInst5 + corecloneCloneInst6 corecloneCloneInst7 self_ + ⦃ ⇓ res => + ⌜ (specs.traits.synthesized.Many.m.post corecloneCloneInst + corecloneCloneInst1 corecloneCloneInst2 corecloneCloneInst3 + corecloneCloneInst4 corecloneCloneInst5 corecloneCloneInst6 + corecloneCloneInst7 ManyInst.corecloneCloneInst ManyInst self_ + res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::trait_generics::Conv::conv::pre]: Source: 'src/specs/traits/trait_generics.rs', lines 8:4-8:32 -/ @[reducible] @@ -1762,6 +2002,27 @@ def specs.generics.empty.spec (T : Type) (N : Std.Usize) (k : Std.Usize) specs.generics.empty T N k ⦃ ⇓ res => ⌜ (specs.generics.empty.post k res).holds ⌝ ⦄ +/-- [hax_tests::specs::generics::first::pre]: + Source: 'src/specs/generics.rs', lines 133:0-133:17 -/ +@[reducible] +def specs.generics.first.pre + {T : Type} {V : Type} (HolderVOptionInst : specs.generics.Holder V + (core.option.Option T)) (v : V) : + RustM Bool + := do + ok true + +def + specs.generics.first.spec {T : Type} {V : Type} (HolderVOptionInst : + specs.generics.Holder V (core.option.Option T)) + (v : V) + (HolderVOptionInstLawful : specs.generics.Holder.Lawful V (core.option.Option + T) HolderVOptionInst) : Prop := + (specs.generics.first.pre HolderVOptionInst v).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.generics.first HolderVOptionInst v + ⦃ ⇓ res => ⌜ True ⌝ ⦄ + /-- [hax_tests::specs::naming::foo::pre]: Source: 'src/specs/naming.rs', lines 5:0-5:20 -/ @[reducible] @@ -2111,6 +2372,40 @@ def ⦃ ⇓ res => ⌜ (specs.traits.trait_generics.use_conv.post ConvCU8Inst c res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::assoc_consts::use_clamp::pre]: + Source: 'src/specs/traits/assoc_consts.rs', lines 47:0-47:23 -/ +@[reducible] +def specs.traits.assoc_consts.use_clamp.pre + {T : Type} (BoundedInst : specs.traits.assoc_consts.Bounded T) (t : T) + (x : Std.U32) : + RustM Bool + := do + let i ← BoundedInst.MAX + ok (x < i) + +/-- [hax_tests::specs::traits::assoc_consts::use_clamp::post]: + Source: 'src/specs/traits/assoc_consts.rs', lines 48:0-48:27 -/ +@[reducible] +def specs.traits.assoc_consts.use_clamp.post + {T : Type} (BoundedInst : specs.traits.assoc_consts.Bounded T) (t : T) + (x : Std.U32) (r : Std.U32) : + RustM Bool + := do + let i ← BoundedInst.MAX + ok (r <= i) + +def + specs.traits.assoc_consts.use_clamp.spec {T : Type} (BoundedInst : + specs.traits.assoc_consts.Bounded T) + (t : T) (x : Std.U32) + (BoundedInstLawful : specs.traits.assoc_consts.Bounded.Lawful T BoundedInst) + : Prop := + (specs.traits.assoc_consts.use_clamp.pre BoundedInst t x).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.traits.assoc_consts.use_clamp BoundedInst t x + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_consts.use_clamp.post BoundedInst t x res).holds ⌝ ⦄ + /-- [hax_tests::specs::naming::lawful_binder::f::post]: Source: 'src/specs/naming.rs', lines 42:4-42:36 -/ @[reducible] @@ -2175,4 +2470,19 @@ def U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.spec (self : Std.U32) ⦃ ⇓ res => ⌜ (U32.Insts.Hax_testsSpecsTraitsImpl_contractG.g.post self res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::assoc_consts::{impl hax_tests::specs::traits::assoc_consts::Bounded for u32}::clamp::pre]: + Source: 'src/specs/traits/assoc_consts.rs', lines 26:4-26:42 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.pre + (self_ : Std.U32) (x : Std.U32) : RustM Bool := do + ok (x < U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.MAX) + +def U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.spec + (self : Std.U32) (x : Std.U32) : Prop := + (U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.pre self x).holds + → + ⦃ ⌜ True ⌝ ⦄ + U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp self x + ⦃ ⇓ res => ⌜ True ⌝ ⦄ + end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index fce113d28d..68ff8c7ac5 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -53,6 +53,11 @@ def specs.contracts.__20.requires.closure := Std.U32 @[reducible] def specs.contracts.__21.ensures.closure := Std.U32 +/-- [hax_tests::specs::contracts::Opaque] + Source: 'src/specs/contracts.rs', lines 148:0-148:14 -/ +@[reducible] +def specs.contracts.Opaque := Unit + /-- Trait declaration: [hax_tests::specs::generics::Val] Source: 'src/specs/generics.rs', lines 16:0-18:1 -/ structure specs.generics.Val (Self : Type) where @@ -80,6 +85,10 @@ structure specs.generics.MyStruct (N : Std.Usize) where structure specs.generics.Pair (T : Type) (N : Std.Usize) where fst : T +/-- Trait declaration: [hax_tests::specs::generics::Holder] + Source: 'src/specs/generics.rs', lines 131:0-131:18 -/ +structure specs.generics.Holder (Self : Type) (T : Type) where + /-- [hax_tests::specs::mutable_borrows::Counter] Source: 'src/specs/mutable_borrows.rs', lines 51:0-53:1 Visibility: public -/ @@ -98,6 +107,19 @@ structure specs.naming.Qux (Self : Type) where @[reducible] def specs.naming.lawful_impl_binder.Wrap (T : Type) := T +/-- Trait declaration: [hax_tests::specs::traits::assoc_consts::Bounded] + Source: 'src/specs/traits/assoc_consts.rs', lines 9:0-18:1 -/ +structure specs.traits.assoc_consts.Bounded (Self : Type) where + MAX : RustM Std.U32 + MIN : RustM Std.U32 + clamp : Self → Std.U32 → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::assoc_consts::Scaled] + Source: 'src/specs/traits/assoc_consts.rs', lines 34:0-38:1 -/ +structure specs.traits.assoc_consts.Scaled (Self : Type) where + BoundedInst : specs.traits.assoc_consts.Bounded Self + scale : Self → Std.U32 → RustM Std.U32 + /-- Trait declaration: [hax_tests::specs::traits::assoc_type_bounds::Bar] Source: 'src/specs/traits/assoc_type_bounds.rs', lines 9:0-12:1 -/ structure specs.traits.assoc_type_bounds.Bar (Self : Type) where @@ -268,6 +290,36 @@ structure specs.traits.synthesized.Tg (Self : Type) (T : Type) where structure specs.traits.synthesized.Assoc (Self : Type) (Self_Item : Type) where item : Self → RustM Self_Item +/-- Trait declaration: [hax_tests::specs::traits::synthesized::K] + Source: 'src/specs/traits/synthesized.rs', lines 43:0-45:1 -/ +structure specs.traits.synthesized.K (Self : Type) where + k : RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Sym] + Source: 'src/specs/traits/synthesized.rs', lines 50:0-53:1 -/ +structure specs.traits.synthesized.Sym (Self : Type) where + KInst : specs.traits.synthesized.K Self + g : forall {U : Type} (KInst1 : specs.traits.synthesized.K U), Std.U32 → + RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Nested] + Source: 'src/specs/traits/synthesized.rs', lines 57:0-60:1 -/ +structure specs.traits.synthesized.Nested (Self : Type) where + m : forall {V : Type} {U : Type} (TgPOptionInst : specs.traits.synthesized.Tg + U (core.option.Option V)), Self → U → Std.U32 → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Many] + Source: 'src/specs/traits/synthesized.rs', lines 64:0-69:1 -/ +structure specs.traits.synthesized.Many (Self : Type) where + corecloneCloneInst : core.clone.Clone Self + m : forall {A : Type} {B : Type} {C : Type} {D : Type} {E : Type} {F : Type} + {G : Type} {H : Type} (corecloneCloneInst1 : core.clone.Clone A) + (corecloneCloneInst2 : core.clone.Clone B) (corecloneCloneInst3 : + core.clone.Clone C) (corecloneCloneInst4 : core.clone.Clone D) + (corecloneCloneInst5 : core.clone.Clone E) (corecloneCloneInst6 : + core.clone.Clone F) (corecloneCloneInst7 : core.clone.Clone G) + (corecloneCloneInst8 : core.clone.Clone H), Self → RustM Std.U32 + /-- Trait declaration: [hax_tests::specs::traits::trait_generics::Conv] Source: 'src/specs/traits/trait_generics.rs', lines 6:0-9:1 -/ structure specs.traits.trait_generics.Conv (Self : Type) (T : Type) where diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean index 7bb55b4343..dc6cfcf7f8 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean @@ -6,6 +6,7 @@ import HaxTests.Extraction.Types import HaxTests.Extraction.Funs import HaxTests.Extraction.Specs import HaxTests.Verification.Lemmas +import HaxTests.Verification.Traits.AssocConsts import HaxTests.Verification.Traits.AssocTypeBounds import HaxTests.Verification.Traits.Basic import HaxTests.Verification.Traits.BlanketImpl @@ -296,6 +297,17 @@ theorem specs.generics.empty.spec.proof (T : Type) (N : Std.Usize) unfold specs.generics.empty.spec specs.generics.empty hax_mvcgen +theorem + specs.generics.first.spec.proof {T : Type} {V : Type} (HolderVOptionInst : + specs.generics.Holder V (core.option.Option + T)) (v : V) + (HolderVOptionInstLawful : specs.generics.Holder.Lawful V (core.option.Option + T) HolderVOptionInst) : + specs.generics.first.spec HolderVOptionInst v HolderVOptionInstLawful + := by + unfold specs.generics.first.spec specs.generics.first + hax_mvcgen + theorem specs.arguments.named.spec.proof (_ : Unit) : specs.arguments.named.spec () := by unfold specs.arguments.named.spec specs.arguments.named diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocConsts.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocConsts.lean new file mode 100644 index 0000000000..0dedae58e3 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocConsts.lean @@ -0,0 +1,73 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::assoc_consts`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.Lawful : + specs.traits.assoc_consts.Bounded.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded + where + clamp_spec := by + intro self x hpre + mvcgen [U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp] + /- `MAX` is a monadic field of the instance: the conditions bind it -/ + simp [specs.traits.assoc_consts.Bounded.clamp.pre, specs.traits.assoc_consts.Bounded.clamp.post] at hpre ⊢ + agrind + +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.spec.proof + (self : Std.U32) (x : Std.U32) : + U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.spec self x + := by + unfold U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp.spec U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.clamp + hax_mvcgen + +theorem U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled.Lawful : + specs.traits.assoc_consts.Scaled.Lawful Std.U32 + U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled + where + BoundedInstLawful := U32.Insts.Hax_testsSpecsTraitsAssoc_constsBounded.Lawful + scale_spec := by + intro self x hpre + mvcgen [U32.Insts.Hax_testsSpecsTraitsAssoc_constsScaled.scale] + /- `MIN` takes its default value, through `ScaledInst.BoundedInst` -/ + simp [specs.traits.assoc_consts.Scaled.scale.pre, specs.traits.assoc_consts.Scaled.scale.post] at hpre ⊢ + agrind + +theorem + specs.traits.assoc_consts.use_clamp.spec.proof {T : Type} (BoundedInst : + specs.traits.assoc_consts.Bounded + T) (t : T) (x : Std.U32) + (BoundedInstLawful : specs.traits.assoc_consts.Bounded.Lawful T BoundedInst) + : specs.traits.assoc_consts.use_clamp.spec BoundedInst t x BoundedInstLawful + := by + unfold specs.traits.assoc_consts.use_clamp.spec specs.traits.assoc_consts.use_clamp + /- The conditions of `use_clamp` are those of `clamp`, `T::MAX` being `Self::MAX` -/ + exact BoundedInstLawful.clamp_spec t x + +end hax_tests diff --git a/tests/hax/src/specs/contracts.rs b/tests/hax/src/specs/contracts.rs index 6f84741365..09f038a9f1 100644 --- a/tests/hax/src/specs/contracts.rs +++ b/tests/hax/src/specs/contracts.rs @@ -144,3 +144,19 @@ fn with_loop(n: u32) -> u32 { } acc } + +struct Opaque; + +// BUG: an opaque method with a precondition, in a `#[hax_lib::attributes]` +// impl. hax-lib puts the decoration fn inside the method body, which +// `#[hax_lib::opaque]` hides from charon: the method references an unknown +// decoration uid, and its precondition is silently dropped. (A free opaque fn +// is fine: its decoration fn is a sibling item.) +#[hax_lib::attributes] +impl Opaque { + #[hax_lib::opaque] + #[hax_lib::requires(x < 100)] + fn opaque_requires(x: u32) -> u32 { + x + 1 + } +} diff --git a/tests/hax/src/specs/generics.rs b/tests/hax/src/specs/generics.rs index f385e3b0ff..e533702848 100644 --- a/tests/hax/src/specs/generics.rs +++ b/tests/hax/src/specs/generics.rs @@ -126,3 +126,11 @@ fn empty(k: usize) -> Option> { fn from_default(k: usize) -> Pair { Pair { fst: T::default() } } + +// A trait clause whose argument mentions another type parameter +trait Holder {} + +#[requires(true)] +fn first>>(v: V) -> u32 { + 0 +} diff --git a/tests/hax/src/specs/traits.rs b/tests/hax/src/specs/traits.rs index 03d52db4b0..1658734745 100644 --- a/tests/hax/src/specs/traits.rs +++ b/tests/hax/src/specs/traits.rs @@ -14,3 +14,4 @@ mod unannotated_sub; mod impl_contract; mod trait_generics; mod synthesized; +mod assoc_consts; diff --git a/tests/hax/src/specs/traits/assoc_consts.rs b/tests/hax/src/specs/traits/assoc_consts.rs new file mode 100644 index 0000000000..046f20ee8d --- /dev/null +++ b/tests/hax/src/specs/traits/assoc_consts.rs @@ -0,0 +1,51 @@ +// Associated constants used in contracts (hax only takes contracts on methods, +// not on constants): in the conditions of the trait, of an impl method (the +// concrete constant) and of a generic caller, with a default value, and through +// a subtrait. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Bounded { + const MAX: u32; + + // A default value + const MIN: u32 = 0; + + #[requires(x < Self::MAX)] + #[ensures(|r| r <= Self::MAX)] + fn clamp(&self, x: u32) -> u32; +} + +#[hax_lib::attributes] +impl Bounded for u32 { + const MAX: u32 = 100; + + // Not `Self::MAX`: hax-lib puts the condition in a fn nested in the method, + // where `Self` is not in scope (it only rewrites associated types) + #[requires(x < ::MAX)] + fn clamp(&self, x: u32) -> u32 { + x + } +} + +// The constants of the supertrait, through the subtrait +#[hax_lib::attributes] +trait Scaled: Bounded { + #[requires(Self::MIN <= x && x <= Self::MAX)] + #[ensures(|r| r <= Self::MAX)] + fn scale(&self, x: u32) -> u32; +} + +impl Scaled for u32 { + fn scale(&self, x: u32) -> u32 { + x + } +} + +// A generic caller: its contract mentions `T::MAX` +#[requires(x < T::MAX)] +#[ensures(|r| r <= T::MAX)] +fn use_clamp(t: &T, x: u32) -> u32 { + t.clamp(x) +} diff --git a/tests/hax/src/specs/traits/synthesized.rs b/tests/hax/src/specs/traits/synthesized.rs index 02be5dbd71..31842e310a 100644 --- a/tests/hax/src/specs/traits/synthesized.rs +++ b/tests/hax/src/specs/traits/synthesized.rs @@ -39,3 +39,120 @@ trait Assoc { #[requires(true)] fn item(&self) -> Self::Item; } + +trait K { + fn k() -> u32; +} + +// Two clauses on the same trait, `Self_: K` and `U: K`: `U::k()` in the +// precondition is read from the instance of `U`, not from that of `Self` +#[hax_lib::attributes] +trait Sym: K { + #[requires(x < U::k() && U::k() < 10)] + fn g(x: u32) -> u32; +} + +// A method clause whose argument mentions another method type parameter +#[hax_lib::attributes] +trait Nested { + #[requires(true)] + fn m>>(&self, u: U, v: u32) -> u32; +} + +// Many clauses on the same trait, with a supertrait without associated type +#[hax_lib::attributes] +trait Many: Clone { + #[requires(true)] + fn m( + &self, + ) -> u32; +} + +// BUG: aeneas fails on the conditions of a trait method when the trait or a +// supertrait has an associated type: it maps their generics positionally to +// the method's, but charon lifts the associated type once per clause path +// (`SubAssoc.len.pre {Self_} {Clause0_Item} {Clause1_Clause0_Item}` vs +// `Self, Self_Clause0_Item`) and after the method's own type parameters +// (`AssocGen.f.post {Self_} {U} {Clause0_Item}` vs `Self, Self_Item, U`). +// - `SubAssoc`, `Call`, `SubGen`, `ManyAssoc`, `Sym2`: "Internal error: the +// generics of the conditions of `…` don't match those of the trait and the +// method", contract dropped (exit 1); +// - `SubBoth`: "Internal error: the generics of the condition `SubBoth::h.pre` +// don't match those it is applied to" (exit 2); +// - `AssocGen`: synthesized post with `res : Clause0_Item`, then "Could not +// find an instance for a trait clause of a pre/post condition" (exit 2). +// The traits are commented out because aeneas fails on them. + +// // A supertrait with an associated type. The decoration fns have one copy of +// // the lifted associated type per clause (`Clause0_Item` for `Self_: Assoc`, +// // `Clause1_Clause0_Item` for `Self_: SubAssoc`), the trait only one +// // (`Self_Clause0_Item`). The result does not mention the associated type. +// #[hax_lib::attributes] +// trait SubAssoc: Assoc { +// #[requires(true)] +// fn len(&self) -> usize; +// } + +// // The same with a generic supertrait, as `FnMut: FnOnce` +// #[hax_lib::attributes] +// trait CallOnce { +// type Output; +// } +// +// #[hax_lib::attributes] +// trait Call: CallOnce { +// #[requires(true)] +// fn call(&self, args: Args) -> Self::Output; +// } + +// // An associated type and a method type parameter: in the decoration fns, the +// // lifted `Clause0_Item` comes after `U`, in the method after `Self` +// #[hax_lib::attributes] +// trait AssocGen { +// type Item; +// +// #[requires(true)] +// fn f(&self, u: U) -> U; +// } + +// // A supertrait with an associated type and a bounded method type parameter: +// // the clause `U: Assoc` of the conditions gets the instance of `U`, not the +// // parent `Self: Assoc` +// #[hax_lib::attributes] +// trait SubGen: Assoc { +// #[requires(true)] +// fn g(&self, u: U) -> U; +// } + +// // Both conditions written, with a supertrait with an associated type +// #[hax_lib::attributes] +// trait SubBoth: Assoc { +// #[requires(true)] +// #[ensures(|r| r == 0)] +// fn h(&self) -> usize; +// } + +// // `Many` with a supertrait with an associated type: the conditions get the +// // instances of `A`…`H` in order, and `Self_Clause0_Item` for both lifted +// // copies of the associated type (`Clause8_Item`, `Clause9_Clause0_Item`) +// #[hax_lib::attributes] +// trait ManyAssoc: Assoc { +// #[requires(true)] +// fn m( +// &self, +// ) -> u32; +// } + +// trait K2 { +// type X; +// +// fn k() -> u32; +// } +// +// // `Sym` with an associated type: two clauses on `K2`, `Self_: K2` and +// // `U: K2`; `U::k()` must be read from the instance of `U` +// #[hax_lib::attributes] +// trait Sym2: K2 { +// #[requires(x < U::k() && U::k() < 10)] +// fn g(x: u32) -> u32; +// } From 24afeb87acc4c2dbf0d3710338795d65c97607cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Fri, 23 Oct 2026 14:22:11 +0000 Subject: [PATCH 13/17] test: ignore generated templates, show aeneas warnings in test-hax --- scripts/test-hax.sh | 2 +- tests/hax/.gitignore | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/test-hax.sh b/scripts/test-hax.sh index 84b74c69eb..daaa027365 100755 --- a/scripts/test-hax.sh +++ b/scripts/test-hax.sh @@ -83,7 +83,7 @@ EOF ;; esac - (cd "$tests" && cargo hax extract "$scenario") + (cd "$tests" && cargo hax extract -v "$scenario") } verify() { diff --git a/tests/hax/.gitignore b/tests/hax/.gitignore index a57a119756..2a66f4cf9f 100644 --- a/tests/hax/.gitignore +++ b/tests/hax/.gitignore @@ -1,5 +1,6 @@ # Only build artifacts and machine-specific files: links to the hax checkout, -# and the dependency versions it resolves to. The Lean project under `proofs/` +# the dependency versions it resolves to, and the `*External_Template.lean` +# files Aeneas regenerates on each extraction. The Lean project under `proofs/` # (extracted code, handwritten proofs, lakefile) is committed, so that CI # catches regressions in the extraction. /Cargo.lock @@ -10,3 +11,5 @@ /proofs/*/lean/.lake/ /proofs/*/lean/llbc/ /proofs/*/lean/aeneas-error.log +/proofs/*/lean/*/Extraction/TypesExternal_Template.lean +/proofs/*/lean/*/Extraction/FunsExternal_Template.lean From 52ca9d52184b4d7e552e3811a80f1ce3407aa9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Fri, 23 Oct 2026 14:23:41 +0000 Subject: [PATCH 14/17] refactor-specs: drop the unused trait contract of impl obligations --- src/extract/ExtractHaxSpecs.ml | 2 +- src/specs/HaxProducer.ml | 19 ++----------------- src/specs/HaxSpecs.ml | 8 +------- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index 07c5ee7671..ff4f5a7b66 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -938,7 +938,7 @@ let emit_obligation ctx fmt (o : HaxSpecs.obligation) = F.pp_close_box fmt (); (* outer hvbox *) F.pp_print_cut fmt ()) - | ImplLawful { impl; proof; _ } -> ( + | ImplLawful { impl; proof } -> ( match Pure.TraitImplId.Map.find_opt impl ctx.trans_trait_impls with | None -> (* Reported by [register_obligation_names] *) () | Some impl -> diff --git a/src/specs/HaxProducer.ml b/src/specs/HaxProducer.ml index 2d62d2df17..023e6055a3 100644 --- a/src/specs/HaxProducer.ml +++ b/src/specs/HaxProducer.ml @@ -367,21 +367,11 @@ let produce (ctx : TranslateCore.trans_ctx) local_trait_decls in (* The Lawful obligations of the local trait impls, in the order of the - declaration groups (dependencies first), with the contract of the - implemented trait if it is local *) + declaration groups (dependencies first) *) let trait_impls = Pure.TraitImplId.Map.of_list (List.map (fun (i : Pure.trait_impl) -> (i.def_id, i)) crate.trait_impls) in - let trait_spec (id : Pure.TraitDeclId.id) : HaxSpecs.trait_spec option = - List.find_map - (fun (s : Spec.spec) -> - match s with - | { kind = HaxSpec (TraitSpec ts); _ } when ts.trait_decl = id -> - Some ts - | _ -> None) - trait_specs - in let impl_obligations = List.concat_map (fun (g : LlbcAst.declaration_group) -> @@ -397,12 +387,7 @@ let produce (ctx : TranslateCore.trans_ctx) span = Some i.item_meta.span; kind = HaxProof - (ImplLawful - { - impl = i.def_id; - spec = trait_spec i.impl_trait.trait_decl_id; - proof = Admitted; - }); + (ImplLawful { impl = i.def_id; proof = Admitted }); } : Spec.proof_obligation) | _ -> None) diff --git a/src/specs/HaxSpecs.ml b/src/specs/HaxSpecs.ml index 851b2d14c2..0adbea4934 100644 --- a/src/specs/HaxSpecs.ml +++ b/src/specs/HaxSpecs.ml @@ -40,13 +40,7 @@ and method_spec = { (** Type for proof-obligation objects. *) and obligation = | FunctionContract of { spec : function_spec; proof : proof } - | ImplLawful of { - impl : Pure.TraitImplId.id; - spec : trait_spec option; - (** The contract of the implemented trait. [None] for a non-local - trait. *) - proof : proof; - } + | ImplLawful of { impl : Pure.TraitImplId.id; proof : proof } (** [.Lawful : X.Lawful … ]: the impl satisfies the contract of its trait *) [@@deriving show] From 2397b0ce5a66d7e67751c34eef9362843f3be9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Fri, 23 Oct 2026 14:43:02 +0000 Subject: [PATCH 15/17] fix-specs: graceful drop trait-method contracts and impl obligations - Mismatch with the number of generics cause the method to be dropped with a warning instead of an internal error. - Dropping warnings no longer escape under -warnings-as-errors (error, exit 1). - One failing spec or obligation no longer aborts the rest of the file. - Impl obligations of an untranslated trait are skipped with a warning. - Lawful field names are reserved before the trait generics. - Tests: the 5 synthesized.rs traits that now extract (contracts dropped), naming.rs lawful_field; the BUG block narrowed to AssocGen and SubBoth. --- src/extract/ExtractHaxSpecs.ml | 87 ++++++++---- src/extract/ExtractSpec.ml | 12 +- src/specs/HaxProducer.ml | 131 ++++++++++-------- src/specs/HaxSpecs.ml | 6 + .../lean/HaxTests/Extraction/Specs.lean | 118 ++++++++++++++++ .../lean/HaxTests/Extraction/Types.lean | 63 +++++++++ tests/hax/src/specs/naming.rs | 18 +++ tests/hax/src/specs/traits/synthesized.rs | 131 +++++++++--------- 8 files changed, 412 insertions(+), 154 deletions(-) diff --git a/src/extract/ExtractHaxSpecs.ml b/src/extract/ExtractHaxSpecs.ml index ff4f5a7b66..eface4089f 100644 --- a/src/extract/ExtractHaxSpecs.ml +++ b/src/extract/ExtractHaxSpecs.ml @@ -313,6 +313,17 @@ let lookup_parent (ctx : ExtractBase.extraction_ctx) (fn : Pure.FunDeclId.id) : (fun (ft : TranslateCore.pure_fun_translation) -> ft.f) (Pure.FunDeclId.Map.find_opt fn ctx.trans_funs) +(** The translated trait impl [impl] and the trait it implements, if both were + translated *) +let trait_impl_and_decl (ctx : ExtractBase.extraction_ctx) + (impl : Pure.TraitImplId.id) : (Pure.trait_impl * Pure.trait_decl) option = + Option.bind (Pure.TraitImplId.Map.find_opt impl ctx.trans_trait_impls) + (fun (i : Pure.trait_impl) -> + Option.map + (fun d -> (i, d)) + (Pure.TraitDeclId.Map.find_opt i.impl_trait.trait_decl_id + ctx.trans_trait_decls)) + (** Register the names of conditions, under the ids of their fns *) let register_conds span (conds : (Pure.fun_decl * string) list) (ctx : ExtractBase.extraction_ctx) : ExtractBase.extraction_ctx = @@ -334,10 +345,11 @@ let warn_untranslated ?(dropped = "the contract") | Some m -> (Some m.span, TranslateCore.name_to_string ctx.trans_ctx m.name) | None -> (opt_span, id) in - [%warn_opt_span] span - (Printf.sprintf - "hax-specs: dropping %s of %s `%s`: the %s was not translated" dropped - kind name kind) + HaxSpecs.warn_dropped (fun () -> + [%warn_opt_span] span + (Printf.sprintf + "hax-specs: dropping %s of %s `%s`: the %s was not translated" + dropped kind name kind)) (** Report a clash between [.Lawful] and the projection of a field of the trait structure [d] (parent clause, associated item or method) named @@ -437,6 +449,21 @@ let register_obligation_names (ctx : ExtractBase.extraction_ctx) "trait impl" (Pure.TraitImplId.to_string impl); ctx + | Some i + when not + (Pure.TraitDeclId.Map.mem i.impl_trait.trait_decl_id + ctx.trans_trait_decls) -> + (* We use the span of the impl: the trait may not be local *) + let id = i.impl_trait.trait_decl_id in + warn_untranslated ~dropped:"the Lawful obligation of an impl" ctx + (Some i.item_meta.span) None "trait" + (match + Pure.TraitDeclId.Map.find_opt id ctx.trans_ctx.crate.trait_decls + with + | Some d -> + TranslateCore.name_to_string ctx.trans_ctx d.item_meta.name + | None -> Pure.TraitDeclId.to_string id); + ctx | Some i -> let span = i.item_meta.span in ExtractBase.ctx_add span (ProofObligationId proof_id) @@ -590,6 +617,26 @@ let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt let open ExtractBase in let span = d.item_meta.span in let no_params_tys = Pure.TypeDeclId.Set.empty in + let parent_field (c : Pure.trait_param) = + lawful_binder_name + (ctx_get_raw (Some span) + (TraitParentClauseId (d.def_id, c.clause_id)) + ctx) + in + let method_field method_id = + ctx_get_raw (Some span) (TraitMethodId (d.def_id, method_id)) ctx ^ "_spec" + in + (* Reserve the field names, so that no parameter takes them, as + [extract_trait_decl] does *) + let ctx = + ctx_reserve_names + (List.map parent_field d.parent_clauses + @ List.map + (fun ({ method_id; _ } : HaxSpecs.method_spec) -> + method_field method_id) + methods) + ctx + in let ctx, type_params, cg_params, trait_clauses = ctx_add_generic_params span d.item_meta.name Item d.llbc_generics d.generics ctx @@ -628,13 +675,8 @@ let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt (* The parents: [

Lawful :

.Lawful Inst.

] *) List.iter (fun (c : Pure.trait_param) -> - let name = - ctx_get_raw (Some span) - (TraitParentClauseId (d.def_id, c.clause_id)) - ctx - in Extract.extract_trait_decl_item ctx fmt - (escape_name (lawful_binder_name name)) + (escape_name (parent_field c)) (fun () -> F.pp_print_space fmt (); emit_lawful_type span ctx fmt (parent_ref d self_ref c))) @@ -666,10 +708,7 @@ let emit_lawful_structure (ctx : ExtractBase.extraction_ctx) fmt F.pp_print_space fmt (); F.pp_open_vbox fmt ctx.indent_incr; F.pp_open_hovbox fmt ctx.indent_incr; - F.pp_print_string fmt - (escape_name - (ctx_get_raw (Some span) (TraitMethodId (d.def_id, method_id)) ctx - ^ "_spec")); + F.pp_print_string fmt (escape_name (method_field method_id)); ExtractTypes.extract_generic_params span ctx fmt no_params_tys Method { sg.generics with trait_clauses = [] } (Some sg.explicit_info) type_params cg_params []; @@ -749,18 +788,14 @@ let emit_fun_binders (ctx : ExtractBase.extraction_ctx) fmt (f : Pure.fun_decl) ExtractTypes.insert_req_space fmt space; (ctx, lawful_names) -(** Emit the binders of the trait impl [impl]: its generic parameters, named as - in its definition (see {!Extract.extract_trait_impl}), then the Lawful - binders of its trait clauses. Return the context with the parameters - registered. *) +(** Emit the binders of the trait impl [impl] of the trait [d]: its generic + parameters, named as in its definition (see {!Extract.extract_trait_impl}), + then the Lawful binders of its trait clauses. Return the context with the + parameters registered. *) let emit_impl_binders (ctx : ExtractBase.extraction_ctx) fmt - (impl : Pure.trait_impl) = + (d : Pure.trait_decl) (impl : Pure.trait_impl) = let open ExtractBase in let span = impl.item_meta.span in - let d = - Pure.TraitDeclId.Map.find impl.impl_trait.trait_decl_id - ctx.trans_trait_decls - in (* Reserve the field names of the trait, as [extract_trait_impl] does *) let ctx = ctx_reserve_names @@ -939,9 +974,9 @@ let emit_obligation ctx fmt (o : HaxSpecs.obligation) = (* outer hvbox *) F.pp_print_cut fmt ()) | ImplLawful { impl; proof } -> ( - match Pure.TraitImplId.Map.find_opt impl ctx.trans_trait_impls with + match trait_impl_and_decl ctx impl with | None -> (* Reported by [register_obligation_names] *) () - | Some impl -> + | Some (impl, d) -> let span = impl.item_meta.span in (* Blank line before the entry. *) F.pp_print_break fmt 0 0; @@ -955,7 +990,7 @@ let emit_obligation ctx fmt (o : HaxSpecs.obligation) = (escape_name (lawful_name (ctx_get_raw (Some span) (TraitImplId impl.def_id) ctx))); - let ctx = emit_impl_binders ctx fmt impl in + let ctx = emit_impl_binders ctx fmt d impl in F.pp_print_space fmt (); F.pp_print_string fmt ":"; F.pp_print_space fmt (); diff --git a/src/extract/ExtractSpec.ml b/src/extract/ExtractSpec.ml index dc779a79c5..7a04f5c6ed 100644 --- a/src/extract/ExtractSpec.ml +++ b/src/extract/ExtractSpec.ml @@ -31,7 +31,15 @@ let register_names (ctx : ExtractBase.extraction_ctx) : | HaxProof ho -> ExtractHaxSpecs.register_obligation_names ctx o.id ho) ctx ctx.proof_obligations -let extract_specs ctx fmt = List.iter (emit_spec ctx fmt) ctx.specs +(** Apply [emit] to [x], ignoring a [CFailure]: it was normally reported when + raised, and only drops the entry [x] (whose output may be partial) *) +let skip_on_failure (emit : 'a -> unit) (x : 'a) : unit = + try emit x with Errors.CFailure _ -> () + +let extract_specs ctx fmt = + List.iter (skip_on_failure (emit_spec ctx fmt)) ctx.specs let extract_proof_obligations ctx fmt = - List.iter (emit_proof_obligation ctx fmt) ctx.proof_obligations + List.iter + (skip_on_failure (emit_proof_obligation ctx fmt)) + ctx.proof_obligations diff --git a/src/specs/HaxProducer.ml b/src/specs/HaxProducer.ml index 023e6055a3..f8f0041c91 100644 --- a/src/specs/HaxProducer.ml +++ b/src/specs/HaxProducer.ml @@ -238,11 +238,10 @@ let produce (ctx : TranslateCore.trans_ctx) (* The output type of the method [m] of [d], in the generics of its condition [dec]. The type parameters of the decoration fns are those of the trait then those of the method, as in the flattened signature of the - method. *) + method. [Error reason] if it can't be computed. *) let method_output_ty (d : Pure.trait_decl) (m : Pure.trait_method) - (dec : Pure.fun_decl) : Pure.ty = + (dec : Pure.fun_decl) : (Pure.ty, string) result = let span = m.item_meta.span in - let name = parent_name ctx (Method m) in let llbc_decl = Pure.TraitDeclId.Map.find d.def_id ctx.crate.trait_decls in let sg = (SymbolicToPureTypes.translate_flat_trait_method_sigs ctx llbc_decl @@ -252,38 +251,40 @@ let produce (ctx : TranslateCore.trans_ctx) in let params = sg.generics in let args = PureUtils.generic_args_of_params dec.signature.generics in - [%cassert] span - (List.length params.types = List.length args.types - && List.length params.const_generics = List.length args.const_generics) - ("Internal error: the generics of the conditions of `" ^ name - ^ "` don't match those of the trait and the method"); - let unsupported () = - [%craise] span - ("hax-specs: cannot synthesize the postcondition of `" ^ name - ^ "`: trait instances in its output type are not supported yet") - in - let subst : PureUtils.subst = - { - ty_subst = PureUtils.make_type_subst params.types args.types; - cg_subst = - PureUtils.make_const_generic_subst params.const_generics - args.const_generics; - tr_subst = (fun _ -> unsupported ()); - tr_self = Self (* Unused: see [visit_Self] *); - } - in - let visitor = - object - inherit [_] PureUtils.subst_visitor - method! visit_Self _ = unsupported () - end - in - let output = - if sg.fwd_info.effect_info.can_fail then - PureUtils.unwrap_result_ty span sg.output - else sg.output - in - visitor#visit_ty subst output + if + List.length params.types <> List.length args.types + || List.length params.const_generics <> List.length args.const_generics + then + Error + "the generics of its conditions don't match those of the trait and the \ + method" + else + let exception Unsupported in + let unsupported () = raise Unsupported in + let subst : PureUtils.subst = + { + ty_subst = PureUtils.make_type_subst params.types args.types; + cg_subst = + PureUtils.make_const_generic_subst params.const_generics + args.const_generics; + tr_subst = (fun _ -> unsupported ()); + tr_self = Self (* Unused: see [visit_Self] *); + } + in + let visitor = + object + inherit [_] PureUtils.subst_visitor + method! visit_Self _ = unsupported () + end + in + let output = + if sg.fwd_info.effect_info.can_fail then + PureUtils.unwrap_result_ty span sg.output + else sg.output + in + try Ok (visitor#visit_ty subst output) + with Unsupported -> + Error "trait instances in its output type are not supported yet" in (* The contracts of the local traits, in the order of the declaration groups (parents first). Every local trait gets one, even without annotated @@ -306,9 +307,10 @@ let produce (ctx : TranslateCore.trans_ctx) Some { method_id = m.method_id; pre = Some pre; post = Some post } in let warn_drop reason = - [%warn] m.item_meta.span - ("hax-specs: dropping the contract of trait method `" - ^ parent_name ctx (Method m) ^ "`: " ^ reason); + HaxSpecs.warn_dropped (fun () -> + [%warn] m.item_meta.span + ("hax-specs: dropping the contract of trait method `" + ^ parent_name ctx (Method m) ^ "`: " ^ reason)); None in (* Only the conditions without annotation are synthesized: if an annotated @@ -320,26 +322,34 @@ let produce (ctx : TranslateCore.trans_ctx) | _, post when dropped a.ensures_uid post -> warn_drop "its #[ensures] is invalid" | pre, post -> ( - (* A failure to synthesize a condition only drops the contract of [m] *) - try - match (pre, post) with - | None, None -> None - | Some pre, Some post -> spec pre post - | None, Some post -> - (* The inputs of [post] but the result *) - let inputs = - fst (Collections.List.pop_last (cond_inputs m post)) - in - spec (synthesize_cond m "pre" post inputs) post - | Some pre, None -> - let ty = method_output_ty d m pre in - let res : Pure.tpat = - { pat = PBound ({ basename = Some "res"; ty }, None); ty } - in - let inputs = cond_inputs m pre @ [ res ] in - spec pre (synthesize_cond m "post" pre inputs) - with Errors.CFailure _ -> - warn_drop "a missing condition could not be synthesized") + (* A failure to synthesize a condition only drops the contract of [m] + (a [CFailure] was reported) *) + let synthesized = + try + match (pre, post) with + | None, None -> Ok None + | Some pre, Some post -> Ok (spec pre post) + | None, Some post -> + (* The inputs of [post] but the result *) + let inputs = + fst (Collections.List.pop_last (cond_inputs m post)) + in + Ok (spec (synthesize_cond m "pre" post inputs) post) + | Some pre, None -> + Result.map + (fun ty -> + let res : Pure.tpat = + { pat = PBound ({ basename = Some "res"; ty }, None); ty } + in + let inputs = cond_inputs m pre @ [ res ] in + spec pre (synthesize_cond m "post" pre inputs)) + (method_output_ty d m pre) + with Errors.CFailure _ -> + Error "a missing condition could not be synthesized" + in + match synthesized with + | Ok s -> s + | Error reason -> warn_drop reason) in let local_trait_decls = List.concat_map @@ -488,8 +498,9 @@ let produce (ctx : TranslateCore.trans_ctx) "unsupported or invalid annotation, or part of a dropped \ contract"] else - [%warn] dec.item_meta.span - (msg "it is attached to no translated item") + HaxSpecs.warn_dropped (fun () -> + [%warn] dec.item_meta.span + (msg "it is attached to no translated item")) | _ -> ()) dec.item_meta.attr_info.attributes in diff --git a/src/specs/HaxSpecs.ml b/src/specs/HaxSpecs.ml index 0adbea4934..60058beb6d 100644 --- a/src/specs/HaxSpecs.ml +++ b/src/specs/HaxSpecs.ml @@ -50,3 +50,9 @@ and proof = Admitted [@@deriving show] (** The extra Lean modules hax specs need to elaborate *) let required_imports () : string list = [ "Hax" ] + +(** Run [warn], a warning about something the hax specs drop. Under + [-warnings-as-errors], the warning raises a [CFailure] once the error is + recorded: we ignore it, so that only the item is dropped. *) +let warn_dropped (warn : unit -> unit) : unit = + try warn () with Errors.CFailure _ -> () diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index 765891ef49..10385f1d28 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -53,6 +53,73 @@ structure specs.generics.Holder.Lawful (Self : Type) (T : Type) (HolderInst : structure specs.naming.Qux.Lawful (Self : Type) (QuxInst : specs.naming.Qux Self) : Prop +/-- [hax_tests::specs::naming::lawful_field::Sub::g::pre]: + Source: 'src/specs/naming.rs', lines 71:4-71:26 -/ +@[reducible] +def specs.naming.lawful_field.Sub.g.pre + {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : + specs.naming.Qux Self_) (SubInst : specs.naming.lawful_field.Sub Self_ + QuxInstLawful g_spec) (self_ : Self_) (x : QuxInstLawful) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::naming::lawful_field::Sub::g::post]: + Source: 'src/specs/naming.rs', lines 74:8-74:45 -/ +@[reducible] +def specs.naming.lawful_field.Sub.g.post + {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : + specs.naming.Qux Self_) (SubInst : specs.naming.lawful_field.Sub Self_ + QuxInstLawful g_spec) (self_ : Self_) (x : QuxInstLawful) (res : Std.U32) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::naming::lawful_field::Sub::h::pre]: + Source: 'src/specs/naming.rs', lines 71:4-71:26 -/ +@[reducible] +def specs.naming.lawful_field.Sub.h.pre + {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : + specs.naming.Qux Self_) (SubInst : specs.naming.lawful_field.Sub Self_ + QuxInstLawful g_spec) (self_ : Self_) (x : g_spec) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::naming::lawful_field::Sub::h::post]: + Source: 'src/specs/naming.rs', lines 77:8-77:38 -/ +@[reducible] +def specs.naming.lawful_field.Sub.h.post + {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : + specs.naming.Qux Self_) (SubInst : specs.naming.lawful_field.Sub Self_ + QuxInstLawful g_spec) (self_ : Self_) (x : g_spec) (res : Std.U32) : + RustM Bool + := do + ok true + +/-- Lawful structure of trait: [hax_tests::specs::naming::lawful_field::Sub] + Source: 'src/specs/naming.rs', lines 72:4-78:5 -/ +structure specs.naming.lawful_field.Sub.Lawful (Self : Type) (QuxInstLawful1 : + Type) (g_spec1 : Type) (SubInst : specs.naming.lawful_field.Sub Self + QuxInstLawful1 g_spec1) : Prop where + QuxInstLawful : specs.naming.Qux.Lawful Self SubInst.QuxInst + g_spec (self_ : Self) (x : QuxInstLawful1) : + (specs.naming.lawful_field.Sub.g.pre SubInst.QuxInst SubInst self_ x).holds + → + ⦃ ⌜ True ⌝ ⦄ + SubInst.g self_ x + ⦃ ⇓ res => + ⌜ (specs.naming.lawful_field.Sub.g.post SubInst.QuxInst SubInst self_ x + res).holds ⌝ ⦄ + h_spec (self_ : Self) (x : g_spec1) : + (specs.naming.lawful_field.Sub.h.pre SubInst.QuxInst SubInst self_ x).holds + → + ⦃ ⌜ True ⌝ ⦄ + SubInst.h self_ x + ⦃ ⇓ res => + ⌜ (specs.naming.lawful_field.Sub.h.post SubInst.QuxInst SubInst self_ x + res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::assoc_consts::Bounded::clamp::pre]: Source: 'src/specs/traits/assoc_consts.rs', lines 8:0-8:22 -/ @[reducible] @@ -1173,6 +1240,57 @@ structure specs.traits.synthesized.Many.Lawful (Self : Type) (ManyInst : corecloneCloneInst7 ManyInst.corecloneCloneInst ManyInst self_ res).holds ⌝ ⦄ +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::SubAssoc] + Source: 'src/specs/traits/synthesized.rs', lines 79:0-82:1 -/ +structure specs.traits.synthesized.SubAssoc.Lawful (Self : Type) + (Self_Clause0_Item : Type) (SubAssocInst : specs.traits.synthesized.SubAssoc + Self Self_Clause0_Item) : Prop where + AssocInstLawful : specs.traits.synthesized.Assoc.Lawful Self + Self_Clause0_Item SubAssocInst.AssocInst + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::CallOnce] + Source: 'src/specs/traits/synthesized.rs', lines 86:0-88:1 -/ +structure specs.traits.synthesized.CallOnce.Lawful (Self : Type) (Args : Type) + (Self_Output : Type) (CallOnceInst : specs.traits.synthesized.CallOnce Self + Args Self_Output) : Prop + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Call] + Source: 'src/specs/traits/synthesized.rs', lines 91:0-94:1 -/ +structure specs.traits.synthesized.Call.Lawful (Self : Type) (Args : Type) + (Self_Clause0_Output : Type) (CallInst : specs.traits.synthesized.Call Self + Args Self_Clause0_Output) : Prop where + CallOnceInstLawful : specs.traits.synthesized.CallOnce.Lawful Self Args + Self_Clause0_Output CallInst.CallOnceInst + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::SubGen] + Source: 'src/specs/traits/synthesized.rs', lines 100:0-103:1 -/ +structure specs.traits.synthesized.SubGen.Lawful (Self : Type) + (Self_Clause0_Item : Type) (SubGenInst : specs.traits.synthesized.SubGen Self + Self_Clause0_Item) : Prop where + AssocInstLawful : specs.traits.synthesized.Assoc.Lawful Self + Self_Clause0_Item SubGenInst.AssocInst + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::ManyAssoc] + Source: 'src/specs/traits/synthesized.rs', lines 109:0-114:1 -/ +structure specs.traits.synthesized.ManyAssoc.Lawful (Self : Type) + (Self_Clause0_Item : Type) (ManyAssocInst : + specs.traits.synthesized.ManyAssoc Self Self_Clause0_Item) : Prop where + AssocInstLawful : specs.traits.synthesized.Assoc.Lawful Self + Self_Clause0_Item ManyAssocInst.AssocInst + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::K2] + Source: 'src/specs/traits/synthesized.rs', lines 116:0-120:1 -/ +structure specs.traits.synthesized.K2.Lawful (Self : Type) (Self_X : Type) + (K2Inst : specs.traits.synthesized.K2 Self Self_X) : Prop + +/-- Lawful structure of trait: [hax_tests::specs::traits::synthesized::Sym2] + Source: 'src/specs/traits/synthesized.rs', lines 125:0-128:1 -/ +structure specs.traits.synthesized.Sym2.Lawful (Self : Type) (Self_Clause0_X : + Type) (Sym2Inst : specs.traits.synthesized.Sym2 Self Self_Clause0_X) : Prop + where + K2InstLawful : specs.traits.synthesized.K2.Lawful Self Self_Clause0_X + Sym2Inst.K2Inst + /-- [hax_tests::specs::traits::trait_generics::Conv::conv::pre]: Source: 'src/specs/traits/trait_generics.rs', lines 8:4-8:32 -/ @[reducible] diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index 68ff8c7ac5..f80e022f34 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -107,6 +107,15 @@ structure specs.naming.Qux (Self : Type) where @[reducible] def specs.naming.lawful_impl_binder.Wrap (T : Type) := T +/-- Trait declaration: [hax_tests::specs::naming::lawful_field::Sub] + Source: 'src/specs/naming.rs', lines 72:4-78:5 + Visibility: public -/ +structure specs.naming.lawful_field.Sub (Self : Type) (QuxInstLawful : Type) + (g_spec : Type) where + QuxInst : specs.naming.Qux Self + g : Self → QuxInstLawful → RustM Std.U32 + h : Self → g_spec → RustM Std.U32 + /-- Trait declaration: [hax_tests::specs::traits::assoc_consts::Bounded] Source: 'src/specs/traits/assoc_consts.rs', lines 9:0-18:1 -/ structure specs.traits.assoc_consts.Bounded (Self : Type) where @@ -320,6 +329,60 @@ structure specs.traits.synthesized.Many (Self : Type) where core.clone.Clone F) (corecloneCloneInst7 : core.clone.Clone G) (corecloneCloneInst8 : core.clone.Clone H), Self → RustM Std.U32 +/-- Trait declaration: [hax_tests::specs::traits::synthesized::SubAssoc] + Source: 'src/specs/traits/synthesized.rs', lines 79:0-82:1 -/ +structure specs.traits.synthesized.SubAssoc (Self : Type) (Self_Clause0_Item : + Type) where + AssocInst : specs.traits.synthesized.Assoc Self Self_Clause0_Item + len : Self → RustM Std.Usize + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::CallOnce] + Source: 'src/specs/traits/synthesized.rs', lines 86:0-88:1 -/ +structure specs.traits.synthesized.CallOnce (Self : Type) (Args : Type) + (Self_Output : Type) where + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Call] + Source: 'src/specs/traits/synthesized.rs', lines 91:0-94:1 -/ +structure specs.traits.synthesized.Call (Self : Type) (Args : Type) + (Self_Clause0_Output : Type) where + CallOnceInst : specs.traits.synthesized.CallOnce Self Args + Self_Clause0_Output + call : Self → Args → RustM Self_Clause0_Output + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::SubGen] + Source: 'src/specs/traits/synthesized.rs', lines 100:0-103:1 -/ +structure specs.traits.synthesized.SubGen (Self : Type) (Self_Clause0_Item : + Type) where + AssocInst : specs.traits.synthesized.Assoc Self Self_Clause0_Item + g : forall {U : Type} {Clause0_Item : Type} (AssocInst1 : + specs.traits.synthesized.Assoc U Clause0_Item), Self → U → RustM U + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::ManyAssoc] + Source: 'src/specs/traits/synthesized.rs', lines 109:0-114:1 -/ +structure specs.traits.synthesized.ManyAssoc (Self : Type) (Self_Clause0_Item : + Type) where + AssocInst : specs.traits.synthesized.Assoc Self Self_Clause0_Item + m : forall {A : Type} {B : Type} {C : Type} {D : Type} {E : Type} {F : Type} + {G : Type} {H : Type} (corecloneCloneInst : core.clone.Clone A) + (corecloneCloneInst1 : core.clone.Clone B) (corecloneCloneInst2 : + core.clone.Clone C) (corecloneCloneInst3 : core.clone.Clone D) + (corecloneCloneInst4 : core.clone.Clone E) (corecloneCloneInst5 : + core.clone.Clone F) (corecloneCloneInst6 : core.clone.Clone G) + (corecloneCloneInst7 : core.clone.Clone H), Self → RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::K2] + Source: 'src/specs/traits/synthesized.rs', lines 116:0-120:1 -/ +structure specs.traits.synthesized.K2 (Self : Type) (Self_X : Type) where + k : RustM Std.U32 + +/-- Trait declaration: [hax_tests::specs::traits::synthesized::Sym2] + Source: 'src/specs/traits/synthesized.rs', lines 125:0-128:1 -/ +structure specs.traits.synthesized.Sym2 (Self : Type) (Self_Clause0_X : Type) + where + K2Inst : specs.traits.synthesized.K2 Self Self_Clause0_X + g : forall {U : Type} {Clause0_X : Type} (K2Inst1 : + specs.traits.synthesized.K2 U Clause0_X), Std.U32 → RustM Std.U32 + /-- Trait declaration: [hax_tests::specs::traits::trait_generics::Conv] Source: 'src/specs/traits/trait_generics.rs', lines 6:0-9:1 -/ structure specs.traits.trait_generics.Conv (Self : Type) (T : Type) where diff --git a/tests/hax/src/specs/naming.rs b/tests/hax/src/specs/naming.rs index 4383ec812a..67551dfaf1 100644 --- a/tests/hax/src/specs/naming.rs +++ b/tests/hax/src/specs/naming.rs @@ -59,3 +59,21 @@ pub mod lawful_impl_binder { } } } + +// No clash: trait type parameters named like the fields `QuxInstLawful` (of +// the parent clause `QuxInst`) and `g_spec` of `Sub.Lawful` become +// `QuxInstLawful1` and `g_spec1` in the structure. +pub mod lawful_field { + #![allow(non_camel_case_types)] + use super::Qux; + use hax_lib::*; + + #[hax_lib::attributes] + pub trait Sub: Qux { + #[requires(true)] + fn g(&self, x: QuxInstLawful) -> u32; + + #[requires(true)] + fn h(&self, x: g_spec) -> u32; + } +} diff --git a/tests/hax/src/specs/traits/synthesized.rs b/tests/hax/src/specs/traits/synthesized.rs index 31842e310a..659001dda6 100644 --- a/tests/hax/src/specs/traits/synthesized.rs +++ b/tests/hax/src/specs/traits/synthesized.rs @@ -68,43 +68,76 @@ trait Many: Clone { ) -> u32; } -// BUG: aeneas fails on the conditions of a trait method when the trait or a -// supertrait has an associated type: it maps their generics positionally to -// the method's, but charon lifts the associated type once per clause path -// (`SubAssoc.len.pre {Self_} {Clause0_Item} {Clause1_Clause0_Item}` vs -// `Self, Self_Clause0_Item`) and after the method's own type parameters +// The contracts of the methods below are dropped with a warning ("the generics +// of its conditions don't match those of the trait and the method"): charon +// lifts the associated type of the trait or a supertrait once per clause path +// in the decoration fns, but only once in the trait. The comments below +// describe the expected conditions. + +// A supertrait with an associated type; the result does not mention it +#[hax_lib::attributes] +trait SubAssoc: Assoc { + #[requires(true)] + fn len(&self) -> usize; +} + +// The same with a generic supertrait, as `FnMut: FnOnce` +#[hax_lib::attributes] +trait CallOnce { + type Output; +} + +#[hax_lib::attributes] +trait Call: CallOnce { + #[requires(true)] + fn call(&self, args: Args) -> Self::Output; +} + +// A supertrait with an associated type and a bounded method type parameter: +// the clause `U: Assoc` of the conditions gets the instance of `U`, not the +// parent `Self: Assoc` +#[hax_lib::attributes] +trait SubGen: Assoc { + #[requires(true)] + fn g(&self, u: U) -> U; +} + +// `Many` with a supertrait with an associated type: the conditions get the +// instances of `A`…`H` in order, and `Self_Clause0_Item` for both lifted +// copies of the associated type (`Clause8_Item`, `Clause9_Clause0_Item`) +#[hax_lib::attributes] +trait ManyAssoc: Assoc { + #[requires(true)] + fn m( + &self, + ) -> u32; +} + +trait K2 { + type X; + + fn k() -> u32; +} + +// `Sym` with an associated type: two clauses on `K2`, `Self_: K2` and +// `U: K2`; `U::k()` must be read from the instance of `U` +#[hax_lib::attributes] +trait Sym2: K2 { + #[requires(x < U::k() && U::k() < 10)] + fn g(x: u32) -> u32; +} + +// BUG: aeneas fails on the conditions of these trait methods: it maps their +// generics positionally to the method's, but charon lifts the associated type +// once per clause path (as above) and after the method's own type parameters // (`AssocGen.f.post {Self_} {U} {Clause0_Item}` vs `Self, Self_Item, U`). -// - `SubAssoc`, `Call`, `SubGen`, `ManyAssoc`, `Sym2`: "Internal error: the -// generics of the conditions of `…` don't match those of the trait and the -// method", contract dropped (exit 1); // - `SubBoth`: "Internal error: the generics of the condition `SubBoth::h.pre` -// don't match those it is applied to" (exit 2); +// don't match those it is applied to", partial `SubBoth.Lawful` (exit 1); // - `AssocGen`: synthesized post with `res : Clause0_Item`, then "Could not -// find an instance for a trait clause of a pre/post condition" (exit 2). +// find an instance for a trait clause of a pre/post condition", partial +// `AssocGen.Lawful` (exit 1). // The traits are commented out because aeneas fails on them. -// // A supertrait with an associated type. The decoration fns have one copy of -// // the lifted associated type per clause (`Clause0_Item` for `Self_: Assoc`, -// // `Clause1_Clause0_Item` for `Self_: SubAssoc`), the trait only one -// // (`Self_Clause0_Item`). The result does not mention the associated type. -// #[hax_lib::attributes] -// trait SubAssoc: Assoc { -// #[requires(true)] -// fn len(&self) -> usize; -// } - -// // The same with a generic supertrait, as `FnMut: FnOnce` -// #[hax_lib::attributes] -// trait CallOnce { -// type Output; -// } -// -// #[hax_lib::attributes] -// trait Call: CallOnce { -// #[requires(true)] -// fn call(&self, args: Args) -> Self::Output; -// } - // // An associated type and a method type parameter: in the decoration fns, the // // lifted `Clause0_Item` comes after `U`, in the method after `Self` // #[hax_lib::attributes] @@ -115,15 +148,6 @@ trait Many: Clone { // fn f(&self, u: U) -> U; // } -// // A supertrait with an associated type and a bounded method type parameter: -// // the clause `U: Assoc` of the conditions gets the instance of `U`, not the -// // parent `Self: Assoc` -// #[hax_lib::attributes] -// trait SubGen: Assoc { -// #[requires(true)] -// fn g(&self, u: U) -> U; -// } - // // Both conditions written, with a supertrait with an associated type // #[hax_lib::attributes] // trait SubBoth: Assoc { @@ -131,28 +155,3 @@ trait Many: Clone { // #[ensures(|r| r == 0)] // fn h(&self) -> usize; // } - -// // `Many` with a supertrait with an associated type: the conditions get the -// // instances of `A`…`H` in order, and `Self_Clause0_Item` for both lifted -// // copies of the associated type (`Clause8_Item`, `Clause9_Clause0_Item`) -// #[hax_lib::attributes] -// trait ManyAssoc: Assoc { -// #[requires(true)] -// fn m( -// &self, -// ) -> u32; -// } - -// trait K2 { -// type X; -// -// fn k() -> u32; -// } -// -// // `Sym` with an associated type: two clauses on `K2`, `Self_: K2` and -// // `U: K2`; `U::k()` must be read from the instance of `U` -// #[hax_lib::attributes] -// trait Sym2: K2 { -// #[requires(x < U::k() && U::k() < 10)] -// fn g(x: u32) -> u32; -// } From 12aa18ae189a6deb97c76a725bfd31d3375d81f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Fri, 23 Oct 2026 14:55:47 +0000 Subject: [PATCH 16/17] test-specs: more trait-level spec tests, -specs hax flag check - Const-generic trait (two impls, [u32; N] blanket impl, generic caller), trait implemented from another module, impl Trait argument, where-clause impl, two impls of a generic trait, projection bound, inherent method of a generic impl, impl for a reference; with their proofs. - Regression test that -specs hax requires -core-models-lib; the error no longer prints the usage text, so its message is checked. --- src/Main.ml | 3 +- .../lean/HaxTests/Extraction/Funs.lean | 160 +++++++++++- .../HaxTests/Extraction/ProofObligations.lean | 91 +++++++ .../lean/HaxTests/Extraction/Specs.lean | 239 +++++++++++++++++- .../lean/HaxTests/Extraction/Types.lean | 32 ++- .../Verification/ProofObligations.lean | 2 + .../Verification/Traits/AssocTypeBounds.lean | 21 ++ .../Verification/Traits/ConstGenerics.lean | 76 ++++++ .../Verification/Traits/GenericImpl.lean | 26 ++ .../HaxTests/Verification/Traits/Modules.lean | 58 +++++ .../Verification/Traits/TraitGenerics.lean | 35 +++ tests/hax/src/specs/naming.rs | 1 - tests/hax/src/specs/traits.rs | 2 + .../hax/src/specs/traits/assoc_type_bounds.rs | 18 ++ tests/hax/src/specs/traits/const_generics.rs | 36 +++ tests/hax/src/specs/traits/generic_impl.rs | 16 ++ tests/hax/src/specs/traits/modules.rs | 43 ++++ tests/hax/src/specs/traits/trait_generics.rs | 15 +- .../src/hax-specs-no-core-models-lib.lean.out | 1 + tests/src/hax-specs-no-core-models-lib.rs | 7 + 20 files changed, 865 insertions(+), 17 deletions(-) create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ConstGenerics.lean create mode 100644 tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Modules.lean create mode 100644 tests/hax/src/specs/traits/const_generics.rs create mode 100644 tests/hax/src/specs/traits/modules.rs create mode 100644 tests/src/hax-specs-no-core-models-lib.lean.out create mode 100644 tests/src/hax-specs-no-core-models-lib.rs diff --git a/src/Main.ml b/src/Main.ml index d413dc3b4b..931b8d6dc9 100644 --- a/src/Main.ml +++ b/src/Main.ml @@ -500,7 +500,8 @@ let () = if Option.is_some !opt_spec_config && not (backend () = Lean) then fail_with_error "The -specs option is valid only for the Lean backend"; if spec_config_is_hax () && not !core_models_lib then - fail_with_error "The -specs hax option requires the -core-models-lib option"; + fail_with_error_no_doc + "The -specs hax option requires the -core-models-lib option"; check_arg_implies !diagnose_detailed "-diagnose-detailed" !diagnose_micro_passes "-diagnose-micro-passes"; diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean index 47debdf4e5..ac010af9ec 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Funs.lean @@ -684,6 +684,17 @@ def specs.traits.assoc_type_bounds.first_bar let t ← ContainerInst.first c ContainerInst.BarInst.bar t +/-- [hax_tests::specs::traits::assoc_type_bounds::proj]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 66:0-71:1 -/ +def specs.traits.assoc_type_bounds.proj + {S : Type} {Clause0_Item : Type} (SourceInst : + specs.traits.assoc_type_bounds.Source S Clause0_Item) (BarInst : + specs.traits.assoc_type_bounds.Bar Clause0_Item) (s : S) : + RustM Std.U32 + := do + let t ← SourceInst.get s + BarInst.bar t + /-- [hax_tests::specs::traits::basic::{impl hax_tests::specs::traits::basic::Foo for u64}::zero]: Source: 'src/specs/traits/basic.rs', lines 35:4-37:5 -/ def U64.Insts.Hax_testsSpecsTraitsBasicFoo.zero : RustM Std.U64 := do @@ -925,6 +936,59 @@ def specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup.dup } +/-- [hax_tests::specs::traits::const_generics::{impl hax_tests::specs::traits::const_generics::Cg<4usize> for u32}::f]: + Source: 'src/specs/traits/const_generics.rs', lines 15:4-17:5 -/ +def U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4.f + (self : Std.U32) (x : Std.Usize) : RustM Std.Usize := do + ok x + +/-- Trait implementation: [hax_tests::specs::traits::const_generics::{impl hax_tests::specs::traits::const_generics::Cg<4usize> for u32}] + Source: 'src/specs/traits/const_generics.rs', lines 14:0-18:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4 : + specs.traits.const_generics.Cg Std.U32 4#usize := { + f := U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4.f +} + +/-- [hax_tests::specs::traits::const_generics::{impl hax_tests::specs::traits::const_generics::Cg<8usize> for u32}::f]: + Source: 'src/specs/traits/const_generics.rs', lines 21:4-23:5 -/ +def U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8.f + (self : Std.U32) (x : Std.Usize) : RustM Std.Usize := do + x + 1#usize + +/-- Trait implementation: [hax_tests::specs::traits::const_generics::{impl hax_tests::specs::traits::const_generics::Cg<8usize> for u32}] + Source: 'src/specs/traits/const_generics.rs', lines 20:0-24:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8 : + specs.traits.const_generics.Cg Std.U32 8#usize := { + f := U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8.f +} + +/-- [hax_tests::specs::traits::const_generics::{impl hax_tests::specs::traits::const_generics::Cg for [u32; N]}::f]: + Source: 'src/specs/traits/const_generics.rs', lines 27:4-29:5 -/ +def ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg.f + {N : Std.Usize} (self : Array Std.U32 N) (_x : Std.Usize) : + RustM Std.Usize + := do + ok N + +/-- Trait implementation: [hax_tests::specs::traits::const_generics::{impl hax_tests::specs::traits::const_generics::Cg for [u32; N]}] + Source: 'src/specs/traits/const_generics.rs', lines 26:0-30:1 -/ +@[reducible] +def ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg (N : Std.Usize) : + specs.traits.const_generics.Cg (Array Std.U32 N) N := { + f := ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg.f +} + +/-- [hax_tests::specs::traits::const_generics::use_cg]: + Source: 'src/specs/traits/const_generics.rs', lines 34:0-36:1 -/ +def specs.traits.const_generics.use_cg + {T : Type} (CgT4Inst : specs.traits.const_generics.Cg T 4#usize) (t : T) + (x : Std.Usize) : + RustM Std.Usize + := do + CgT4Inst.f t x + /-- [hax_tests::specs::traits::default_methods::D::next]: Source: 'src/specs/traits/default_methods.rs', lines 12:4-14:5 -/ @[trait_default] @@ -1161,6 +1225,29 @@ def specs.traits.generic_impl.k let i1 ← SubInst.s y i + i1 +/-- [hax_tests::specs::traits::generic_impl::{hax_tests::specs::traits::generic_impl::Wrapper}::get]: + Source: 'src/specs/traits/generic_impl.rs', lines 71:4-73:5 -/ +def specs.traits.generic_impl.Wrapper.get + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (self : specs.traits.generic_impl.Wrapper T) : + RustM Std.U64 + := do + FooInst.f self.inner + +/-- [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for &'_0 u64}::f]: + Source: 'src/specs/traits/generic_impl.rs', lines 78:4-80:5 -/ +def Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f + (self : Std.U64) : RustM Std.U64 := do + self % 11#u64 + +/-- Trait implementation: [hax_tests::specs::traits::generic_impl::{impl hax_tests::specs::traits::generic_impl::Foo for &'_0 u64}] + Source: 'src/specs/traits/generic_impl.rs', lines 77:0-81:1 -/ +@[reducible] +def Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo : + specs.traits.generic_impl.Foo Std.U64 := { + f := Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f +} + /-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f]: Source: 'src/specs/traits/impl_contract.rs', lines 16:4-18:5 -/ def U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f @@ -1222,6 +1309,48 @@ def U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo : U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo.f BarInst } +/-- [hax_tests::specs::traits::modules::c::{impl hax_tests::specs::traits::modules::a::b::T for hax_tests::specs::traits::modules::c::S}::t]: + Source: 'src/specs/traits/modules.rs', lines 21:8-23:9 + Visibility: public -/ +def specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT.t + (self : specs.traits.modules.c.S) : RustM Std.U32 := do + ok 0#u32 + +/-- Trait implementation: [hax_tests::specs::traits::modules::c::{impl hax_tests::specs::traits::modules::a::b::T for hax_tests::specs::traits::modules::c::S}] + Source: 'src/specs/traits/modules.rs', lines 20:4-24:5 -/ +@[reducible] +def specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT : + specs.traits.modules.a.b.T specs.traits.modules.c.S := { + t := specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT.t +} + +/-- [hax_tests::specs::traits::modules::impl_arg]: + Source: 'src/specs/traits/modules.rs', lines 29:0-31:1 -/ +def specs.traits.modules.impl_arg + {T0 : Type} (abTInst : specs.traits.modules.a.b.T T0) (x : T0) : + RustM Std.U32 + := do + abTInst.t x + +/-- [hax_tests::specs::traits::modules::{impl hax_tests::specs::traits::modules::a::b::T for hax_tests::specs::traits::modules::W}::t]: + Source: 'src/specs/traits/modules.rs', lines 40:4-42:5 + Visibility: public -/ +def specs.traits.modules.W.Insts.Hax_testsSpecsTraitsModulesABT.t + {U : Type} (abTInst : specs.traits.modules.a.b.T U) + (self : specs.traits.modules.W U) : + RustM Std.U32 + := do + abTInst.t self + +/-- Trait implementation: [hax_tests::specs::traits::modules::{impl hax_tests::specs::traits::modules::a::b::T for hax_tests::specs::traits::modules::W}] + Source: 'src/specs/traits/modules.rs', lines 36:0-43:1 -/ +@[reducible] +def specs.traits.modules.W.Insts.Hax_testsSpecsTraitsModulesABT {U : Type} + (abTInst : specs.traits.modules.a.b.T U) : specs.traits.modules.a.b.T + (specs.traits.modules.W U) := { + t := specs.traits.modules.W.Insts.Hax_testsSpecsTraitsModulesABT.t abTInst +} + /-- [hax_tests::specs::traits::mut_self::{impl hax_tests::specs::traits::mut_self::Counter for u32}::incr]: Source: 'src/specs/traits/mut_self.rs', lines 19:4-21:5 -/ def U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.incr @@ -1306,13 +1435,13 @@ def specs.traits.supertraits.via_u8 (x : Std.U8) : RustM Std.Usize := do i - i1 /-- [hax_tests::specs::traits::trait_generics::{impl hax_tests::specs::traits::trait_generics::Conv for u32}::conv]: - Source: 'src/specs/traits/trait_generics.rs', lines 12:4-14:5 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 13:4-15:5 -/ def U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8.conv (self : Std.U32) (_t : Std.U8) : RustM Std.U32 := do ok 0#u32 /-- Trait implementation: [hax_tests::specs::traits::trait_generics::{impl hax_tests::specs::traits::trait_generics::Conv for u32}] - Source: 'src/specs/traits/trait_generics.rs', lines 11:0-15:1 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 12:0-16:1 -/ @[reducible] def U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8 : specs.traits.trait_generics.Conv Std.U32 Std.U8 := { @@ -1320,7 +1449,7 @@ def U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8 : } /-- [hax_tests::specs::traits::trait_generics::use_conv]: - Source: 'src/specs/traits/trait_generics.rs', lines 18:0-20:1 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 19:0-21:1 -/ def specs.traits.trait_generics.use_conv {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv C Std.U8) (c : C) : @@ -1328,6 +1457,31 @@ def specs.traits.trait_generics.use_conv := do ConvCU8Inst.conv c 0#u8 +/-- [hax_tests::specs::traits::trait_generics::{impl hax_tests::specs::traits::trait_generics::Conv for u32}::conv]: + Source: 'src/specs/traits/trait_generics.rs', lines 24:4-26:5 -/ +def U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16.conv + (self : Std.U32) (_t : Std.U16) : RustM Std.U32 := do + ok 1#u32 + +/-- Trait implementation: [hax_tests::specs::traits::trait_generics::{impl hax_tests::specs::traits::trait_generics::Conv for u32}] + Source: 'src/specs/traits/trait_generics.rs', lines 23:0-27:1 -/ +@[reducible] +def U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16 : + specs.traits.trait_generics.Conv Std.U32 Std.U16 := { + conv := U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16.conv +} + +/-- [hax_tests::specs::traits::trait_generics::use_both]: + Source: 'src/specs/traits/trait_generics.rs', lines 31:0-33:1 -/ +def specs.traits.trait_generics.use_both + {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv C Std.U8) + (ConvCU16Inst : specs.traits.trait_generics.Conv C Std.U16) (c : C) : + RustM Std.U32 + := do + let i ← ConvCU8Inst.conv c 0#u8 + let i1 ← ConvCU16Inst.conv c 0#u16 + i + i1 + /-- [hax_tests::specs::traits::unannotated_sub::{impl hax_tests::specs::traits::unannotated_sub::A for u32}::a]: Source: 'src/specs/traits/unannotated_sub.rs', lines 17:4-19:5 -/ def U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.a diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean index e3e1024e14..2c26cded88 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/ProofObligations.lean @@ -182,6 +182,22 @@ theorem specs.traits.builtin_bound.WU32.Insts.Hax_testsSpecsTraitsBuiltin_boundDup := by sorry +theorem U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4.Lawful : + specs.traits.const_generics.Cg.Lawful Std.U32 4#usize + U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4 + := by sorry + +theorem U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8.Lawful : + specs.traits.const_generics.Cg.Lawful Std.U32 8#usize + U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8 + := by sorry + +theorem ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg.Lawful (N : + Std.Usize) : + specs.traits.const_generics.Cg.Lawful (Array Std.U32 N) N + (ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg N) + := by sorry + theorem U32.Insts.Hax_testsSpecsTraitsDefault_methodsD.Lawful : specs.traits.default_methods.D.Lawful Std.U32 U32.Insts.Hax_testsSpecsTraitsDefault_methodsD @@ -253,6 +269,11 @@ theorem specs.traits.generic_impl.SingleU64.Insts.Hax_testsSpecsTraitsGeneric_implSub := by sorry +theorem Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful : + specs.traits.generic_impl.Foo.Lawful Std.U64 + Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo + := by sorry + theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.Lawful : specs.traits.impl_contract.Foo.Lawful Std.U32 U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo @@ -273,6 +294,18 @@ theorem U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo.Lawful : U32.Insts.Hax_testsSpecsTraitsMethod_genericsFoo := by sorry +theorem specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT.Lawful : + specs.traits.modules.a.b.T.Lawful specs.traits.modules.c.S + specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT + := by sorry + +theorem specs.traits.modules.W.Insts.Hax_testsSpecsTraitsModulesABT.Lawful {U : + Type} (abTInst : specs.traits.modules.a.b.T U) + (abTInstLawful : specs.traits.modules.a.b.T.Lawful U abTInst) : + specs.traits.modules.a.b.T.Lawful (specs.traits.modules.W U) + (specs.traits.modules.W.Insts.Hax_testsSpecsTraitsModulesABT abTInst) + := by sorry + theorem U32.Insts.Hax_testsSpecsTraitsMut_selfCounter.Lawful : specs.traits.mut_self.Counter.Lawful Std.U32 U32.Insts.Hax_testsSpecsTraitsMut_selfCounter @@ -298,6 +331,11 @@ theorem U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8.Lawful : U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU8 := by sorry +theorem U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16.Lawful : + specs.traits.trait_generics.Conv.Lawful Std.U32 Std.U16 + U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16 + := by sorry + theorem U32.Insts.Hax_testsSpecsTraitsUnannotated_subA.Lawful : specs.traits.unannotated_sub.A.Lawful Std.U32 U32.Insts.Hax_testsSpecsTraitsUnannotated_subA @@ -574,6 +612,21 @@ theorem ContainerInstLawful := by sorry +theorem + specs.traits.assoc_type_bounds.proj.spec.proof {S : Type} {Clause0_Item : + Type} (SourceInst : + specs.traits.assoc_type_bounds.Source + S Clause0_Item) (BarInst : + specs.traits.assoc_type_bounds.Bar + Clause0_Item) (s : S) + (SourceInstLawful : specs.traits.assoc_type_bounds.Source.Lawful S + Clause0_Item SourceInst) + (BarInstLawful : specs.traits.assoc_type_bounds.Bar.Lawful Clause0_Item + BarInst) : + specs.traits.assoc_type_bounds.proj.spec SourceInst BarInst s + SourceInstLawful BarInstLawful + := by sorry + theorem specs.traits.builtin_bound.dup.spec.proof {T : Type} (corecloneCloneInst : core.clone.Clone T) (x : T) @@ -591,6 +644,20 @@ theorem specs.traits.trait_generics.use_conv.spec ConvCU8Inst c ConvCU8InstLawful := by sorry +theorem + specs.traits.trait_generics.use_both.spec.proof {C : Type} (ConvCU8Inst : + specs.traits.trait_generics.Conv + C Std.U8) (ConvCU16Inst : + specs.traits.trait_generics.Conv + C Std.U16) (c : C) + (ConvCU8InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U8 + ConvCU8Inst) + (ConvCU16InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U16 + ConvCU16Inst) : + specs.traits.trait_generics.use_both.spec ConvCU8Inst ConvCU16Inst c + ConvCU8InstLawful ConvCU16InstLawful + := by sorry + theorem specs.traits.assoc_consts.use_clamp.spec.proof {T : Type} (BoundedInst : specs.traits.assoc_consts.Bounded @@ -599,6 +666,21 @@ theorem : specs.traits.assoc_consts.use_clamp.spec BoundedInst t x BoundedInstLawful := by sorry +theorem + specs.traits.const_generics.use_cg.spec.proof {T : Type} (CgT4Inst : + specs.traits.const_generics.Cg T + 4#usize) (t : T) (x : Std.Usize) + (CgT4InstLawful : specs.traits.const_generics.Cg.Lawful T 4#usize CgT4Inst) : + specs.traits.const_generics.use_cg.spec CgT4Inst t x CgT4InstLawful + := by sorry + +theorem + specs.traits.modules.impl_arg.spec.proof {T0 : Type} (abTInst : + specs.traits.modules.a.b.T T0) + (x : T0) (abTInstLawful : specs.traits.modules.a.b.T.Lawful T0 abTInst) : + specs.traits.modules.impl_arg.spec abTInst x abTInstLawful + := by sorry + theorem specs.naming.lawful_binder.f.spec.proof {T : Type} (QuxInst : specs.naming.Qux T) @@ -607,6 +689,15 @@ theorem specs.naming.lawful_binder.f.spec QuxInst QuxInstLawful1 x QuxInstLawful := by sorry +theorem + specs.traits.generic_impl.Wrapper.get.spec.proof {T : Type} (FooInst : + specs.traits.generic_impl.Foo + T) + (self : specs.traits.generic_impl.Wrapper T) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : + specs.traits.generic_impl.Wrapper.get.spec FooInst self FooInstLawful + := by sorry + theorem U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec.proof (self : Std.U32) : U32.Insts.Hax_testsSpecsTraitsImpl_contractFoo.f.spec self := by sorry diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean index 10385f1d28..a654252298 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Specs.lean @@ -54,7 +54,7 @@ structure specs.naming.Qux.Lawful (Self : Type) (QuxInst : specs.naming.Qux Self) : Prop /-- [hax_tests::specs::naming::lawful_field::Sub::g::pre]: - Source: 'src/specs/naming.rs', lines 71:4-71:26 -/ + Source: 'src/specs/naming.rs', lines 70:4-70:26 -/ @[reducible] def specs.naming.lawful_field.Sub.g.pre {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : @@ -65,7 +65,7 @@ def specs.naming.lawful_field.Sub.g.pre ok true /-- [hax_tests::specs::naming::lawful_field::Sub::g::post]: - Source: 'src/specs/naming.rs', lines 74:8-74:45 -/ + Source: 'src/specs/naming.rs', lines 73:8-73:45 -/ @[reducible] def specs.naming.lawful_field.Sub.g.post {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : @@ -76,7 +76,7 @@ def specs.naming.lawful_field.Sub.g.post ok true /-- [hax_tests::specs::naming::lawful_field::Sub::h::pre]: - Source: 'src/specs/naming.rs', lines 71:4-71:26 -/ + Source: 'src/specs/naming.rs', lines 70:4-70:26 -/ @[reducible] def specs.naming.lawful_field.Sub.h.pre {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : @@ -87,7 +87,7 @@ def specs.naming.lawful_field.Sub.h.pre ok true /-- [hax_tests::specs::naming::lawful_field::Sub::h::post]: - Source: 'src/specs/naming.rs', lines 77:8-77:38 -/ + Source: 'src/specs/naming.rs', lines 76:8-76:38 -/ @[reducible] def specs.naming.lawful_field.Sub.h.post {Self_ : Type} {QuxInstLawful : Type} {g_spec : Type} (QuxInst : @@ -98,7 +98,7 @@ def specs.naming.lawful_field.Sub.h.post ok true /-- Lawful structure of trait: [hax_tests::specs::naming::lawful_field::Sub] - Source: 'src/specs/naming.rs', lines 72:4-78:5 -/ + Source: 'src/specs/naming.rs', lines 71:4-77:5 -/ structure specs.naming.lawful_field.Sub.Lawful (Self : Type) (QuxInstLawful1 : Type) (g_spec1 : Type) (SubInst : specs.naming.lawful_field.Sub Self QuxInstLawful1 g_spec1) : Prop where @@ -266,6 +266,40 @@ structure specs.traits.assoc_type_bounds.Container.Lawful (Self : Type) ⌜ (specs.traits.assoc_type_bounds.Container.first.post ContainerInst self_ res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::assoc_type_bounds::Source::get::pre]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 61:4-61:32 -/ +@[reducible] +def specs.traits.assoc_type_bounds.Source.get.pre + {Self_ : Type} {Clause0_Item : Type} (SourceInst : + specs.traits.assoc_type_bounds.Source Self_ Clause0_Item) (self_ : Self_) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::assoc_type_bounds::Source::get::post]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 56:0-56:22 -/ +@[reducible] +def specs.traits.assoc_type_bounds.Source.get.post + {Self_ : Type} {Clause0_Item : Type} (SourceInst : + specs.traits.assoc_type_bounds.Source Self_ Clause0_Item) (self_ : Self_) + (t : Clause0_Item) : + RustM Bool + := do + ok true + +/-- Lawful structure of trait: [hax_tests::specs::traits::assoc_type_bounds::Source] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 57:0-62:1 -/ +structure specs.traits.assoc_type_bounds.Source.Lawful (Self : Type) (Self_Item + : Type) (SourceInst : specs.traits.assoc_type_bounds.Source Self Self_Item) : + Prop where + get_spec (self_ : Self) : + (specs.traits.assoc_type_bounds.Source.get.pre SourceInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + SourceInst.get self_ + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_type_bounds.Source.get.post SourceInst self_ + res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::basic::Foo::f1::pre]: Source: 'src/specs/traits/basic.rs', lines 9:4-9:25 -/ @[reducible] @@ -441,6 +475,37 @@ structure specs.traits.builtin_bound.Dup.Lawful (Self : Type) (DupInst : ⌜ (specs.traits.builtin_bound.Dup.dup.post DupInst.corecloneCloneInst DupInst self_ res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::const_generics::Cg::f::pre]: + Source: 'src/specs/traits/const_generics.rs', lines 7:0-7:22 -/ +@[reducible] +def specs.traits.const_generics.Cg.f.pre + {Self_ : Type} {N : Std.Usize} (CgInst : specs.traits.const_generics.Cg Self_ + N) (self_ : Self_) (x : Std.Usize) : + RustM Bool + := do + ok (x < N) + +/-- [hax_tests::specs::traits::const_generics::Cg::f::post]: + Source: 'src/specs/traits/const_generics.rs', lines 7:0-7:22 -/ +@[reducible] +def specs.traits.const_generics.Cg.f.post + {Self_ : Type} {N : Std.Usize} (CgInst : specs.traits.const_generics.Cg Self_ + N) (self_ : Self_) (x : Std.Usize) (res : Std.Usize) : + RustM Bool + := do + ok (res <= N) + +/-- Lawful structure of trait: [hax_tests::specs::traits::const_generics::Cg] + Source: 'src/specs/traits/const_generics.rs', lines 8:0-12:1 -/ +structure specs.traits.const_generics.Cg.Lawful (Self : Type) (N : Std.Usize) + (CgInst : specs.traits.const_generics.Cg Self N) : Prop where + f_spec (self_ : Self) (x : Std.Usize) : + (specs.traits.const_generics.Cg.f.pre CgInst self_ x).holds → + ⦃ ⌜ True ⌝ ⦄ + CgInst.f self_ x + ⦃ ⇓ res => + ⌜ (specs.traits.const_generics.Cg.f.post CgInst self_ x res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::default_methods::D::next::pre]: Source: 'src/specs/traits/default_methods.rs', lines 6:0-6:22 -/ @[reducible] @@ -776,6 +841,36 @@ structure specs.traits.minimal.Foo.Lawful (Self : Type) (FooInst : ⦃ ⇓ res => ⌜ (specs.traits.minimal.Foo.h.post FooInst self_ x res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::modules::a::b::T::t::pre]: + Source: 'src/specs/traits/modules.rs', lines 11:12-11:31 -/ +@[reducible] +def specs.traits.modules.a.b.T.t.pre + {Self_ : Type} (TInst : specs.traits.modules.a.b.T Self_) (self_ : Self_) : + RustM Bool + := do + ok true + +/-- [hax_tests::specs::traits::modules::a::b::T::t::post]: + Source: 'src/specs/traits/modules.rs', lines 8:8-8:30 -/ +@[reducible] +def specs.traits.modules.a.b.T.t.post + {Self_ : Type} (TInst : specs.traits.modules.a.b.T Self_) (self_ : Self_) + (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + +/-- Lawful structure of trait: [hax_tests::specs::traits::modules::a::b::T] + Source: 'src/specs/traits/modules.rs', lines 9:8-12:9 -/ +structure specs.traits.modules.a.b.T.Lawful (Self : Type) (TInst : + specs.traits.modules.a.b.T Self) : Prop where + t_spec (self_ : Self) : + (specs.traits.modules.a.b.T.t.pre TInst self_).holds → + ⦃ ⌜ True ⌝ ⦄ + TInst.t self_ + ⦃ ⇓ res => + ⌜ (specs.traits.modules.a.b.T.t.post TInst self_ res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::mut_self::Counter::incr::pre]: Source: 'src/specs/traits/mut_self.rs', lines 5:0-5:22 -/ @[reducible] @@ -1292,7 +1387,7 @@ structure specs.traits.synthesized.Sym2.Lawful (Self : Type) (Self_Clause0_X : Sym2Inst.K2Inst /-- [hax_tests::specs::traits::trait_generics::Conv::conv::pre]: - Source: 'src/specs/traits/trait_generics.rs', lines 8:4-8:32 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 9:4-9:32 -/ @[reducible] def specs.traits.trait_generics.Conv.conv.pre {Self_ : Type} {T : Type} (ConvInst : specs.traits.trait_generics.Conv Self_ @@ -1302,7 +1397,7 @@ def specs.traits.trait_generics.Conv.conv.pre ok true /-- [hax_tests::specs::traits::trait_generics::Conv::conv::post]: - Source: 'src/specs/traits/trait_generics.rs', lines 5:0-5:22 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 6:0-6:22 -/ @[reducible] def specs.traits.trait_generics.Conv.conv.post {Self_ : Type} {T : Type} (ConvInst : specs.traits.trait_generics.Conv Self_ @@ -1312,7 +1407,7 @@ def specs.traits.trait_generics.Conv.conv.post ok (res < 10#u32) /-- Lawful structure of trait: [hax_tests::specs::traits::trait_generics::Conv] - Source: 'src/specs/traits/trait_generics.rs', lines 6:0-9:1 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 7:0-10:1 -/ structure specs.traits.trait_generics.Conv.Lawful (Self : Type) (T : Type) (ConvInst : specs.traits.trait_generics.Conv Self T) : Prop where conv_spec (self_ : Self) (t : T) : @@ -2450,6 +2545,34 @@ def ⌜ (specs.traits.assoc_type_bounds.first_bar.post ContainerInst c res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::assoc_type_bounds::proj::post]: + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 65:0-65:26 -/ +@[reducible] +def specs.traits.assoc_type_bounds.proj.post + {S : Type} {Clause0_Item : Type} (SourceInst : + specs.traits.assoc_type_bounds.Source S Clause0_Item) (BarInst : + specs.traits.assoc_type_bounds.Bar Clause0_Item) (s : S) (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + +def + specs.traits.assoc_type_bounds.proj.spec {S : Type} {Clause0_Item : Type} + (SourceInst : + specs.traits.assoc_type_bounds.Source + S Clause0_Item) (BarInst : + specs.traits.assoc_type_bounds.Bar + Clause0_Item) (s : S) + (SourceInstLawful : specs.traits.assoc_type_bounds.Source.Lawful S + Clause0_Item SourceInst) + (BarInstLawful : specs.traits.assoc_type_bounds.Bar.Lawful Clause0_Item + BarInst) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.assoc_type_bounds.proj SourceInst BarInst s + ⦃ ⇓ res => + ⌜ (specs.traits.assoc_type_bounds.proj.post SourceInst BarInst s + res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::builtin_bound::dup::post]: Source: 'src/specs/traits/builtin_bound.rs', lines 11:0-11:20 -/ @[reducible] @@ -2470,7 +2593,7 @@ def ⌜ (specs.traits.builtin_bound.dup.post corecloneCloneInst x res).holds ⌝ ⦄ /-- [hax_tests::specs::traits::trait_generics::use_conv::post]: - Source: 'src/specs/traits/trait_generics.rs', lines 17:0-17:26 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 18:0-18:26 -/ @[reducible] def specs.traits.trait_generics.use_conv.post {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv C Std.U8) @@ -2490,6 +2613,33 @@ def ⦃ ⇓ res => ⌜ (specs.traits.trait_generics.use_conv.post ConvCU8Inst c res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::trait_generics::use_both::post]: + Source: 'src/specs/traits/trait_generics.rs', lines 30:0-30:26 -/ +@[reducible] +def specs.traits.trait_generics.use_both.post + {C : Type} (ConvCU8Inst : specs.traits.trait_generics.Conv C Std.U8) + (ConvCU16Inst : specs.traits.trait_generics.Conv C Std.U16) (c : C) + (res : Std.U32) : + RustM Bool + := do + ok (res < 20#u32) + +def + specs.traits.trait_generics.use_both.spec {C : Type} (ConvCU8Inst : + specs.traits.trait_generics.Conv C + Std.U8) (ConvCU16Inst : + specs.traits.trait_generics.Conv C + Std.U16) (c : C) + (ConvCU8InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U8 + ConvCU8Inst) + (ConvCU16InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U16 + ConvCU16Inst) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.trait_generics.use_both ConvCU8Inst ConvCU16Inst c + ⦃ ⇓ res => + ⌜ (specs.traits.trait_generics.use_both.post ConvCU8Inst ConvCU16Inst c + res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::assoc_consts::use_clamp::pre]: Source: 'src/specs/traits/assoc_consts.rs', lines 47:0-47:23 -/ @[reducible] @@ -2524,6 +2674,57 @@ def ⦃ ⇓ res => ⌜ (specs.traits.assoc_consts.use_clamp.post BoundedInst t x res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::const_generics::use_cg::pre]: + Source: 'src/specs/traits/const_generics.rs', lines 32:0-32:18 -/ +@[reducible] +def specs.traits.const_generics.use_cg.pre + {T : Type} (CgT4Inst : specs.traits.const_generics.Cg T 4#usize) (t : T) + (x : Std.Usize) : + RustM Bool + := do + ok (x < 4#usize) + +/-- [hax_tests::specs::traits::const_generics::use_cg::post]: + Source: 'src/specs/traits/const_generics.rs', lines 33:0-33:26 -/ +@[reducible] +def specs.traits.const_generics.use_cg.post + {T : Type} (CgT4Inst : specs.traits.const_generics.Cg T 4#usize) (t : T) + (x : Std.Usize) (res : Std.Usize) : + RustM Bool + := do + ok (res <= 4#usize) + +def + specs.traits.const_generics.use_cg.spec {T : Type} (CgT4Inst : + specs.traits.const_generics.Cg T + 4#usize) (t : T) (x : Std.Usize) + (CgT4InstLawful : specs.traits.const_generics.Cg.Lawful T 4#usize CgT4Inst) + : Prop := + (specs.traits.const_generics.use_cg.pre CgT4Inst t x).holds → + ⦃ ⌜ True ⌝ ⦄ + specs.traits.const_generics.use_cg CgT4Inst t x + ⦃ ⇓ res => + ⌜ (specs.traits.const_generics.use_cg.post CgT4Inst t x res).holds ⌝ ⦄ + +/-- [hax_tests::specs::traits::modules::impl_arg::post]: + Source: 'src/specs/traits/modules.rs', lines 28:0-28:26 -/ +@[reducible] +def specs.traits.modules.impl_arg.post + {T0 : Type} (abTInst : specs.traits.modules.a.b.T T0) (x : T0) + (res : Std.U32) : + RustM Bool + := do + ok (res < 10#u32) + +def + specs.traits.modules.impl_arg.spec {T0 : Type} (abTInst : + specs.traits.modules.a.b.T T0) (x : T0) + (abTInstLawful : specs.traits.modules.a.b.T.Lawful T0 abTInst) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.modules.impl_arg abTInst x + ⦃ ⇓ res => + ⌜ (specs.traits.modules.impl_arg.post abTInst x res).holds ⌝ ⦄ + /-- [hax_tests::specs::naming::lawful_binder::f::post]: Source: 'src/specs/naming.rs', lines 42:4-42:36 -/ @[reducible] @@ -2542,6 +2743,26 @@ def specs.naming.lawful_binder.f.spec {T : Type} (QuxInst : specs.naming.Qux T) ⦃ ⇓ res => ⌜ (specs.naming.lawful_binder.f.post QuxInst QuxInstLawful1 x res).holds ⌝ ⦄ +/-- [hax_tests::specs::traits::generic_impl::{hax_tests::specs::traits::generic_impl::Wrapper}::get::post]: + Source: 'src/specs/traits/generic_impl.rs', lines 70:4-70:31 -/ +@[reducible] +def specs.traits.generic_impl.Wrapper.get.post + {T : Type} (FooInst : specs.traits.generic_impl.Foo T) + (self_ : specs.traits.generic_impl.Wrapper T) (res : Std.U64) : + RustM Bool + := do + ok (res <= 10#u64) + +def + specs.traits.generic_impl.Wrapper.get.spec {T : Type} (FooInst : + specs.traits.generic_impl.Foo T) + (self : specs.traits.generic_impl.Wrapper T) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : Prop := + ⦃ ⌜ True ⌝ ⦄ + specs.traits.generic_impl.Wrapper.get FooInst self + ⦃ ⇓ res => + ⌜ (specs.traits.generic_impl.Wrapper.get.post FooInst self res).holds ⌝ ⦄ + /-- [hax_tests::specs::traits::impl_contract::{impl hax_tests::specs::traits::impl_contract::Foo for u32}::f::pre]: Source: 'src/specs/traits/impl_contract.rs', lines 14:4-14:28 -/ @[reducible] diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean index f80e022f34..9a90b39a4a 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Extraction/Types.lean @@ -108,7 +108,7 @@ structure specs.naming.Qux (Self : Type) where def specs.naming.lawful_impl_binder.Wrap (T : Type) := T /-- Trait declaration: [hax_tests::specs::naming::lawful_field::Sub] - Source: 'src/specs/naming.rs', lines 72:4-78:5 + Source: 'src/specs/naming.rs', lines 71:4-77:5 Visibility: public -/ structure specs.naming.lawful_field.Sub (Self : Type) (QuxInstLawful : Type) (g_spec : Type) where @@ -151,6 +151,12 @@ structure specs.traits.assoc_type_bounds.One where @[reducible] def specs.traits.assoc_type_bounds.Box1 (T : Type) := T +/-- Trait declaration: [hax_tests::specs::traits::assoc_type_bounds::Source] + Source: 'src/specs/traits/assoc_type_bounds.rs', lines 57:0-62:1 -/ +structure specs.traits.assoc_type_bounds.Source (Self : Type) (Self_Item : + Type) where + get : Self → RustM Self_Item + /-- Trait declaration: [hax_tests::specs::traits::basic::Foo] Source: 'src/specs/traits/basic.rs', lines 7:0-20:1 -/ structure specs.traits.basic.Foo (Self : Type) where @@ -185,6 +191,11 @@ def specs.traits.builtin_bound.One := Unit structure specs.traits.builtin_bound.W (T : Type) where x : T +/-- Trait declaration: [hax_tests::specs::traits::const_generics::Cg] + Source: 'src/specs/traits/const_generics.rs', lines 8:0-12:1 -/ +structure specs.traits.const_generics.Cg (Self : Type) (N : Std.Usize) where + f : Self → Std.Usize → RustM Std.Usize + /-- Trait declaration: [hax_tests::specs::traits::default_methods::D] Source: 'src/specs/traits/default_methods.rs', lines 7:0-15:1 -/ structure specs.traits.default_methods.D (Self : Type) where @@ -258,6 +269,23 @@ structure specs.traits.minimal.Foo (Self : Type) where g : Self → RustM Std.U32 h : Self → Std.U32 → RustM Std.U32 +/-- Trait declaration: [hax_tests::specs::traits::modules::a::b::T] + Source: 'src/specs/traits/modules.rs', lines 9:8-12:9 + Visibility: public -/ +structure specs.traits.modules.a.b.T (Self : Type) where + t : Self → RustM Std.U32 + +/-- [hax_tests::specs::traits::modules::c::S] + Source: 'src/specs/traits/modules.rs', lines 17:4-17:17 + Visibility: public -/ +@[reducible] +def specs.traits.modules.c.S := Unit + +/-- [hax_tests::specs::traits::modules::W] + Source: 'src/specs/traits/modules.rs', lines 33:0-33:15 -/ +@[reducible] +def specs.traits.modules.W (U : Type) := U + /-- Trait declaration: [hax_tests::specs::traits::mut_self::Counter] Source: 'src/specs/traits/mut_self.rs', lines 6:0-12:1 -/ structure specs.traits.mut_self.Counter (Self : Type) where @@ -384,7 +412,7 @@ structure specs.traits.synthesized.Sym2 (Self : Type) (Self_Clause0_X : Type) specs.traits.synthesized.K2 U Clause0_X), Std.U32 → RustM Std.U32 /-- Trait declaration: [hax_tests::specs::traits::trait_generics::Conv] - Source: 'src/specs/traits/trait_generics.rs', lines 6:0-9:1 -/ + Source: 'src/specs/traits/trait_generics.rs', lines 7:0-10:1 -/ structure specs.traits.trait_generics.Conv (Self : Type) (T : Type) where conv : Self → T → RustM Std.U32 diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean index dc6cfcf7f8..dbfdec840e 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/ProofObligations.lean @@ -11,11 +11,13 @@ import HaxTests.Verification.Traits.AssocTypeBounds import HaxTests.Verification.Traits.Basic import HaxTests.Verification.Traits.BlanketImpl import HaxTests.Verification.Traits.BuiltinBound +import HaxTests.Verification.Traits.ConstGenerics import HaxTests.Verification.Traits.DefaultMethods import HaxTests.Verification.Traits.Diamond import HaxTests.Verification.Traits.GenericImpl import HaxTests.Verification.Traits.ImplContract import HaxTests.Verification.Traits.MethodGenerics +import HaxTests.Verification.Traits.Modules import HaxTests.Verification.Traits.MutSelf import HaxTests.Verification.Traits.Supertraits import HaxTests.Verification.Traits.TraitGenerics diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean index e7223d5628..6224f89923 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/AssocTypeBounds.lean @@ -89,4 +89,25 @@ theorem -- `Bar.bar.post` and `first_bar.post` are both `ok (res < 10#u32)`: defeq mvcgen [h1, h2] +theorem + specs.traits.assoc_type_bounds.proj.spec.proof {S : Type} {Clause0_Item : + Type} (SourceInst : + specs.traits.assoc_type_bounds.Source + S Clause0_Item) (BarInst : + specs.traits.assoc_type_bounds.Bar + Clause0_Item) (s : S) + (SourceInstLawful : specs.traits.assoc_type_bounds.Source.Lawful S + Clause0_Item SourceInst) + (BarInstLawful : specs.traits.assoc_type_bounds.Bar.Lawful Clause0_Item + BarInst) : + specs.traits.assoc_type_bounds.proj.spec SourceInst BarInst s + SourceInstLawful BarInstLawful + := by + unfold specs.traits.assoc_type_bounds.proj.spec specs.traits.assoc_type_bounds.proj + /- The bound `S::Item: Bar` is a clause of `proj`, with its own Lawful + binder -/ + have h1 := SourceInstLawful.get_spec + have h2 := BarInstLawful.bar_spec + mvcgen [h1, h2] + end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ConstGenerics.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ConstGenerics.lean new file mode 100644 index 0000000000..7d37da56e8 --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/ConstGenerics.lean @@ -0,0 +1,76 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::const_generics`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4.Lawful : + specs.traits.const_generics.Cg.Lawful Std.U32 4#usize + U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4 + where + f_spec := by + intro self x hpre + mvcgen [U32.Insts.Hax_testsSpecsTraitsConst_genericsCg4.f] + simp [specs.traits.const_generics.Cg.f.pre, specs.traits.const_generics.Cg.f.post] at hpre ⊢ + scalar_tac + +theorem U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8.Lawful : + specs.traits.const_generics.Cg.Lawful Std.U32 8#usize + U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8 + where + f_spec := by + intro self x hpre + simp [specs.traits.const_generics.Cg.f.pre] at hpre + mvcgen [U32.Insts.Hax_testsSpecsTraitsConst_genericsCg8.f] + · simp [specs.traits.const_generics.Cg.f.post] + scalar_tac + · -- no overflow: `x < 8` + scalar_tac + +theorem ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg.Lawful (N : + Std.Usize) : + specs.traits.const_generics.Cg.Lawful (Array Std.U32 N) N + (ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg N) + where + f_spec := by + intro self x _ + mvcgen [ArrayU32N.Insts.Hax_testsSpecsTraitsConst_genericsCg.f] + simp [specs.traits.const_generics.Cg.f.post] + +theorem + specs.traits.const_generics.use_cg.spec.proof {T : Type} (CgT4Inst : + specs.traits.const_generics.Cg T + 4#usize) (t : T) (x : Std.Usize) + (CgT4InstLawful : specs.traits.const_generics.Cg.Lawful T 4#usize CgT4Inst) : + specs.traits.const_generics.use_cg.spec CgT4Inst t x CgT4InstLawful + := by + unfold specs.traits.const_generics.use_cg.spec specs.traits.const_generics.use_cg + /- The conditions of `use_cg` are those of `f` at `N := 4` -/ + exact CgT4InstLawful.f_spec t x + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean index 7f8ca11492..e8b2601b95 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/GenericImpl.lean @@ -126,4 +126,30 @@ theorem simp [hfy] at * agrind +theorem + specs.traits.generic_impl.Wrapper.get.spec.proof {T : Type} (FooInst : + specs.traits.generic_impl.Foo + T) + (self : specs.traits.generic_impl.Wrapper T) + (FooInstLawful : specs.traits.generic_impl.Foo.Lawful T FooInst) : + specs.traits.generic_impl.Wrapper.get.spec FooInst self FooInstLawful + := by + unfold specs.traits.generic_impl.Wrapper.get.spec specs.traits.generic_impl.Wrapper.get + -- The clause of the `impl` block comes with its Lawful binder + have h := FooInstLawful.f_spec + mvcgen [h] + +theorem Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.Lawful : + specs.traits.generic_impl.Foo.Lawful Std.U64 + Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo + where + f_spec := by + intro self _ + mvcgen [Shared0U64.Insts.Hax_testsSpecsTraitsGeneric_implFoo.f] + rename_i r hr + simp only [specs.traits.generic_impl.Foo.f.post] + have : self.val % 11 < 11 := Nat.mod_lt _ (by decide) + simp [hr] + scalar_tac + end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Modules.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Modules.lean new file mode 100644 index 0000000000..3a2bd2e93d --- /dev/null +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/Modules.lean @@ -0,0 +1,58 @@ +-- Handwritten proofs of the obligations of `Extraction/ProofObligations.lean`. +-- Covers the test module `hax_tests::specs::traits::modules`. +import Aeneas +import CoreModels +import HaxTests.Extraction.Types +import HaxTests.Extraction.Funs +import HaxTests.Extraction.Specs +import HaxTests.Verification.Lemmas +open CoreModels Aeneas +open Aeneas.Std hiding namespace core alloc +open RustM ControlFlow Error +open Std.Do +set_option linter.dupNamespace false +set_option linter.hashCommand false +set_option linter.unusedVariables false +set_option linter.style.whitespace false +set_option linter.style.setOption false +set_option linter.style.longLine false +set_option mvcgen.warning false + +/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/ +set_option maxHeartbeats 1000000 + +/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/ +set_option maxRecDepth 2048 + +/- You can remove the following line by using the CLI option `-all-computable`: -/ +noncomputable section + +namespace hax_tests + +theorem specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT.Lawful : + specs.traits.modules.a.b.T.Lawful specs.traits.modules.c.S + specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT + where + t_spec := by + intro self _ + mvcgen [specs.traits.modules.c.S.Insts.Hax_testsSpecsTraitsModulesABT.t] + +theorem specs.traits.modules.W.Insts.Hax_testsSpecsTraitsModulesABT.Lawful {U : + Type} (abTInst : specs.traits.modules.a.b.T U) + (abTInstLawful : specs.traits.modules.a.b.T.Lawful U abTInst) : + specs.traits.modules.a.b.T.Lawful (specs.traits.modules.W U) + (specs.traits.modules.W.Insts.Hax_testsSpecsTraitsModulesABT abTInst) + where + t_spec self hpre := abTInstLawful.t_spec self hpre + +theorem + specs.traits.modules.impl_arg.spec.proof {T0 : Type} (abTInst : + specs.traits.modules.a.b.T T0) + (x : T0) (abTInstLawful : specs.traits.modules.a.b.T.Lawful T0 abTInst) : + specs.traits.modules.impl_arg.spec abTInst x abTInstLawful + := by + unfold specs.traits.modules.impl_arg.spec specs.traits.modules.impl_arg + have h := abTInstLawful.t_spec + mvcgen [h] + +end hax_tests diff --git a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean index 9993581f25..e77f0d0647 100644 --- a/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean +++ b/tests/hax/proofs/hax-tests/lean/HaxTests/Verification/Traits/TraitGenerics.lean @@ -51,4 +51,39 @@ theorem have hc := ConvCU8InstLawful.conv_spec mvcgen [hc] +theorem U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16.Lawful : + specs.traits.trait_generics.Conv.Lawful Std.U32 Std.U16 + U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16 + where + conv_spec := by + intro self t _ + mvcgen [U32.Insts.Hax_testsSpecsTraitsTrait_genericsConvU16.conv] + +theorem + specs.traits.trait_generics.use_both.spec.proof {C : Type} (ConvCU8Inst : + specs.traits.trait_generics.Conv + C Std.U8) (ConvCU16Inst : + specs.traits.trait_generics.Conv + C Std.U16) (c : C) + (ConvCU8InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U8 + ConvCU8Inst) + (ConvCU16InstLawful : specs.traits.trait_generics.Conv.Lawful C Std.U16 + ConvCU16Inst) : + specs.traits.trait_generics.use_both.spec ConvCU8Inst ConvCU16Inst c + ConvCU8InstLawful ConvCU16InstLawful + := by + unfold specs.traits.trait_generics.use_both.spec + specs.traits.trait_generics.use_both + -- One Lawful binder per argument of `Conv` + have h8 := ConvCU8InstLawful.conv_spec + have h16 := ConvCU16InstLawful.conv_spec + mvcgen [h8, h16] + · -- both results are `< 10` + simp [specs.traits.trait_generics.Conv.conv.post, + specs.traits.trait_generics.use_both.post] at * + agrind + · -- no overflow + simp [specs.traits.trait_generics.Conv.conv.post] at * + agrind + end hax_tests diff --git a/tests/hax/src/specs/naming.rs b/tests/hax/src/specs/naming.rs index 67551dfaf1..60371143db 100644 --- a/tests/hax/src/specs/naming.rs +++ b/tests/hax/src/specs/naming.rs @@ -66,7 +66,6 @@ pub mod lawful_impl_binder { pub mod lawful_field { #![allow(non_camel_case_types)] use super::Qux; - use hax_lib::*; #[hax_lib::attributes] pub trait Sub: Qux { diff --git a/tests/hax/src/specs/traits.rs b/tests/hax/src/specs/traits.rs index 1658734745..8c1eb8f694 100644 --- a/tests/hax/src/specs/traits.rs +++ b/tests/hax/src/specs/traits.rs @@ -15,3 +15,5 @@ mod impl_contract; mod trait_generics; mod synthesized; mod assoc_consts; +mod const_generics; +mod modules; diff --git a/tests/hax/src/specs/traits/assoc_type_bounds.rs b/tests/hax/src/specs/traits/assoc_type_bounds.rs index 9ffd7c3d02..003f76941e 100644 --- a/tests/hax/src/specs/traits/assoc_type_bounds.rs +++ b/tests/hax/src/specs/traits/assoc_type_bounds.rs @@ -51,3 +51,21 @@ impl Container for Box1 { fn first_bar(c: &C) -> u32 { c.first().bar() } + +// `get` is annotated so that its Lawful field says it doesn't fail +#[hax_lib::attributes] +trait Source { + type Item; + + #[ensures(|_| true)] + fn get(&self) -> Self::Item; +} + +// A bound on an associated type in a `where` clause +#[ensures(|res| res < 10)] +fn proj(s: &S) -> u32 +where + S::Item: Bar, +{ + s.get().bar() +} diff --git a/tests/hax/src/specs/traits/const_generics.rs b/tests/hax/src/specs/traits/const_generics.rs new file mode 100644 index 0000000000..7af8793bf8 --- /dev/null +++ b/tests/hax/src/specs/traits/const_generics.rs @@ -0,0 +1,36 @@ +// A trait with a const generic parameter used in its conditions, two impls +// at different values for the same type, a generic caller at a fixed value, +// and a blanket impl over arrays whose length is the parameter. + +use hax_lib::*; + +#[hax_lib::attributes] +trait Cg { + #[requires(x < N)] + #[ensures(|res| res <= N)] + fn f(&self, x: usize) -> usize; +} + +impl Cg<4> for u32 { + fn f(&self, x: usize) -> usize { + x + } +} + +impl Cg<8> for u32 { + fn f(&self, x: usize) -> usize { + x + 1 + } +} + +impl Cg for [u32; N] { + fn f(&self, _x: usize) -> usize { + N + } +} + +#[requires(x < 4)] +#[ensures(|res| res <= 4)] +fn use_cg>(t: &T, x: usize) -> usize { + t.f(x) +} diff --git a/tests/hax/src/specs/traits/generic_impl.rs b/tests/hax/src/specs/traits/generic_impl.rs index cf44dc11ce..ab556ac659 100644 --- a/tests/hax/src/specs/traits/generic_impl.rs +++ b/tests/hax/src/specs/traits/generic_impl.rs @@ -63,3 +63,19 @@ impl Sub for Single { fn k(x: &T, y: &U) -> u64 { x.f() + y.s() } + +// An inherent method whose `impl` block has a clause on the annotated trait +#[hax_lib::attributes] +impl Wrapper { + #[ensures(|res| res <= 10)] + fn get(&self) -> u64 { + self.inner.f() + } +} + +// An impl for a reference type +impl Foo for &u64 { + fn f(&self) -> u64 { + **self % 11 + } +} diff --git a/tests/hax/src/specs/traits/modules.rs b/tests/hax/src/specs/traits/modules.rs new file mode 100644 index 0000000000..c4cde58a9c --- /dev/null +++ b/tests/hax/src/specs/traits/modules.rs @@ -0,0 +1,43 @@ +// A trait declared in a nested module and implemented from another module, +// an `impl Trait` argument, and an impl with a `where` clause. + +use hax_lib::*; + +mod a { + pub mod b { + #[hax_lib::attributes] + pub trait T { + #[ensures(|res| res < 10)] + fn t(&self) -> u32; + } + } +} + +mod c { + pub struct S; + + // An impl from another module + impl super::a::b::T for S { + fn t(&self) -> u32 { + 0 + } + } +} + +// `impl Trait` argument: an anonymous type parameter with a clause +#[ensures(|res| res < 10)] +fn impl_arg(x: impl a::b::T) -> u32 { + x.t() +} + +struct W(U); + +// The clause of the impl is in a `where` clause +impl a::b::T for W +where + U: a::b::T, +{ + fn t(&self) -> u32 { + self.0.t() + } +} diff --git a/tests/hax/src/specs/traits/trait_generics.rs b/tests/hax/src/specs/traits/trait_generics.rs index 5ad961c7c3..f3f8f00bdc 100644 --- a/tests/hax/src/specs/traits/trait_generics.rs +++ b/tests/hax/src/specs/traits/trait_generics.rs @@ -1,4 +1,5 @@ -// A trait with a generic parameter, a concrete impl and a generic caller. +// A trait with a generic parameter, two impls for the same type at different +// arguments, and generic callers bounded by one or both. use hax_lib::*; @@ -18,3 +19,15 @@ impl Conv for u32 { fn use_conv>(c: &C) -> u32 { c.conv(0) } + +impl Conv for u32 { + fn conv(&self, _t: u16) -> u32 { + 1 + } +} + +// Two clauses on the same trait at different arguments +#[ensures(|res| res < 20)] +fn use_both + Conv>(c: &C) -> u32 { + c.conv(0u8) + c.conv(0u16) +} diff --git a/tests/src/hax-specs-no-core-models-lib.lean.out b/tests/src/hax-specs-no-core-models-lib.lean.out new file mode 100644 index 0000000000..155c223300 --- /dev/null +++ b/tests/src/hax-specs-no-core-models-lib.lean.out @@ -0,0 +1 @@ +[Error] The -specs hax option requires the -core-models-lib option diff --git a/tests/src/hax-specs-no-core-models-lib.rs b/tests/src/hax-specs-no-core-models-lib.rs new file mode 100644 index 0000000000..90f449de86 --- /dev/null +++ b/tests/src/hax-specs-no-core-models-lib.rs @@ -0,0 +1,7 @@ +//@ [lean] known-failure +//@ [!lean] skip +//@ [lean] aeneas-args=-specs hax +//! `-specs hax` requires `-core-models-lib`: the generated specs refer to the +//! `CoreModels` library. + +pub fn f() {} From 4aefccc867beefe0e90b2e16279134bf8592e2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Blaudeau?= Date: Fri, 23 Oct 2026 14:59:40 +0000 Subject: [PATCH 17/17] docs: align hax-specs with the current behaviour --- documentation/hax-specs.md | 122 ++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 29 deletions(-) diff --git a/documentation/hax-specs.md b/documentation/hax-specs.md index a93ae62d9f..c828f7c8cb 100644 --- a/documentation/hax-specs.md +++ b/documentation/hax-specs.md @@ -2,22 +2,26 @@ ## High-level documentation -When Aeneas is invoked with `-specs hax` (Lean backend only) it reads the -contracts written with [`hax_lib`](https://github.com/cryspen/hax) annotations -in the Rust code and emits them as Lean statements of correctness, together with -the proof obligations stating that the code meets them. +When Aeneas is invoked with `-specs hax` (Lean backend only, together with +`-core-models-lib`) it reads the contracts written with +[`hax_lib`](https://github.com/cryspen/hax) annotations in the Rust code and +emits them as Lean statements of correctness, together with the proof +obligations stating that the code meets them. ### Overview There are several kinds of rust-written specs: * *Function level specs*: `#[requires(..)]` / `#[ensures(\|res\|..)]` on a - function. Those generate specification functions`.pre`, `.post`, a + function. Those generate specification functions `.pre`, `.post`, a statement of correctness `.spec`, and the obligation `.spec.proof` -* *Trait level specs*: every trait gets a *companion* structure `.Lawful` - that registers the specifications attached to methods and constants. Every - implementation generates a corresponding obligation of lawfulness. - * If no annotation is written, the companion structure is empty. +* *Trait level specs*: every local trait gets a *companion* structure + `.Lawful` that registers the specifications attached to its methods. + Every local implementation, including derived impls and the impls of foreign + traits (e.g. `Clone`, or the `Fn*` impls of closures), generates a + corresponding obligation of lawfulness. + * If no annotation is written, the companion structure has no method field + (the parent fields remain). * `#[requires(..)]` / `#[ensures(\|res\|..)]` on the methods of trait generate specification functions `..pre`, `..post`, and add a field `_spec` to the companion structure `.Lawful`. @@ -101,7 +105,7 @@ trait B: A { fn b(&self) -> usize; } -impl B for Foo { ... } +impl B for u8 { ... } ``` ```lean @@ -124,12 +128,15 @@ structure B.Lawful ```lean -- ProofObligations.lean -theorem Foo.Insts.BLawful : specs.traits.supertraits.B.Lawful U32 := by sorry +theorem U8.Insts.Hax_testsSpecsTraitsSupertraitsB.Lawful : + specs.traits.supertraits.B.Lawful Std.U8 + U8.Insts.Hax_testsSpecsTraitsSupertraitsB + := by sorry ``` -One lawful instances per parent clause `

InstLawful : P.Lawful … +One Lawful field per parent clause `

InstLawful : P.Lawful … Inst.

Inst`, one spec per annotated method `_spec`. A trait with no -annotated method and no parent still gets an empty structure. Each +annotated method and no parent still gets an empty structure. Each local implementation gets a corresponding proof obligation. #### Foreign traits @@ -143,9 +150,11 @@ following the same conventions. ### Diagnostics -All messages start with `hax-specs:`. Warnings marked *(span)* point at the Rust -source when it is known and become errors with `-warnings-as-errors`; the others -are logged at warning level. +The warnings below start with `hax-specs:`. Those marked *(span)* point at the +Rust source when it is known; with `-warnings-as-errors` they become errors: +the item is still dropped and the extraction continues, but Aeneas exits with +code 1. The others are logged at warning level (shown by `cargo hax extract +-v`). * ``multiple #[requires] on `f`; ignoring extras`` (or `#[ensures]`) : More than one condition of a kind on an item: the first one is used. @@ -154,9 +163,19 @@ are logged at warning level. * ``argument count mismatch for `f.pre` (takes N, expected M); dropping this condition`` : The condition does not take the arguments of the function (plus the result, for a post). -* ``dropping the contract of trait method `m`: its #[requires] is invalid`` (or - `#[ensures]`) *(span)* : A condition of a trait method was dropped: the whole - method contract is dropped. +* ``dropping the contract of trait method `m`: `` *(span)* : the whole + contract of the trait method is dropped (its `_spec` field is not + generated). The reasons: + * `its #[requires] is invalid` (or `#[ensures]`): one of its conditions was + dropped (see above); + * `the generics of its conditions don't match those of the trait and the + method`: only `#[requires]` is written, and the postcondition cannot be + synthesized (see [Limitations](#limitations)); + * `trait instances in its output type are not supported yet`: only + `#[requires]` is written, and the output type of the method mentions a trait + instance; + * `a missing condition could not be synthesized`: an error was reported while + synthesizing it. * ``the contract of `m` is checked as a standalone spec only; it is independent of the trait-level contract`` Contract on a method of a trait impl. * ``dropping the hax decoration `d`: it is attached to no translated item`` @@ -165,9 +184,20 @@ are logged at warning level. of a dropped contract`` A decoration that was not used (e.g. `decreases`, an extra or dropped condition). * ``dropping the contract of function `f`: the function was not translated`` - *(span)* The annotated function failed to translate. Same for a trait (``the - contract of trait `X` ``) and a trait impl (``the Lawful obligation of trait - impl `I` ``). + *(span)* The annotated function failed to translate. Same for a trait + (``dropping the contract of trait `X`: the trait was not translated``) and a + trait impl (``dropping the Lawful obligation of trait impl `I`: the trait impl + was not translated``). +* ``dropping the Lawful obligation of an impl of trait `X`: the trait was not + translated`` *(span)* The impl was translated, but not the trait it + implements. + +If a spec or an obligation fails to extract, the error is reported and only that +entry is skipped (its output may be partial, and the following entries may be +mis-indented); Aeneas exits with code 1. + +Command-line errors: `The -specs option is valid only for the Lean backend`, +and `The -specs hax option requires the -core-models-lib option`. Name clashes between the generated names (`.pre`, `.post`, `.spec`, `.spec.proof`, `.Lawful`) and the names of the crate items are errors (`Name @@ -181,7 +211,7 @@ is fine). - **No `@[spec]` registration.** The obligations are plain theorems: `mvcgen` does not use them automatically. A caller unfolds the callee's `.spec` or passes the theorem explicitly (see below). -- **Impl-level contracts**: see [Inputs](#inputs). +- **Impl-level contracts**: see [Overview](#overview). - **`ProofObligations.lean` is a template**: every proof is `sorry`, and it is overwritten on each extraction. Copy the obligations to a handwritten file to prove them. Nothing checks the copy against the template: after a @@ -191,12 +221,46 @@ is fine). (`BuiltinOrAuto`, e.g. `Clone` for a tuple) is printed as `BuiltinClone …`, not as a `CoreModels` instance, so no `Lawful` theorem exists for it (e.g. to fill the `Clone` parent field of an impl of `Dup: Clone` for a tuple). -- **Dropped trait-method contracts** (with a warning, see - [Diagnostics](#diagnostics)): when the generics of the conditions match those - of the trait and the method ambiguously (e.g. a supertrait with an associated - type, plus several method type parameters with the same bound that no input - distinguishes), and when a postcondition must be synthesized for a method - whose output type mentions a trait instance. +- **Trait methods and associated types.** Charon lifts the associated types of + a trait to type parameters, but not the same way in the trait and in the + decoration functions of its conditions: once per clause path in the latter + (`Clause0_Item`, `Clause1_Clause0_Item`, …), and after the type parameters of + the method. Aeneas maps the generics of the conditions to those of the trait + and the method by position, so: + - the contract is dropped with a warning (`the generics of its conditions + don't match those of the trait and the method`) when only `#[requires]` is + written and a supertrait has an associated type (e.g. `trait SubAssoc: + Assoc`, or `trait Call: CallOnce` with `type Output` in + `CallOnce`); + - extraction fails (exit code 1, partial `.Lawful`) when `#[ensures]` + is written (with or without `#[requires]`) and a supertrait has an + associated type (``Internal error: the generics of the condition `…` don't + match those it is applied to``), or when the trait has an associated type and the method a type + parameter (`Could not find an instance for a trait clause of a pre/post + condition`). + + The cases are in `tests/hax/src/specs/traits/synthesized.rs` (the failing + ones are commented out). +- **Compile with `--cfg hax_backend_lean`.** `cargo hax` sets it. Without it, + `hax_lib` encodes the decoration functions for hax's legacy engine: the + future values of `&mut` arguments come before the result in a postcondition + (Aeneas expects them after it), and a function without arguments gets + conditions with a unit argument. The second is detected: Aeneas drops these + conditions (e.g. ``argument count mismatch for `f.pre` (takes 1, expected 0); + dropping this condition``). The first is not: the postcondition may silently + refer to the wrong values. +- **Associated constants** are not covered by `.Lawful`: nothing says + that reading one does not fail, so the spec of a generic function that reads + `T::C` outside of its conditions may not be provable. +- **Recursive associated-type bounds** (`type Item: Foo` in `trait Foo`) are + not supported: Charon cannot lift them, and Lean rejects the generated trait + structure. +- **`dyn Trait`** is out of scope: a `dyn Trait` argument gets no Lawful + hypothesis in the spec of the function (and Aeneas does not translate calls + through `dyn` yet). +- **Mutually recursive methods** of an impl need one joint proof: the + obligation is a single `.Lawful` theorem, so prove the methods together + in a separate lemma and use it for each field. ### Proving the obligations