From d9b8399be5eb0f9401349a346e48c81a83563a8c Mon Sep 17 00:00:00 2001 From: Keemosty12 Date: Fri, 17 Apr 2026 21:52:23 +0800 Subject: [PATCH 1/3] Filter Mapper by source inference --- .../src/expr/inference/canonic.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs index bdf4b627339..4a3d4ef1b3f 100644 --- a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs +++ b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs @@ -535,6 +535,9 @@ impl<'db> SemanticRewriter, MapperError> for Mapper<'db, '_> { let TypeLongId::Var(var) = value else { return value.default_rewrite(self); }; + if var.inference_id != self.mapping.source_inference_id { + return value.default_rewrite(self); + } let id = self .mapping .type_var_mapping @@ -553,6 +556,9 @@ impl<'db> SemanticRewriter, MapperError> for Mapper<'db, '_> { let ConstValue::Var(var, ty) = value else { return value.default_rewrite(self); }; + if var.inference_id != self.mapping.source_inference_id { + return value.default_rewrite(self); + } let id = self .mapping .const_var_mapping @@ -582,6 +588,9 @@ impl<'db> SemanticRewriter, MapperError> for Mapper<'db, '_> { return value.default_rewrite(self); }; let var = var_id.long(self.get_db()); + if var.inference_id != self.mapping.source_inference_id { + return value.default_rewrite(self); + } let id = self .mapping .impl_var_mapping @@ -614,6 +623,9 @@ impl<'db> SemanticRewriter, MapperError> for Mapper<'db, return value.default_rewrite(self); }; let var = var_id.long(self.get_db()); + if var.inference_id != self.mapping.source_inference_id { + return value.default_rewrite(self); + } let id = self .mapping .negative_impl_var_mapping From f35447e6926397ba687652981f355460e69b0510 Mon Sep 17 00:00:00 2001 From: Keemosty12 Date: Mon, 20 Apr 2026 21:00:27 +0800 Subject: [PATCH 2/3] Add regression tests for mapper inference context filtering --- .../src/expr/inference/canonic.rs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs index 4a3d4ef1b3f..4b739d92010 100644 --- a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs +++ b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs @@ -639,3 +639,68 @@ impl<'db> SemanticRewriter, MapperError> for Mapper<'db, Ok(RewriteResult::Modified) } } + +#[cfg(test)] +mod tests { + use cairo_lang_utils::Intern; + use salsa::Database; + + use super::{Mapper, VarMapping}; + use crate::expr::inference::{ + ConstVar, InferenceId, LocalConstVarId, LocalTypeVarId, TypeVar, + }; + use crate::items::constant::ConstValue; + use crate::test_utils::SemanticDatabaseForTesting; + use crate::types::TypeLongId; + + #[test] + fn mapper_maps_type_var_from_source_inference_context() { + let db = SemanticDatabaseForTesting::default(); + let db: &dyn Database = &db; + let mut mapping = VarMapping::new_to_canonic(InferenceId::NoContext); + mapping.type_var_mapping.insert(LocalTypeVarId(0), LocalTypeVarId(7)); + + let original = TypeLongId::Var(TypeVar { + inference_id: InferenceId::NoContext, + id: LocalTypeVarId(0), + }); + + let mapped = Mapper::map(db, original, &mapping).unwrap(); + assert_eq!( + mapped, + TypeLongId::Var(TypeVar { inference_id: InferenceId::Canonical, id: LocalTypeVarId(7) }) + ); + } + + #[test] + fn mapper_ignores_type_var_from_other_inference_context() { + let db = SemanticDatabaseForTesting::default(); + let db: &dyn Database = &db; + let mut mapping = VarMapping::new_to_canonic(InferenceId::NoContext); + mapping.type_var_mapping.insert(LocalTypeVarId(0), LocalTypeVarId(7)); + + let original = TypeLongId::Var(TypeVar { + inference_id: InferenceId::Canonical, + id: LocalTypeVarId(0), + }); + + let mapped = Mapper::map(db, original.clone(), &mapping).unwrap(); + assert_eq!(mapped, original); + } + + #[test] + fn mapper_ignores_const_var_from_other_inference_context() { + let db = SemanticDatabaseForTesting::default(); + let db: &dyn Database = &db; + let mut mapping = VarMapping::new_to_canonic(InferenceId::NoContext); + mapping.const_var_mapping.insert(LocalConstVarId(0), LocalConstVarId(3)); + let ty = TypeLongId::Tuple(vec![]).intern(db); + let original = ConstValue::Var( + ConstVar { inference_id: InferenceId::Canonical, id: LocalConstVarId(0) }, + ty, + ); + + let mapped = Mapper::map(db, original.clone(), &mapping).unwrap(); + assert_eq!(mapped, original); + } +} From 0603f4c4dd68c2389bad50946c68943ff3b38919 Mon Sep 17 00:00:00 2001 From: Keemosty12 Date: Mon, 20 Apr 2026 22:58:08 +0800 Subject: [PATCH 3/3] test(semantic): use inference-allocated vars in mapper regression --- .../src/expr/inference/canonic.rs | 75 +++++++++++-------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs index 4b739d92010..55a13c74b94 100644 --- a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs +++ b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs @@ -647,59 +647,74 @@ mod tests { use super::{Mapper, VarMapping}; use crate::expr::inference::{ - ConstVar, InferenceId, LocalConstVarId, LocalTypeVarId, TypeVar, + InferenceData, InferenceId, LocalConstVarId, LocalTypeVarId, TypeVar, }; use crate::items::constant::ConstValue; use crate::test_utils::SemanticDatabaseForTesting; - use crate::types::TypeLongId; + use crate::TypeLongId; + + fn overlapping_type_vars_from_inference<'db>( + db: &'db dyn Database, + ) -> (TypeVar<'db>, TypeVar<'db>) { + let mut source_inference_data = InferenceData::new(InferenceId::NoContext); + let mut source_inference = source_inference_data.inference(db); + let source_var = source_inference.new_type_var_raw(None); + + let mut foreign_inference_data = InferenceData::new(InferenceId::Canonical); + let mut foreign_inference = foreign_inference_data.inference(db); + let foreign_var = foreign_inference.new_type_var_raw(None); + + assert_eq!(source_var.id, foreign_var.id); + (source_var, foreign_var) + } #[test] - fn mapper_maps_type_var_from_source_inference_context() { + fn mapper_maps_source_type_var_created_by_inference() { let db = SemanticDatabaseForTesting::default(); let db: &dyn Database = &db; - let mut mapping = VarMapping::new_to_canonic(InferenceId::NoContext); - mapping.type_var_mapping.insert(LocalTypeVarId(0), LocalTypeVarId(7)); - - let original = TypeLongId::Var(TypeVar { - inference_id: InferenceId::NoContext, - id: LocalTypeVarId(0), - }); + let (source_var, _) = overlapping_type_vars_from_inference(db); + let mapped_var_id = LocalTypeVarId(source_var.id.0 + 7); + let original = TypeLongId::Var(source_var); + let mut mapping = VarMapping::new_to_canonic(source_var.inference_id); + mapping.type_var_mapping.insert(source_var.id, mapped_var_id); let mapped = Mapper::map(db, original, &mapping).unwrap(); - assert_eq!( - mapped, - TypeLongId::Var(TypeVar { inference_id: InferenceId::Canonical, id: LocalTypeVarId(7) }) - ); + let TypeLongId::Var(mapped_var) = mapped else { panic!("expected type var after map") }; + assert_eq!(mapped_var.inference_id, InferenceId::Canonical); + assert_eq!(mapped_var.id, mapped_var_id); } #[test] - fn mapper_ignores_type_var_from_other_inference_context() { + fn mapper_ignores_foreign_type_var_with_overlapping_local_id() { let db = SemanticDatabaseForTesting::default(); let db: &dyn Database = &db; - let mut mapping = VarMapping::new_to_canonic(InferenceId::NoContext); - mapping.type_var_mapping.insert(LocalTypeVarId(0), LocalTypeVarId(7)); - - let original = TypeLongId::Var(TypeVar { - inference_id: InferenceId::Canonical, - id: LocalTypeVarId(0), - }); + let (source_var, foreign_var) = overlapping_type_vars_from_inference(db); + let mut mapping = VarMapping::new_to_canonic(source_var.inference_id); + mapping.type_var_mapping.insert(source_var.id, LocalTypeVarId(source_var.id.0 + 7)); + let original = TypeLongId::Var(foreign_var); let mapped = Mapper::map(db, original.clone(), &mapping).unwrap(); assert_eq!(mapped, original); } #[test] - fn mapper_ignores_const_var_from_other_inference_context() { + fn mapper_ignores_foreign_const_var_with_overlapping_local_id() { let db = SemanticDatabaseForTesting::default(); let db: &dyn Database = &db; - let mut mapping = VarMapping::new_to_canonic(InferenceId::NoContext); - mapping.const_var_mapping.insert(LocalConstVarId(0), LocalConstVarId(3)); - let ty = TypeLongId::Tuple(vec![]).intern(db); - let original = ConstValue::Var( - ConstVar { inference_id: InferenceId::Canonical, id: LocalConstVarId(0) }, - ty, - ); + let mut source_inference_data = InferenceData::new(InferenceId::NoContext); + let mut source_inference = source_inference_data.inference(db); + let source_var = source_inference.new_const_var_raw(None); + + let mut foreign_inference_data = InferenceData::new(InferenceId::Canonical); + let mut foreign_inference = foreign_inference_data.inference(db); + let foreign_var = foreign_inference.new_const_var_raw(None); + assert_eq!(source_var.id, foreign_var.id); + let mut mapping = VarMapping::new_to_canonic(source_var.inference_id); + mapping.const_var_mapping.insert(source_var.id, LocalConstVarId(source_var.id.0 + 3)); + + let ty = TypeLongId::Tuple(vec![]).intern(db); + let original = ConstValue::Var(foreign_var, ty); let mapped = Mapper::map(db, original.clone(), &mapping).unwrap(); assert_eq!(mapped, original); }