diff --git a/Changelog.md b/Changelog.md index db00cebf387..56d87f3f39f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,7 @@ # Motoko compiler changelog +## 0.13.5 (FUTURE) + * motoko (`moc`) * Breaking change (minor): @@ -33,6 +35,15 @@ On upgrade, the transient variable `invocations` will be reset to `0` and `value`, now implicitly `stable`, will retain its current value. Legacy actors and classes declared without the `persistent` keyword have the same semantics as before. + + * Added new primitive `replyDeadline : () -> Nat64` to obtain when a response for a best-effort message is due (#4795). + +* motoko-base + + * Added `Text.fromList` and `Text.toList` functions (dfinity/motoko-base#676). + + * Added `Text.fromArray/fromVarArray` functions (dfinity/motoko-base#674). + ## 0.13.4 (2024-11-29) * motoko (`moc`) diff --git a/nix/sources.json b/nix/sources.json index 9120bf939fc..cc6d4ab383e 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -26,10 +26,10 @@ "homepage": "", "owner": "luc-blaeser", "repo": "ic", - "rev": "33075cd385ea2ec4170f522406b1ff8f507fa744", - "sha256": "0swx7r78wjybx7fkfqsn9p3lqxmszgg24q4hrnxmscvyhb22hqia", + "rev": "bebe89514a6abd26e940b295323823169911a965", + "sha256": "1g68fyi5acbcgs2kjribk97fj8ki5g6pd99nwl5azz1rw1b0xycx", "type": "tarball", - "url": "https://github.com/luc-blaeser/ic/archive/33075cd385ea2ec4170f522406b1ff8f507fa744.tar.gz", + "url": "https://github.com/luc-blaeser/ic/archive/bebe89514a6abd26e940b295323823169911a965.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "ic-hs": { diff --git a/src/codegen/compile_classical.ml b/src/codegen/compile_classical.ml index e21c5f2eb39..a16282ca4db 100644 --- a/src/codegen/compile_classical.ml +++ b/src/codegen/compile_classical.ml @@ -5086,6 +5086,7 @@ module IC = struct E.add_func_import env "ic0" "msg_reject" (i32s 2) []; E.add_func_import env "ic0" "msg_reply_data_append" (i32s 2) []; E.add_func_import env "ic0" "msg_reply" [] []; + E.add_func_import env "ic0" "msg_deadline" [] [I64Type]; E.add_func_import env "ic0" "performance_counter" [I32Type] [I64Type]; E.add_func_import env "ic0" "trap" (i32s 2) []; E.add_func_import env "ic0" "stable64_write" (i64s 3) []; @@ -5351,7 +5352,7 @@ module IC = struct (fun env -> system_call env "msg_caller_copy") (fun env -> compile_unboxed_const 0l) | _ -> - E.trap_with env (Printf.sprintf "cannot get caller when running locally") + E.trap_with env "cannot get caller when running locally" let method_name env = match E.mode env with @@ -5361,7 +5362,7 @@ module IC = struct (fun env -> system_call env "msg_method_name_copy") (fun env -> compile_unboxed_const 0l) | _ -> - E.trap_with env (Printf.sprintf "cannot get method_name when running locally") + E.trap_with env "cannot get method_name when running locally" let arg_data env = match E.mode env with @@ -5371,7 +5372,14 @@ module IC = struct (fun env -> system_call env "msg_arg_data_copy") (fun env -> compile_unboxed_const 0l) | _ -> - E.trap_with env (Printf.sprintf "cannot get arg_data when running locally") + E.trap_with env "cannot get arg_data when running locally" + + let deadline env = + match E.mode env with + | Flags.(ICMode | RefMode) -> + system_call env "msg_deadline" + | _ -> + E.trap_with env "cannot get deadline when running locally" let reject env arg_instrs = match E.mode env with @@ -5381,7 +5389,7 @@ module IC = struct Blob.as_ptr_len env ^^ system_call env "msg_reject" | _ -> - E.trap_with env (Printf.sprintf "cannot reject when running locally") + E.trap_with env "cannot reject when running locally" let error_code env = Func.share_code0 Func.Always env "error_code" [I32Type] (fun env -> @@ -12095,7 +12103,7 @@ and compile_prim_invocation (env : E.t) ae p es at = Serialization.serialize env ts ^^ IC.reply_with_data env | _ -> - E.trap_with env (Printf.sprintf "cannot reply when running locally") + E.trap_with env "cannot reply when running locally" end | ICRejectPrim, [e] -> @@ -12144,6 +12152,9 @@ and compile_prim_invocation (env : E.t) ae p es at = | ICMethodNamePrim, [] -> SR.Vanilla, IC.method_name env + | ICReplyDeadlinePrim, [] -> + SR.UnboxedWord64 Type.Nat64, IC.deadline env + | ICStableRead ty, [] -> (* * On initial install: diff --git a/src/codegen/compile_enhanced.ml b/src/codegen/compile_enhanced.ml index 03699d03789..61d21e839f5 100644 --- a/src/codegen/compile_enhanced.ml +++ b/src/codegen/compile_enhanced.ml @@ -4744,6 +4744,7 @@ module IC = struct E.add_func_import env "ic0" "msg_reject" (i64s 2) []; E.add_func_import env "ic0" "msg_reply_data_append" (i64s 2) []; E.add_func_import env "ic0" "msg_reply" [] []; + E.add_func_import env "ic0" "msg_deadline" [] [I64Type]; E.add_func_import env "ic0" "performance_counter" [I32Type] [I64Type]; E.add_func_import env "ic0" "trap" (i64s 2) []; E.add_func_import env "ic0" "stable64_write" (i64s 3) []; @@ -5071,7 +5072,7 @@ module IC = struct system_call env "msg_caller_copy") (fun env -> compile_unboxed_const 0L) | _ -> - E.trap_with env (Printf.sprintf "cannot get caller when running locally") + E.trap_with env "cannot get caller when running locally" let method_name env = match E.mode env with @@ -5083,7 +5084,7 @@ module IC = struct system_call env "msg_method_name_copy") (fun env -> compile_unboxed_const 0L) | _ -> - E.trap_with env (Printf.sprintf "cannot get method_name when running locally") + E.trap_with env "cannot get method_name when running locally" let arg_data env = match E.mode env with @@ -5095,7 +5096,14 @@ module IC = struct system_call env "msg_arg_data_copy") (fun env -> compile_unboxed_const 0L) | _ -> - E.trap_with env (Printf.sprintf "cannot get arg_data when running locally") + E.trap_with env "cannot get arg_data when running locally" + + let deadline env = + match E.mode env with + | Flags.(ICMode | RefMode) -> + system_call env "msg_deadline" + | _ -> + E.trap_with env "cannot get deadline when running locally" let reject env arg_instrs = match E.mode env with @@ -5105,7 +5113,7 @@ module IC = struct Blob.as_ptr_len env ^^ system_call env "msg_reject" | _ -> - E.trap_with env (Printf.sprintf "cannot reject when running locally") + E.trap_with env "cannot reject when running locally" let error_code env = Func.share_code0 Func.Always env "error_code" [I64Type] (fun env -> @@ -12190,7 +12198,7 @@ and compile_prim_invocation (env : E.t) ae p es at = Serialization.serialize env ts ^^ IC.reply_with_data env | _ -> - E.trap_with env (Printf.sprintf "cannot reply when running locally") + E.trap_with env "cannot reply when running locally" end | ICRejectPrim, [e] -> @@ -12239,6 +12247,9 @@ and compile_prim_invocation (env : E.t) ae p es at = | ICMethodNamePrim, [] -> SR.Vanilla, IC.method_name env + | ICReplyDeadlinePrim, [] -> + SR.UnboxedWord64 Type.Nat64, IC.deadline env + | ICStableRead ty, [] -> SR.Vanilla, Persistence.load env ty diff --git a/src/ir_def/arrange_ir.ml b/src/ir_def/arrange_ir.ml index 02cb40bde7d..b0f110029fb 100644 --- a/src/ir_def/arrange_ir.ml +++ b/src/ir_def/arrange_ir.ml @@ -118,6 +118,7 @@ and prim = function | ICCallPrim -> Atom "ICCallPrim" | ICCallRawPrim -> Atom "ICCallRawPrim" | ICMethodNamePrim -> Atom "ICMethodNamePrim" + | ICReplyDeadlinePrim -> Atom "ICReplyDeadlinePrim" | ICStableWrite t -> "ICStableWrite" $$ [typ t] | ICStableRead t -> "ICStableRead" $$ [typ t] diff --git a/src/ir_def/check_ir.ml b/src/ir_def/check_ir.ml index 0d9f45279a6..37e84da5623 100644 --- a/src/ir_def/check_ir.ml +++ b/src/ir_def/check_ir.ml @@ -627,6 +627,8 @@ let rec check_exp env (exp:Ir.exp) : unit = T.unit <: t | ICMethodNamePrim, [] -> T.text <: t + | ICReplyDeadlinePrim, [] -> + T.nat64 <: t | ICStableRead t1, [] -> check_typ env t1; check (store_typ t1) "Invalid type argument to ICStableRead"; diff --git a/src/ir_def/ir.ml b/src/ir_def/ir.ml index 18b28c8b9ff..192a7453446 100644 --- a/src/ir_def/ir.ml +++ b/src/ir_def/ir.ml @@ -175,6 +175,7 @@ and prim = | ICCallPrim | ICCallRawPrim | ICMethodNamePrim + | ICReplyDeadlinePrim | ICArgDataPrim | ICStableWrite of Type.typ (* serialize value of stable type to stable memory *) | ICStableRead of Type.typ (* deserialize value of stable type from stable memory *) @@ -322,7 +323,8 @@ let map_prim t_typ t_id p = | ICCallerPrim | ICCallPrim | ICCallRawPrim - | ICMethodNamePrim -> p + | ICMethodNamePrim + | ICReplyDeadlinePrim -> p | ICStableWrite t -> ICStableWrite (t_typ t) | ICStableRead t -> ICStableRead (t_typ t) | ICStableSize t -> ICStableSize (t_typ t) diff --git a/src/ir_interpreter/interpret_ir.ml b/src/ir_interpreter/interpret_ir.ml index 6c0e5301013..ce426ac2f85 100644 --- a/src/ir_interpreter/interpret_ir.ml +++ b/src/ir_interpreter/interpret_ir.ml @@ -462,6 +462,8 @@ and interpret_exp_mut env exp (k : V.value V.cont) = f (V.Tup[vc; kv; rv; cv]) v2 k | ICCallerPrim, [] -> k env.caller + | ICReplyDeadlinePrim, [] -> + k (V.Nat64 Numerics.Nat64.zero) | ICStableRead t, [] -> let (_, tfs) = T.as_obj t in let ve = List.fold_left diff --git a/src/lowering/desugar.ml b/src/lowering/desugar.ml index d79d3ccb942..7049a6d8a6c 100644 --- a/src/lowering/desugar.ml +++ b/src/lowering/desugar.ml @@ -166,6 +166,9 @@ and exp' at note = function | S.CallE ({it=S.AnnotE ({it=S.PrimE "caller";_},_);_}, _, {it=S.TupE es;_}) -> assert (es = []); I.PrimE (I.ICCallerPrim, []) + | S.CallE ({it=S.AnnotE ({it=S.PrimE "deadline";_},_);_}, _, {it=S.TupE es;_}) -> + assert (es = []); + I.PrimE (I.ICReplyDeadlinePrim, []) | S.CallE ({it=S.AnnotE ({it=S.PrimE "time";_},_);_}, _, {it=S.TupE es;_}) -> assert (es = []); I.PrimE (I.SystemTimePrim, []) diff --git a/src/mo_values/prim.ml b/src/mo_values/prim.ml index 0248598a95a..a9cd01ad965 100644 --- a/src/mo_values/prim.ml +++ b/src/mo_values/prim.ml @@ -229,6 +229,7 @@ let prim trap = | "rts_upgrade_instructions") -> fun _ v k -> as_unit v; k (Int (Int.of_int 0)) | "time" -> fun _ v k -> as_unit v; k (Value.Nat64 (Numerics.Nat64.of_int 42)) + | "deadline" -> fun _ v k -> as_unit v; k (Value.Nat64 Numerics.Nat64.zero) | "idlHash" -> fun _ v k -> let s = as_text v in k (Nat32 (Nat32.wrapping_of_big_int (Big_int.big_int_of_int32 (Lib.Uint32.to_int32 (Idllib.IdlHash.idl_hash s))))) diff --git a/src/prelude/prim.mo b/src/prelude/prim.mo index 209337400e0..1ccda0c81ee 100644 --- a/src/prelude/prim.mo +++ b/src/prelude/prim.mo @@ -304,6 +304,10 @@ func error(message : Text) : Error { func errorCode(e : Error) : ErrorCode = ((prim "cast" : Error -> (ErrorCode, Text)) e).0; func errorMessage(e : Error) : Text = ((prim "cast" : Error -> (ErrorCode, Text)) e).1; +// Message deadline (best-effort messaging) + +func replyDeadline() : Nat64 = (prim "deadline" : () -> Nat64) (); + // Time func time() : Nat64 = (prim "time" : () -> Nat64)(); diff --git a/test/fail/ok/no-timer-canc.tc.ok b/test/fail/ok/no-timer-canc.tc.ok index e1877945e59..a78867d5f6e 100644 --- a/test/fail/ok/no-timer-canc.tc.ok +++ b/test/fail/ok/no-timer-canc.tc.ok @@ -204,6 +204,7 @@ no-timer-canc.mo:3.10-3.21: type error [M0119], object field cancelTimer is not regionStoreNat32 : (Region, Nat64, Nat32) -> (); regionStoreNat64 : (Region, Nat64, Nat64) -> (); regionStoreNat8 : (Region, Nat64, Nat8) -> (); + replyDeadline : () -> Nat64; rts_callback_table_count : () -> Nat; rts_callback_table_size : () -> Nat; rts_collector_instructions : () -> Nat; diff --git a/test/fail/ok/no-timer-set.tc.ok b/test/fail/ok/no-timer-set.tc.ok index f4951c74796..f539873cf9e 100644 --- a/test/fail/ok/no-timer-set.tc.ok +++ b/test/fail/ok/no-timer-set.tc.ok @@ -204,6 +204,7 @@ no-timer-set.mo:3.10-3.18: type error [M0119], object field setTimer is not cont regionStoreNat32 : (Region, Nat64, Nat32) -> (); regionStoreNat64 : (Region, Nat64, Nat64) -> (); regionStoreNat8 : (Region, Nat64, Nat8) -> (); + replyDeadline : () -> Nat64; rts_callback_table_count : () -> Nat; rts_callback_table_size : () -> Nat; rts_collector_instructions : () -> Nat; diff --git a/test/fail/ok/suggest-long-ai.tc.ok b/test/fail/ok/suggest-long-ai.tc.ok index 7f50d74de08..e7ecd37f791 100644 --- a/test/fail/ok/suggest-long-ai.tc.ok +++ b/test/fail/ok/suggest-long-ai.tc.ok @@ -205,6 +205,7 @@ suggest-long-ai.mo:4.1-4.5: type error [M0072], field stableM does not exist in regionStoreNat32 : (Region, Nat64, Nat32) -> (); regionStoreNat64 : (Region, Nat64, Nat64) -> (); regionStoreNat8 : (Region, Nat64, Nat8) -> (); + replyDeadline : () -> Nat64; rts_callback_table_count : () -> Nat; rts_callback_table_size : () -> Nat; rts_collector_instructions : () -> Nat; diff --git a/test/fail/ok/suggest-short-ai.tc.ok b/test/fail/ok/suggest-short-ai.tc.ok index da8382a1215..50afa55780a 100644 --- a/test/fail/ok/suggest-short-ai.tc.ok +++ b/test/fail/ok/suggest-short-ai.tc.ok @@ -205,6 +205,7 @@ suggest-short-ai.mo:4.1-4.5: type error [M0072], field s does not exist in type: regionStoreNat32 : (Region, Nat64, Nat32) -> (); regionStoreNat64 : (Region, Nat64, Nat64) -> (); regionStoreNat8 : (Region, Nat64, Nat8) -> (); + replyDeadline : () -> Nat64; rts_callback_table_count : () -> Nat; rts_callback_table_size : () -> Nat; rts_collector_instructions : () -> Nat; diff --git a/test/run-drun/composite-query.mo b/test/run-drun/composite-query.mo index 30695acad59..1aa83a93a11 100644 --- a/test/run-drun/composite-query.mo +++ b/test/run-drun/composite-query.mo @@ -16,6 +16,7 @@ actor Composites { }; public composite query func cq1() : async () { + assert 0 : Nat64 == Prim.replyDeadline(); }; public composite query func cq2() : async () { diff --git a/test/run-drun/ok/composite-query.tc.ok b/test/run-drun/ok/composite-query.tc.ok index 771ebcfc7fb..a312e5e19e8 100644 --- a/test/run-drun/ok/composite-query.tc.ok +++ b/test/run-drun/ok/composite-query.tc.ok @@ -1,8 +1,8 @@ -composite-query.mo:30.11-30.13: warning [M0145], this pattern of type +composite-query.mo:31.11-31.13: warning [M0145], this pattern of type ?Class__1 does not cover value null -composite-query.mo:35.11-35.13: warning [M0145], this pattern of type +composite-query.mo:36.11-36.13: warning [M0145], this pattern of type ?Class__1 does not cover value null diff --git a/test/run-drun/ok/query2.run-ir.ok b/test/run-drun/ok/query2.run-ir.ok index 61bf2dcd7f0..2d5d7ae3f3b 100644 --- a/test/run-drun/ok/query2.run-ir.ok +++ b/test/run-drun/ok/query2.run-ir.ok @@ -9,4 +9,4 @@ In read: 6 6 The following fails in the interpreter, for lack of query semantics -query2.mo:35.4-35.18: execution error, assertion failure +query2.mo:37.4-37.18: execution error, assertion failure diff --git a/test/run-drun/ok/query2.run-low.ok b/test/run-drun/ok/query2.run-low.ok index 61bf2dcd7f0..2d5d7ae3f3b 100644 --- a/test/run-drun/ok/query2.run-low.ok +++ b/test/run-drun/ok/query2.run-low.ok @@ -9,4 +9,4 @@ In read: 6 6 The following fails in the interpreter, for lack of query semantics -query2.mo:35.4-35.18: execution error, assertion failure +query2.mo:37.4-37.18: execution error, assertion failure diff --git a/test/run-drun/ok/query2.run.ok b/test/run-drun/ok/query2.run.ok index 61bf2dcd7f0..2d5d7ae3f3b 100644 --- a/test/run-drun/ok/query2.run.ok +++ b/test/run-drun/ok/query2.run.ok @@ -9,4 +9,4 @@ In read: 6 6 The following fails in the interpreter, for lack of query semantics -query2.mo:35.4-35.18: execution error, assertion failure +query2.mo:37.4-37.18: execution error, assertion failure diff --git a/test/run-drun/query2.mo b/test/run-drun/query2.mo index 0c29847042d..34d097d3b74 100644 --- a/test/run-drun/query2.mo +++ b/test/run-drun/query2.mo @@ -6,12 +6,14 @@ actor counter = { Prim.debugPrintNat c; }; public func printCounter () : async () { + assert 0 : Nat64 == Prim.replyDeadline(); Prim.debugPrintNat c; }; public func get() : async Nat { return c }; public query func read() : async Nat { + assert 0 : Nat64 == Prim.replyDeadline(); let tmp = c; c += 1; Prim.debugPrint "In read:";