This document shows electrolysis's current coverage of the Rust Reference by testing the translation of code examples (taken from the Reference or made up on the spot). Some sections have been added on top of the Reference to display details and edge cases.
A ✔ means the translated Lean code type checks, whereas a ✗ marks unimplemented language features. A few examples also come with example Lean proofs that are also checked automatically and give greater assurance of semantics preservation.
Well, that's what MIR is for.
Skeleton code that surrounds each transpilation, which will be hidden in all further examples. The crate name ('test' in these examples) becomes the root namespace.
Files inside a crate may freely reference items between them. On the other hand, Lean files may only import other files non-recursively and declarations must be strictly sorted in order of usage for termination checking. We therefore translate a crate into a single Lean file and perform a topological sort on its items.
// this file intentionally left blank
import core.generated noncomputable theory open bool open [class] classical open [notation] function open [class] int open [notation] list open [class] nat open [notation] prod.ops open [notation] unit
Modules are translated to namespaces. extern crate
and use
directives are ignored, instead external theories are imported when some item of them is used.
mod foo { use std::cmp::Ordering; struct Bar(Ordering); }
inductive test.foo.Bar := mk {} : (core.cmp.Ordering) → test.foo.Bar
Rust fn
s are translated to curried definitions. The return type is wrapped in a semantics monad, which in the simplest case is option
for modelling nontermination. The proofs unwrap it using sem.terminates_with h x
, which asserts that x
terminates and that the predicate h
holds on the return value.
fn add(x: i32, y: i32) -> i32 { x + y } fn first((value, _): (i32, i32)) -> i32 { value }
fn first(_1: (i32, i32)) -> i32 { let mut _0: i32; // return pointer scope 1 { let _2: i32; // "value" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:11: 5:16 } let mut _3: i32; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:11: 5:16 _2 = (_1.0: i32); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:11: 5:16 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:43: 5:48 _3 = _2; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:43: 5:48 _0 = _3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:43: 5:48 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:50: 5:50 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:50: 5:50 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:5:50: 5:50 } } fn add(_1: i32, _2: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:1:8: 1:9 let _4: i32; // "y" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:1:16: 1:17 } let mut _5: i32; let mut _6: i32; let mut _7: (i32, bool); bb0: { StorageLive(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:1:8: 1:9 _3 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:1:8: 1:9 StorageLive(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:1:16: 1:17 _4 = _2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:1:16: 1:17 StorageLive(_5); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:2:5: 2:6 _5 = _3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:2:5: 2:6 StorageLive(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:2:9: 2:10 _6 = _4; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:2:9: 2:10 _7 = CheckedAdd(_5, _6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:2:5: 2:10 assert(!(_7.1: bool), "attempt to add with overflow") -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:2:5: 2:10 } bb1: { _0 = (_7.0: i32); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:2:5: 2:10 StorageDead(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:3:2: 3:2 StorageDead(_5); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:3:2: 3:2 StorageDead(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:3:2: 3:2 StorageDead(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:3:2: 3:2 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/lib.rs:3:2: 3:2 } }
definition test.add (xₐ : i32) (yₐ : i32) : sem (i32) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t5 ← «x$3»; let' t6 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits t5 t6); let' t7 ← «$tmp0»; let' ret ← t7.1; return (ret) definition test.first («$a1» : (i32 × i32)) : sem (i32) := let' «value$2» ← «$a1».1; let' t3 ← «value$2»; let' ret ← t3; return (ret)
example (x y : i32) [is_i32 (x + y)] : sem.terminates_with (λ sum, x + y = sum) (test.add x y) := by rewrite [↑test.add, if_pos `is_i32 (x + y)`, ▸*] example (x y : i32) : sem.terminates_with (λ z, z = x) (test.first (x, y)) := rfl
fn foo<A, B>(x: A, y: B) {}
fn foo(_1: A, _2: B) -> () { let mut _0: (); // return pointer scope 1 { let _3: A; // "x" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:14: 1:15 let _4: B; // "y" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:20: 1:21 } let mut _5: (); bb0: { StorageLive(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:14: 1:15 _3 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:14: 1:15 StorageLive(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:20: 1:21 _4 = _2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:20: 1:21 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:26: 1:28 drop(_2) -> [return: bb5, unwind: bb4]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } bb1: { resume; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:1: 1:28 } bb2: { drop(_3) -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } bb3: { drop(_1) -> bb2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } bb4: { drop(_4) -> bb3; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } bb5: { drop(_4) -> [return: bb6, unwind: bb3]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } bb6: { StorageDead(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 drop(_1) -> [return: bb7, unwind: bb2]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } bb7: { drop(_3) -> bb8; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } bb8: { StorageDead(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/1/lib.rs:1:28: 1:28 } }
definition test.foo {A : Type₁} {B : Type₁} (xₐ : A) (yₐ : B) : sem (unit) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' ret ← ⋆; return (⋆)
fn foo<T>(x: &[T]) where T: Default {} fn main() { foo(&[1, 2]); }
fn main() -> () { let mut _0: (); // return pointer let mut _1: (); let mut _2: &[i32]; let mut _3: &[i32; 2]; let mut _4: &[i32; 2]; let mut _5: [i32; 2]; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 StorageLive(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 StorageLive(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 _4 = promoted0; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 _3 = &(*_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 _2 = _3 as &[i32] (Unsize); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 _1 = foo::<i32>(_2) -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:13: 3:25 } bb1: { StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:26: 3:26 StorageDead(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:26: 3:26 StorageDead(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:26: 3:26 _0 = (); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:11: 3:28 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:28: 3:28 } } promoted0 in main: &[i32; 2] = { let mut _0: &[i32; 2]; // return pointer let mut _1: [i32; 2]; bb0: { _1 = [const 1i32, const 2i32]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:18: 3:24 _0 = &_1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:3:17: 3:24 } } fn foo(_1: &[T]) -> () { let mut _0: (); // return pointer scope 1 { let _2: &[T]; // "x" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:1:11: 1:12 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:1:11: 1:12 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:1:11: 1:12 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:1:37: 1:39 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:1:39: 1:39 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.1 Generic functions/2/lib.rs:1:39: 1:39 } }
definition test.foo {T : Type₁} [«core.default.Default T» : core.default.Default T] (xₐ : (slice T)) : sem (unit) := let' «x$2» ← xₐ; let' ret ← ⋆; return (⋆) definition test.main : sem (unit) := do promoted_0 ← let' t1 ← [(1 : int), (2 : int)]; let' ret ← t1; return (ret) ; let' t4 ← promoted_0; let' t3 ← t4; let' t2 ← t3; dostep «$tmp» ← @test.foo i32 (@core.«i32 as core.default.Default») t2; let' t1 ← «$tmp»; let' ret ← ⋆; return (⋆)
Divergence is represented as MonadZero.mzero
(in the simplest case, none
). Because MIR distinguishes between normal and divergent control flow, calls to diverging functions are eagerly replaced by mzero
(which of course only works because of the absence of side effects).
fn my_err(s: &str) -> ! { //println!("{}", s); panic!(); } fn f(i: i32) -> i32 { if i == 42 { return 42; } else { my_err("Bad number!"); } }
static my_err::_FILE_LINE: (&'static str, u32) = { let mut _0: (&'static str, u32); // return pointer bb0: { _0 = (const "ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs", const 3u32); // scope 0 at <panic macros>:5:47: 5:76 return; // scope 0 at <panic macros>:5:1: 5:78 } } fn my_err(_1: &str) -> ! { let mut _0: !; // return pointer scope 1 { let _2: &str; // "s" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:1:11: 1:12 } let mut _3: (); let mut _4: !; let mut _5: &(&'static str, u32); let mut _6: &(&'static str, u32); bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:1:11: 1:12 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:1:11: 1:12 StorageLive(_4); // scope 1 at <panic macros>:3:1: 6:17 StorageLive(_5); // scope 1 at <panic macros>:4:9: 6:15 StorageLive(_6); // scope 1 at <panic macros>:6:1: 6:13 _6 = &my_err::_FILE_LINE; // scope 1 at <panic macros>:6:1: 6:13 _5 = &(*_6); // scope 1 at <panic macros>:6:1: 6:13 std::rt::begin_panic::<&'static str>(const "explicit panic", _5); // scope 1 at <panic macros>:3:1: 6:17 } } fn f(_1: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let _2: i32; // "i" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:6:6: 6:7 } let mut _3: bool; let mut _4: i32; let mut _5: (); let mut _6: !; let mut _7: (); let mut _8: (); let mut _9: !; let mut _10: &str; let mut _11: &'static str; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:6:6: 6:7 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:6:6: 6:7 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:7:8: 7:15 StorageLive(_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:7:8: 7:9 _4 = _2; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:7:8: 7:9 _3 = Eq(_4, const 42i32); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:7:8: 7:15 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:7:15: 7:15 StorageDead(_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:7:15: 7:15 if(_3) -> [true: bb1, false: bb2]; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:7:5: 12:6 } bb1: { StorageLive(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:8:9: 8:18 _0 = const 42i32; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:8:16: 8:18 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:13:2: 13:2 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:13:2: 13:2 } bb2: { StorageLive(_9); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:11:9: 11:30 StorageLive(_10); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:11:16: 11:29 StorageLive(_11); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:11:16: 11:29 _11 = const "Bad number!"; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:11:16: 11:29 _10 = &(*_11); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:11:16: 11:29 my_err(_10); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs:11:9: 11:30 } }
definition test.my_err.«$_FILE_LINE» : sem (string × u32) := let' ret ← ("ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/6.1.3.2 Diverging functions/lib.rs", (3 : nat)); return (ret) definition test.my_err (sₐ : string) : sem (empty) := let' «s$2» ← sₐ; let' t6 ← test.my_err.«$_FILE_LINE»; let' t5 ← t6; mzero definition test.f (iₐ : i32) : sem (i32) := let' «i$2» ← iₐ; let' t4 ← «i$2»; let' t3 ← t4 =ᵇ (42 : int); if t3 = bool.tt then let' ret ← (42 : int); return (ret) else let' t11 ← "Bad number!"; let' t10 ← t11; mzero
For now, we assume that mutable reference return values will always point into the first argument. Then the return value can be represented as a lens on that argument. We immediately probe the new lens in order to catch out-of-bounds borrows eagerly.
fn foo(xs: &mut [i32]) -> &mut i32 { &mut xs[0] }
fn foo(_1: &mut [i32]) -> &mut i32 { let mut _0: &mut i32; // return pointer scope 1 { let _2: &mut [i32]; // "xs" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:1:8: 1:10 } let mut _3: &mut i32; let mut _4: &mut i32; let mut _5: usize; let mut _6: bool; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:1:8: 1:10 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:1:8: 1:10 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:1:36: 3:2 StorageLive(_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:2:5: 2:15 _5 = Len((*_2)); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:2:10: 2:15 _6 = Lt(const 0usize, _5); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:2:10: 2:15 assert(_6, "index out of bounds: the len is {} but the index is {}", _5, const 0usize) -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:2:10: 2:15 } bb1: { _4 = &mut (*_2)[const 0usize]; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:2:5: 2:15 _3 = &mut (*_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:2:5: 2:15 _0 = &mut (*_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:1:36: 3:2 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:3:2: 3:2 StorageDead(_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:3:2: 3:2 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:3:2: 3:2 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/7 Returning mutable reference to first argument./lib.rs:3:2: 3:2 } }
definition test.foo (xsₐ : (slice i32)) : sem ((lens (slice i32) i32) × (slice i32)) := let' «xs$2» ← @lens.id (slice i32); do «$tmp0» ← do «$tmp0» ← lens.get «xs$2» xsₐ; return (list.length «$tmp0»); let' t5 ← «$tmp0»; let' t6 ← (0 : nat) <ᵇ t5; let' t4 ← (lens.index _ (0 : nat) ∘ₗ «xs$2»); do «$tmp» ← lens.get t4 xsₐ; let' t3 ← (t4); do «$tmp» ← lens.get t3 xsₐ; let' ret ← (t3); do «$tmp» ← lens.get ret xsₐ; return (ret, xsₐ)
example (x y : i32) : sem.terminates_with (λ r, lens.get r.1 [x, y] = return x) (test.foo [x, y]) := rfl
In general, we would have to return a sum type of lenses that represents which argument the return value points into. The callee would then match on the sum and combine the return value with the corresponding argument lens.
fn foo<'a>(x: &'a mut i32, y: &'a mut i32) -> &'a mut i32 { if *x > 0 { x } else { y } }
fn foo(_1: &'a mut i32, _2: &'a mut i32) -> &'a mut i32 { let mut _0: &'a mut i32; // return pointer scope 1 { let _3: &'a mut i32; // "x" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:12: 1:13 let _4: &'a mut i32; // "y" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:28: 1:29 } let mut _5: &'a mut i32; let mut _6: &'a mut i32; let mut _7: bool; let mut _8: i32; let mut _9: &'a mut i32; bb0: { StorageLive(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:12: 1:13 _3 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:12: 1:13 StorageLive(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:28: 1:29 _4 = _2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:28: 1:29 StorageLive(_5); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:59: 3:2 StorageLive(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:5: 2:31 StorageLive(_7); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:8: 2:14 StorageLive(_8); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:8: 2:10 _8 = (*_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:8: 2:10 _7 = Gt(_8, const 0i32); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:8: 2:14 StorageDead(_7); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:14: 2:14 StorageDead(_8); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:14: 2:14 if(_7) -> [true: bb1, false: bb2]; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:5: 2:31 } bb1: { _6 = &mut (*_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:17: 2:18 goto -> bb3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:5: 2:31 } bb2: { StorageLive(_9); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:26: 2:31 _9 = &mut (*_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:28: 2:29 _6 = &mut (*_9); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:26: 2:31 StorageDead(_9); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:31: 2:31 goto -> bb3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:5: 2:31 } bb3: { _5 = &mut (*_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:2:5: 2:31 _0 = &mut (*_5); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:1:59: 3:2 StorageDead(_5); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:3:2: 3:2 StorageDead(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:3:2: 3:2 StorageDead(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:3:2: 3:2 StorageDead(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:3:2: 3:2 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.3 Functions/8 Returning arbitrary mutable references./lib.rs:3:2: 3:2 } }
/- test.foo: unimplemented: returning mutable reference to argument other than the first -/
type Point = (u8, u8); const p: Point = (41, 68);
const p: (u8, u8) = { let mut _0: (u8, u8); // return pointer bb0: { _0 = (const 41u8, const 68u8); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.4 Type aliases/lib.rs:2:18: 2:26 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.4 Type aliases/lib.rs:2:1: 2:27 } }
definition test.Point := (u8 × u8) definition test.p : sem (u8 × u8) := let' ret ← ((41 : nat), (68 : nat)); return (ret)
While MIR prevents us from having to support three different loop constructs, it doesn't help with having to support three different struct constructs.
struct Point {x: i32, y: i32} fn main() { let p = Point {x: 10, y: 11}; let px: i32 = p.x; }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: Point; // "p" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:4:9: 4:10 scope 2 { let _2: i32; // "px" in scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:5:9: 5:11 } } let mut _3: i32; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:4:9: 4:10 _1 = Point { x: const 10i32, y: const 11i32 }; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:4:13: 4:33 StorageLive(_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:5:9: 5:11 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:5:19: 5:22 _3 = (_1.0: i32); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:5:19: 5:22 _2 = _3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:5:19: 5:22 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:5:23: 5:23 _0 = (); // scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:3:11: 6:2 StorageDead(_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:6:2: 6:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:6:2: 6:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/1/lib.rs:6:2: 6:2 } }
structure test.Point := mk {} :: (x : i32) (y : i32) definition test.main : sem (unit) := let' «p$1» ← test.Point.mk (10 : int) (11 : int); let' t3 ← (test.Point.x «p$1»); let' «px$2» ← t3; let' ret ← ⋆; return (⋆)
struct Point(i32, i32); fn main() { let p = Point(10, 11); let px: i32 = match p { Point(x, _) => x }; }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: Point; // "p" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:4:9: 4:10 scope 2 { let _2: i32; // "px" in scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:9: 5:11 } scope 3 { let _3: i32; // "x" in scope 3 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:35: 5:36 } } let mut _4: i32; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:4:9: 4:10 _1 = Point::{{constructor}}(const 10i32, const 11i32); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:4:13: 4:26 StorageLive(_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:9: 5:11 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:35: 5:36 _3 = (_1.0: i32); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:35: 5:36 StorageLive(_4); // scope 3 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:44: 5:45 _4 = _3; // scope 3 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:44: 5:45 _2 = _4; // scope 3 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:44: 5:45 StorageDead(_4); // scope 3 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:45: 5:45 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:5:47: 5:47 _0 = (); // scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:3:11: 6:2 StorageDead(_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:6:2: 6:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:6:2: 6:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/2/lib.rs:6:2: 6:2 } }
inductive test.Point := mk {} : i32 → i32 → test.Point definition test.main : sem (unit) := let' «p$1» ← test.Point.mk (10 : int) (11 : int); let' «x$3» ← match «p$1» with test.Point.mk x0 x1 := x0 end; let' t4 ← «x$3»; let' «px$2» ← t4; let' ret ← ⋆; return (⋆)
struct Cookie; fn main() { let c = [Cookie, Cookie {}, Cookie, Cookie {}]; }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: [Cookie; 4]; // "c" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:9: 4:10 } let mut _2: Cookie; let mut _3: Cookie; let mut _4: Cookie; let mut _5: Cookie; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:9: 4:10 StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:14: 4:20 _2 = Cookie::{{constructor}}; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:14: 4:20 StorageLive(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:22: 4:31 _3 = Cookie::{{constructor}}; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:22: 4:31 StorageLive(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:33: 4:39 _4 = Cookie::{{constructor}}; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:33: 4:39 StorageLive(_5); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:41: 4:50 _5 = Cookie::{{constructor}}; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:41: 4:50 _1 = [_2, _3, _4, _5]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:13: 4:51 StorageDead(_5); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:52: 4:52 StorageDead(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:52: 4:52 StorageDead(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:52: 4:52 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:4:52: 4:52 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:3:11: 5:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:5:2: 5:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.5 Structs/3/lib.rs:5:2: 5:2 } }
structure test.Cookie := mk {} :: definition test.main : sem (unit) := let' t2 ← test.Cookie.mk; let' t3 ← test.Cookie.mk; let' t4 ← test.Cookie.mk; let' t5 ← test.Cookie.mk; let' «c$1» ← [t2, t3, t4, t5]; let' ret ← ⋆; return (⋆)
enum Animal { Dog, Cat, } fn main() { let mut a: Animal = Animal::Dog; a = Animal::Cat; }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let mut _1: Animal; // "a" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1/lib.rs:7:9: 7:14 } bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1/lib.rs:7:9: 7:14 _1 = Animal::Dog; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1/lib.rs:7:25: 7:36 _1 = Animal::Cat; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1/lib.rs:8:5: 8:20 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1/lib.rs:6:11: 9:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1/lib.rs:9:2: 9:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1/lib.rs:9:2: 9:2 } }
inductive test.Animal := | Dog {} : test.Animal | Cat {} : test.Animal definition test.Animal.discr (self : test.Animal) : isize := match self with | test.Animal.Dog := 0 | test.Animal.Cat := 1 end definition test.main : sem (unit) := let' «a$1» ← test.Animal.Dog; let' «a$1» ← test.Animal.Cat; let' ret ← ⋆; return (⋆)
struct Name; enum Animal { Dog (Name, u32), Cat { name: Name, weight: u32 }, } fn main() { let mut a: Animal = Animal::Dog(Name, 37); a = Animal::Cat { name: Name, weight: 2 }; }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let mut _1: Animal; // "a" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:9:9: 9:14 } let mut _2: Name; let mut _3: Name; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:9:9: 9:14 StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:9:37: 9:41 _2 = Name::{{constructor}}; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:9:37: 9:41 _1 = Animal::Dog(_2, const 37u32); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:9:25: 9:46 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:9:47: 9:47 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:10:29: 10:33 _3 = Name::{{constructor}}; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:10:29: 10:33 _1 = Animal::Cat { name: _3, weight: const 2u32 }; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:10:5: 10:46 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:10:47: 10:47 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:8:11: 11:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:11:2: 11:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/1 Struct-like enum variants./lib.rs:11:2: 11:2 } }
structure test.Name := mk {} :: structure test.Animal.Cat.struct := mk {} :: (name : (test.Name)) (weight : u32) inductive test.Animal := | Dog {} : (test.Name) → u32 → test.Animal | Cat {} : test.Animal.Cat.struct → test.Animal definition test.main : sem (unit) := let' t2 ← test.Name.mk; let' «a$1» ← test.Animal.Dog t2 (37 : nat); let' t3 ← test.Name.mk; let' «a$1» ← test.Animal.Cat (test.Animal.Cat.struct.mk t3 (2 : nat)); let' ret ← ⋆; return (⋆)
enum Foo { Bar = 123, } fn main() { let x = Foo::Bar as u32; // x is now 123u32 }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: u32; // "x" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:6:9: 6:10 } let mut _2: Foo; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:6:9: 6:10 StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:6:13: 6:21 _2 = Foo::Bar; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:6:13: 6:21 _1 = _2 as u32 (Misc); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:6:13: 6:28 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:6:29: 6:29 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:5:11: 7:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:7:2: 7:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:7:2: 7:2 } } const Foo::Bar::{{initializer}}: isize = { let mut _0: isize; // return pointer bb0: { _0 = const 123isize; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:2:11: 2:14 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.6 Enumerations/2 Enum discriminants./lib.rs:2:11: 2:14 } }
inductive test.Foo := | Bar {} : test.Foo definition test.Foo.discr (self : test.Foo) : isize := match self with | test.Foo.Bar := 123 end definition test.main : sem (unit) := let' t2 ← test.Foo.Bar; do «$tmp0» ← (signed_to_unsigned u32.bits (test.Foo.discr t2)); let' «x$1» ← «$tmp0»; let' ret ← ⋆; return (⋆)
Constants are fun: If you want to be system-independent, expressions like usize::MAX + 1
or 1usize << 33
suddenly are not so constant any more. Therefore, we wrap them in the semantics burrito monad.
const BIT1: u32 = 1 << 0; const BIT2: u32 = 1 << 1; const BITS: [u32; 2] = [BIT1, BIT2]; const STRING: &'static str = "bitstring"; struct BitsNStrings<'a> { mybits: [u32; 2], mystring: &'a str, } const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { mybits: BITS, mystring: STRING, };
const BITS_N_STRINGS: BitsNStrings<'static> = { let mut _0: BitsNStrings<'static>; // return pointer let mut _1: &'static str; let mut _2: &'static str; bb0: { _2 = STRING; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:14:15: 14:21 _1 = &(*_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:14:15: 14:21 _0 = BitsNStrings<'static> { mybits: BITS, mystring: _1 }; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:12:47: 15:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:12:1: 15:3 } } const STRING: &'static str = { let mut _0: &'static str; // return pointer bb0: { _0 = const "bitstring"; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:5:30: 5:41 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:5:1: 5:42 } } const BIT2: u32 = { let mut _0: u32; // return pointer let mut _1: (u32, bool); bb0: { _1 = CheckedShl(const 1u32, const 1i32); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:2:19: 2:25 assert(!(_1.1: bool), "attempt to shift left with overflow") -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:2:19: 2:25 } bb1: { _0 = (_1.0: u32); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:2:19: 2:25 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:2:1: 2:26 } } const BitsNStrings::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 2usize; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:8:19: 8:20 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:8:19: 8:20 } } const BITS::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 2usize; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:4:19: 4:20 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:4:19: 4:20 } } const BIT1: u32 = { let mut _0: u32; // return pointer let mut _1: (u32, bool); bb0: { _1 = CheckedShl(const 1u32, const 0i32); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:1:19: 1:25 assert(!(_1.1: bool), "attempt to shift left with overflow") -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:1:19: 1:25 } bb1: { _0 = (_1.0: u32); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:1:19: 1:25 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:1:1: 1:26 } } const BITS: [u32; 2] = { let mut _0: [u32; 2]; // return pointer bb0: { _0 = [BIT1, BIT2]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:4:24: 4:36 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.7 Constant items/1/lib.rs:4:1: 4:37 } }
definition test.BIT1 : sem u32 := do «$tmp0» ← sem.map (λx, (x, tt)) (checked.shls u32.bits (1 : nat) (0 : int)); let' t1 ← «$tmp0»; let' ret ← t1.1; return (ret) definition test.BIT2 : sem u32 := do «$tmp0» ← sem.map (λx, (x, tt)) (checked.shls u32.bits (1 : nat) (1 : int)); let' t1 ← «$tmp0»; let' ret ← t1.1; return (ret) definition test.BITS : sem (array u32 2) := do «$tmp0» ← do «$tmp0» ← test.BIT1; do «$tmp1» ← test.BIT2; return ([«$tmp0», «$tmp1»]); let' ret ← «$tmp0»; return (ret) definition test.STRING : sem string := let' ret ← "bitstring"; return (ret) structure test.BitsNStrings := mk {} :: (mybits : (array u32 2)) (mystring : string) definition test.BITS_N_STRINGS : sem (test.BitsNStrings) := do «$tmp0» ← test.STRING; let' t2 ← «$tmp0»; let' t1 ← t2; do «$tmp0» ← do «$tmp0» ← test.BITS; return (test.BitsNStrings.mk «$tmp0» t1); let' ret ← «$tmp0»; return (ret)
No semantic difference from constants without unsafe code or *Cell
s.
static LEVELS: u32 = 0;
static LEVELS: u32 = { let mut _0: u32; // return pointer bb0: { _0 = const 0u32; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.8 Static items/2/lib.rs:1:22: 1:23 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.8 Static items/2/lib.rs:1:1: 1:24 } }
definition test.LEVELS : sem u32 := let' ret ← (0 : nat); return (ret)
Traits, type classes, what's the difference? Well, apart from the implicit Self
parameter becoming explicit, we always use explicit calls in the generated code because some Rust types (immutable references, integer types) are translated into the same Lean type, making implicit calls ambiguous. Most proof code should be fine though (see below).
struct Foo; trait Shape { fn area(&self) -> i64; } trait Circle : Shape { fn radius(&self) -> i64; } impl Shape for Foo { fn area(&self) -> i64 { 1 } } impl Circle for Foo { fn radius(&self) -> i64 { //println!("calling area: {}", self.area()); -1 } } fn main() { let c = Foo; c.radius(); }
fn <Foo as Circle>::radius(_1: &Foo) -> i64 { let mut _0: i64; // return pointer scope 1 { let _2: &Foo; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:11:15: 11:20 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:11:15: 11:20 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:11:15: 11:20 _0 = const -1i64; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:13:9: 13:11 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:14:6: 14:6 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:14:6: 14:6 } } fn <Foo as Shape>::area(_1: &Foo) -> i64 { let mut _0: i64; // return pointer scope 1 { let _2: &Foo; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:6:13: 6:18 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:6:13: 6:18 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:6:13: 6:18 _0 = const 1i64; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:7:9: 7:10 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:8:6: 8:6 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:8:6: 8:6 } } fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: Foo; // "c" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:18:9: 18:10 } let mut _2: i64; let mut _3: &Foo; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:18:9: 18:10 _1 = Foo::{{constructor}}; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:18:13: 18:16 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:19:5: 19:6 _3 = &_1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:19:5: 19:6 _2 = <Foo as Circle>::radius(_3) -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:19:5: 19:15 } bb1: { StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:19:16: 19:16 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:17:11: 20:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:20:2: 20:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/1/lib.rs:20:2: 20:2 } }
structure test.Foo := mk {} :: definition test.«test.Foo as test.Shape».area (selfₐ : (test.Foo)) : sem (i64) := let' «self$2» ← selfₐ; let' ret ← (1 : int); return (ret) definition test.«test.Foo as test.Circle».radius (selfₐ : (test.Foo)) : sem (i64) := let' «self$2» ← selfₐ; let' ret ← (-1 : int); return (ret) structure test.Shape [class] (Self : Type₁) := (area : (Self → sem (i64))) definition test.«test.Foo as test.Shape» [instance] := ⦃ test.Shape (test.Foo), area := @test.«test.Foo as test.Shape».area ⦄ structure test.Circle [class] (Self : Type₁) extends test.Shape Self := (radius : (Self → sem (i64))) attribute [coercion] test.Circle.to_Shape definition test.«test.Foo as test.Circle» [instance] := ⦃ test.Circle (test.Foo), (@test.«test.Foo as test.Shape»), radius := @test.«test.Foo as test.Circle».radius ⦄ definition test.main : sem (unit) := let' «c$1» ← test.Foo.mk; let' t3 ← «c$1»; dostep «$tmp» ← @test.«test.Foo as test.Circle».radius t3; let' t2 ← «$tmp»; let' ret ← ⋆; return (⋆)
example (foo : Foo) : sem.terminates_with (λ r, r = 1) (Shape.area foo) := rfl example (foo : Foo) : sem.terminates_with (λ r, r = -1) (Circle.radius foo) := rfl
trait Seq<T> { fn len(&self) -> u32; fn elt_at(&self, n: u32) -> T; fn iter<F>(&self, F) where F: Fn(T); }
structure test.Seq [class] (Self : Type₁) (T : Type₁) := (len : (Self → sem (u32))) (elt_at : (Self → u32 → sem (T))) (iter : Π {F : Type₁} [«core.ops.Fn F T» : core.ops.Fn F T unit], (Self → F → sem (unit)))
Default methods are terrible. They should be part of the type class just like standard methods, but they also depend on the type class in order to call other trait methods, creating a cyclic dependency. For now, we just declare them outside of (after) the type class, which works for all current proofs, but can create problems (see below).
trait Foo { fn bar(&self); fn baz(&self) { self.bar() } } struct Bar; impl Foo for Bar { fn bar(&self) {} }
fn Foo::baz(_1: &Self) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Self; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:12: 3:17 } let mut _3: &Self; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:12: 3:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:12: 3:17 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:21: 3:25 _3 = &(*_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:21: 3:25 _0 = <Self as Foo>::bar(_3) -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:21: 3:31 } bb1: { StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:33: 3:33 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:33: 3:33 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:3:33: 3:33 } } fn <Bar as Foo>::bar(_1: &Bar) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Bar; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:9:12: 9:17 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:9:12: 9:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:9:12: 9:17 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:9:19: 9:21 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:9:21: 9:21 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/2 Default methods./lib.rs:9:21: 9:21 } }
structure test.Foo [class] (Self : Type₁) := (bar : (Self → sem (unit))) definition test.Foo.baz {Self : Type₁} [«test.Foo Self» : test.Foo Self] (selfₐ : Self) : sem (unit) := let' «self$2» ← selfₐ; let' t3 ← «self$2»; dostep «$tmp» ← @test.Foo.bar Self «test.Foo Self» t3; let' ret ← «$tmp»; return (⋆) structure test.Bar := mk {} :: definition test.«test.Bar as test.Foo».bar (selfₐ : (test.Bar)) : sem (unit) := let' «self$2» ← selfₐ; let' ret ← ⋆; return (⋆) definition test.«test.Bar as test.Foo» [instance] := ⦃ test.Foo (test.Bar), bar := @test.«test.Bar as test.Foo».bar ⦄
trait Foo { fn bar(&self); fn baz(&self) { self.bar() } } struct Bar; impl Foo for Bar { fn bar(&self) { self.baz() } }
fn Foo::baz(_1: &Self) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Self; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:12: 3:17 } let mut _3: &Self; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:12: 3:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:12: 3:17 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:21: 3:25 _3 = &(*_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:21: 3:25 _0 = <Self as Foo>::bar(_3) -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:21: 3:31 } bb1: { StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:33: 3:33 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:33: 3:33 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:3:33: 3:33 } } fn <Bar as Foo>::bar(_1: &Bar) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Bar; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:12: 9:17 } let mut _3: &Bar; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:12: 9:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:12: 9:17 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:21: 9:25 _3 = &(*_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:21: 9:25 _0 = <Bar as Foo>::baz(_3) -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:21: 9:31 } bb1: { StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:33: 9:33 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:33: 9:33 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/3 Calling default methods from inside the trait./lib.rs:9:33: 9:33 } }
structure test.Foo [class] (Self : Type₁) := (bar : (Self → sem (unit))) definition test.Foo.baz {Self : Type₁} [«test.Foo Self» : test.Foo Self] (selfₐ : Self) : sem (unit) := let' «self$2» ← selfₐ; let' t3 ← «self$2»; dostep «$tmp» ← @test.Foo.bar Self «test.Foo Self» t3; let' ret ← «$tmp»; return (⋆) structure test.Bar := mk {} :: /- unimplemented: circular dependencies: test.«test.Bar as test.Foo», test.«test.Bar as test.Foo».bar definition test.«test.Bar as test.Foo» [instance] := ⦃ test.Foo (test.Bar), bar := @test.«test.Bar as test.Foo».bar ⦄ definition test.«test.Bar as test.Foo».bar (selfₐ : (test.Bar)) : sem (unit) := let' «self$2» ← selfₐ; let' t3 ← «self$2»; dostep «$tmp» ← @test.Foo.baz (test.Bar) (@test.«test.Bar as test.Foo») t3; let' ret ← «$tmp»; return (⋆) -/
trait Foo { fn bar(&self); fn baz(&self) { self.bar() } } struct Bar; impl Foo for Bar { fn bar(&self) {} fn baz(&self) {} }
fn <Bar as Foo>::baz(_1: &Bar) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Bar; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:10:12: 10:17 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:10:12: 10:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:10:12: 10:17 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:10:19: 10:21 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:10:21: 10:21 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:10:21: 10:21 } } fn Foo::baz(_1: &Self) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Self; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:12: 3:17 } let mut _3: &Self; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:12: 3:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:12: 3:17 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:21: 3:25 _3 = &(*_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:21: 3:25 _0 = <Self as Foo>::bar(_3) -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:21: 3:31 } bb1: { StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:33: 3:33 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:33: 3:33 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:3:33: 3:33 } } fn <Bar as Foo>::bar(_1: &Bar) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Bar; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:9:12: 9:17 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:9:12: 9:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:9:12: 9:17 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:9:19: 9:21 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:9:21: 9:21 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/4 Overriding default methods./lib.rs:9:21: 9:21 } }
structure test.Foo [class] (Self : Type₁) := (bar : (Self → sem (unit))) definition test.Foo.baz {Self : Type₁} [«test.Foo Self» : test.Foo Self] (selfₐ : Self) : sem (unit) := let' «self$2» ← selfₐ; let' t3 ← «self$2»; dostep «$tmp» ← @test.Foo.bar Self «test.Foo Self» t3; let' ret ← «$tmp»; return (⋆) structure test.Bar := mk {} :: definition test.«test.Bar as test.Foo».bar (selfₐ : (test.Bar)) : sem (unit) := let' «self$2» ← selfₐ; let' ret ← ⋆; return (⋆) /- test.«test.Bar as test.Foo».baz: unimplemented: overriding default method |test.«test.Bar as test.Foo».baz -/ /- test.«test.Bar as test.Foo»: failed dependencies |test.«test.Bar as test.Foo».baz -/
struct Surface {} trait Shape { fn draw(&self, &Surface); } fn draw_twice<T: Shape>(surface: Surface, sh: T) { sh.draw(&surface); sh.draw(&surface); }
fn draw_twice(_1: Surface, _2: T) -> () { let mut _0: (); // return pointer scope 1 { let _3: Surface; // "surface" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:25: 6:32 let _4: T; // "sh" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:43: 6:45 } let mut _5: (); let mut _6: &T; let mut _7: (); let mut _8: &Surface; let mut _9: &Surface; let mut _10: (); let mut _11: &T; let mut _12: &Surface; let mut _13: &Surface; bb0: { StorageLive(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:25: 6:32 _3 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:25: 6:32 StorageLive(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:43: 6:45 _4 = _2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:43: 6:45 StorageLive(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:5: 7:7 _6 = &_4; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:5: 7:7 StorageLive(_8); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:13: 7:21 StorageLive(_9); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:13: 7:21 _9 = &_3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:13: 7:21 _8 = &(*_9); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:13: 7:21 _5 = <T as Shape>::draw(_6, _8) -> [return: bb4, unwind: bb3]; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:5: 7:22 } bb1: { resume; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:1: 9:2 } bb2: { drop(_4) -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:9:2: 9:2 } bb3: { drop(_2) -> bb2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:9:2: 9:2 } bb4: { StorageDead(_8); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:23: 7:23 StorageDead(_9); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:23: 7:23 StorageDead(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:7:23: 7:23 StorageLive(_11); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:5: 8:7 _11 = &_4; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:5: 8:7 StorageLive(_12); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:13: 8:21 StorageLive(_13); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:13: 8:21 _13 = &_3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:13: 8:21 _12 = &(*_13); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:13: 8:21 _10 = <T as Shape>::draw(_11, _12) -> [return: bb5, unwind: bb3]; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:5: 8:22 } bb5: { StorageDead(_12); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:23: 8:23 StorageDead(_13); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:23: 8:23 StorageDead(_11); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:8:23: 8:23 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:6:50: 9:2 drop(_2) -> [return: bb6, unwind: bb2]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:9:2: 9:2 } bb6: { drop(_4) -> bb7; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:9:2: 9:2 } bb7: { StorageDead(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:9:2: 9:2 StorageDead(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:9:2: 9:2 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/5 Trait bounds./lib.rs:9:2: 9:2 } }
structure test.Surface := mk {} :: structure test.Shape [class] (Self : Type₁) := (draw : (Self → (test.Surface) → sem (unit))) definition test.draw_twice {T : Type₁} [«test.Shape T» : test.Shape T] (surfaceₐ : (test.Surface)) (shₐ : T) : sem (unit) := let' «surface$3» ← surfaceₐ; let' «sh$4» ← shₐ; let' t6 ← «sh$4»; let' t9 ← «surface$3»; let' t8 ← t9; dostep «$tmp» ← @test.Shape.draw T «test.Shape T» t6 t8; let' t5 ← «$tmp»; let' t11 ← «sh$4»; let' t13 ← «surface$3»; let' t12 ← t13; dostep «$tmp» ← @test.Shape.draw T «test.Shape T» t11 t12; let' t10 ← «$tmp»; let' ret ← ⋆; return (⋆)
You would think that a language with awesome dependent types like Lean would not have any problem declaring a type as a type class member, and you would be right. What it cannot express, however, are definitional type equalities like in Iterator<Item=T>
, which could be written as Iterator::Item ~ T
in a more Haskell-y syntax. Therefore, we follow the original paper [1] on associated types in Haskell and desugar them into type parameters. This does weaken type class inference, which is another reason why we don't do that inference in generated code. We might be able to regain inference in a potential future version of Lean that supports functional dependencies.
[1] System F with Type Equality Coercions
Martin Sulzmann, Manuel M. T. Chakravarty, Simon Peyton Jones, and Kevin Donnelly.
In G. Necula, editor, Proceedings of The Third ACM SIGPLAN Workshop on Types in Language Design and Implementation, ACM Press, 2007.
trait Container { type E; fn empty() -> Self; fn insert(&mut self, Self::E); } impl<T> Container for Vec<T> { type E = T; fn empty() -> Vec<T> { Vec::new() } fn insert(&mut self, x: T) { self.push(x); } }
fn <std::vec::Vec<T> as Container>::insert(_1: &mut std::vec::Vec<T>, _2: T) -> () { let mut _0: (); // return pointer scope 1 { let _3: &mut std::vec::Vec<T>; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:15: 10:24 let _4: T; // "x" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:26: 10:27 } let mut _5: (); let mut _6: &mut std::vec::Vec<T>; let mut _7: (); let mut _8: T; bb0: { StorageLive(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:15: 10:24 _3 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:15: 10:24 StorageLive(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:26: 10:27 _4 = _2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:26: 10:27 StorageLive(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:34: 10:38 _6 = &mut (*_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:34: 10:38 StorageLive(_8); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:44: 10:45 _8 = _4; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:44: 10:45 _5 = <std::vec::Vec<T>><T>::push(_6, _8) -> [return: bb5, unwind: bb4]; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:34: 10:46 } bb1: { resume; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:5: 10:49 } bb2: { drop(_4) -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:49: 10:49 } bb3: { drop(_2) -> bb2; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:49: 10:49 } bb4: { drop(_8) -> bb3; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:47: 10:47 } bb5: { drop(_8) -> [return: bb6, unwind: bb3]; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:47: 10:47 } bb6: { StorageDead(_8); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:47: 10:47 StorageDead(_6); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:47: 10:47 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:32: 10:49 drop(_2) -> [return: bb7, unwind: bb2]; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:49: 10:49 } bb7: { drop(_4) -> bb8; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:49: 10:49 } bb8: { StorageDead(_4); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:49: 10:49 StorageDead(_3); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:49: 10:49 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:10:49: 10:49 } } fn <std::vec::Vec<T> as Container>::empty() -> std::vec::Vec<T> { let mut _0: std::vec::Vec<T>; // return pointer bb0: { _0 = <std::vec::Vec<T>><T>::new() -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:9:28: 9:38 } bb1: { return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/6 Associated types./lib.rs:9:40: 9:40 } }
structure test.Container [class] (Self : Type₁) («<Self as Container>.E» : Type₁) := (empty : (sem (Self))) (insert : (Self → «<Self as Container>.E» → sem (unit × Self))) definition test.«collections.vec.Vec<T> as test.Container».empty {T : Type₁} : sem ((collections.vec.Vec T)) := dostep «$tmp» ← @collections.vec.«Vec<T>».new T; let' ret ← «$tmp»; return (ret) definition test.«collections.vec.Vec<T> as test.Container».insert {T : Type₁} (selfₐ : (collections.vec.Vec T)) (xₐ : T) : sem (unit × (collections.vec.Vec T)) := let' «self$3» ← @lens.id (collections.vec.Vec T); let' «x$4» ← xₐ; let' t6 ← («self$3»); do «$tmp» ← lens.get t6 selfₐ; let' t8 ← «x$4»; do «$tmp0» ← lens.get t6 selfₐ; dostep «$tmp» ← @collections.vec.«Vec<T>».push T «$tmp0» t8; match «$tmp» with (t5, «t6$») := do selfₐ ← lens.set t6 selfₐ «t6$»; let' ret ← ⋆; return (⋆, selfₐ) end definition test.«collections.vec.Vec<T> as test.Container» [instance] {T : Type₁} := ⦃ test.Container (collections.vec.Vec T) T, empty := @test.«collections.vec.Vec<T> as test.Container».empty T, insert := @test.«collections.vec.Vec<T> as test.Container».insert T ⦄
A trait object type &Trait
can be interpreted as an existential type ∃ (T : Trait), T
or, generically for all traits in Lean, as a dependent record
structure trait_obj (Trait : Type → Type) := -- `Trait` explicitly takes `Self` in Lean
(ActualType : Type)
(impl : Trait ActualType)
(self : ActualType)
We could then specify that a trait object indeed implements its trait by generating an instance of type Trait (trait_obj Trait)
. The instance would call the respective function on impl
with self
, and, in the case of &mut self
methods, place the new value of self
back into the trait object.
However, this wouldn't integrate well (or at all) currently because of technical reasons (trait_obj Trait
living in Type₂
and Lean's universe hierarchy being noncumulative, if you really want to know), so we simply don't touch that yet.
trait Shape { fn draw(&self) {} } impl Shape for i32 { } fn main() { let mycircle = 0i32; let myshape: &Shape = &mycircle; myshape.draw(); }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: i32; // "mycircle" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:7:9: 7:17 scope 2 { let _2: &Shape; // "myshape" in scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:8:9: 8:16 } } let mut _3: &i32; let mut _4: &i32; let mut _5: (); let mut _6: &Shape; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:7:9: 7:17 _1 = const 0i32; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:7:20: 7:24 StorageLive(_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:8:9: 8:16 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:8:27: 8:36 StorageLive(_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:8:27: 8:36 _4 = &_1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:8:27: 8:36 _3 = &(*_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:8:27: 8:36 _2 = _3 as &Shape (Unsize); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:8:27: 8:36 StorageLive(_6); // scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:9:5: 9:12 _6 = &(*_2); // scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:9:5: 9:12 _5 = <Shape as Shape>::draw(_6) -> bb1; // scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:9:5: 9:19 } bb1: { StorageDead(_6); // scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:9:20: 9:20 _0 = (); // scope 2 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:6:11: 10:2 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:10:2: 10:2 StorageDead(_4); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:10:2: 10:2 StorageDead(_2); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:10:2: 10:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:10:2: 10:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:10:2: 10:2 } } fn Shape::draw(_1: &Self) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Self; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:2:13: 2:18 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:2:13: 2:18 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:2:13: 2:18 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:2:20: 2:22 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:2:22: 2:22 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/7 Trait objects./lib.rs:2:22: 2:22 } }
structure test.Shape [class] (Self : Type₁) := mk definition test.Shape.draw {Self : Type₁} [«test.Shape Self» : test.Shape Self] (selfₐ : Self) : sem (unit) := let' «self$2» ← selfₐ; let' ret ← ⋆; return (⋆) /- test.main: unimplemented: trait object -/ definition test.«i32 as test.Shape» [instance] := ⦃ test.Shape i32 ⦄
trait Num { fn from_i32(n: i32) -> Self; } impl Num for i64 { fn from_i32(n: i32) -> i64 { n as i64 } } fn main() { let x: i64 = Num::from_i32(42); }
fn <i64 as Num>::from_i32(_1: i32) -> i64 { let mut _0: i64; // return pointer scope 1 { let _2: i32; // "n" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:17: 5:18 } let mut _3: i32; bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:17: 5:18 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:17: 5:18 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:34: 5:35 _3 = _2; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:34: 5:35 _0 = _3 as i64 (Misc); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:34: 5:42 StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:44: 5:44 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:44: 5:44 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:5:44: 5:44 } } fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: i64; // "x" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:8:9: 8:10 } bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:8:9: 8:10 _1 = <i64 as Num>::from_i32(const 42i32) -> bb1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:8:18: 8:35 } bb1: { _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:7:11: 9:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:9:2: 9:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.9 Traits/8 Static trait methods./lib.rs:9:2: 9:2 } }
structure test.Num [class] (Self : Type₁) := (from_i32 : (i32 → sem (Self))) definition test.«i64 as test.Num».from_i32 (nₐ : i32) : sem (i64) := let' «n$2» ← nₐ; let' t3 ← «n$2»; do «$tmp0» ← (signed_to_signed i64.bits t3); let' ret ← «$tmp0»; return (ret) definition test.«i64 as test.Num» [instance] := ⦃ test.Num i64, from_i32 := @test.«i64 as test.Num».from_i32 ⦄ definition test.main : sem (unit) := dostep «$tmp» ← @test.«i64 as test.Num».from_i32 (42 : int); let' «x$1» ← «$tmp»; let' ret ← ⋆; return (⋆)
See 6.1.9 Traits.
struct Point {x: i32, y: i32} impl Point { fn log(&self) { //println!("Point is at ({}, {})", self.x, self.y); } } fn main() { let my_point = Point {x: 10, y:11}; my_point.log(); }
fn Point::log(_1: &Point) -> () { let mut _0: (); // return pointer scope 1 { let _2: &Point; // "self" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:4:12: 4:17 } bb0: { StorageLive(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:4:12: 4:17 _2 = _1; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:4:12: 4:17 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:4:19: 6:6 StorageDead(_2); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:6:6: 6:6 return; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:6:6: 6:6 } } fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: Point; // "my_point" in scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:10:9: 10:17 } let mut _2: (); let mut _3: &Point; bb0: { StorageLive(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:10:9: 10:17 _1 = Point { x: const 10i32, y: const 11i32 }; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:10:20: 10:39 StorageLive(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:11:5: 11:13 _3 = &_1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:11:5: 11:13 _2 = Point::log(_3) -> bb1; // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:11:5: 11:19 } bb1: { StorageDead(_3); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:11:20: 11:20 _0 = (); // scope 1 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:9:11: 12:2 StorageDead(_1); // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:12:2: 12:2 return; // scope 0 at ref/6 Items And Attributes/6.1 Items/6.1.10 Implementations/2 That other type of implementations./lib.rs:12:2: 12:2 } }
structure test.Point := mk {} :: (x : i32) (y : i32) definition test.Point.log (selfₐ : (test.Point)) : sem (unit) := let' «self$2» ← selfₐ; let' ret ← ⋆; return (⋆) definition test.main : sem (unit) := let' «my_point$1» ← test.Point.mk (10 : int) (11 : int); let' t3 ← «my_point$1»; dostep «$tmp» ← @test.Point.log t3; let' t2 ← «$tmp»; let' ret ← ⋆; return (⋆)
Most attributes do not influence the language semantics, so we can ignore them. Except for...
Since the verification should not depend on the host system, we skip all items marked with #[cfg(..)]
except for the harmless #[cfg(not(test))]
. These items instead have to be axiomatized in a sensible way by the user.
#[cfg(any(unix, windows))] fn foo() {} #[cfg(all(unix, target_pointer_width = "32"))] fn bar() {} #[cfg(not(foo))] fn not_foo() {} #[cfg(not(test))] fn not_test() {}
fn not_foo() -> () { let mut _0: (); // return pointer bb0: { _0 = (); // scope 0 at ref/6 Items And Attributes/6.3 Attributes/6.3.8 Conditional compilation/lib.rs:8:14: 8:16 return; // scope 0 at ref/6 Items And Attributes/6.3 Attributes/6.3.8 Conditional compilation/lib.rs:8:16: 8:16 } } fn foo() -> () { let mut _0: (); // return pointer bb0: { _0 = (); // scope 0 at ref/6 Items And Attributes/6.3 Attributes/6.3.8 Conditional compilation/lib.rs:2:10: 2:12 return; // scope 0 at ref/6 Items And Attributes/6.3 Attributes/6.3.8 Conditional compilation/lib.rs:2:12: 2:12 } } fn not_test() -> () { let mut _0: (); // return pointer bb0: { _0 = (); // scope 0 at ref/6 Items And Attributes/6.3 Attributes/6.3.8 Conditional compilation/lib.rs:11:15: 11:17 return; // scope 0 at ref/6 Items And Attributes/6.3 Attributes/6.3.8 Conditional compilation/lib.rs:11:17: 11:17 } }
definition test.foo : sem (unit) := let' ret ← ⋆; return (⋆) definition test.not_foo : sem (unit) := let' ret ← ⋆; return (⋆) definition test.not_test : sem (unit) := let' ret ← ⋆; return (⋆)
fn foo() { fn bar() {} bar() }
fn foo::bar() -> () { let mut _0: (); // return pointer bb0: { _0 = (); // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.1 Item declarations/lib.rs:2:14: 2:16 return; // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.1 Item declarations/lib.rs:2:16: 2:16 } } fn foo() -> () { let mut _0: (); // return pointer bb0: { _0 = foo::bar() -> bb1; // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.1 Item declarations/lib.rs:3:5: 3:10 } bb1: { return; // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.1 Item declarations/lib.rs:4:2: 4:2 } }
definition test.foo.bar : sem (unit) := let' ret ← ⋆; return (⋆) definition test.foo : sem (unit) := dostep «$tmp» ← @test.foo.bar; let' ret ← «$tmp»; return (⋆)
fn foo() -> i32 { let a = 1; a }
fn foo() -> i32 { let mut _0: i32; // return pointer scope 1 { let _1: i32; // "a" in scope 1 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:2:9: 2:10 } let mut _2: i32; bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:2:9: 2:10 _1 = const 1i32; // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:2:13: 2:14 StorageLive(_2); // scope 1 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:3:5: 3:6 _2 = _1; // scope 1 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:3:5: 3:6 _0 = _2; // scope 1 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:3:5: 3:6 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:4:2: 4:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:4:2: 4:2 return; // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.1 Declaration Statements/7.1.1.2 let statements/lib.rs:4:2: 4:2 } }
definition test.foo : sem (i32) := let' «a$1» ← (1 : int); let' t2 ← «a$1»; let' ret ← t2; return (ret)
fn foo() { 1; }
fn foo() -> () { let mut _0: (); // return pointer let mut _1: i32; bb0: { _1 = const 1i32; // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.2 Expression statements/lib.rs:2:5: 2:6 _0 = (); // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.2 Expression statements/lib.rs:1:10: 3:2 return; // scope 0 at ref/7 Statements and expressions/7.1 Statements/7.1.2 Expression statements/lib.rs:3:2: 3:2 } }
definition test.foo : sem (unit) := let' t1 ← (1 : int); let' ret ← ⋆; return (⋆)
Lean3 will have support for char
literals! Exciting!
fn main() { (); // unit type "hello"; // string type //'5'; // character type 5; // integer type }
fn main() -> () { let mut _0: (); // return pointer let mut _1: (); let mut _2: &'static str; let mut _3: i32; bb0: { _1 = (); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.1 Literal expressions/lib.rs:2:5: 2:7 _2 = const "hello"; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.1 Literal expressions/lib.rs:3:5: 3:12 _3 = const 5i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.1 Literal expressions/lib.rs:5:5: 5:6 _0 = (); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.1 Literal expressions/lib.rs:1:11: 6:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.1 Literal expressions/lib.rs:6:2: 6:2 } }
definition test.main : sem (unit) := let' t1 ← ⋆; let' t2 ← "hello"; let' t3 ← (5 : int); let' ret ← ⋆; return (⋆)
fn main() { (0, 4); ("a", 4usize, true); }
fn main() -> () { let mut _0: (); // return pointer let mut _1: (i32, i32); let mut _2: (&'static str, usize, bool); bb0: { _1 = (const 0i32, const 4i32); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/1/lib.rs:2:5: 2:11 _2 = (const "a", const 4usize, const true); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/1/lib.rs:3:5: 3:24 _0 = (); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/1/lib.rs:1:11: 4:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/1/lib.rs:4:2: 4:2 } }
definition test.main : sem (unit) := let' t1 ← ((0 : int), (4 : int)); let' t2 ← ("a", (4 : nat), tt); let' ret ← ⋆; return (⋆)
Lean uses the much more satisfying definition of tuples as nested pairs, which has the interesting side-effect of unary tuples not being a thing.
fn main() { (0,); // single-element tuple (0); // zero in parentheses }
fn main() -> () { let mut _0: (); // return pointer let mut _1: (i32,); let mut _2: i32; bb0: { _1 = (const 0i32,); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/2/lib.rs:2:5: 2:9 _2 = const 0i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/2/lib.rs:3:5: 3:8 _0 = (); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/2/lib.rs:1:11: 4:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.3 Tuple expressions/2/lib.rs:4:2: 4:2 } }
definition test.main : sem (unit) := let' t1 ← (0 : int); let' t2 ← (0 : int); let' ret ← ⋆; return (⋆)
fn main() { struct Point { x: i64, y: i64 } struct NothingInMe { } struct TuplePoint(i64, i64); mod game { pub struct User<'a> { pub name: &'a str, pub age: u32, pub score: usize } } struct Cookie; fn some_fn<T>(t: T) {} Point {x: 10, y: 20}; NothingInMe {}; TuplePoint(10, 20); let u = game::User {name: "Joe", age: 35, score: 100_000}; some_fn::<Cookie>(Cookie); }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _4: main::game::User<'_>; // "u" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:9: 11:10 } let mut _1: main::Point; let mut _2: main::NothingInMe; let mut _3: main::TuplePoint; let mut _5: &str; let mut _6: &'static str; let mut _7: (); let mut _8: main::Cookie; bb0: { _1 = main::Point { x: const 10i64, y: const 20i64 }; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:8:5: 8:25 _2 = main::NothingInMe; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:9:5: 9:19 _3 = main::TuplePoint::{{constructor}}(const 10i64, const 20i64); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:10:5: 10:23 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:9: 11:10 StorageLive(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:31: 11:36 StorageLive(_6); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:31: 11:36 _6 = const "Joe"; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:31: 11:36 _5 = &(*_6); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:31: 11:36 _4 = main::game::User<'_> { name: _5, age: const 35u32, score: const 100000usize }; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:13: 11:62 StorageDead(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:63: 11:63 StorageDead(_6); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:11:63: 11:63 StorageLive(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:12:23: 12:29 _8 = main::Cookie::{{constructor}}; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:12:23: 12:29 _7 = main::some_fn::<main::Cookie>(_8) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:12:5: 12:30 } bb1: { StorageDead(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:12:31: 12:31 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:1:11: 13:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:13:2: 13:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:13:2: 13:2 } } fn main::some_fn(_1: T) -> () { let mut _0: (); // return pointer scope 1 { let _2: T; // "t" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:34: 6:35 } let mut _3: (); bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:34: 6:35 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:34: 6:35 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:40: 6:42 drop(_1) -> [return: bb3, unwind: bb2]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:42: 6:42 } bb1: { resume; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:20: 6:42 } bb2: { drop(_2) -> bb1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:42: 6:42 } bb3: { drop(_2) -> bb4; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:42: 6:42 } bb4: { StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:42: 6:42 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/lib.rs:6:42: 6:42 } }
structure test.main.Point := mk {} :: (x : i64) (y : i64) structure test.main.NothingInMe := mk {} :: inductive test.main.TuplePoint := mk {} : i64 → i64 → test.main.TuplePoint structure test.main.game.User := mk {} :: (name : string) (age : u32) (score : usize) structure test.main.Cookie := mk {} :: definition test.main.some_fn {T : Type₁} (tₐ : T) : sem (unit) := let' «t$2» ← tₐ; let' ret ← ⋆; return (⋆) definition test.main : sem (unit) := let' t1 ← test.main.Point.mk (10 : int) (20 : int); let' t2 ← test.main.NothingInMe.mk; let' t3 ← test.main.TuplePoint.mk (10 : int) (20 : int); let' t6 ← "Joe"; let' t5 ← t6; let' «u$4» ← test.main.game.User.mk t5 (35 : nat) (100000 : nat); let' t8 ← test.main.Cookie.mk; dostep «$tmp» ← @test.main.some_fn (test.main.Cookie) t8; let' t7 ← «$tmp»; let' ret ← ⋆; return (⋆)
fn main() { struct Point3d { x: i32, y: i32, z: i32 } let base = Point3d {x: 1, y: 2, z: 3}; Point3d {y: 0, z: 10, .. base}; }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: main::Point3d; // "base" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/2/lib.rs:4:9: 4:13 } let mut _2: main::Point3d; bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/2/lib.rs:4:9: 4:13 _1 = main::Point3d { x: const 1i32, y: const 2i32, z: const 3i32 }; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/2/lib.rs:4:16: 4:42 _2 = main::Point3d { x: (_1.0: i32), y: const 0i32, z: const 10i32 }; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/2/lib.rs:5:5: 5:35 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/2/lib.rs:1:11: 6:2 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/2/lib.rs:6:2: 6:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.4 Struct expressions/2/lib.rs:6:2: 6:2 } }
structure test.main.Point3d := mk {} :: (x : i32) (y : i32) (z : i32) definition test.main : sem (unit) := let' «base$1» ← test.main.Point3d.mk (1 : int) (2 : int) (3 : int); let' t2 ← test.main.Point3d.mk (test.main.Point3d.x «base$1») (0 : int) (10 : int); let' ret ← ⋆; return (⋆)
Well, that's what we have MIR for.
fn foo() -> i32 { let x: i32 = { ; 5 }; x }
fn foo() -> i32 { let mut _0: i32; // return pointer scope 1 { let _1: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:2:9: 2:10 } let mut _2: i32; bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:2:9: 2:10 _1 = const 5i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:2:22: 2:23 StorageLive(_2); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:3:5: 3:6 _2 = _1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:3:5: 3:6 _0 = _2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:3:5: 3:6 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:4:2: 4:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:4:2: 4:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.5 Block expressions/lib.rs:4:2: 4:2 } }
definition test.foo : sem (i32) := let' «x$1» ← (5 : int); let' t2 ← «x$1»; let' ret ← t2; return (ret)
See 6.1.9 Traits and 6.1.10 Implementations.
Yes, that's some beautiful tuple struct extraction code.
fn main() { struct Point { x: i64, y: i64 } struct TuplePoint(i64, i64); Point {x: 10, y: 20}.x; TuplePoint(10, 20).0; }
fn main() -> () { let mut _0: (); // return pointer let mut _1: i64; let mut _2: i64; let mut _3: main::Point; let mut _4: i64; let mut _5: i64; let mut _6: main::TuplePoint; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:5:5: 5:27 StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:5:5: 5:25 _3 = main::Point { x: const 10i64, y: const 20i64 }; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:5:5: 5:25 _2 = (_3.0: i64); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:5:5: 5:27 _1 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:5:5: 5:27 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:5:28: 5:28 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:5:28: 5:28 StorageLive(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:6:5: 6:25 StorageLive(_6); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:6:5: 6:23 _6 = main::TuplePoint::{{constructor}}(const 10i64, const 20i64); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:6:5: 6:23 _5 = (_6.0: i64); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:6:5: 6:25 _4 = _5; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:6:5: 6:25 StorageDead(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:6:26: 6:26 StorageDead(_6); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:6:26: 6:26 _0 = (); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:1:11: 7:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.7 Field expressions/lib.rs:7:2: 7:2 } }
structure test.main.Point := mk {} :: (x : i64) (y : i64) inductive test.main.TuplePoint := mk {} : i64 → i64 → test.main.TuplePoint definition test.main : sem (unit) := let' t3 ← test.main.Point.mk (10 : int) (20 : int); let' t2 ← (test.main.Point.x t3); let' t1 ← t2; let' t6 ← test.main.TuplePoint.mk (10 : int) (20 : int); let' t5 ← match t6 with test.main.TuplePoint.mk x0 x1 := x0 end; let' t4 ← t5; let' ret ← ⋆; return (⋆)
fn main() { [1, 2, 3, 4]; ["a", "b", "c", "d"]; [0; 128]; // array with 128 zeros [0u8, 0u8, 0u8, 0u8]; }
const main::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 128usize; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:4:9: 4:12 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:4:9: 4:12 } } fn main() -> () { let mut _0: (); // return pointer let mut _1: [i32; 4]; let mut _2: [&'static str; 4]; let mut _3: [i32; 128]; let mut _4: [u8; 4]; bb0: { _1 = [const 1i32, const 2i32, const 3i32, const 4i32]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:2:5: 2:17 _2 = [const "a", const "b", const "c", const "d"]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:3:5: 3:25 _3 = [const 0i32; const 128usize]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:4:5: 4:13 _4 = [const 0u8, const 0u8, const 0u8, const 0u8]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:5:5: 5:25 _0 = (); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:1:11: 6:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.8 Array expressions/lib.rs:6:2: 6:2 } }
definition test.main : sem (unit) := let' t1 ← [(1 : int), (2 : int), (3 : int), (4 : int)]; let' t2 ← ["a", "b", "c", "d"]; let' t3 ← list.replicate 128 (0 : int); let' t4 ← [(0 : nat), (0 : nat), (0 : nat), (0 : nat)]; let' ret ← ⋆; return (⋆)
fn foo() -> i32 { ([1, 2, 3, 4])[0] } fn bar() -> &'static str { let n = 10; let y = (["a", "b"])[n]; // panics y }
fn bar() -> &'static str { let mut _0: &'static str; // return pointer scope 1 { let _1: usize; // "n" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:6:9: 6:10 scope 2 { let _2: &'static str; // "y" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:9: 7:10 } } let mut _3: &'static str; let mut _4: [&'static str; 2]; let mut _5: usize; let mut _6: usize; let mut _7: bool; bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:6:9: 6:10 _1 = const 10usize; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:6:13: 6:15 StorageLive(_2); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:9: 7:10 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:28 StorageLive(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:25 _4 = [const "a", const "b"]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:25 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:26: 7:27 _5 = _1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:26: 7:27 _6 = Len(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:28 _7 = Lt(_5, _6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:28 assert(_7, "index out of bounds: the len is {} but the index is {}", _6, _5) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:28 } bb1: { _3 = _4[_5]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:28 _2 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:13: 7:28 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:29: 7:29 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:29: 7:29 StorageDead(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:7:29: 7:29 _0 = &(*_2); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:8:5: 8:6 StorageDead(_2); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:9:2: 9:2 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:9:2: 9:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:9:2: 9:2 } } fn foo() -> i32 { let mut _0: i32; // return pointer let mut _1: i32; let mut _2: [i32; 4]; let mut _3: usize; let mut _4: bool; bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:22 StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:19 _2 = [const 1i32, const 2i32, const 3i32, const 4i32]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:19 _3 = Len(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:22 _4 = Lt(const 0usize, _3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:22 assert(_4, "index out of bounds: the len is {} but the index is {}", _3, const 0usize) -> bb1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:22 } bb1: { _1 = _2[const 0usize]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:22 _0 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:2:5: 2:22 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:3:2: 3:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:3:2: 3:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.9 Index expressions/lib.rs:3:2: 3:2 } }
definition test.foo : sem (i32) := let' t2 ← [(1 : int), (2 : int), (3 : int), (4 : int)]; let' t3 ← list.length t2; let' t4 ← (0 : nat) <ᵇ t3; do «$tmp0» ← core.«[T] as core.slice.SliceExt».get_unchecked t2 (0 : nat); let' t1 ← «$tmp0»; let' ret ← t1; return (ret) definition test.bar : sem (string) := let' «n$1» ← (10 : nat); let' t4 ← ["a", "b"]; let' t5 ← «n$1»; let' t6 ← list.length t4; let' t7 ← t5 <ᵇ t6; do «$tmp0» ← core.«[T] as core.slice.SliceExt».get_unchecked t4 t5; let' t3 ← «$tmp0»; let' «y$2» ← t3; let' ret ← «y$2»; return (ret)
example : sem.terminates_with (λ r, r = 1) test.foo := rfl example : ¬sem.terminates test.bar := id
fn main() { 1..2; // std::ops::Range 3..; // std::ops::RangeFrom ..4; // std::ops::RangeTo ..; // std::ops::RangeFull // still feature gated // 1...2; // std::ops::RangeInclusive // ...4; // std::ops::RangeToInclusive }
fn main() -> () { let mut _0: (); // return pointer let mut _1: std::ops::Range<i32>; let mut _2: i32; let mut _3: i32; let mut _4: std::ops::RangeFrom<i32>; let mut _5: i32; let mut _6: std::ops::RangeTo<i32>; let mut _7: i32; let mut _8: std::ops::RangeFull; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:2:5: 2:6 _2 = const 1i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:2:5: 2:6 StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:2:8: 2:9 _3 = const 2i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:2:8: 2:9 _1 = std::ops::Range<i32> { start: _2, end: _3 }; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:2:5: 2:9 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:2:10: 2:10 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:2:10: 2:10 StorageLive(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:3:5: 3:6 _5 = const 3i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:3:5: 3:6 _4 = std::ops::RangeFrom<i32> { start: _5 }; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:3:5: 3:8 StorageDead(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:3:9: 3:9 StorageLive(_7); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:4:7: 4:8 _7 = const 4i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:4:7: 4:8 _6 = std::ops::RangeTo<i32> { end: _7 }; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:4:5: 4:8 StorageDead(_7); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:4:9: 4:9 _8 = std::ops::RangeFull::{{constructor}}; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:5:5: 5:7 _0 = (); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:1:11: 10:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.10 Range expressions/lib.rs:10:2: 10:2 } }
definition test.main : sem (unit) := let' t2 ← (1 : int); let' t3 ← (2 : int); let' t1 ← core.ops.Range.mk t2 t3; let' t5 ← (3 : int); let' t4 ← core.ops.RangeFrom.mk t5; let' t7 ← (4 : int); let' t6 ← core.ops.RangeTo.mk t7; let' t8 ← core.ops.RangeFull.mk; let' ret ← ⋆; return (⋆)
fn foo(mut x: i32, y: &i32, b: bool) { -x; !x; *y; !b; &x; &mut x; }
fn foo(_1: i32, _2: &i32, _3: bool) -> () { let mut _0: (); // return pointer scope 1 { let mut _4: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:8: 1:13 let _5: &i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:20: 1:21 let _6: bool; // "b" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:29: 1:30 } let mut _7: i32; let mut _8: i32; let mut _9: bool; let mut _10: i32; let mut _11: i32; let mut _12: i32; let mut _13: i32; let mut _14: bool; let mut _15: bool; let mut _16: &i32; let mut _17: &mut i32; bb0: { StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:8: 1:13 _4 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:8: 1:13 StorageLive(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:20: 1:21 _5 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:20: 1:21 StorageLive(_6); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:29: 1:30 _6 = _3; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:29: 1:30 StorageLive(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:2:6: 2:7 _8 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:2:6: 2:7 _9 = Eq(_8, const -2147483648i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:2:5: 2:7 assert(!_9, "attempt to negate with overflow") -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:2:5: 2:7 } bb1: { _7 = Neg(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:2:5: 2:7 StorageDead(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:2:8: 2:8 StorageLive(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:3:6: 3:7 _11 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:3:6: 3:7 _10 = Not(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:3:5: 3:7 StorageDead(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:3:8: 3:8 StorageLive(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:4:5: 4:7 _13 = (*_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:4:5: 4:7 _12 = _13; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:4:5: 4:7 StorageDead(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:4:8: 4:8 StorageLive(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:5:6: 5:7 _15 = _6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:5:6: 5:7 _14 = Not(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:5:5: 5:7 StorageDead(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:5:8: 5:8 _16 = &_4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:6:5: 6:7 _17 = &mut _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:7:5: 7:11 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:1:38: 8:2 StorageDead(_6); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:8:2: 8:2 StorageDead(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:8:2: 8:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:8:2: 8:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/lib.rs:8:2: 8:2 } }
definition test.foo (xₐ : i32) (yₐ : i32) (bₐ : bool) : sem (unit) := let' «x$4» ← xₐ; let' «y$5» ← yₐ; let' «b$6» ← bₐ; let' t8 ← «x$4»; let' t9 ← t8 =ᵇ (-2147483648 : int); do «$tmp0» ← checked.neg i32.bits t8; let' t7 ← «$tmp0»; let' t11 ← «x$4»; let' t10 ← sbitnot i32.bits t11; let' t13 ← «y$5»; let' t12 ← t13; let' t15 ← «b$6»; let' t14 ← bool.bnot t15; let' t16 ← «x$4»; let' t17 ← @lens.id i32; do «$tmp» ← lens.get t17 «x$4»; let' ret ← ⋆; return (⋆)
A mutable reference points somewhere into a local of type T
and can read from and write into that values of type S
. We represent this as a lens T S
and statically keep track of which local the lens focuses on. The act of mutable borrowing translates to creating a new lens.
struct S { x: [i32; 2] } fn foo(mut s: S) -> i32 { let p = &mut s.x[0]; *p }
fn foo(_1: S) -> i32 { let mut _0: i32; // return pointer scope 1 { let mut _2: S; // "s" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:3:8: 3:13 scope 2 { let _3: &mut i32; // "p" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:4:9: 4:10 } } let mut _4: usize; let mut _5: bool; let mut _6: i32; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:3:8: 3:13 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:3:8: 3:13 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:4:9: 4:10 _4 = Len((_2.0: [i32; 2])); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:4:18: 4:24 _5 = Lt(const 0usize, _4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:4:18: 4:24 assert(_5, "index out of bounds: the len is {} but the index is {}", _4, const 0usize) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:4:18: 4:24 } bb1: { _3 = &mut (_2.0: [i32; 2])[const 0usize]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:4:13: 4:24 StorageLive(_6); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:5:5: 5:7 _6 = (*_3); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:5:5: 5:7 _0 = _6; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:5:5: 5:7 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:6:2: 6:2 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:6:2: 6:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:6:2: 6:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:6:2: 6:2 } } const S::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 2usize; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:1:21: 1:22 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Basic borrowing of local paths./lib.rs:1:21: 1:22 } }
structure test.S := mk {} :: (x : (array i32 2)) definition test.foo (sₐ : (test.S)) : sem (i32) := let' «s$2» ← sₐ; let' t4 ← list.length (test.S.x «s$2»); let' t5 ← (0 : nat) <ᵇ t4; let' «p$3» ← (lens.index _ (0 : nat) ∘ₗ lens.mk (return ∘ test.S.x) (λ (o : (test.S)) i, return ⦃ (test.S), x := i ⦄)); do «$tmp» ← lens.get «p$3» «s$2»; do «$tmp0» ← lens.get «p$3» «s$2»; let' t6 ← «$tmp0»; let' ret ← t6; return (ret)
example : sem.terminates_with (λ i, i = 41) (test.foo ⦃test.S, x := [41, 42]⦄) := rfl
Reborrowing means composing a new lens onto the existing one.
struct S { x: [i32; 2] } fn foo(s: &mut S) -> i32 { let p = &mut s.x[0]; *p }
fn foo(_1: &mut S) -> i32 { let mut _0: i32; // return pointer scope 1 { let _2: &mut S; // "s" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:3:8: 3:9 scope 2 { let _3: &mut i32; // "p" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:4:9: 4:10 } } let mut _4: usize; let mut _5: bool; let mut _6: i32; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:3:8: 3:9 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:3:8: 3:9 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:4:9: 4:10 _4 = Len(((*_2).0: [i32; 2])); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:4:18: 4:24 _5 = Lt(const 0usize, _4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:4:18: 4:24 assert(_5, "index out of bounds: the len is {} but the index is {}", _4, const 0usize) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:4:18: 4:24 } bb1: { _3 = &mut ((*_2).0: [i32; 2])[const 0usize]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:4:13: 4:24 StorageLive(_6); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:5:5: 5:7 _6 = (*_3); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:5:5: 5:7 _0 = _6; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:5:5: 5:7 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:6:2: 6:2 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:6:2: 6:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:6:2: 6:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:6:2: 6:2 } } const S::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 2usize; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:1:21: 1:22 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./0 Reborrowing./lib.rs:1:21: 1:22 } }
structure test.S := mk {} :: (x : (array i32 2)) definition test.foo (sₐ : (test.S)) : sem (i32 × (test.S)) := let' «s$2» ← @lens.id (test.S); do «$tmp0» ← do «$tmp0» ← do «$tmp0» ← lens.get «s$2» sₐ; return ((test.S.x «$tmp0»)); return (list.length «$tmp0»); let' t4 ← «$tmp0»; let' t5 ← (0 : nat) <ᵇ t4; let' «p$3» ← (lens.index _ (0 : nat) ∘ₗ lens.mk (return ∘ test.S.x) (λ (o : (test.S)) i, return ⦃ (test.S), x := i ⦄) ∘ₗ «s$2»); do «$tmp» ← lens.get «p$3» sₐ; do «$tmp0» ← lens.get «p$3» sₐ; let' t6 ← «$tmp0»; let' ret ← t6; return (ret, sₐ)
Nested storing of &mut
makes the static tracking harder.
fn foo(mut x: i32, mut y: i32) -> i32 { { let rs = [&mut x, &mut y]; *rs[0] += 1; } x }
fn foo(_1: i32, _2: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let mut _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:1:8: 1:13 let mut _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:1:20: 1:25 scope 2 { let _6: [&mut i32; 2]; // "rs" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:13: 3:15 } } let mut _5: (); let mut _7: &mut i32; let mut _8: &mut i32; let mut _9: &mut i32; let mut _10: usize; let mut _11: bool; let mut _12: (i32, bool); let mut _13: i32; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:1:8: 1:13 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:1:8: 1:13 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:1:20: 1:25 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:1:20: 1:25 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:13: 3:15 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:19: 3:25 _7 = &mut _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:19: 3:25 StorageLive(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:27: 3:33 StorageLive(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:27: 3:33 _9 = &mut _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:27: 3:33 _8 = &mut (*_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:27: 3:33 _6 = [_7, _8]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:18: 3:34 StorageDead(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:35: 3:35 StorageDead(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:35: 3:35 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:3:35: 3:35 _10 = Len(_6); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:4:10: 4:15 _11 = Lt(const 0usize, _10); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:4:10: 4:15 assert(_11, "index out of bounds: the len is {} but the index is {}", _10, const 0usize) -> bb1; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:4:10: 4:15 } bb1: { _12 = CheckedAdd((*_6[const 0usize]), const 1i32); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:4:9: 4:20 assert(!(_12.1: bool), "attempt to add with overflow") -> bb2; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:4:9: 4:20 } bb2: { (*_6[const 0usize]) = (_12.0: i32); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:4:9: 4:20 _5 = (); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:2:5: 5:6 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:5:6: 5:6 StorageLive(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:6:5: 6:6 _13 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:6:5: 6:6 _0 = _13; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:6:5: 6:6 StorageDead(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:7:2: 7:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:7:2: 7:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:7:2: 7:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.11 Unary operator expressions/2 Mutable borrowing./2 Nested storing of mut refs./lib.rs:7:2: 7:2 } }
/- test.foo: unimplemented: arbitrary move of &mut | _7 -/
fn unsigned(x: u32, y: u32) { x + y; x - y; x * y; x / y; x % y; } fn signed(x: i32, y: i32) { x + y; x - y; x * y; x / y; x % y; }
fn signed(_1: i32, _2: i32) -> () { let mut _0: (); // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:9:11: 9:12 let _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:9:19: 9:20 } let mut _5: i32; let mut _6: i32; let mut _7: i32; let mut _8: (i32, bool); let mut _9: i32; let mut _10: i32; let mut _11: i32; let mut _12: (i32, bool); let mut _13: i32; let mut _14: i32; let mut _15: i32; let mut _16: (i32, bool); let mut _17: i32; let mut _18: i32; let mut _19: i32; let mut _20: bool; let mut _21: bool; let mut _22: bool; let mut _23: bool; let mut _24: i32; let mut _25: i32; let mut _26: i32; let mut _27: bool; let mut _28: bool; let mut _29: bool; let mut _30: bool; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:9:11: 9:12 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:9:11: 9:12 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:9:19: 9:20 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:9:19: 9:20 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:5: 10:6 _6 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:5: 10:6 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:9: 10:10 _7 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:9: 10:10 _8 = CheckedAdd(_6, _7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:5: 10:10 assert(!(_8.1: bool), "attempt to add with overflow") -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:5: 10:10 } bb1: { _5 = (_8.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:5: 10:10 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:11: 10:11 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:10:11: 10:11 StorageLive(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:5: 11:6 _10 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:5: 11:6 StorageLive(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:9: 11:10 _11 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:9: 11:10 _12 = CheckedSub(_10, _11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:5: 11:10 assert(!(_12.1: bool), "attempt to subtract with overflow") -> bb2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:5: 11:10 } bb2: { _9 = (_12.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:5: 11:10 StorageDead(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:11: 11:11 StorageDead(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:11:11: 11:11 StorageLive(_14); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:5: 12:6 _14 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:5: 12:6 StorageLive(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:9: 12:10 _15 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:9: 12:10 _16 = CheckedMul(_14, _15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:5: 12:10 assert(!(_16.1: bool), "attempt to multiply with overflow") -> bb3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:5: 12:10 } bb3: { _13 = (_16.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:5: 12:10 StorageDead(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:11: 12:11 StorageDead(_14); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:12:11: 12:11 StorageLive(_18); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:6 _18 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:6 StorageLive(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:9: 13:10 _19 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:9: 13:10 _20 = Eq(_19, const 0i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:10 assert(!_20, "attempt to divide by zero") -> bb4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:10 } bb4: { _21 = Eq(_19, const -1i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:10 _22 = Eq(_18, const -2147483648i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:10 _23 = BitAnd(_21, _22); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:10 assert(!_23, "attempt to divide with overflow") -> bb5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:10 } bb5: { _17 = Div(_18, _19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:5: 13:10 StorageDead(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:11: 13:11 StorageDead(_18); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:13:11: 13:11 StorageLive(_25); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:6 _25 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:6 StorageLive(_26); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:9: 14:10 _26 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:9: 14:10 _27 = Eq(_26, const 0i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:10 assert(!_27, "attempt to calculate the remainder with a divisor of zero") -> bb6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:10 } bb6: { _28 = Eq(_26, const -1i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:10 _29 = Eq(_25, const -2147483648i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:10 _30 = BitAnd(_28, _29); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:10 assert(!_30, "attempt to calculate the remainder with overflow") -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:10 } bb7: { _24 = Rem(_25, _26); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:5: 14:10 StorageDead(_26); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:11: 14:11 StorageDead(_25); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:14:11: 14:11 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:9:27: 15:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:15:2: 15:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:15:2: 15:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:15:2: 15:2 } } fn unsigned(_1: u32, _2: u32) -> () { let mut _0: (); // return pointer scope 1 { let _3: u32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:1:13: 1:14 let _4: u32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:1:21: 1:22 } let mut _5: u32; let mut _6: u32; let mut _7: u32; let mut _8: (u32, bool); let mut _9: u32; let mut _10: u32; let mut _11: u32; let mut _12: (u32, bool); let mut _13: u32; let mut _14: u32; let mut _15: u32; let mut _16: (u32, bool); let mut _17: u32; let mut _18: u32; let mut _19: u32; let mut _20: bool; let mut _21: u32; let mut _22: u32; let mut _23: u32; let mut _24: bool; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:1:13: 1:14 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:1:13: 1:14 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:1:21: 1:22 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:1:21: 1:22 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:5: 2:6 _6 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:5: 2:6 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:9: 2:10 _7 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:9: 2:10 _8 = CheckedAdd(_6, _7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:5: 2:10 assert(!(_8.1: bool), "attempt to add with overflow") -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:5: 2:10 } bb1: { _5 = (_8.0: u32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:5: 2:10 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:11: 2:11 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:2:11: 2:11 StorageLive(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:5: 3:6 _10 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:5: 3:6 StorageLive(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:9: 3:10 _11 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:9: 3:10 _12 = CheckedSub(_10, _11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:5: 3:10 assert(!(_12.1: bool), "attempt to subtract with overflow") -> bb2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:5: 3:10 } bb2: { _9 = (_12.0: u32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:5: 3:10 StorageDead(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:11: 3:11 StorageDead(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:3:11: 3:11 StorageLive(_14); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:5: 4:6 _14 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:5: 4:6 StorageLive(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:9: 4:10 _15 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:9: 4:10 _16 = CheckedMul(_14, _15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:5: 4:10 assert(!(_16.1: bool), "attempt to multiply with overflow") -> bb3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:5: 4:10 } bb3: { _13 = (_16.0: u32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:5: 4:10 StorageDead(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:11: 4:11 StorageDead(_14); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:4:11: 4:11 StorageLive(_18); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:5: 5:6 _18 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:5: 5:6 StorageLive(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:9: 5:10 _19 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:9: 5:10 _20 = Eq(_19, const 0u32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:5: 5:10 assert(!_20, "attempt to divide by zero") -> bb4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:5: 5:10 } bb4: { _17 = Div(_18, _19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:5: 5:10 StorageDead(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:11: 5:11 StorageDead(_18); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:5:11: 5:11 StorageLive(_22); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:5: 6:6 _22 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:5: 6:6 StorageLive(_23); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:9: 6:10 _23 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:9: 6:10 _24 = Eq(_23, const 0u32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:5: 6:10 assert(!_24, "attempt to calculate the remainder with a divisor of zero") -> bb5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:5: 6:10 } bb5: { _21 = Rem(_22, _23); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:5: 6:10 StorageDead(_23); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:11: 6:11 StorageDead(_22); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:6:11: 6:11 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:1:29: 7:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:7:2: 7:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:7:2: 7:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.1 Arithmetic operators/lib.rs:7:2: 7:2 } }
definition test.unsigned (xₐ : u32) (yₐ : u32) : sem (unit) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «x$3»; let' t7 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.add u32.bits t6 t7); let' t8 ← «$tmp0»; let' t5 ← t8.1; let' t10 ← «x$3»; let' t11 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sub u32.bits t10 t11); let' t12 ← «$tmp0»; let' t9 ← t12.1; let' t14 ← «x$3»; let' t15 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.mul u32.bits t14 t15); let' t16 ← «$tmp0»; let' t13 ← t16.1; let' t18 ← «x$3»; let' t19 ← «y$4»; let' t20 ← t19 =ᵇ (0 : nat); do «$tmp0» ← checked.div u32.bits t18 t19; let' t17 ← «$tmp0»; let' t22 ← «x$3»; let' t23 ← «y$4»; let' t24 ← t23 =ᵇ (0 : nat); do «$tmp0» ← checked.rem u32.bits t22 t23; let' t21 ← «$tmp0»; let' ret ← ⋆; return (⋆) definition test.signed (xₐ : i32) (yₐ : i32) : sem (unit) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «x$3»; let' t7 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits t6 t7); let' t8 ← «$tmp0»; let' t5 ← t8.1; let' t10 ← «x$3»; let' t11 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.ssub i32.bits t10 t11); let' t12 ← «$tmp0»; let' t9 ← t12.1; let' t14 ← «x$3»; let' t15 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.smul i32.bits t14 t15); let' t16 ← «$tmp0»; let' t13 ← t16.1; let' t18 ← «x$3»; let' t19 ← «y$4»; let' t20 ← t19 =ᵇ (0 : int); let' t21 ← t19 =ᵇ (-1 : int); let' t22 ← t18 =ᵇ (-2147483648 : int); let' t23 ← band t21 t22; do «$tmp0» ← checked.sdiv i32.bits t18 t19; let' t17 ← «$tmp0»; let' t25 ← «x$3»; let' t26 ← «y$4»; let' t27 ← t26 =ᵇ (0 : int); let' t28 ← t26 =ᵇ (-1 : int); let' t29 ← t25 =ᵇ (-2147483648 : int); let' t30 ← band t28 t29; do «$tmp0» ← checked.srem i32.bits t25 t26; let' t24 ← «$tmp0»; let' ret ← ⋆; return (⋆)
fn unsigned(x: u32, y: u32) { x & y; x | y; x ^ y; x << y; x >> y; } fn signed(x: i32, y: i32) { x & y; x | y; x ^ y; x << y; x >> y; } fn bool(x: bool, y: bool) { x & y; x | y; x ^ y; }
fn bool(_1: bool, _2: bool) -> () { let mut _0: (); // return pointer scope 1 { let _3: bool; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:17:9: 17:10 let _4: bool; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:17:18: 17:19 } let mut _5: bool; let mut _6: bool; let mut _7: bool; let mut _8: bool; let mut _9: bool; let mut _10: bool; let mut _11: bool; let mut _12: bool; let mut _13: bool; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:17:9: 17:10 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:17:9: 17:10 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:17:18: 17:19 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:17:18: 17:19 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:18:5: 18:6 _6 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:18:5: 18:6 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:18:9: 18:10 _7 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:18:9: 18:10 _5 = BitAnd(_6, _7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:18:5: 18:10 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:18:11: 18:11 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:18:11: 18:11 StorageLive(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:19:5: 19:6 _9 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:19:5: 19:6 StorageLive(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:19:9: 19:10 _10 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:19:9: 19:10 _8 = BitOr(_9, _10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:19:5: 19:10 StorageDead(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:19:11: 19:11 StorageDead(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:19:11: 19:11 StorageLive(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:20:5: 20:6 _12 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:20:5: 20:6 StorageLive(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:20:9: 20:10 _13 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:20:9: 20:10 _11 = BitXor(_12, _13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:20:5: 20:10 StorageDead(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:20:11: 20:11 StorageDead(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:20:11: 20:11 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:17:27: 21:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:21:2: 21:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:21:2: 21:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:21:2: 21:2 } } fn signed(_1: i32, _2: i32) -> () { let mut _0: (); // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:9:11: 9:12 let _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:9:19: 9:20 } let mut _5: i32; let mut _6: i32; let mut _7: i32; let mut _8: i32; let mut _9: i32; let mut _10: i32; let mut _11: i32; let mut _12: i32; let mut _13: i32; let mut _14: i32; let mut _15: i32; let mut _16: i32; let mut _17: (i32, bool); let mut _18: i32; let mut _19: i32; let mut _20: i32; let mut _21: (i32, bool); bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:9:11: 9:12 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:9:11: 9:12 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:9:19: 9:20 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:9:19: 9:20 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:10:5: 10:6 _6 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:10:5: 10:6 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:10:9: 10:10 _7 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:10:9: 10:10 _5 = BitAnd(_6, _7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:10:5: 10:10 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:10:11: 10:11 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:10:11: 10:11 StorageLive(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:11:5: 11:6 _9 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:11:5: 11:6 StorageLive(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:11:9: 11:10 _10 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:11:9: 11:10 _8 = BitOr(_9, _10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:11:5: 11:10 StorageDead(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:11:11: 11:11 StorageDead(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:11:11: 11:11 StorageLive(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:12:5: 12:6 _12 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:12:5: 12:6 StorageLive(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:12:9: 12:10 _13 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:12:9: 12:10 _11 = BitXor(_12, _13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:12:5: 12:10 StorageDead(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:12:11: 12:11 StorageDead(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:12:11: 12:11 StorageLive(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:5: 13:6 _15 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:5: 13:6 StorageLive(_16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:10: 13:11 _16 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:10: 13:11 _17 = CheckedShl(_15, _16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:5: 13:11 assert(!(_17.1: bool), "attempt to shift left with overflow") -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:5: 13:11 } bb1: { _14 = (_17.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:5: 13:11 StorageDead(_16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:12: 13:12 StorageDead(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:13:12: 13:12 StorageLive(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:5: 14:6 _19 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:5: 14:6 StorageLive(_20); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:10: 14:11 _20 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:10: 14:11 _21 = CheckedShr(_19, _20); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:5: 14:11 assert(!(_21.1: bool), "attempt to shift right with overflow") -> bb2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:5: 14:11 } bb2: { _18 = (_21.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:5: 14:11 StorageDead(_20); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:12: 14:12 StorageDead(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:14:12: 14:12 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:9:27: 15:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:15:2: 15:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:15:2: 15:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:15:2: 15:2 } } fn unsigned(_1: u32, _2: u32) -> () { let mut _0: (); // return pointer scope 1 { let _3: u32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:1:13: 1:14 let _4: u32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:1:21: 1:22 } let mut _5: u32; let mut _6: u32; let mut _7: u32; let mut _8: u32; let mut _9: u32; let mut _10: u32; let mut _11: u32; let mut _12: u32; let mut _13: u32; let mut _14: u32; let mut _15: u32; let mut _16: u32; let mut _17: (u32, bool); let mut _18: u32; let mut _19: u32; let mut _20: u32; let mut _21: (u32, bool); bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:1:13: 1:14 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:1:13: 1:14 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:1:21: 1:22 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:1:21: 1:22 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:2:5: 2:6 _6 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:2:5: 2:6 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:2:9: 2:10 _7 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:2:9: 2:10 _5 = BitAnd(_6, _7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:2:5: 2:10 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:2:11: 2:11 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:2:11: 2:11 StorageLive(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:3:5: 3:6 _9 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:3:5: 3:6 StorageLive(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:3:9: 3:10 _10 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:3:9: 3:10 _8 = BitOr(_9, _10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:3:5: 3:10 StorageDead(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:3:11: 3:11 StorageDead(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:3:11: 3:11 StorageLive(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:4:5: 4:6 _12 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:4:5: 4:6 StorageLive(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:4:9: 4:10 _13 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:4:9: 4:10 _11 = BitXor(_12, _13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:4:5: 4:10 StorageDead(_13); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:4:11: 4:11 StorageDead(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:4:11: 4:11 StorageLive(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:5: 5:6 _15 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:5: 5:6 StorageLive(_16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:10: 5:11 _16 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:10: 5:11 _17 = CheckedShl(_15, _16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:5: 5:11 assert(!(_17.1: bool), "attempt to shift left with overflow") -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:5: 5:11 } bb1: { _14 = (_17.0: u32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:5: 5:11 StorageDead(_16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:12: 5:12 StorageDead(_15); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:5:12: 5:12 StorageLive(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:5: 6:6 _19 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:5: 6:6 StorageLive(_20); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:10: 6:11 _20 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:10: 6:11 _21 = CheckedShr(_19, _20); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:5: 6:11 assert(!(_21.1: bool), "attempt to shift right with overflow") -> bb2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:5: 6:11 } bb2: { _18 = (_21.0: u32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:5: 6:11 StorageDead(_20); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:12: 6:12 StorageDead(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:6:12: 6:12 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:1:29: 7:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:7:2: 7:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:7:2: 7:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.2 Bitwise operators/lib.rs:7:2: 7:2 } }
definition test.unsigned (xₐ : u32) (yₐ : u32) : sem (unit) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «x$3»; let' t7 ← «y$4»; let' t5 ← bitand u32.bits t6 t7; let' t9 ← «x$3»; let' t10 ← «y$4»; let' t8 ← bitor u32.bits t9 t10; let' t12 ← «x$3»; let' t13 ← «y$4»; let' t11 ← bitxor u32.bits t12 t13; let' t15 ← «x$3»; let' t16 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.shl u32.bits t15 t16); let' t17 ← «$tmp0»; let' t14 ← t17.1; let' t19 ← «x$3»; let' t20 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.shr u32.bits t19 t20); let' t21 ← «$tmp0»; let' t18 ← t21.1; let' ret ← ⋆; return (⋆) definition test.signed (xₐ : i32) (yₐ : i32) : sem (unit) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «x$3»; let' t7 ← «y$4»; let' t5 ← sbitand i32.bits t6 t7; let' t9 ← «x$3»; let' t10 ← «y$4»; let' t8 ← sbitor i32.bits t9 t10; let' t12 ← «x$3»; let' t13 ← «y$4»; let' t11 ← sbitxor i32.bits t12 t13; let' t15 ← «x$3»; let' t16 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sshls i32.bits t15 t16); let' t17 ← «$tmp0»; let' t14 ← t17.1; let' t19 ← «x$3»; let' t20 ← «y$4»; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sshrs i32.bits t19 t20); let' t21 ← «$tmp0»; let' t18 ← t21.1; let' ret ← ⋆; return (⋆) definition test.bool (xₐ : bool) (yₐ : bool) : sem (unit) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «x$3»; let' t7 ← «y$4»; let' t5 ← band t6 t7; let' t9 ← «x$3»; let' t10 ← «y$4»; let' t8 ← bor t9 t10; let' t12 ← «x$3»; let' t13 ← «y$4»; let' t11 ← bxor t12 t13; let' ret ← ⋆; return (⋆)
fn main(x: bool, y: bool) { x && y; x || y; }
fn main(_1: bool, _2: bool) -> () { let mut _0: (); // return pointer scope 1 { let _3: bool; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:1:9: 1:10 let _4: bool; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:1:18: 1:19 } let mut _5: bool; let mut _6: bool; let mut _7: bool; let mut _8: bool; let mut _9: bool; let mut _10: bool; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:1:9: 1:10 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:1:9: 1:10 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:1:18: 1:19 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:1:18: 1:19 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:6 _6 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:6 if(_6) -> [true: bb3, false: bb2]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:11 } bb1: { _5 = const true; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:11 goto -> bb4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:11 } bb2: { _5 = const false; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:11 goto -> bb4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:11 } bb3: { StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:10: 2:11 _7 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:10: 2:11 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:11: 2:11 if(_7) -> [true: bb1, false: bb2]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:5: 2:11 } bb4: { StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:2:12: 2:12 StorageLive(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:6 _9 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:6 if(_9) -> [true: bb5, false: bb7]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:11 } bb5: { _8 = const true; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:11 goto -> bb8; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:11 } bb6: { _8 = const false; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:11 goto -> bb8; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:11 } bb7: { StorageLive(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:10: 3:11 _10 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:10: 3:11 StorageDead(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:11: 3:11 if(_10) -> [true: bb5, false: bb6]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:5: 3:11 } bb8: { StorageDead(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:3:12: 3:12 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:1:27: 4:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:4:2: 4:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:4:2: 4:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.3 Lazy boolean operators/lib.rs:4:2: 4:2 } }
definition test.main (xₐ : bool) (yₐ : bool) : sem (unit) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «x$3»; if t6 = bool.tt then let' t7 ← «y$4»; if t7 = bool.tt then let' t5 ← tt; let' t9 ← «x$3»; if t9 = bool.tt then let' t8 ← tt; let' ret ← ⋆; return (⋆) else let' t10 ← «y$4»; if t10 = bool.tt then let' t8 ← tt; let' ret ← ⋆; return (⋆) else let' t8 ← ff; let' ret ← ⋆; return (⋆) else let' t5 ← ff; let' t9 ← «x$3»; if t9 = bool.tt then let' t8 ← tt; let' ret ← ⋆; return (⋆) else let' t10 ← «y$4»; if t10 = bool.tt then let' t8 ← tt; let' ret ← ⋆; return (⋆) else let' t8 ← ff; let' ret ← ⋆; return (⋆) else let' t5 ← ff; let' t9 ← «x$3»; if t9 = bool.tt then let' t8 ← tt; let' ret ← ⋆; return (⋆) else let' t10 ← «y$4»; if t10 = bool.tt then let' t8 ← tt; let' ret ← ⋆; return (⋆) else let' t8 ← ff; let' ret ← ⋆; return (⋆)
fn foo(x: i32, y: i32) -> bool { x < y } // etc...
fn foo(_1: i32, _2: i32) -> bool { let mut _0: bool; // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:8: 1:9 let _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:16: 1:17 } let mut _5: i32; let mut _6: i32; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:8: 1:9 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:8: 1:9 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:16: 1:17 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:16: 1:17 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:34: 1:35 _5 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:34: 1:35 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:38: 1:39 _6 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:38: 1:39 _0 = Lt(_5, _6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:34: 1:39 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:41: 1:41 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:41: 1:41 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:41: 1:41 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:41: 1:41 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.4 Comparison operators/lib.rs:1:41: 1:41 } }
definition test.foo (xₐ : i32) (yₐ : i32) : sem (bool) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t5 ← «x$3»; let' t6 ← «y$4»; let' ret ← t5 <ᵇ t6; return (ret)
fn foo(x: isize) -> u32 { x as u32 } // etc...
fn foo(_1: isize) -> u32 { let mut _0: u32; // return pointer scope 1 { let _2: isize; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:8: 1:9 } let mut _3: isize; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:8: 1:9 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:8: 1:9 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:27: 1:28 _3 = _2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:27: 1:28 _0 = _3 as u32 (Misc); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:27: 1:35 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:37: 1:37 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:37: 1:37 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/1 Integral casts./lib.rs:1:37: 1:37 } }
definition test.foo (xₐ : isize) : sem (u32) := let' «x$2» ← xₐ; let' t3 ← «x$2»; do «$tmp0» ← (signed_to_unsigned u32.bits t3); let' ret ← «$tmp0»; return (ret)
A no-op without trait objects and with identifying [T;N]
and [T]
.
fn foo(x: &[u32; 2]) -> &[u32] { x }
fn foo(_1: &[u32; 2]) -> &[u32] { let mut _0: &[u32]; // return pointer scope 1 { let _2: &[u32; 2]; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:8: 1:9 } let mut _3: &[u32; 2]; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:8: 1:9 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:8: 1:9 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:34: 1:35 _3 = &(*_2); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:34: 1:35 _0 = _3 as &[u32] (Unsize); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:34: 1:35 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:37: 1:37 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:37: 1:37 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:37: 1:37 } } const foo::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 2usize; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:18: 1:19 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.5 Type cast expressions/2 Unsize casts./lib.rs:1:18: 1:19 } }
definition test.foo (xₐ : (array u32 2)) : sem ((slice u32)) := let' «x$2» ← xₐ; let' t3 ← «x$2»; let' ret ← t3; return (ret)
fn main() { let mut x = 1; x = 2; }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let mut _1: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/lib.rs:2:9: 2:14 } bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/lib.rs:2:9: 2:14 _1 = const 1i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/lib.rs:2:17: 2:18 _1 = const 2i32; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/lib.rs:3:5: 3:10 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/lib.rs:1:11: 4:2 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/lib.rs:4:2: 4:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/lib.rs:4:2: 4:2 } }
definition test.main : sem (unit) := let' «x$1» ← (1 : int); let' «x$1» ← (2 : int); let' ret ← ⋆; return (⋆)
struct S { x: [i32; 2] } fn foo(mut s: S, i: usize) -> S { s.x[i] = 2; s }
fn foo(_1: S, _2: usize) -> S { let mut _0: S; // return pointer scope 1 { let mut _3: S; // "s" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:3:8: 3:13 let _4: usize; // "i" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:3:18: 3:19 } let mut _5: usize; let mut _6: usize; let mut _7: bool; let mut _8: S; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:3:8: 3:13 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:3:8: 3:13 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:3:18: 3:19 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:3:18: 3:19 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:4:9: 4:10 _5 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:4:9: 4:10 _6 = Len((_3.0: [i32; 2])); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:4:5: 4:11 _7 = Lt(_5, _6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:4:5: 4:11 assert(_7, "index out of bounds: the len is {} but the index is {}", _6, _5) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:4:5: 4:11 } bb1: { (_3.0: [i32; 2])[_5] = const 2i32; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:4:5: 4:15 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:4:16: 4:16 StorageLive(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:5:5: 5:6 _8 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:5:5: 5:6 _0 = _8; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:5:5: 5:6 StorageDead(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:6:2: 6:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:6:2: 6:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:6:2: 6:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:6:2: 6:2 } } const S::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 2usize; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:1:21: 1:22 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/1 Assignment through lvalue paths./lib.rs:1:21: 1:22 } }
structure test.S := mk {} :: (x : (array i32 2)) definition test.foo (sₐ : (test.S)) (iₐ : usize) : sem ((test.S)) := let' «s$3» ← sₐ; let' «i$4» ← iₐ; let' t5 ← «i$4»; let' t6 ← list.length (test.S.x «s$3»); let' t7 ← t5 <ᵇ t6; do «$tmp2» ← sem.lift_opt (list.update (test.S.x «s$3») t5 (2 : int)); let' «s$3» ← ⦃ (test.S), x := «$tmp2» ⦄; let' t8 ← «s$3»; let' ret ← t8; return (ret)
example : sem.terminates_with (λ s', s' = ⦃test.S, x := [2, 42]⦄) (test.foo ⦃test.S, x := [41, 42]⦄ 0) := rfl example : ¬sem.terminates (test.foo ⦃test.S, x := [41, 42]⦄ 2) := id
struct S { x: [i32; 2] } fn foo(mut s: S) { let p = &mut s.x[0]; *p = 2; }
fn foo(_1: S) -> () { let mut _0: (); // return pointer scope 1 { let mut _2: S; // "s" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:3:8: 3:13 scope 2 { let _3: &mut i32; // "p" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:4:9: 4:10 } } let mut _4: usize; let mut _5: bool; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:3:8: 3:13 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:3:8: 3:13 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:4:9: 4:10 _4 = Len((_2.0: [i32; 2])); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:4:18: 4:24 _5 = Lt(const 0usize, _4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:4:18: 4:24 assert(_5, "index out of bounds: the len is {} but the index is {}", _4, const 0usize) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:4:18: 4:24 } bb1: { _3 = &mut (_2.0: [i32; 2])[const 0usize]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:4:13: 4:24 (*_3) = const 2i32; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:5:5: 5:11 _0 = (); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:3:18: 6:2 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:6:2: 6:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:6:2: 6:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:6:2: 6:2 } } const S::{{initializer}}: usize = { let mut _0: usize; // return pointer bb0: { _0 = const 2usize; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:1:21: 1:22 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.12 Binary operator expressions/7.2.12.6 Assignment expressions/3 Assignment through mut refs./lib.rs:1:21: 1:22 } }
structure test.S := mk {} :: (x : (array i32 2)) definition test.foo (sₐ : (test.S)) : sem (unit) := let' «s$2» ← sₐ; let' t4 ← list.length (test.S.x «s$2»); let' t5 ← (0 : nat) <ᵇ t4; let' «p$3» ← (lens.index _ (0 : nat) ∘ₗ lens.mk (return ∘ test.S.x) (λ (o : (test.S)) i, return ⦃ (test.S), x := i ⦄)); do «$tmp» ← lens.get «p$3» «s$2»; do «s$2» ← lens.set «p$3» «s$2» (2 : int); let' ret ← ⋆; return (⋆)
Desugared in MIR
Calling a function increments the step counter via the dostep
notation.
(Yes, that's the actual example from the reference. Though the implementation of add
is hidden by default.)
fn add(x: i32, y: i32) -> i32 { 0 } fn main() { let x: i32 = add(1i32, 2i32); }
fn main() -> () { let mut _0: (); // return pointer scope 1 { let _1: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:4:9: 4:10 } bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:4:9: 4:10 _1 = add(const 1i32, const 2i32) -> bb1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:4:18: 4:33 } bb1: { _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:3:11: 5:2 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:5:2: 5:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:5:2: 5:2 } } fn add(_1: i32, _2: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:8: 1:9 let _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:16: 1:17 } bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:8: 1:9 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:8: 1:9 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:16: 1:17 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:16: 1:17 _0 = const 0i32; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:33: 1:34 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:36: 1:36 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:36: 1:36 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/lib.rs:1:36: 1:36 } }
definition test.add (xₐ : i32) (yₐ : i32) : sem (i32) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' ret ← (0 : int); return (ret) definition test.main : sem (unit) := dostep «$tmp» ← @test.add (1 : int) (2 : int); let' «x$1» ← «$tmp»; let' ret ← ⋆; return (⋆)
Passing a mutable reference means reading the current value from the lens, then writing back the new value through the lens.
fn set(x: &mut i32, y: i32) { *x = y ; () // FIXME: removing this line leaves `ret` uninitialized, which sounds at least like 'undesired behavior' from MIR } fn foo() -> i32 { let mut x = 1; set(&mut x, 2); x }
fn foo() -> i32 { let mut _0: i32; // return pointer scope 1 { let mut _1: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:7:9: 7:14 } let mut _2: (); let mut _3: &mut i32; let mut _4: &mut i32; let mut _5: i32; bb0: { StorageLive(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:7:9: 7:14 _1 = const 1i32; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:7:17: 7:18 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:8:9: 8:15 StorageLive(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:8:9: 8:15 _4 = &mut _1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:8:9: 8:15 _3 = &mut (*_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:8:9: 8:15 _2 = set(_3, const 2i32) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:8:5: 8:19 } bb1: { StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:8:20: 8:20 StorageDead(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:8:20: 8:20 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:9:5: 9:6 _5 = _1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:9:5: 9:6 _0 = _5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:9:5: 9:6 StorageDead(_1); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:10:2: 10:2 StorageDead(_5); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:10:2: 10:2 return; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:10:2: 10:2 } } fn set(_1: &mut i32, _2: i32) -> () { let mut _0: (); // return pointer scope 1 { let _3: &mut i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:1:8: 1:9 let _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:1:21: 1:22 } let mut _5: i32; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:1:8: 1:9 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:1:8: 1:9 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:1:21: 1:22 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:1:21: 1:22 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:2:10: 2:11 _5 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:2:10: 2:11 (*_3) = _5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:2:5: 2:11 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:3:10: 3:10 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:3:11: 3:13 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:4:2: 4:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:4:2: 4:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/1 Mutable reference parameters./lib.rs:4:2: 4:2 } }
definition test.set (xₐ : i32) (yₐ : i32) : sem (unit × i32) := let' «x$3» ← @lens.id i32; let' «y$4» ← yₐ; let' t5 ← «y$4»; do xₐ ← lens.set «x$3» xₐ t5; let' ret ← ⋆; return (⋆, xₐ) definition test.foo : sem (i32) := let' «x$1» ← (1 : int); let' t4 ← @lens.id i32; do «$tmp» ← lens.get t4 «x$1»; let' t3 ← (t4); do «$tmp» ← lens.get t3 «x$1»; do «$tmp0» ← lens.get t3 «x$1»; dostep «$tmp» ← @test.set «$tmp0» (2 : int); match «$tmp» with (t2, «t3$») := do «x$1» ← lens.set t3 «x$1» «t3$»; let' t5 ← «x$1»; let' ret ← t5; return (ret) end
example : sem.terminates_with (λ r, r = 2) test.foo := rfl
We know that the return value will be a lens into the first argument, so we compose it with that one's lens. Note that we also get back the new value of the first argument.
fn foo(xs: &mut [i32]) -> &mut i32 { &mut xs[0] } fn bar(xs: &mut [i32]) { *foo(xs) = 2; }
fn foo(_1: &mut [i32]) -> &mut i32 { let mut _0: &mut i32; // return pointer scope 1 { let _2: &mut [i32]; // "xs" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:1:8: 1:10 } let mut _3: &mut i32; let mut _4: &mut i32; let mut _5: usize; let mut _6: bool; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:1:8: 1:10 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:1:8: 1:10 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:1:36: 3:2 StorageLive(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:2:5: 2:15 _5 = Len((*_2)); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:2:10: 2:15 _6 = Lt(const 0usize, _5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:2:10: 2:15 assert(_6, "index out of bounds: the len is {} but the index is {}", _5, const 0usize) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:2:10: 2:15 } bb1: { _4 = &mut (*_2)[const 0usize]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:2:5: 2:15 _3 = &mut (*_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:2:5: 2:15 _0 = &mut (*_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:1:36: 3:2 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:3:2: 3:2 StorageDead(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:3:2: 3:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:3:2: 3:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:3:2: 3:2 } } fn bar(_1: &mut [i32]) -> () { let mut _0: (); // return pointer scope 1 { let _2: &mut [i32]; // "xs" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:5:8: 5:10 } let mut _3: &mut i32; let mut _4: &mut [i32]; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:5:8: 5:10 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:5:8: 5:10 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:6:6: 6:13 StorageLive(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:6:10: 6:12 _4 = &mut (*_2); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:6:10: 6:12 _3 = foo(_4) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:6:6: 6:13 } bb1: { (*_3) = const 2i32; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:6:5: 6:17 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:6:18: 6:18 StorageDead(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:6:18: 6:18 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:5:24: 7:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:7:2: 7:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.14 Call expressions/2 Mutable references as return values./lib.rs:7:2: 7:2 } }
definition test.foo (xsₐ : (slice i32)) : sem ((lens (slice i32) i32) × (slice i32)) := let' «xs$2» ← @lens.id (slice i32); do «$tmp0» ← do «$tmp0» ← lens.get «xs$2» xsₐ; return (list.length «$tmp0»); let' t5 ← «$tmp0»; let' t6 ← (0 : nat) <ᵇ t5; let' t4 ← (lens.index _ (0 : nat) ∘ₗ «xs$2»); do «$tmp» ← lens.get t4 xsₐ; let' t3 ← (t4); do «$tmp» ← lens.get t3 xsₐ; let' ret ← (t3); do «$tmp» ← lens.get ret xsₐ; return (ret, xsₐ) definition test.bar (xsₐ : (slice i32)) : sem (unit × (slice i32)) := let' «xs$2» ← @lens.id (slice i32); let' t4 ← («xs$2»); do «$tmp» ← lens.get t4 xsₐ; do «$tmp0» ← lens.get t4 xsₐ; dostep «$tmp» ← @test.foo «$tmp0»; match «$tmp» with («t3$», «t4$») := do xsₐ ← lens.set t4 xsₐ «t4$»; let' t3 ← («t3$» ∘ₗ t4); do xsₐ ← lens.set t3 xsₐ (2 : int); let' ret ← ⋆; return (⋆, xsₐ) end
example (x y : i32) : sem.terminates_with (λ r, r.2 = [2, y]) (test.bar [x, y]) := rfl
Compiling lambda expressions means creating a closure structure, a function for the lambda body taking that structure (and returning it for FnMut
), and implementing the respective Fn trait.
fn apply<T, R, F: FnOnce(T) -> R>(f: F, x: T) -> R { f(x) } fn foo(x: i32, y: i32) -> i32 { apply(|x| x + y, x) }
fn foo::{{closure}}(_1: [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20 y:&i32], _2: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:12: 6:13 } let mut _4: i32; let mut _5: i32; let mut _6: (i32, bool); bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:12: 6:13 _3 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:12: 6:13 StorageLive(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:15: 6:16 _4 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:15: 6:16 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:19: 6:20 _5 = (*(_1.0: &i32)); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:19: 6:20 _6 = CheckedAdd(_4, _5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:15: 6:20 assert(!(_6.1: bool), "attempt to add with overflow") -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:15: 6:20 } bb1: { _0 = (_6.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:15: 6:20 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:20: 6:20 StorageDead(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:20: 6:20 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:20: 6:20 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:20: 6:20 } } fn foo(_1: i32, _2: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:5:8: 5:9 let _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:5:16: 5:17 } let mut _5: [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20 y:&i32]; let mut _6: &i32; let mut _7: i32; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:5:8: 5:9 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:5:8: 5:9 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:5:16: 5:17 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:5:16: 5:17 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20 _6 = &_4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20 _5 = [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20] { y: _6 }; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:22: 6:23 _7 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:22: 6:23 _0 = apply::<i32, i32, [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:11: 6:20 y:&i32]>(_5, _7) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:6:5: 6:24 } bb1: { StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:7:2: 7:2 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:7:2: 7:2 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:7:2: 7:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:7:2: 7:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:7:2: 7:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:7:2: 7:2 } } fn apply(_1: F, _2: T) -> R { let mut _0: R; // return pointer scope 1 { let _3: F; // "f" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:1:35: 1:36 let _4: T; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:1:41: 1:42 } let mut _5: F; let mut _6: (); let mut _7: (T,); let mut _8: T; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:1:35: 1:36 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:1:35: 1:36 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:1:41: 1:42 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:1:41: 1:42 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:2:5: 2:6 _5 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:2:5: 2:6 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:2:5: 2:9 StorageLive(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:2:7: 2:8 _8 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:2:7: 2:8 _7 = (_8,); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:2:5: 2:9 _0 = <F as std::ops::FnOnce<(T,)>>::call_once(_5, _7) -> [return: bb8, unwind: bb9]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:2:5: 2:9 } bb1: { resume; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:1:1: 3:2 } bb2: { drop(_3) -> bb1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb3: { drop(_1) -> bb2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb4: { drop(_4) -> bb3; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb5: { drop(_2) -> bb4; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb6: { drop(_5) -> bb5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb7: { drop(_8) -> bb6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb8: { drop(_7) -> [return: bb10, unwind: bb7]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb9: { drop(_7) -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb10: { StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 drop(_8) -> [return: bb11, unwind: bb6]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb11: { StorageDead(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 drop(_5) -> [return: bb12, unwind: bb5]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb12: { StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 drop(_2) -> [return: bb13, unwind: bb4]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb13: { drop(_4) -> [return: bb14, unwind: bb3]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb14: { StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 drop(_1) -> [return: bb15, unwind: bb2]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb15: { drop(_3) -> bb16; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } bb16: { StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/lib.rs:3:2: 3:2 } }
definition test.apply {T : Type₁} {R : Type₁} {F : Type₁} [«core.ops.FnOnce F T» : core.ops.FnOnce F T R] (fₐ : F) (xₐ : T) : sem (R) := let' «f$3» ← fₐ; let' «x$4» ← xₐ; let' t5 ← «f$3»; let' t8 ← «x$4»; let' t7 ← t8; dostep «$tmp» ← @core.ops.FnOnce.call_once F T R «core.ops.FnOnce F T» t5 t7; let' ret ← «$tmp»; return (ret) section structure test.foo.closure_13 (U0 : Type₁) := (val : U0) definition test.foo.closure_13.fn («$a1» : (test.foo.closure_13 i32)) (xₐ : i32) : sem (i32) := let' «x$3» ← xₐ; let' t4 ← «x$3»; let' t5 ← (test.foo.closure_13.val «$a1»); do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits t4 t5); let' t6 ← «$tmp0»; let' ret ← t6.1; return (ret) definition test.foo.closure_13.inst [instance] : core.ops.FnOnce (test.foo.closure_13 i32) i32 i32 := core.ops.FnOnce.mk_simple (λ self args, let' xₐ ← args; test.foo.closure_13.fn self xₐ ) end definition test.foo (xₐ : i32) (yₐ : i32) : sem (i32) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «y$4»; let' t5 ← test.foo.closure_13.mk t6; let' t7 ← «x$3»; dostep «$tmp» ← @test.apply i32 i32 (test.foo.closure_13 i32) (@test.foo.closure_13.inst ) t5 t7; let' ret ← «$tmp»; return (ret)
Mutable closures work out of the box as long as they don't close over mutable references - that would require nested storing of &mut
.
fn apply<T, F: FnMut(T) -> T>(mut f: F, x: T) -> T { let y = f(x); f(y) } fn foo(x: i32, mut y: i32) -> i32 { apply(move |x| { y += 1; x + y }, x) }
fn foo::{{closure}}(_1: &mut [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6 y:i32], _2: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:17: 7:18 } let mut _4: (i32, bool); let mut _5: i32; let mut _6: i32; let mut _7: (i32, bool); bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:17: 7:18 _3 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:17: 7:18 _4 = CheckedAdd(((*_1).0: i32), const 1i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:8:9: 8:15 assert(!(_4.1: bool), "attempt to add with overflow") -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:8:9: 8:15 } bb1: { ((*_1).0: i32) = (_4.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:8:9: 8:15 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:9:9: 9:10 _5 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:9:9: 9:10 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:9:13: 9:14 _6 = ((*_1).0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:9:13: 9:14 _7 = CheckedAdd(_5, _6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:9:9: 9:14 assert(!(_7.1: bool), "attempt to add with overflow") -> bb2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:9:9: 9:14 } bb2: { _0 = (_7.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:9:9: 9:14 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:10:6: 10:6 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:10:6: 10:6 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:10:6: 10:6 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:10:6: 10:6 } } fn foo(_1: i32, _2: i32) -> i32 { let mut _0: i32; // return pointer scope 1 { let _3: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:6:8: 6:9 let mut _4: i32; // "y" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:6:16: 6:21 } let mut _5: [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6 y:i32]; let mut _6: i32; let mut _7: i32; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:6:8: 6:9 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:6:8: 6:9 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:6:16: 6:21 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:6:16: 6:21 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6 _6 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6 _5 = [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6] { y: _6 }; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6 StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:10:8: 10:9 _7 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:10:8: 10:9 _0 = apply::<i32, [closure@ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:11: 10:6 y:i32]>(_5, _7) -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:7:5: 10:10 } bb1: { StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:11:2: 11:2 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:11:2: 11:2 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:11:2: 11:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:11:2: 11:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:11:2: 11:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:11:2: 11:2 } } fn apply(_1: F, _2: T) -> T { let mut _0: T; // return pointer scope 1 { let mut _3: F; // "f" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:1:31: 1:36 let _4: T; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:1:41: 1:42 scope 2 { let _5: T; // "y" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:9: 2:10 } } let mut _6: &mut F; let mut _7: (); let mut _8: (T,); let mut _9: T; let mut _10: &mut F; let mut _11: (T,); let mut _12: T; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:1:31: 1:36 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:1:31: 1:36 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:1:41: 1:42 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:1:41: 1:42 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:9: 2:10 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:13: 2:14 _6 = &mut _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:13: 2:14 StorageLive(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:13: 2:17 StorageLive(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:15: 2:16 _9 = _4; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:15: 2:16 _8 = (_9,); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:13: 2:17 _5 = <F as std::ops::FnMut<(T,)>>::call_mut(_6, _8) -> [return: bb8, unwind: bb9]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:13: 2:17 } bb1: { resume; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:1:1: 4:2 } bb2: { drop(_3) -> bb1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb3: { drop(_1) -> bb2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb4: { drop(_4) -> bb3; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb5: { drop(_2) -> bb4; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb6: { drop(_5) -> bb5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb7: { drop(_9) -> bb6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:18: 2:18 } bb8: { drop(_8) -> [return: bb10, unwind: bb7]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:18: 2:18 } bb9: { drop(_8) -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:18: 2:18 } bb10: { StorageDead(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:18: 2:18 drop(_9) -> [return: bb11, unwind: bb6]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:18: 2:18 } bb11: { StorageDead(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:18: 2:18 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:2:18: 2:18 StorageLive(_10); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:3:5: 3:6 _10 = &mut _3; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:3:5: 3:6 StorageLive(_11); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:3:5: 3:9 StorageLive(_12); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:3:7: 3:8 _12 = _5; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:3:7: 3:8 _11 = (_12,); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:3:5: 3:9 _0 = <F as std::ops::FnMut<(T,)>>::call_mut(_10, _11) -> [return: bb13, unwind: bb15]; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:3:5: 3:9 } bb12: { drop(_12) -> bb5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb13: { drop(_5) -> [return: bb16, unwind: bb14]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb14: { drop(_11) -> bb12; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb15: { drop(_5) -> bb14; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb16: { StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 drop(_11) -> [return: bb17, unwind: bb12]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb17: { StorageDead(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 drop(_12) -> [return: bb18, unwind: bb5]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb18: { StorageDead(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 StorageDead(_10); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 drop(_2) -> [return: bb19, unwind: bb4]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb19: { drop(_4) -> [return: bb20, unwind: bb3]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb20: { StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 drop(_1) -> [return: bb21, unwind: bb2]; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb21: { drop(_3) -> bb22; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } bb22: { StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.15 Lambda expressions/1 Mutable closures./lib.rs:4:2: 4:2 } }
definition test.apply {T : Type₁} {F : Type₁} [«core.ops.FnMut F T» : core.ops.FnMut F T T] (fₐ : F) (xₐ : T) : sem (T) := let' «f$3» ← fₐ; let' «x$4» ← xₐ; let' t6 ← @lens.id F; do «$tmp» ← lens.get t6 «f$3»; let' t9 ← «x$4»; let' t8 ← t9; do «$tmp0» ← lens.get t6 «f$3»; dostep «$tmp» ← @core.ops.FnMut.call_mut F T T «core.ops.FnMut F T» «$tmp0» t8; match «$tmp» with («y$5», «t6$») := do «f$3» ← lens.set t6 «f$3» «t6$»; let' t10 ← @lens.id F; do «$tmp» ← lens.get t10 «f$3»; let' t12 ← «y$5»; let' t11 ← t12; do «$tmp0» ← lens.get t10 «f$3»; dostep «$tmp» ← @core.ops.FnMut.call_mut F T T «core.ops.FnMut F T» «$tmp0» t11; match «$tmp» with (ret, «t10$») := do «f$3» ← lens.set t10 «f$3» «t10$»; return (ret) end end section structure test.foo.closure_13 (U0 : Type₁) := (val : U0) definition test.foo.closure_13.fn («$a1» : (test.foo.closure_13 i32)) (xₐ : i32) : sem (i32 × (test.foo.closure_13 i32)) := let' «x$3» ← xₐ; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits (test.foo.closure_13.val «$a1») (1 : int)); let' t4 ← «$tmp0»; let' «$a1» ← test.foo.closure_13.mk t4.1; let' t5 ← «x$3»; let' t6 ← (test.foo.closure_13.val «$a1»); do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits t5 t6); let' t7 ← «$tmp0»; let' ret ← t7.1; return (ret, «$a1») definition test.foo.closure_13.inst [instance] : core.ops.FnMut (test.foo.closure_13 i32) i32 i32 := core.ops.FnMut.mk_simple (λ self args, let' xₐ ← args; test.foo.closure_13.fn self xₐ ) end definition test.foo (xₐ : i32) (yₐ : i32) : sem (i32) := let' «x$3» ← xₐ; let' «y$4» ← yₐ; let' t6 ← «y$4»; let' t5 ← test.foo.closure_13.mk t6; let' t7 ← «x$3»; dostep «$tmp» ← @test.apply i32 (test.foo.closure_13 i32) (@test.foo.closure_13.inst ) t5 t7; let' ret ← «$tmp»; return (ret)
There is no for
, while
, loop
, continue
, or break
in MIR, just control flow edges. So we search for strongly connected components in the MIR graph (via petgraph), translate them into separate helper definitions, and compute a fixed point (if any) via a generic loop combinator.
fn foo(mut x: i32) { while x != 0 { if x == 1 { continue }; if x == 2 { break; }; if x == 3 { return; } x -= 1; } }
fn foo(_1: i32) -> () { let mut _0: (); // return pointer scope 1 { let mut _2: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:1:8: 1:13 } let mut _3: bool; let mut _4: i32; let mut _5: (); let mut _6: (); let mut _7: bool; let mut _8: i32; let mut _9: !; let mut _10: (); let mut _11: bool; let mut _12: i32; let mut _13: (); let mut _14: !; let mut _15: (); let mut _16: bool; let mut _17: i32; let mut _18: (); let mut _19: !; let mut _20: (i32, bool); bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:1:8: 1:13 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:1:8: 1:13 goto -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:5: 7:6 } bb1: { StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:11: 2:17 StorageLive(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:11: 2:12 _4 = _2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:11: 2:12 _3 = Ne(_4, const 0i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:11: 2:17 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:17: 2:17 StorageDead(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:17: 2:17 if(_3) -> [true: bb3, false: bb2]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:5: 7:6 } bb2: { _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:5: 7:6 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:8:2: 8:2 goto -> bb10; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:8:2: 8:2 } bb3: { StorageLive(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:12: 3:18 StorageLive(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:12: 3:13 _8 = _2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:12: 3:13 _7 = Eq(_8, const 1i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:12: 3:18 StorageDead(_7); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:18: 3:18 StorageDead(_8); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:18: 3:18 if(_7) -> [true: bb4, false: bb5]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:9: 3:31 } bb4: { StorageLive(_9); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:21: 3:29 goto -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:21: 3:29 } bb5: { _6 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:3:9: 3:31 StorageLive(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:12: 4:18 StorageLive(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:12: 4:13 _12 = _2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:12: 4:13 _11 = Eq(_12, const 2i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:12: 4:18 StorageDead(_11); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:18: 4:18 StorageDead(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:18: 4:18 if(_11) -> [true: bb6, false: bb7]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:9: 4:29 } bb6: { StorageLive(_14); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:21: 4:26 goto -> bb2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:21: 4:26 } bb7: { _10 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:4:9: 4:29 StorageLive(_16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:12: 5:18 StorageLive(_17); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:12: 5:13 _17 = _2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:12: 5:13 _16 = Eq(_17, const 3i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:12: 5:18 StorageDead(_16); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:18: 5:18 StorageDead(_17); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:18: 5:18 if(_16) -> [true: bb8, false: bb9]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:9: 5:30 } bb8: { StorageLive(_19); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:21: 5:27 _0 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:21: 5:27 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:8:2: 8:2 goto -> bb10; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:21: 5:27 } bb9: { _15 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:5:9: 5:30 _20 = CheckedSub(_2, const 1i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:6:9: 6:15 assert(!(_20.1: bool), "attempt to subtract with overflow") -> bb11; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:6:9: 6:15 } bb10: { return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:8:2: 8:2 } bb11: { _2 = (_20.0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:6:9: 6:15 _5 = (); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:18: 7:6 goto -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./lib.rs:2:5: 7:6 } }
section definition test.foo.loop_1 (state__ : i32) : sem (sum (i32) (unit)) := let' «x$2» ← state__; let' t4 ← «x$2»; let' t3 ← t4 ≠ᵇ (0 : int); if t3 = bool.tt then let' t8 ← «x$2»; let' t7 ← t8 =ᵇ (1 : int); if t7 = bool.tt then return (sum.inl «x$2») else let' t6 ← ⋆; let' t12 ← «x$2»; let' t11 ← t12 =ᵇ (2 : int); if t11 = bool.tt then do tmp__ ← let' ret ← ⋆; return (⋆) ; return (sum.inr tmp__)else let' t10 ← ⋆; let' t17 ← «x$2»; let' t16 ← t17 =ᵇ (3 : int); if t16 = bool.tt then do tmp__ ← let' ret ← ⋆; return (⋆) ; return (sum.inr tmp__)else let' t15 ← ⋆; do «$tmp0» ← sem.map (λx, (x, tt)) (checked.ssub i32.bits «x$2» (1 : int)); let' t20 ← «$tmp0»; let' «x$2» ← t20.1; let' t5 ← ⋆; return (sum.inl «x$2») else do tmp__ ← let' ret ← ⋆; return (⋆) ; return (sum.inr tmp__) definition test.foo (xₐ : i32) : sem (unit) := let' «x$2» ← xₐ; loop (test.foo.loop_1) «x$2» end
Basically an instance of Returning arbitrary mutable references.
/* // would require generalized mutually inductive types enum List<T> { Single(T), Cons(T, Box<List<T>>), } impl<T> List<T> { fn last_mut(&mut self) -> &mut T { let mut xs = self; loop { let tmp = xs; xs = match tmp { &mut List::Single(ref mut x) => return x, &mut List::Cons(_, ref mut b) => &mut *b, }; } } }*/ fn foo(mut xs: &mut [i32]) { loop { let tmp = xs; xs = &mut tmp[2..]; } }
fn foo(_1: &mut [i32]) -> () { let mut _0: (); // return pointer scope 1 { let mut _2: &mut [i32]; // "xs" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:21:8: 21:14 scope 2 { let _5: &mut [i32]; // "tmp" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:23:13: 23:16 } } let mut _3: !; let mut _4: (); let mut _6: &mut [i32]; let mut _7: &mut [i32]; let mut _8: &mut [i32]; let mut _9: &mut [i32]; let mut _10: std::ops::RangeFrom<usize>; let mut _11: usize; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:21:8: 21:14 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:21:8: 21:14 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:22:5: 25:6 goto -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:22:5: 25:6 } bb1: { StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:23:13: 23:16 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:23:19: 23:21 _6 = _2; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:23:19: 23:21 _5 = _6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:23:19: 23:21 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:23:22: 23:22 StorageLive(_7); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:14: 24:27 StorageLive(_8); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:19: 24:27 StorageLive(_9); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:19: 24:22 _9 = &mut (*_5); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:19: 24:22 StorageLive(_10); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:23: 24:26 StorageLive(_11); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:23: 24:24 _11 = const 2usize; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:23: 24:24 _10 = std::ops::RangeFrom<usize> { start: _11 }; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:23: 24:26 _8 = <[i32] as std::ops::IndexMut<std::ops::RangeFrom<usize>>>::index_mut(_9, _10) -> bb2; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:19: 24:27 } bb2: { _7 = &mut (*_8); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:14: 24:27 _2 = &mut (*_7); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:9: 24:27 StorageDead(_7); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:28: 24:28 StorageDead(_8); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:28: 24:28 StorageDead(_10); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:28: 24:28 StorageDead(_11); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:28: 24:28 StorageDead(_9); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:24:28: 24:28 _4 = (); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:22:10: 25:6 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:25:6: 25:6 goto -> bb1; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.16-20 Loops./1 Mutable borrowing in loops./lib.rs:22:5: 25:6 } }
/- test.foo: unimplemented: &mut nested in type -/
We currently translate all arms of an if
or match
separately, which is easy but not ideal if the control flow converges again at a later point (where 'not ideal' is a nice way of saying 'overhead exponential in the number of sequential if
s'). It works fine for now, but we should factor out convergence points into separate helper definitions at some point (just as we're already doing for loops).
fn foo(b: bool, c: bool) -> i32 { let mut x = 0; if b { x += 1 } if c { x += 1 } x }
fn foo(_1: bool, _2: bool) -> i32 { let mut _0: i32; // return pointer scope 1 { let _3: bool; // "b" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:1:8: 1:9 let _4: bool; // "c" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:1:17: 1:18 scope 2 { let mut _5: i32; // "x" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:2:9: 2:14 } } let mut _6: (); let mut _7: bool; let mut _8: (i32, bool); let mut _9: (); let mut _10: bool; let mut _11: (i32, bool); let mut _12: i32; bb0: { StorageLive(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:1:8: 1:9 _3 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:1:8: 1:9 StorageLive(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:1:17: 1:18 _4 = _2; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:1:17: 1:18 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:2:9: 2:14 _5 = const 0i32; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:2:17: 2:18 StorageLive(_7); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:8: 3:9 _7 = _3; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:8: 3:9 StorageDead(_7); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:9: 3:9 if(_7) -> [true: bb1, false: bb2]; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:5: 3:20 } bb1: { _8 = CheckedAdd(_5, const 1i32); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:12: 3:18 assert(!(_8.1: bool), "attempt to add with overflow") -> bb3; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:12: 3:18 } bb2: { _6 = (); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:5: 3:20 goto -> bb4; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:5: 3:20 } bb3: { _5 = (_8.0: i32); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:12: 3:18 goto -> bb4; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:3:5: 3:20 } bb4: { StorageLive(_10); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:8: 4:9 _10 = _4; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:8: 4:9 StorageDead(_10); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:9: 4:9 if(_10) -> [true: bb5, false: bb6]; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:5: 4:20 } bb5: { _11 = CheckedAdd(_5, const 1i32); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:12: 4:18 assert(!(_11.1: bool), "attempt to add with overflow") -> bb7; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:12: 4:18 } bb6: { _9 = (); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:5: 4:20 goto -> bb8; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:5: 4:20 } bb7: { _5 = (_11.0: i32); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:12: 4:18 goto -> bb8; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:4:5: 4:20 } bb8: { StorageLive(_12); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:5:5: 5:6 _12 = _5; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:5:5: 5:6 _0 = _12; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:5:5: 5:6 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:6:2: 6:2 StorageDead(_12); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:6:2: 6:2 StorageDead(_4); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:6:2: 6:2 StorageDead(_3); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:6:2: 6:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.21 if expressions/lib.rs:6:2: 6:2 } }
definition test.foo (bₐ : bool) (cₐ : bool) : sem (i32) := let' «b$3» ← bₐ; let' «c$4» ← cₐ; let' «x$5» ← (0 : int); let' t7 ← «b$3»; if t7 = bool.tt then do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits «x$5» (1 : int)); let' t8 ← «$tmp0»; let' «x$5» ← t8.1; let' t10 ← «c$4»; if t10 = bool.tt then do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits «x$5» (1 : int)); let' t11 ← «$tmp0»; let' «x$5» ← t11.1; let' t12 ← «x$5»; let' ret ← t12; return (ret) else let' t9 ← ⋆; let' t12 ← «x$5»; let' ret ← t12; return (ret) else let' t6 ← ⋆; let' t10 ← «c$4»; if t10 = bool.tt then do «$tmp0» ← sem.map (λx, (x, tt)) (checked.sadd i32.bits «x$5» (1 : int)); let' t11 ← «$tmp0»; let' «x$5» ← t11.1; let' t12 ← «x$5»; let' ret ← t12; return (ret) else let' t9 ← ⋆; let' t12 ← «x$5»; let' ret ← t12; return (ret)
fn f1(x: i32) -> &'static str { match x { 1 => "one", 2 => "two", 3 => "three", 4 => "four", 5 => "five", _ => "something else", } } fn f2(x: i32) -> &'static str { match x { e @ 1 ... 5 => "got a range element", _ => "anything", } } fn f3(x: &i32) { let y = match *x { 0 => "zero", _ => "some" }; let z = match x { &0 => "zero", _ => "some" }; } fn f4(x: i32) { let message = match x { 0 | 1 => "not many", 2 ... 9 => "a few", _ => "lots" }; } fn f5(x: Option<i32>) -> Option<i32> { match x { Some(x) if x < 10 => Some(x), Some(x) => None, None => panic!(), } }
fn f5(_1: std::option::Option<i32>) -> std::option::Option<i32> { let mut _0: std::option::Option<i32>; // return pointer scope 1 { let _2: std::option::Option<i32>; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:32:7: 32:8 scope 2 { let _3: i32; // "x" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:14: 34:15 } scope 3 { let _4: i32; // "x" in scope 3 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:35:14: 35:15 } } let mut _5: bool; let mut _6: i32; let mut _7: i32; let mut _8: !; let mut _9: &(&'static str, u32); let mut _10: &(&'static str, u32); bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:32:7: 32:8 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:32:7: 32:8 switch(_2) -> [None: bb2, Some: bb3]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:9: 34:16 } bb1: { StorageLive(_7); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:35: 34:36 _7 = _3; // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:35: 34:36 _0 = std::option::Option<i32>::Some(_7,); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:30: 34:37 StorageDead(_7); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:37: 34:37 goto -> bb5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:33:5: 37:6 } bb2: { StorageLive(_8); // scope 1 at <panic macros>:3:1: 6:17 StorageLive(_9); // scope 1 at <panic macros>:4:9: 6:15 StorageLive(_10); // scope 1 at <panic macros>:6:1: 6:13 _10 = &f5::_FILE_LINE; // scope 1 at <panic macros>:6:1: 6:13 _9 = &(*_10); // scope 1 at <panic macros>:6:1: 6:13 std::rt::begin_panic::<&'static str>(const "explicit panic", _9); // scope 1 at <panic macros>:3:1: 6:17 } bb3: { StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:14: 34:15 _3 = ((_2 as Some).0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:14: 34:15 StorageLive(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:20: 34:26 StorageLive(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:20: 34:21 _6 = _3; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:20: 34:21 _5 = Lt(_6, const 10i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:20: 34:26 StorageDead(_5); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:26: 34:26 StorageDead(_6); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:26: 34:26 if(_5) -> [true: bb1, false: bb4]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:34:20: 34:26 } bb4: { StorageLive(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:35:14: 35:15 _4 = ((_2 as Some).0: i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:35:14: 35:15 _0 = std::option::Option<i32>::None; // scope 3 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:35:20: 35:24 goto -> bb5; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:33:5: 37:6 } bb5: { StorageDead(_4); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:37:6: 37:6 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:37:6: 37:6 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:38:2: 38:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:38:2: 38:2 } } fn f4(_1: i32) -> () { let mut _0: (); // return pointer scope 1 { let _2: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:24:7: 24:8 scope 2 { let _3: &str; // "message" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:25:9: 25:16 } } let mut _4: bool; let mut _5: bool; bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:24:7: 24:8 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:24:7: 24:8 StorageLive(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:25:9: 25:16 switchInt(_2) -> [0i32: bb1, 1i32: bb1, otherwise: bb4]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:26:9: 26:10 } bb1: { _3 = const "not many"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:26:19: 26:29 goto -> bb6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:25:19: 29:6 } bb2: { _3 = const "a few"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:27:20: 27:27 goto -> bb6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:25:19: 29:6 } bb3: { _3 = const "lots"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:28:19: 28:25 goto -> bb6; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:25:19: 29:6 } bb4: { _4 = Le(const 2i32, _2); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:27:9: 27:16 if(_4) -> [true: bb5, false: bb3]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:27:9: 27:16 } bb5: { _5 = Le(_2, const 9i32); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:27:9: 27:16 if(_5) -> [true: bb2, false: bb3]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:27:9: 27:16 } bb6: { _0 = (); // scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:24:15: 30:2 StorageDead(_3); // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:30:2: 30:2 StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:30:2: 30:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:30:2: 30:2 } } fn f1(_1: i32) -> &'static str { let mut _0: &'static str; // return pointer scope 1 { let _2: i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:1:7: 1:8 } bb0: { StorageLive(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:1:7: 1:8 _2 = _1; // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:1:7: 1:8 switchInt(_2) -> [1i32: bb1, 2i32: bb2, 3i32: bb3, 4i32: bb4, 5i32: bb5, otherwise: bb6]; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:3:9: 3:10 } bb1: { _0 = const "one"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:3:14: 3:19 goto -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:2:5: 9:6 } bb2: { _0 = const "two"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:4:14: 4:19 goto -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:2:5: 9:6 } bb3: { _0 = const "three"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:5:14: 5:21 goto -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:2:5: 9:6 } bb4: { _0 = const "four"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:6:14: 6:20 goto -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:2:5: 9:6 } bb5: { _0 = const "five"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:7:14: 7:20 goto -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:2:5: 9:6 } bb6: { _0 = const "something else"; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:8:14: 8:30 goto -> bb7; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:2:5: 9:6 } bb7: { StorageDead(_2); // scope 0 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:10:2: 10:2 return; // scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:10:2: 10:2 } } static f5::_FILE_LINE: (&'static str, u32) = { let mut _0: (&'static str, u32); // return pointer bb0: { _0 = (const "ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs", const 36u32); // scope 0 at <panic macros>:5:47: 5:76 return; // scope 0 at <panic macros>:5:1: 5:78 } } fn f3(_1: &i32) -> () { let mut _0: (); // return pointer scope 1 { let _2: &i32; // "x" in scope 1 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:19:7: 19:8 scope 2 { let _3: &str; // "y" in scope 2 at ref/7 Statements and expressions/7.2 Expressions/7.2.22 Match expressions/lib.rs:20:9: 20:10 scope 3 { let _4: &