Module counterexamples

Source
Expand description

§Non-compiling examples

The following examples will not compile, preventing unsoundness.

§Covariant escapes to inner

use nolife::{scope, BoxScope, Family};

struct Covariant<'a> {
    x: &'a str,
}

struct CovariantFamily;

impl<'a> Family<'a> for CovariantFamily {
    type Family = Covariant<'a>;
}

fn covariant_inner() {
    {
        let mut scope = BoxScope::<CovariantFamily, _>::new(scope!({
            let mut f = Covariant { x: "bbb" };
            loop {
                freeze!(&mut f);
                println!("Called {}", f.x)
            }
        }));

        {
            let s = String::from("foodog");
            scope.enter(|f| {
                f.x = &s;
            });
        }
    }
}

§Covariant escapes to outer

use nolife::{scope, BoxScope, Family};
use std::cell::Cell;

struct Covariant<'a> {
    x: &'a str,
}

struct CovariantFamily;

impl<'a> Family<'a> for CovariantFamily {
    type Family = Covariant<'a>;
}

fn covariant_outer() {
    let output = Cell::new("foo");
    {
        let mut scope = BoxScope::<CovariantFamily>::new_dyn(scope!({
            let mut f = Covariant { x: "bbb" };
            loop {
                freeze!(&mut f);
                println!("Called {}", f.x)
            }
        }));

        {
            scope.enter(|f| {
                output.set(f.x);
            });
        }
    }
    println!("{}", output.get());
}

§Covariant escapes to inner 2

use nolife::{scope, BoxScope, Family};

struct Covariant<'a> {
    x: &'a str,
}

struct CovariantFamily;

impl<'a> Family<'a> for CovariantFamily {
    type Family = Covariant<'a>;
}

fn box_covariant_inner() {
    {
        let mut scope = BoxScope::<CovariantFamily, _>::new(scope!({
            let x = String::from("aaaaa");
            let mut f = Covariant { x: &x };
            loop {
                freeze!(&mut f);
                println!("Called {}", f.x)
            }
        }));

        {
            let s = String::from("dangling");
            scope.enter(|f| f.x = &s);
        }
    };
}

§Covariant escapes to outer 2

use nolife::{scope, BoxScope, Family};
use std::cell::Cell;

struct Covariant<'a> {
    x: &'a str,
}

struct CovariantFamily;

impl<'a> Family<'a> for CovariantFamily {
    type Family = Covariant<'a>;
}

fn box_covariant_outer() {
    let outer = Cell::new("foo");
    {
        let mut scope = BoxScope::<CovariantFamily, _>::new(scope!({
            let x = String::from("aaaaa");
            let mut f = Covariant { x: &x };
            loop {
                freeze!(&mut f);
                println!("Called {}", f.x)
            }
        }));

        let inner = scope.enter(|f| f.x);
        outer.set(inner);
    };
    println!("{}", outer.get());
}

§Covariant with Drop

use nolife::{scope, BoxScope, Family};

struct CovariantDrop<'a> {
    x: &'a str,
}

impl<'a> Drop for CovariantDrop<'a> {
    fn drop(&mut self) {
        println!("Dropping {}", self.x)
    }
}
struct CovariantDropFamily;

impl<'a> Family<'a> for CovariantDropFamily {
    type Family = CovariantDrop<'a>;
}

fn covariant_drop() {
    {
        let mut scope = BoxScope::<CovariantDropFamily, _>::new(scope!({
            let mut f = CovariantDrop { x: "inner" };
            loop {
                println!("Called {}", f.x);
                freeze!(&mut f);
            }
        }));

        let outer = String::from("outer");

        {
            scope.enter(|f| {
                f.x = &outer;
            });
        }
    }
}

§Contravariant example

use std::cell::Cell;

struct Contravariant<'a> {
    f: Box<dyn FnMut(&'a mut str) + 'a>,
}

struct ContravariantFamily;

impl<'a> nolife::Family<'a> for ContravariantFamily {
    type Family = Contravariant<'a>;
}

