miden-assembly 0.32.0

Miden VM assembly language
Documentation
// IMPORT EDGE CASES AND REGRESSIONS
// ================================================================================================

use super::*;

#[test]
fn asm_import_source_digest_reexport_is_rejected_without_panicking() {
    use std::panic::{AssertUnwindSafe, catch_unwind};

    let context = TestContext::new();
    let parsed = catch_unwind(AssertUnwindSafe(|| {
        context.parse_module(source_file!(
            &context,
            "namespace m::n\n\npub use {foo} from 0x0000000000000000000000000000000000000000000000000000000000000000\n"
        ))
    }));

    assert!(parsed.is_ok(), "parser panicked, expected a structured error");
    let err = parsed
        .unwrap()
        .expect_err("expected source-level digest re-export to be rejected");
    assert_diagnostic!(&err, "digest imports are not supported in source `use` declarations");
}

#[test]
fn asm_import_source_digest_alias_chain_is_rejected_without_panicking() {
    use std::panic::{AssertUnwindSafe, catch_unwind};

    let context = TestContext::new();
    let parsed = catch_unwind(AssertUnwindSafe(|| {
        context.parse_module(source_file!(
            &context,
            r#"
                    namespace m::n

                    pub use {foo} from 0x0000000000000000000000000000000000000000000000000000000000000000
                    pub use {foo as bar} from m::n

                    pub proc calls_bar
                        call.bar
                    end
                "#
        ))
    }));

    assert!(parsed.is_ok(), "parser panicked, expected a structured error");
    let err = parsed
        .unwrap()
        .expect_err("expected source-level digest alias chain to be rejected");
    assert_diagnostic!(&err, "digest imports are not supported in source `use` declarations");
}

#[test]
fn asm_import_direct_digest_invoke_assembles_without_source_import() {
    use std::panic::{AssertUnwindSafe, catch_unwind};

    let program = r#"
        begin
            exec.0xc2545da99d3a1f3f38d957c7893c44d78998d8ea8b11aba7e22c8c2b2a213dae
        end
    "#;

    let assembled = catch_unwind(AssertUnwindSafe(|| {
        Assembler::default().assemble_program("program", program)
    }));

    assert!(
        assembled.is_ok(),
        "assembly panicked, expected direct opaque digest invoke to be allowed"
    );
    assembled
        .unwrap()
        .expect("expected direct digest invocation to assemble successfully");
}

#[test]
fn asm_import_direct_digest_invoke_parses_with_warnings_as_errors() {
    use std::sync::Arc;

    use crate::DefaultSourceManager;

    let source_manager: Arc<dyn crate::SourceManager> = Arc::new(DefaultSourceManager::default());
    let program = r#"
        begin
            exec.0xc2545da99d3a1f3f38d957c7893c44d78998d8ea8b11aba7e22c8c2b2a213dae
        end
    "#;

    let mut parser = Module::parser(None);
    parser.set_warnings_as_errors(true);

    parser
        .parse_str(None, program, source_manager)
        .expect("expected direct digest invocation to parse without import warnings");
}

#[test]
fn asm_import_direct_digest_forward_decl_assembles_without_source_import() {
    use std::sync::Arc;

    use crate::DefaultSourceManager;

    let source_manager: Arc<dyn crate::SourceManager> = Arc::new(DefaultSourceManager::default());
    let program = r#"
        proc helper
            exec.0xc2545da99d3a1f3f38d957c7893c44d78998d8ea8b11aba7e22c8c2b2a213dae
        end

        begin
            call.helper
        end
    "#;

    Assembler::new(source_manager)
        .assemble_program("program", program)
        .expect("expected direct digest invocation in helper proc to assemble");
}

#[test]
fn forward_declared_import_used_by_type_ref_is_not_reported_unused_when_warnings_are_errors() {
    use std::sync::Arc;

    use crate::DefaultSourceManager;

    let source_manager: Arc<dyn crate::SourceManager> = Arc::new(DefaultSourceManager::default());
    let module = r#"
        namespace m

        type Local = foo::Type
        use external::module as foo
    "#;

    let mut parser = Module::parser(None);
    parser.set_warnings_as_errors(true);

    parser
        .parse_str(None, module, source_manager)
        .expect("expected forward-declared import used by type ref to count as used");
}

