From 96f17fc6168b0c645463ccc834d2758ac9b97ad5 Mon Sep 17 00:00:00 2001 From: rvanasa Date: Fri, 24 Oct 2025 14:41:42 -0400 Subject: [PATCH 1/2] Add 'blob:' import placeholder flag for moc.js --- src/js/moc_js.ml | 1 + src/lang_utils/error_codes.ml | 1 + src/lowering/desugar.ml | 10 +++++++--- src/mo_config/flags.ml | 1 + src/mo_interpreter/interpret.ml | 10 +++++++--- src/pipeline/resolve_import.ml | 25 ++++++++++++++++--------- test/test-moc.js | 9 +++++++++ 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/js/moc_js.ml b/src/js/moc_js.ml index 8d0b667efe1..92ee7afeb91 100644 --- a/src/js/moc_js.ml +++ b/src/js/moc_js.ml @@ -28,6 +28,7 @@ let () = method setPublicMetadata entries = set_public_metadata entries method setRunStepLimit limit = js_set_run_step_limit limit method setTypecheckerCombineSrcs combineSrcs = Flags.typechecker_combine_srcs := combineSrcs + method setBlobImportPlaceholders placeholders = Flags.blob_import_placeholders := placeholders method gcFlags option = gc_flags option method run list s = Flags.compiled := false; wrap_output (fun _ -> js_run list s) method check s = Flags.compiled := false; js_check s diff --git a/src/lang_utils/error_codes.ml b/src/lang_utils/error_codes.ml index beaefab0f69..3b1ebae9aed 100644 --- a/src/lang_utils/error_codes.ml +++ b/src/lang_utils/error_codes.ml @@ -245,6 +245,7 @@ let warning_codes = [ "M0235", None, "Deprecate for caffeine"; "M0236", None, "Suggest contextual dot notation"; "M0237", None, "Suggest redundant explicit arguments"; + "M0238", None, "Blob import placeholder"; ] let try_find_explanation code = diff --git a/src/lowering/desugar.ml b/src/lowering/desugar.ml index ed16a36fba5..57fdc6bf8ad 100644 --- a/src/lowering/desugar.ml +++ b/src/lowering/desugar.ml @@ -1215,9 +1215,13 @@ and transform_import (i : S.import) : Ir.dec list = | S.IDLPath (fp, canister_id) -> primE (I.ActorOfIdBlob t) [blobE canister_id] | S.ImportedValuePath path -> - let contents = Lib.FilePath.contents path in - assert T.(t = Prim Blob); - blobE contents + if !Mo_config.Flags.blob_import_placeholders then + raise (Invalid_argument ("M0238: blob import placeholder")) + else begin + let contents = Lib.FilePath.contents path in + assert T.(t = Prim Blob); + blobE contents + end in [ letP (pat p) rhs ] type import_declaration = Ir.dec list diff --git a/src/mo_config/flags.ml b/src/mo_config/flags.ml index 85845a84e40..6ba0aa6bd48 100644 --- a/src/mo_config/flags.ml +++ b/src/mo_config/flags.ml @@ -80,6 +80,7 @@ let stable_memory_access_limit = ref stable_memory_access_limit_default let experimental_stable_memory_default = 0 (* _ < 0: error; _ = 0: warn, _ > 0: allow *) let experimental_stable_memory = ref experimental_stable_memory_default let typechecker_combine_srcs = ref false (* useful for the language server *) +let blob_import_placeholders = ref false (* when enabled, blob:file imports resolve as empty blobs *) let default_warning_levels = M.empty |> M.add "M0223" Allow (* don't report redundant instantions *) diff --git a/src/mo_interpreter/interpret.ml b/src/mo_interpreter/interpret.ml index e9e822b0204..0f6fa3419dd 100644 --- a/src/mo_interpreter/interpret.ml +++ b/src/mo_interpreter/interpret.ml @@ -459,9 +459,13 @@ and interpret_exp_mut env exp (k : V.value V.cont) = | LibPath {path; _} -> k (find path env.libs) | ImportedValuePath path -> - let contents = Lib.FilePath.contents path in - assert T.(exp.note.note_typ = Prim Blob); - k (V.Blob contents) + if !Mo_config.Flags.blob_import_placeholders then + trap exp.at "M0238: blob import placeholder" + else begin + let contents = Lib.FilePath.contents path in + assert T.(exp.note.note_typ = Prim Blob); + k (V.Blob contents) + end | IDLPath _ -> trap exp.at "actor import" | PrimPath -> k (find "@prim" env.libs) ) diff --git a/src/pipeline/resolve_import.ml b/src/pipeline/resolve_import.ml index 5574fa599ed..b99017b9b5b 100644 --- a/src/pipeline/resolve_import.ml +++ b/src/pipeline/resolve_import.ml @@ -156,15 +156,22 @@ let add_idl_import msgs imported ri_ref at full_path bytes = err_file_does_not_exist msgs at full_path let add_value_import msgs imported ri_ref at path = - let add_no_extension _file_exists f = f in - match resolve_lib_import at path add_no_extension with - | Ok full_path -> begin - let ri = ImportedValuePath full_path in - ri_ref := ri; - imported := RIM.add ri at !imported - end - | Error err -> - Diag.add_msg msgs err + if !Mo_config.Flags.blob_import_placeholders then begin + (* When placeholders are enabled, skip file existence check *) + let ri = ImportedValuePath path in + ri_ref := ri; + imported := RIM.add ri at !imported + end else begin + let add_no_extension _file_exists f = f in + match resolve_lib_import at path add_no_extension with + | Ok full_path -> begin + let ri = ImportedValuePath full_path in + ri_ref := ri; + imported := RIM.add ri at !imported + end + | Error err -> + Diag.add_msg msgs err + end let add_prim_import imported ri_ref at = ri_ref := PrimPath; diff --git a/test/test-moc.js b/test/test-moc.js index 2488db5cf99..2a33a073e30 100644 --- a/test/test-moc.js +++ b/test/test-moc.js @@ -245,3 +245,12 @@ assert(Motoko.parseMotokoTypedWithScopeCache(/*enable_recovery=*/false, ["bad.mo // TODO: This requires avoid dropping 'code' field in all checks though all pipeline e.g. infer_prog // assert(Motoko.parseMotokoTypedWithScopeCache(/*enable_recovery=*/true, ["bad.mo"], new Map()).code != null); +// `blob:` import placeholders +Motoko.setBlobImportPlaceholders(true); +Motoko.saveFile("blob.mo", 'import MyBlob "blob:file:path/to/blob.txt"; MyBlob.size();'); +assert(Motoko.parseMotoko(/*enable_recovery=*/true, "blob.mo").code != null); +assert.deepStrictEqual(Motoko.run([], "blob.mo"), { + stdout: "", + stderr: "blob.mo:1.1-1.43: execution error, M0238: blob import placeholder\n", + result: { error: {} }, +}); From 31b4269e01241b29703f39bdf2ed16a9bf7c690a Mon Sep 17 00:00:00 2001 From: rvanasa Date: Fri, 24 Oct 2025 16:15:05 -0400 Subject: [PATCH 2/2] Simplify --- src/lang_utils/error_codes.ml | 1 - src/lowering/desugar.ml | 2 +- src/mo_interpreter/interpret.ml | 2 +- test/test-moc.js | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lang_utils/error_codes.ml b/src/lang_utils/error_codes.ml index 3b1ebae9aed..beaefab0f69 100644 --- a/src/lang_utils/error_codes.ml +++ b/src/lang_utils/error_codes.ml @@ -245,7 +245,6 @@ let warning_codes = [ "M0235", None, "Deprecate for caffeine"; "M0236", None, "Suggest contextual dot notation"; "M0237", None, "Suggest redundant explicit arguments"; - "M0238", None, "Blob import placeholder"; ] let try_find_explanation code = diff --git a/src/lowering/desugar.ml b/src/lowering/desugar.ml index 57fdc6bf8ad..62d43e7e034 100644 --- a/src/lowering/desugar.ml +++ b/src/lowering/desugar.ml @@ -1216,7 +1216,7 @@ and transform_import (i : S.import) : Ir.dec list = primE (I.ActorOfIdBlob t) [blobE canister_id] | S.ImportedValuePath path -> if !Mo_config.Flags.blob_import_placeholders then - raise (Invalid_argument ("M0238: blob import placeholder")) + raise (Invalid_argument ("blob import placeholder")) else begin let contents = Lib.FilePath.contents path in assert T.(t = Prim Blob); diff --git a/src/mo_interpreter/interpret.ml b/src/mo_interpreter/interpret.ml index 0f6fa3419dd..808576a6add 100644 --- a/src/mo_interpreter/interpret.ml +++ b/src/mo_interpreter/interpret.ml @@ -460,7 +460,7 @@ and interpret_exp_mut env exp (k : V.value V.cont) = k (find path env.libs) | ImportedValuePath path -> if !Mo_config.Flags.blob_import_placeholders then - trap exp.at "M0238: blob import placeholder" + trap exp.at "blob import placeholder" else begin let contents = Lib.FilePath.contents path in assert T.(exp.note.note_typ = Prim Blob); diff --git a/test/test-moc.js b/test/test-moc.js index 2a33a073e30..a7ed5fc6cf8 100644 --- a/test/test-moc.js +++ b/test/test-moc.js @@ -251,6 +251,6 @@ Motoko.saveFile("blob.mo", 'import MyBlob "blob:file:path/to/blob.txt"; MyBlob.s assert(Motoko.parseMotoko(/*enable_recovery=*/true, "blob.mo").code != null); assert.deepStrictEqual(Motoko.run([], "blob.mo"), { stdout: "", - stderr: "blob.mo:1.1-1.43: execution error, M0238: blob import placeholder\n", + stderr: "blob.mo:1.1-1.43: execution error, blob import placeholder\n", result: { error: {} }, });