1+ use cairo_lang_defs:: db:: DefsGroup ;
2+ use cairo_lang_defs:: ids:: LanguageElementId ;
13use cairo_lang_filesystem:: db:: { FilesGroup , files_group_input, set_crate_configs_input} ;
2- use cairo_lang_filesystem:: ids:: BlobLongId ;
4+ use cairo_lang_filesystem:: ids:: { BlobLongId , FileLongId } ;
5+ use cairo_lang_parser:: db:: ParserGroup ;
36use cairo_lang_semantic:: corelib:: CorelibSemantic ;
47use cairo_lang_semantic:: test_utils:: setup_test_function_ex;
58use cairo_lang_test_utils:: parse_test_file:: TestRunnerResult ;
@@ -26,23 +29,11 @@ fn test_cache_check(
2629 inputs : & OrderedHashMap < String , String > ,
2730 args : & OrderedHashMap < String , String > ,
2831) -> TestRunnerResult {
29- let db = & mut LoweringDatabaseForTesting :: default ( ) ;
30-
3132 let function = & inputs[ "function_code" ] ;
3233 let function_name = & inputs[ "function_name" ] ;
3334 let module_code = inputs. get ( "module_code" ) . map_or ( "" , String :: as_str) ;
34- let ( test_function, _semantic_diagnostics) =
35- setup_test_function_ex ( db, function, function_name, module_code, None , None ) . split ( ) ;
36-
37- let artifact = generate_crate_cache ( db, test_function. module_id . owning_crate ( db) ) . unwrap ( ) ;
38- let core_artifact = generate_crate_cache ( db, db. core_crate ( ) ) . unwrap ( ) ;
39- let mut new_db = LoweringDatabaseForTesting :: new ( ) ;
40- let crt = new_db. crate_input ( new_db. core_crate ( ) ) ;
41- let mut crate_configs = files_group_input ( & new_db) . crate_configs ( & new_db) . clone ( ) . unwrap ( ) ;
42- let config = crate_configs. get_mut ( crt) . unwrap ( ) ;
43- config. cache_file = Some ( BlobLongId :: Virtual ( core_artifact) ) ;
44- set_crate_configs_input ( & mut new_db, Some ( crate_configs) ) ;
4535
36+ let ( new_db, artifact) = generate_cached_db ( function, function_name, module_code) ;
4637 let cached_file = BlobLongId :: Virtual ( artifact) . intern ( & new_db) ;
4738 let ( test_function, semantic_diagnostics) = setup_test_function_ex (
4839 & new_db,
@@ -78,3 +69,63 @@ fn test_cache_check(
7869 error,
7970 }
8071}
72+
73+ /// Compiles `function`/`module_code` to generate the crate cache (and the corelib cache), then
74+ /// returns a fresh db with the corelib cache loaded plus the crate-cache artifact. Callers wire the
75+ /// artifact in as the test crate's `cache_file` via
76+ /// `setup_test_function_ex(.., Some(BlobLongId::Virtual(artifact).intern(&db)))`.
77+ fn generate_cached_db (
78+ function : & str ,
79+ function_name : & str ,
80+ module_code : & str ,
81+ ) -> ( LoweringDatabaseForTesting , Vec < u8 > ) {
82+ let db = & mut LoweringDatabaseForTesting :: default ( ) ;
83+ let ( test_function, _) =
84+ setup_test_function_ex ( db, function, function_name, module_code, None , None ) . split ( ) ;
85+
86+ let artifact = generate_crate_cache ( db, test_function. module_id . owning_crate ( db) ) . unwrap ( ) ;
87+ let core_artifact = generate_crate_cache ( db, db. core_crate ( ) ) . unwrap ( ) ;
88+
89+ let mut new_db = LoweringDatabaseForTesting :: new ( ) ;
90+ let crt = new_db. crate_input ( new_db. core_crate ( ) ) ;
91+ let mut crate_configs = files_group_input ( & new_db) . crate_configs ( & new_db) . clone ( ) . unwrap ( ) ;
92+ crate_configs. get_mut ( crt) . unwrap ( ) . cache_file = Some ( BlobLongId :: Virtual ( core_artifact) ) ;
93+ set_crate_configs_input ( & mut new_db, Some ( crate_configs) ) ;
94+ ( new_db, artifact)
95+ }
96+
97+ /// File syntax roots are canonical (file-keyed via `SyntaxNode::new_canonical_root`). For an
98+ /// external (plugin-generated) file restored from a crate cache, the root reached from a cached
99+ /// stable ptr must therefore be the very node `db.file_syntax` mints — not a detached duplicate.
100+ #[ test]
101+ fn cached_external_file_root_is_canonical ( ) {
102+ let function = "fn foo() {}" ;
103+ let module_code = "\
104+ #[derive(Drop)]
105+ struct MyStruct {
106+ x: felt252,
107+ }" ;
108+ let ( db, artifact) = generate_cached_db ( function, "foo" , module_code) ;
109+ let cached_file = BlobLongId :: Virtual ( artifact) . intern ( & db) ;
110+ let ( cached_function, _) =
111+ setup_test_function_ex ( & db, function, "foo" , module_code, None , Some ( cached_file) ) . split ( ) ;
112+
113+ // The `#[derive(Drop)]` impl lives in an external file; its cached stable ptr must resolve to
114+ // the canonical `file_syntax` root.
115+ let mut checked = 0 ;
116+ for impl_id in db. module_impls_ids ( cached_function. module_id ) . unwrap ( ) {
117+ let stable_ptr = impl_id. untyped_stable_ptr ( & db) ;
118+ let ext_file = stable_ptr. file_id ( & db) ;
119+ if !matches ! ( ext_file. long( & db) , FileLongId :: External ( _) ) {
120+ continue ;
121+ }
122+ let root = stable_ptr. 0 . ancestors_with_self ( & db) . last ( ) . unwrap ( ) ;
123+ assert_eq ! (
124+ root,
125+ db. file_syntax( ext_file) . unwrap( ) ,
126+ "external root differs from file_syntax (detached node minted on load?)"
127+ ) ;
128+ checked += 1 ;
129+ }
130+ assert ! ( checked > 0 , "expected at least one external (derive-generated) file" ) ;
131+ }
0 commit comments