#[test]
fn forward_declared_import_used_by_proc_signature_is_not_reported_unused_when_warnings_are_errors()
{
    use std::sync::Arc;

    use crate::DefaultSourceManager;

    let source_manager: Arc<dyn crate::SourceManager> = Arc::new(DefaultSourceManager::default());
    let module = r#"
        namespace m

        pub proc check(value: foo::Type) -> foo::Type
            nop
        end
        use external::module as foo
    "#;

    let mut parser = Module::parser(None);
    parser.set_warnings_as_errors(true);

    parser
        .parse_str(None, module, source_manager)
        .expect("expected forward-declared import used by signature type to count as used");
}

#[test]
fn kernel_import_used_by_proc_signature_is_not_reported_unused_when_warnings_are_errors() {
    let context = TestContext::new();
    context
        .parse_kernel(source_file!(
            &context,
            r#"
            namespace $kernel

            use external::module as foo

            pub proc check(value: foo::Type) -> foo::Type
                nop
            end
            "#
        ))
        .expect("expected kernel signature type import to count as used");
}

#[test]
fn forward_declared_import_used_by_constant_ref_is_not_reported_unused_when_warnings_are_errors() {
    use std::sync::Arc;

    use crate::DefaultSourceManager;

    let source_manager: Arc<dyn crate::SourceManager> = Arc::new(DefaultSourceManager::default());
    let module = r#"
        namespace m

        const LOCAL = foo::BAR
        use external::module as foo
    "#;

    let mut parser = Module::parser(None);
    parser.set_warnings_as_errors(true);

    parser
        .parse_str(None, module, source_manager)
        .expect("expected forward-declared import used by constant ref to count as used");
}

#[test]
fn asm_import_source_digest_import_is_rejected_without_panicking() {
    use std::panic::{AssertUnwindSafe, catch_unwind};

    let program = r#"
        use {foo} from 0x0000000000000000000000000000000000000000000000000000000000000000

        begin
            exec.foo
        end
    "#;

    let assembled = catch_unwind(AssertUnwindSafe(|| {
        Assembler::default().assemble_program("program", program)
    }));

    assert!(assembled.is_ok(), "assembly panicked, expected a structured error");
    let err = assembled
        .unwrap()
        .expect_err("expected source-level digest import to be rejected");
    assert_diagnostic!(&err, "digest imports are not supported in source `use` declarations");
}

#[test]
fn invoking_local_type_alias_returns_error_instead_of_panicking() {
    use std::panic::{AssertUnwindSafe, catch_unwind};

    let masm = "type foo = u32\nbegin\n    exec.foo\nend\n";

    let result =
        catch_unwind(AssertUnwindSafe(|| Assembler::default().assemble_program("program", masm)));

    let result = result.expect("assembly panicked, expected a structured error");
    let err = result.expect_err("assembly unexpectedly succeeded");
    assert_diagnostic!(&err, "invalid symbol reference: wrong type");
    assert_diagnostic!(&err, "expected this symbol to reference a procedure item");
}

#[test]
fn invoking_local_type_alias_is_rejected_during_semantic_analysis() {
    let context = TestContext::new();
    let masm = source_file!(&context, "type foo = u32\nbegin\n    exec.foo\nend\n");

    let err = context
        .parse_program(masm)
        .expect_err("semantic analysis unexpectedly accepted invoking a local type alias");
    assert_diagnostic!(&err, "invalid symbol reference: wrong type");
    assert_diagnostic!(&err, "expected this symbol to reference a procedure item");
}

#[test]
fn invoking_imported_type_alias_returns_error_instead_of_panicking() {
    use std::panic::{AssertUnwindSafe, catch_unwind};

    let context = TestContext::new();
    let lib_src = source_file!(
        &context,
        "\
namespace test::types

pub type foo = u32

pub proc fun(in: foo)
    push.1
end"
    );
    let lib = context.parse_module(lib_src).expect("library module parsing must succeed");
    let library = Assembler::new(context.source_manager())
        .assemble_library("test", lib, None::<Box<Module>>)
        .expect("library assembly must succeed");

    let mut assembler = Assembler::new(context.source_manager());
    assembler
        .link_package(Arc::from(library), Linkage::Dynamic)
        .expect("library linking must succeed");

    let program = "use test::types\nbegin\n    exec.types::foo\nend\n";
    let result = catch_unwind(AssertUnwindSafe(|| assembler.assemble_program("program", program)));

    let result = result.expect("assembly panicked, expected a structured error");
    let err = result.expect_err("assembly unexpectedly succeeded");
    assert_diagnostic!(&err, "invalid procedure reference: path refers to a non-procedure item");
    assert_diagnostic!(&err, "test::types::foo");
}