Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/assert-debug-test/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions examples/assert-debug-test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
cargo-features = ["trim-paths"]

[package]
name = "assert_debug_test"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[profile.release]
debug = true
panic = "abort"
trim-paths = ["diagnostics", "object"]

[profile.dev]
debug = true
panic = "abort"
trim-paths = ["diagnostics", "object"]
37 changes: 37 additions & 0 deletions examples/assert-debug-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Example for testing Rust assert! macro source location preservation.
//!
//! Build with:
//! cargo build --release --target wasm32-unknown-unknown \
//! --manifest-path examples/assert-debug-test/Cargo.toml
//!
//! Check HIR for source locations:
//! ./bin/midenc examples/assert-debug-test/target/wasm32-unknown-unknown/release/assert_debug_test.wasm \
//! --entrypoint=assert_debug_test::test_assert \
//! -Ztrim-path-prefix=examples/assert-debug-test \
//! -Zprint-hir-source-locations \
//! --debug full --emit=hir=-
//!

#![no_std]

#[panic_handler]
fn my_panic(_info: &core::panic::PanicInfo) -> ! {
core::arch::wasm32::unreachable()
}

#[no_mangle]
pub extern "C" fn test_assert(x: u32) -> u32 {
assert!(x > 100);
x
}

#[no_mangle]
pub extern "C" fn test_multiple_asserts(a: u32, b: u32) -> u32 {
assert!(a > 0);

assert!(b > 0);

assert!(a != b);

a + b
}
165 changes: 165 additions & 0 deletions tests/integration/src/rust_masm_tests/debug_source_locations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
//! Tests that verify debug source location information is correctly preserved
//! from Rust source code through to MASM compilation and execution.
//!

use std::panic::{self, AssertUnwindSafe};
use std::path::PathBuf;
use std::process::Command;
use std::sync::Arc;

use miden_core::Felt;
use miden_debug::Executor;
use miden_lib::MidenLib;
use midenc_compile::compile_to_memory;
use midenc_session::{InputFile, STDLIB};

use crate::testing::setup;

// Get path to examples/assert-debug-test test.
fn get_assert_debug_test_path() -> PathBuf {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
.unwrap_or_else(|_| std::env::current_dir().unwrap().to_str().unwrap().to_string());
PathBuf::from(manifest_dir)
.parent()
.unwrap()
.parent()
.unwrap()
.join("examples")
.join("assert-debug-test")
}

fn create_executor_with_std(
args: Vec<Felt>,
package: &miden_mast_package::Package,
) -> Executor {
let mut exec = Executor::new(args);
let std_library = (*STDLIB).clone();
exec.dependency_resolver_mut()
.add(*std_library.digest(), std_library.clone().into());
let base_library = Arc::new(MidenLib::default().as_ref().clone());
exec.dependency_resolver_mut()
.add(*base_library.digest(), base_library.clone().into());
exec.with_dependencies(package.manifest.dependencies())
.expect("Failed to set up dependencies");
exec
}

#[test]
fn test_rust_assert_macro_source_location_with_debug_executor() {
setup::enable_compiler_instrumentation();

let example_path = get_assert_debug_test_path();
let example_path_str = example_path.to_string_lossy();

let manifest_path = example_path.join("Cargo.toml");
let status = Command::new("cargo")
.args([
"build",
"--release",
"--target",
"wasm32-unknown-unknown",
"--manifest-path",
manifest_path.to_str().unwrap(),
])
.status()
.expect("Failed to run cargo build");
assert!(status.success(), "Failed to build assert-debug-test example");

let wasm_path = example_path
.join("target")
.join("wasm32-unknown-unknown")
.join("release")
.join("assert_debug_test.wasm");

let input_file = InputFile::from_path(&wasm_path).expect("Failed to load wasm file");
let context = setup::default_context(
[input_file],
&[
"--debug",
"full",
&format!("-Ztrim-path-prefix={}", example_path_str),
"--entrypoint",
"assert_debug_test::test_assert",
],
);

let artifact = compile_to_memory(context.clone())
.expect("Failed to compile wasm to masm");
let package = artifact.unwrap_mast();
let program = package.unwrap_program();
let session = context.session_rc();

// First, test that the function works when assertion passes (x > 100)
{
let args = vec![Felt::new(200)];
let exec = create_executor_with_std(args, &package);

let trace = exec.execute(&program, session.source_manager.clone());
let result: u32 = trace.parse_result().expect("Failed to parse result");
assert_eq!(result, 200, "When x > 100, function should return x");
eprintln!("SUCCESS: Assertion passed when x=200 > 100");
}

// Now test that when assertion fails (x <= 100), we get a panic with source location
{
let args = vec![Felt::new(50)]; // x = 50, assert!(50 > 100) fails
let exec = create_executor_with_std(args, &package);

// Clone values needed for the closure
let program_clone = program.clone();
let source_manager = session.source_manager.clone();

// Capture the panic output
let result = panic::catch_unwind(AssertUnwindSafe(move || {
exec.execute(&program_clone, source_manager)
}));

// The execution should panic (fail) because assert!(50 > 100) fails
assert!(
result.is_err(),
"Execution should have panicked due to failed assertion (x=50 <= 100)"
);

// Check the panic message for source location information
if let Err(panic_info) = result {
let panic_message = if let Some(s) = panic_info.downcast_ref::<String>() {
s.clone()
} else if let Some(s) = panic_info.downcast_ref::<&str>() {
s.to_string()
} else {
"Unknown panic".to_string()
};

eprintln!("\n=== Panic message from failed assertion ===");
eprintln!("{panic_message}");
eprintln!("============================================\n");

// The panic message should indicate an assertion failure
assert!(
panic_message.contains("assertion failed"),
"Panic message should indicate assertion failure. Got: {panic_message}"
);

// Check if source location info is present
let has_source_file = panic_message.contains("lib.rs")
|| panic_message.contains("src/");

let has_line_info = panic_message.contains(":32")
|| panic_message.contains(":33");

let has_any_source_info = has_source_file || has_line_info;

// FIXME: Currently source locations show <unavailable> in stack traces.
// This test documents the current behavior.
eprintln!(
"SUCCESS: Assertion correctly failed when x=50 <= 100"
);
eprintln!("Has source file reference: {}", has_source_file);
eprintln!("Has line info: {}", has_line_info);

if has_any_source_info {
eprintln!("Source locations are being resolved!");
}
}
}
}
1 change: 1 addition & 0 deletions tests/integration/src/rust_masm_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::testing::eval_package;

mod abi_transform;
mod apps;
mod debug_source_locations;
mod examples;
mod instructions;
mod intrinsics;
Expand Down
Loading