Skip to content
Merged
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
225 changes: 73 additions & 152 deletions Cargo.lock

Large diffs are not rendered by default.

119 changes: 119 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,119 @@
//! 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},
path::PathBuf,
};

use miden_core::Felt;
use midenc_frontend_wasm::WasmTranslationConfig;

use crate::{CompilerTest, testing::executor_with_std};

/// Get the absolute path to the assert-debug-test fixture.
fn get_test_fixture_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()
.join("rust-apps-wasm")
.join("rust-sdk")
.join("assert-debug-test")
}

#[test]
fn test_rust_assert_macro_source_location_with_debug_executor() {
let config = WasmTranslationConfig::default();
let fixture_path = get_test_fixture_path();
let fixture_path_str = fixture_path.to_string_lossy();

// Note: cargo-miden automatically:
// 1. Passes --debug to midenc
// 2. Adds -Ztrim-path-prefix when debug is enabled
let mut test = CompilerTest::rust_source_cargo_miden(
"../rust-apps-wasm/rust-sdk/assert-debug-test",
config,
[],
);

eprintln!("\n=== Fixture path ===");
eprintln!("{fixture_path_str}");
eprintln!("============================================\n");

let package = test.compiled_package();
let program = package.unwrap_program();

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

let trace = exec.execute(&program, test.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 = executor_with_std(args, Some(&package));

// Clone values needed for the closure
let program_clone = program.clone();
let source_manager = test.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(":20") || panic_message.contains(":21");

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!");
}
}
}
}
29 changes: 7 additions & 22 deletions tests/integration/src/rust_masm_tests/examples.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
use std::{borrow::Borrow, collections::VecDeque, sync::Arc};
use std::{borrow::Borrow, collections::VecDeque};

use miden_core::utils::{Deserializable, Serializable};
use miden_debug::{Executor, ToMidenRepr};
use miden_lib::MidenLib;
use miden_mast_package::{Package, SectionId};
use miden_debug::ToMidenRepr;
use miden_mast_package::SectionId;
use miden_objects::account::AccountComponentMetadata;
use midenc_expect_test::{expect, expect_file};
use midenc_frontend_wasm::WasmTranslationConfig;
use midenc_hir::{
Felt, FunctionIdent, Ident, Immediate, Op, SourceSpan, SymbolTable, interner::Symbol,
};
use midenc_session::STDLIB;
use prop::test_runner::{Config, TestRunner};
use proptest::prelude::*;

use crate::{CompilerTest, CompilerTestBuilder, cargo_proj::project};
use crate::{CompilerTest, CompilerTestBuilder, cargo_proj::project, testing::executor_with_std};

#[test]
fn storage_example() {
Expand Down Expand Up @@ -63,19 +61,6 @@ fn storage_example() {
.assert_eq(&toml);
}

fn executor_with_std(package: &Package, args: Vec<Felt>) -> Result<Executor, TestCaseError> {
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())
.map_err(|err| TestCaseError::fail(err.to_string()))?;
Ok(exec)
}