fn contravariant() {
    let outer: Cell<&str> = Cell::new("toto");

    {
        let mut scope = nolife::BoxScope::<ContravariantFamily, _>::new(nolife::scope!({
            loop {
                let mut x = String::from("inner");

                let mut f = Contravariant {
                    f: Box::new(|_| {}),
                };
                freeze!(&mut f);
                (f.f)(&mut x);
            }
        }));

        scope.enter(|f| {
            f.f = Box::new(|inner| outer.set(inner));
        });
    }
    println!("{}", outer.get());
}

§Covariant coming from a previous scope

use nolife::{scope, BoxScope, Family};

struct Covariant<'a> {
    x: &'a str,
}

struct CovariantFamily;

impl<'a> Family<'a> for CovariantFamily {
    type Family = Covariant<'a>;
}

fn covariant_inner() {
    {
        let mut scope = BoxScope::<CovariantFamily>::new_dyn(scope!({
            let mut f = Covariant { x: "bbb" };
            loop {
                freeze!(&mut f);
                println!("Called {}", f.x)
            }
        }));
        {
            let s = String::from("foodog");

            {
                scope.enter(|f| {
                    f.x = &s;
                });
            }
        }
        scope.enter(|_f| ());
    }
}

§Signature of enter is not sound, #7 https://github.com/dureuill/nolife/issues/7

Example lifted as-is from @steffahn

use nolife::{BoxScope, Family, TimeCapsule, scope};

struct Foo<'a> {
    s: String,
    r: Option<&'a mut String>,
}

struct FooFamily;

impl<'a> Family<'a> for FooFamily {
   type Family = Foo<'a>;
}

fn storing_own_reference() {
    {
        let mut scope: BoxScope<FooFamily, _> = BoxScope::new(scope!({
            let mut f = Foo {
                s: String::from("Hello World!"),
                r: None,
            };
            freeze_forever!(&mut f)
        }));

        scope.enter(|foo| {
            foo.r = Some(&mut foo.s);
        });
        scope.enter(|foo| {
            let alias1: &mut String = &mut foo.s;
            let alias2: &mut String = foo.r.as_deref_mut().unwrap(); // miri will complain here already
            // two aliasing mutable references!!

            let s: &str = alias1;
            let owner: String = std::mem::take(alias2);

            println!("Now it exists: {s}");
            drop(owner);
            println!("Now it's gone: {s}");
        })
    }
}

§Recursion is not allowed

use nolife::{scope, SingleFamily, TopScope};

fn recursive_sub_scope() {
    fn some_scope(x: u32) -> impl TopScope<Family = SingleFamily<u32>> {
        scope!({
            if x == 0 {
                freeze_forever!(&mut 0)
            } else {
                sub_scope!(some_scope(x - 1));
                freeze_forever!(&mut 0)
            }
        })
    }
}

§Attempting to save the frozen future in an async block

use nolife::{scope, SingleFamily, TopScope};
fn forcing_inner_async() {
    fn some_scope(x: u32) -> impl TopScope<Family = SingleFamily<u32>> {
        scope!({
            let fut = async {
                freeze!(&mut 0);
            };
            // poll future
            // bang!
            panic!()
        })
    }
}

# Dropping a borrowed input to a scope.

use nolife::{scope, BoxScope, SingleFamily, TopScope};

fn ref_scope() {
    fn scope_with_ref<'scope, 'a: 'scope>(
        s: &'a str,
    ) -> impl TopScope<Family = SingleFamily<usize>> + 'scope {
        scope!({ freeze_forever!(&mut s.len()) })
    }
    let x = "Intel the Beagle".to_string();
    let mut scope = BoxScope::<SingleFamily<usize>, _>::new(scope_with_ref(&x));

    drop(x);

    scope.enter(|x| assert_eq!(*x, 16));
}

# Dropping a borrowed input to a scope, erased version

use nolife::{scope, BoxScope, SingleFamily, TopScope};

fn ref_scope() {
    fn scope_with_ref<'scope, 'a: 'scope>(
        s: &'a str,
    ) -> impl TopScope<Family = SingleFamily<usize>> + 'scope {
        scope!({ freeze_forever!(&mut s.len()) })
    }
    let x = "Intel the Beagle".to_string();
    let mut scope = BoxScope::<SingleFamily<usize>, _>::new_dyn(scope_with_ref(&x));

    drop(x);

    scope.enter(|x| assert_eq!(*x, 16));
}