#[test]
fn fibonacci() {
fn expected_fib(n: u32) -> u32 {
Expand All @@ -100,7 +85,7 @@ fn fibonacci() {
TestRunner::default()
.run(&(1u32..30), move |a| {
let rust_out = expected_fib(a);
let exec = executor_with_std(&package, vec![Felt::new(a as u64)])?;
let exec = executor_with_std(vec![Felt::new(a as u64)], Some(&package));
let output: u32 =
exec.execute_into(&package.unwrap_program(), test.session.source_manager.clone());
dbg!(output);
Expand Down Expand Up @@ -143,7 +128,7 @@ fn collatz() {
.run(&(1u32..30), move |a| {
let rust_out = expected(a);
let args = a.to_felts().to_vec();
let exec = executor_with_std(&package, args)?;
let exec = executor_with_std(args, Some(&package));
let output: u32 =
exec.execute_into(&package.unwrap_program(), test.session.source_manager.clone());
dbg!(output);
Expand Down Expand Up @@ -223,7 +208,7 @@ fn is_prime() {
prop_assert_eq!(rust_out as i32, result);

let args = a.to_felts().to_vec();
let exec = executor_with_std(&package, args)?;
let exec = executor_with_std(args, Some(&package));
let output: u32 =
exec.execute_into(&package.unwrap_program(), test.session.source_manager.clone());
dbg!(output);
Expand Down
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
2 changes: 1 addition & 1 deletion tests/integration/src/rust_masm_tests/rust_sdk/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn component_macros_account_and_note() {
let note_package = note.compiled_package();
let program = note_package.unwrap_program();

let mut exec = executor_with_std(vec![]);
let mut exec = executor_with_std(vec![], None);
exec.dependency_resolver_mut()
.add(account_package.digest(), account_package.into());
exec.with_dependencies(note_package.manifest.dependencies())
Expand Down
23 changes: 5 additions & 18 deletions tests/integration/src/rust_masm_tests/rust_sdk/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use std::{collections::BTreeMap, env, path::PathBuf, sync::Arc};
use std::{collections::BTreeMap, env, path::PathBuf};

use miden_core::{
Felt, FieldElement, Word,
utils::{Deserializable, Serializable},
};
use miden_debug::Executor;
use miden_lib::MidenLib;
use miden_mast_package::Package;
use miden_objects::account::{AccountComponentMetadata, AccountComponentTemplate, InitStorageData};
use midenc_expect_test::expect_file;
use midenc_frontend_wasm::WasmTranslationConfig;
Expand All @@ -17,23 +14,13 @@ use crate::{
CompilerTest, CompilerTestBuilder,
cargo_proj::project,
compiler_test::{sdk_alloc_crate_path, sdk_crate_path},
testing::executor_with_std,
};

mod base;
mod macros;
mod stdlib;

fn executor_with_std(args: Vec<Felt>) -> 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
}

#[test]
#[ignore = "until https://github.com/0xMiden/compiler/issues/439 is fixed"]
fn account() {
Expand Down Expand Up @@ -181,7 +168,7 @@ fn rust_sdk_cross_ctx_account_and_note() {
test.expect_masm(expect_file![format!("../../../expected/rust_sdk/cross_ctx_note.masm")]);
let package = test.compiled_package();
let program = package.unwrap_program();
let mut exec = executor_with_std(vec![]);
let mut exec = executor_with_std(vec![], None);
exec.dependency_resolver_mut()
.add(account_package.digest(), account_package.into());
exec.with_dependencies(package.manifest.dependencies())
Expand Down Expand Up @@ -238,7 +225,7 @@ fn rust_sdk_cross_ctx_account_and_note_word() {
test.expect_ir(expect_file![format!("../../../expected/rust_sdk/cross_ctx_note_word.hir")]);
test.expect_masm(expect_file![format!("../../../expected/rust_sdk/cross_ctx_note_word.masm")]);
let package = test.compiled_package();
let mut exec = executor_with_std(vec![]);
let mut exec = executor_with_std(vec![], None);
exec.dependency_resolver_mut()
.add(account_package.digest(), account_package.into());
exec.with_dependencies(package.manifest.dependencies())
Expand Down Expand Up @@ -310,7 +297,7 @@ fn rust_sdk_cross_ctx_word_arg_account_and_note() {
)]);
let package = test.compiled_package();
assert!(package.is_program());
let mut exec = executor_with_std(vec![]);
let mut exec = executor_with_std(vec![], None);
exec.dependency_resolver_mut()
.add(account_package.digest(), account_package.into());
exec.with_dependencies(package.manifest.dependencies())
Expand Down
26 changes: 26 additions & 0 deletions tests/integration/src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,37 @@ mod eval;
mod initializer;
pub mod setup;

use std::sync::Arc;

use miden_core::Felt;
use miden_debug::Executor;
use miden_lib::MidenLib;
use miden_mast_package::Package;
use midenc_session::STDLIB;

pub use self::{
eval::{compile_link_output_to_package, compile_test_module, eval_link_output, eval_package},
initializer::Initializer,
};

/// Creates an executor with standard library and base library loaded.
///
/// If a package is provided, its dependencies will also be added to the executor.
pub fn executor_with_std(args: Vec<Felt>, package: Option<&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());
if let Some(pkg) = package {
exec.with_dependencies(pkg.manifest.dependencies())
.expect("Failed to set up dependencies");
}
exec
}

/// Pretty-print `report` to a String
pub fn format_report(report: miden_assembly::diagnostics::Report) -> String {
use core::fmt::Write;
Expand Down
Loading