From c78329e68b89e4058028c0f3458117c4614d0a1d Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sun, 30 Nov 2025 13:11:01 -0500 Subject: [PATCH] Fix .to_str() bug, add some regression tests --- src/eval/interpreter.zig | 10 +- .../eval/record_i64_field_addition.md | 136 ++++++ .../snapshots/eval/record_i64_field_update.md | 253 +++++++++++ test/snapshots/eval/robot_simulator_i64.md | 411 ++++++++++++++++++ test/snapshots/eval/str_to_utf8_method.md | 86 ++++ 5 files changed, 894 insertions(+), 2 deletions(-) create mode 100644 test/snapshots/eval/record_i64_field_addition.md create mode 100644 test/snapshots/eval/record_i64_field_update.md create mode 100644 test/snapshots/eval/robot_simulator_i64.md create mode 100644 test/snapshots/eval/str_to_utf8_method.md diff --git a/src/eval/interpreter.zig b/src/eval/interpreter.zig index 5b82266bc6..3593409916 100644 --- a/src/eval/interpreter.zig +++ b/src/eval/interpreter.zig @@ -10870,7 +10870,10 @@ pub const Interpreter = struct { if (lambda_expr == .e_low_level_lambda) { const low_level = lambda_expr.e_low_level_lambda; var args = [1]StackValue{receiver_value}; - const result = try self.callLowLevelBuiltin(low_level.op, &args, roc_ops, null); + // Get return type from the dot access expression for low-level builtins that need it + const return_ct_var = can.ModuleEnv.varFrom(da.expr_idx); + const return_rt_var = try self.translateTypeVar(self.env, return_ct_var); + const result = try self.callLowLevelBuiltin(low_level.op, &args, roc_ops, return_rt_var); receiver_value.decref(&self.runtime_layout_store, roc_ops); method_func.decref(&self.runtime_layout_store, roc_ops); self.env = saved_env; @@ -10990,7 +10993,10 @@ pub const Interpreter = struct { all_args[1 + idx] = arg; } - const result = try self.callLowLevelBuiltin(low_level.op, all_args, roc_ops, null); + // Get return type from the dot access expression for low-level builtins that need it + const return_ct_var = can.ModuleEnv.varFrom(dac.expr_idx); + const return_rt_var = try self.translateTypeVar(self.env, return_ct_var); + const result = try self.callLowLevelBuiltin(low_level.op, all_args, roc_ops, return_rt_var); receiver_value.decref(&self.runtime_layout_store, roc_ops); for (arg_values) |arg| arg.decref(&self.runtime_layout_store, roc_ops); diff --git a/test/snapshots/eval/record_i64_field_addition.md b/test/snapshots/eval/record_i64_field_addition.md new file mode 100644 index 0000000000..25a5ee4864 --- /dev/null +++ b/test/snapshots/eval/record_i64_field_addition.md @@ -0,0 +1,136 @@ +# META +~~~ini +description=Record with I64 field type and arithmetic operation +type=snippet +~~~ +# SOURCE +~~~roc +Robot : { x : I64, y : I64 } + +advance : Robot -> Robot +advance = |robot| { ..robot, y: robot.y + 1 } + +expect advance({ x: 7, y: 3 }) == { x: 7, y: 4 } +~~~ +# EXPECTED +NIL +# PROBLEMS +NIL +# TOKENS +~~~zig +UpperIdent,OpColon,OpenCurly,LowerIdent,OpColon,UpperIdent,Comma,LowerIdent,OpColon,UpperIdent,CloseCurly, +LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent, +LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,DoubleDot,LowerIdent,Comma,LowerIdent,OpColon,LowerIdent,NoSpaceDotLowerIdent,OpPlus,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +EndOfFile, +~~~ +# PARSE +~~~clojure +(file + (type-module) + (statements + (s-type-decl + (header (name "Robot") + (args)) + (ty-record + (anno-record-field (name "x") + (ty (name "I64"))) + (anno-record-field (name "y") + (ty (name "I64"))))) + (s-type-anno (name "advance") + (ty-fn + (ty (name "Robot")) + (ty (name "Robot")))) + (s-decl + (p-ident (raw "advance")) + (e-lambda + (args + (p-ident (raw "robot"))) + (e-record + (ext + (e-ident (raw "robot"))) + (field (field "y") + (e-binop (op "+") + (e-field-access + (e-ident (raw "robot")) + (e-ident (raw "y"))) + (e-int (raw "1"))))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "advance")) + (e-record + (field (field "x") + (e-int (raw "7"))) + (field (field "y") + (e-int (raw "3"))))) + (e-record + (field (field "x") + (e-int (raw "7"))) + (field (field "y") + (e-int (raw "4")))))))) +~~~ +# FORMATTED +~~~roc +NO CHANGE +~~~ +# CANONICALIZE +~~~clojure +(can-ir + (d-let + (p-assign (ident "advance")) + (e-lambda + (args + (p-assign (ident "robot"))) + (e-record + (ext + (e-lookup-local + (p-assign (ident "robot")))) + (fields + (field (name "y") + (e-binop (op "add") + (e-dot-access (field "y") + (receiver + (e-lookup-local + (p-assign (ident "robot"))))) + (e-num (value "1"))))))) + (annotation + (ty-fn (effectful false) + (ty-lookup (name "Robot") (local)) + (ty-lookup (name "Robot") (local))))) + (s-alias-decl + (ty-header (name "Robot")) + (ty-record + (field (field "x") + (ty-lookup (name "I64") (builtin))) + (field (field "y") + (ty-lookup (name "I64") (builtin))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "advance"))) + (e-record + (fields + (field (name "x") + (e-num (value "7"))) + (field (name "y") + (e-num (value "3")))))) + (e-record + (fields + (field (name "x") + (e-num (value "7"))) + (field (name "y") + (e-num (value "4")))))))) +~~~ +# TYPES +~~~clojure +(inferred-types + (defs + (patt (type "Robot -> Robot"))) + (type_decls + (alias (type "Robot") + (ty-header (name "Robot")))) + (expressions + (expr (type "Robot -> Robot")))) +~~~ diff --git a/test/snapshots/eval/record_i64_field_update.md b/test/snapshots/eval/record_i64_field_update.md new file mode 100644 index 0000000000..28c4774f21 --- /dev/null +++ b/test/snapshots/eval/record_i64_field_update.md @@ -0,0 +1,253 @@ +# META +~~~ini +description=Record update with I64 field type and arithmetic +type=snippet +~~~ +# SOURCE +~~~roc +Robot : { x : I64, y : I64 } + +advance : Robot -> Robot +advance = |robot| { ..robot, y: robot.y + 1 } + +retreat : Robot -> Robot +retreat = |robot| { ..robot, y: robot.y - 1 } + +expect advance({ x: 7, y: 3 }) == { x: 7, y: 4 } +expect retreat({ x: 7, y: 3 }) == { x: 7, y: 2 } +expect advance(retreat({ x: 0, y: 0 })) == { x: 0, y: 0 } +~~~ +# EXPECTED +NIL +# PROBLEMS +NIL +# TOKENS +~~~zig +UpperIdent,OpColon,OpenCurly,LowerIdent,OpColon,UpperIdent,Comma,LowerIdent,OpColon,UpperIdent,CloseCurly, +LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent, +LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,DoubleDot,LowerIdent,Comma,LowerIdent,OpColon,LowerIdent,NoSpaceDotLowerIdent,OpPlus,Int,CloseCurly, +LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent, +LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,DoubleDot,LowerIdent,Comma,LowerIdent,OpColon,LowerIdent,NoSpaceDotLowerIdent,OpBinaryMinus,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +EndOfFile, +~~~ +# PARSE +~~~clojure +(file + (type-module) + (statements + (s-type-decl + (header (name "Robot") + (args)) + (ty-record + (anno-record-field (name "x") + (ty (name "I64"))) + (anno-record-field (name "y") + (ty (name "I64"))))) + (s-type-anno (name "advance") + (ty-fn + (ty (name "Robot")) + (ty (name "Robot")))) + (s-decl + (p-ident (raw "advance")) + (e-lambda + (args + (p-ident (raw "robot"))) + (e-record + (ext + (e-ident (raw "robot"))) + (field (field "y") + (e-binop (op "+") + (e-field-access + (e-ident (raw "robot")) + (e-ident (raw "y"))) + (e-int (raw "1"))))))) + (s-type-anno (name "retreat") + (ty-fn + (ty (name "Robot")) + (ty (name "Robot")))) + (s-decl + (p-ident (raw "retreat")) + (e-lambda + (args + (p-ident (raw "robot"))) + (e-record + (ext + (e-ident (raw "robot"))) + (field (field "y") + (e-binop (op "-") + (e-field-access + (e-ident (raw "robot")) + (e-ident (raw "y"))) + (e-int (raw "1"))))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "advance")) + (e-record + (field (field "x") + (e-int (raw "7"))) + (field (field "y") + (e-int (raw "3"))))) + (e-record + (field (field "x") + (e-int (raw "7"))) + (field (field "y") + (e-int (raw "4")))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "retreat")) + (e-record + (field (field "x") + (e-int (raw "7"))) + (field (field "y") + (e-int (raw "3"))))) + (e-record + (field (field "x") + (e-int (raw "7"))) + (field (field "y") + (e-int (raw "2")))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "advance")) + (e-apply + (e-ident (raw "retreat")) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "0")))))) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "0")))))))) +~~~ +# FORMATTED +~~~roc +NO CHANGE +~~~ +# CANONICALIZE +~~~clojure +(can-ir + (d-let + (p-assign (ident "advance")) + (e-lambda + (args + (p-assign (ident "robot"))) + (e-record + (ext + (e-lookup-local + (p-assign (ident "robot")))) + (fields + (field (name "y") + (e-binop (op "add") + (e-dot-access (field "y") + (receiver + (e-lookup-local + (p-assign (ident "robot"))))) + (e-num (value "1"))))))) + (annotation + (ty-fn (effectful false) + (ty-lookup (name "Robot") (local)) + (ty-lookup (name "Robot") (local))))) + (d-let + (p-assign (ident "retreat")) + (e-lambda + (args + (p-assign (ident "robot"))) + (e-record + (ext + (e-lookup-local + (p-assign (ident "robot")))) + (fields + (field (name "y") + (e-binop (op "sub") + (e-dot-access (field "y") + (receiver + (e-lookup-local + (p-assign (ident "robot"))))) + (e-num (value "1"))))))) + (annotation + (ty-fn (effectful false) + (ty-lookup (name "Robot") (local)) + (ty-lookup (name "Robot") (local))))) + (s-alias-decl + (ty-header (name "Robot")) + (ty-record + (field (field "x") + (ty-lookup (name "I64") (builtin))) + (field (field "y") + (ty-lookup (name "I64") (builtin))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "advance"))) + (e-record + (fields + (field (name "x") + (e-num (value "7"))) + (field (name "y") + (e-num (value "3")))))) + (e-record + (fields + (field (name "x") + (e-num (value "7"))) + (field (name "y") + (e-num (value "4"))))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "retreat"))) + (e-record + (fields + (field (name "x") + (e-num (value "7"))) + (field (name "y") + (e-num (value "3")))))) + (e-record + (fields + (field (name "x") + (e-num (value "7"))) + (field (name "y") + (e-num (value "2"))))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "advance"))) + (e-call + (e-lookup-local + (p-assign (ident "retreat"))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "0"))))))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "0")))))))) +~~~ +# TYPES +~~~clojure +(inferred-types + (defs + (patt (type "Robot -> Robot")) + (patt (type "Robot -> Robot"))) + (type_decls + (alias (type "Robot") + (ty-header (name "Robot")))) + (expressions + (expr (type "Robot -> Robot")) + (expr (type "Robot -> Robot")))) +~~~ diff --git a/test/snapshots/eval/robot_simulator_i64.md b/test/snapshots/eval/robot_simulator_i64.md new file mode 100644 index 0000000000..d49cef6991 --- /dev/null +++ b/test/snapshots/eval/robot_simulator_i64.md @@ -0,0 +1,411 @@ +# META +~~~ini +description=Robot simulator with I64 coordinates and record updates +type=snippet +~~~ +# SOURCE +~~~roc +Robot : { x : I64, y : I64 } + +advance_y : Robot -> Robot +advance_y = |robot| { ..robot, y: robot.y + 1 } + +retreat_y : Robot -> Robot +retreat_y = |robot| { ..robot, y: robot.y - 1 } + +advance_x : Robot -> Robot +advance_x = |robot| { ..robot, x: robot.x + 1 } + +retreat_x : Robot -> Robot +retreat_x = |robot| { ..robot, x: robot.x - 1 } + +expect advance_y({ x: 0, y: 0 }) == { x: 0, y: 1 } +expect retreat_y({ x: 0, y: 0 }) == { x: 0, y: -1 } +expect advance_x({ x: 0, y: 0 }) == { x: 1, y: 0 } +expect retreat_x({ x: 0, y: 0 }) == { x: -1, y: 0 } +expect advance_y(retreat_y({ x: 5, y: 5 })) == { x: 5, y: 5 } +~~~ +# EXPECTED +NIL +# PROBLEMS +NIL +# TOKENS +~~~zig +UpperIdent,OpColon,OpenCurly,LowerIdent,OpColon,UpperIdent,Comma,LowerIdent,OpColon,UpperIdent,CloseCurly, +LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent, +LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,DoubleDot,LowerIdent,Comma,LowerIdent,OpColon,LowerIdent,NoSpaceDotLowerIdent,OpPlus,Int,CloseCurly, +LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent, +LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,DoubleDot,LowerIdent,Comma,LowerIdent,OpColon,LowerIdent,NoSpaceDotLowerIdent,OpBinaryMinus,Int,CloseCurly, +LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent, +LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,DoubleDot,LowerIdent,Comma,LowerIdent,OpColon,LowerIdent,NoSpaceDotLowerIdent,OpPlus,Int,CloseCurly, +LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent, +LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,DoubleDot,LowerIdent,Comma,LowerIdent,OpColon,LowerIdent,NoSpaceDotLowerIdent,OpBinaryMinus,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +KwExpect,LowerIdent,NoSpaceOpenRound,LowerIdent,NoSpaceOpenRound,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly,CloseRound,CloseRound,OpEquals,OpenCurly,LowerIdent,OpColon,Int,Comma,LowerIdent,OpColon,Int,CloseCurly, +EndOfFile, +~~~ +# PARSE +~~~clojure +(file + (type-module) + (statements + (s-type-decl + (header (name "Robot") + (args)) + (ty-record + (anno-record-field (name "x") + (ty (name "I64"))) + (anno-record-field (name "y") + (ty (name "I64"))))) + (s-type-anno (name "advance_y") + (ty-fn + (ty (name "Robot")) + (ty (name "Robot")))) + (s-decl + (p-ident (raw "advance_y")) + (e-lambda + (args + (p-ident (raw "robot"))) + (e-record + (ext + (e-ident (raw "robot"))) + (field (field "y") + (e-binop (op "+") + (e-field-access + (e-ident (raw "robot")) + (e-ident (raw "y"))) + (e-int (raw "1"))))))) + (s-type-anno (name "retreat_y") + (ty-fn + (ty (name "Robot")) + (ty (name "Robot")))) + (s-decl + (p-ident (raw "retreat_y")) + (e-lambda + (args + (p-ident (raw "robot"))) + (e-record + (ext + (e-ident (raw "robot"))) + (field (field "y") + (e-binop (op "-") + (e-field-access + (e-ident (raw "robot")) + (e-ident (raw "y"))) + (e-int (raw "1"))))))) + (s-type-anno (name "advance_x") + (ty-fn + (ty (name "Robot")) + (ty (name "Robot")))) + (s-decl + (p-ident (raw "advance_x")) + (e-lambda + (args + (p-ident (raw "robot"))) + (e-record + (ext + (e-ident (raw "robot"))) + (field (field "x") + (e-binop (op "+") + (e-field-access + (e-ident (raw "robot")) + (e-ident (raw "x"))) + (e-int (raw "1"))))))) + (s-type-anno (name "retreat_x") + (ty-fn + (ty (name "Robot")) + (ty (name "Robot")))) + (s-decl + (p-ident (raw "retreat_x")) + (e-lambda + (args + (p-ident (raw "robot"))) + (e-record + (ext + (e-ident (raw "robot"))) + (field (field "x") + (e-binop (op "-") + (e-field-access + (e-ident (raw "robot")) + (e-ident (raw "x"))) + (e-int (raw "1"))))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "advance_y")) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "0"))))) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "1")))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "retreat_y")) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "0"))))) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "-1")))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "advance_x")) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "0"))))) + (e-record + (field (field "x") + (e-int (raw "1"))) + (field (field "y") + (e-int (raw "0")))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "retreat_x")) + (e-record + (field (field "x") + (e-int (raw "0"))) + (field (field "y") + (e-int (raw "0"))))) + (e-record + (field (field "x") + (e-int (raw "-1"))) + (field (field "y") + (e-int (raw "0")))))) + (s-expect + (e-binop (op "==") + (e-apply + (e-ident (raw "advance_y")) + (e-apply + (e-ident (raw "retreat_y")) + (e-record + (field (field "x") + (e-int (raw "5"))) + (field (field "y") + (e-int (raw "5")))))) + (e-record + (field (field "x") + (e-int (raw "5"))) + (field (field "y") + (e-int (raw "5")))))))) +~~~ +# FORMATTED +~~~roc +NO CHANGE +~~~ +# CANONICALIZE +~~~clojure +(can-ir + (d-let + (p-assign (ident "advance_y")) + (e-lambda + (args + (p-assign (ident "robot"))) + (e-record + (ext + (e-lookup-local + (p-assign (ident "robot")))) + (fields + (field (name "y") + (e-binop (op "add") + (e-dot-access (field "y") + (receiver + (e-lookup-local + (p-assign (ident "robot"))))) + (e-num (value "1"))))))) + (annotation + (ty-fn (effectful false) + (ty-lookup (name "Robot") (local)) + (ty-lookup (name "Robot") (local))))) + (d-let + (p-assign (ident "retreat_y")) + (e-lambda + (args + (p-assign (ident "robot"))) + (e-record + (ext + (e-lookup-local + (p-assign (ident "robot")))) + (fields + (field (name "y") + (e-binop (op "sub") + (e-dot-access (field "y") + (receiver + (e-lookup-local + (p-assign (ident "robot"))))) + (e-num (value "1"))))))) + (annotation + (ty-fn (effectful false) + (ty-lookup (name "Robot") (local)) + (ty-lookup (name "Robot") (local))))) + (d-let + (p-assign (ident "advance_x")) + (e-lambda + (args + (p-assign (ident "robot"))) + (e-record + (ext + (e-lookup-local + (p-assign (ident "robot")))) + (fields + (field (name "x") + (e-binop (op "add") + (e-dot-access (field "x") + (receiver + (e-lookup-local + (p-assign (ident "robot"))))) + (e-num (value "1"))))))) + (annotation + (ty-fn (effectful false) + (ty-lookup (name "Robot") (local)) + (ty-lookup (name "Robot") (local))))) + (d-let + (p-assign (ident "retreat_x")) + (e-lambda + (args + (p-assign (ident "robot"))) + (e-record + (ext + (e-lookup-local + (p-assign (ident "robot")))) + (fields + (field (name "x") + (e-binop (op "sub") + (e-dot-access (field "x") + (receiver + (e-lookup-local + (p-assign (ident "robot"))))) + (e-num (value "1"))))))) + (annotation + (ty-fn (effectful false) + (ty-lookup (name "Robot") (local)) + (ty-lookup (name "Robot") (local))))) + (s-alias-decl + (ty-header (name "Robot")) + (ty-record + (field (field "x") + (ty-lookup (name "I64") (builtin))) + (field (field "y") + (ty-lookup (name "I64") (builtin))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "advance_y"))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "0")))))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "1"))))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "retreat_y"))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "0")))))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "-1"))))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "advance_x"))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "0")))))) + (e-record + (fields + (field (name "x") + (e-num (value "1"))) + (field (name "y") + (e-num (value "0"))))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "retreat_x"))) + (e-record + (fields + (field (name "x") + (e-num (value "0"))) + (field (name "y") + (e-num (value "0")))))) + (e-record + (fields + (field (name "x") + (e-num (value "-1"))) + (field (name "y") + (e-num (value "0"))))))) + (s-expect + (e-binop (op "eq") + (e-call + (e-lookup-local + (p-assign (ident "advance_y"))) + (e-call + (e-lookup-local + (p-assign (ident "retreat_y"))) + (e-record + (fields + (field (name "x") + (e-num (value "5"))) + (field (name "y") + (e-num (value "5"))))))) + (e-record + (fields + (field (name "x") + (e-num (value "5"))) + (field (name "y") + (e-num (value "5")))))))) +~~~ +# TYPES +~~~clojure +(inferred-types + (defs + (patt (type "Robot -> Robot")) + (patt (type "Robot -> Robot")) + (patt (type "Robot -> Robot")) + (patt (type "Robot -> Robot"))) + (type_decls + (alias (type "Robot") + (ty-header (name "Robot")))) + (expressions + (expr (type "Robot -> Robot")) + (expr (type "Robot -> Robot")) + (expr (type "Robot -> Robot")) + (expr (type "Robot -> Robot")))) +~~~ diff --git a/test/snapshots/eval/str_to_utf8_method.md b/test/snapshots/eval/str_to_utf8_method.md new file mode 100644 index 0000000000..e7ebace097 --- /dev/null +++ b/test/snapshots/eval/str_to_utf8_method.md @@ -0,0 +1,86 @@ +# META +~~~ini +description=Test str.to_utf8() method call syntax +type=snippet +~~~ +# SOURCE +~~~roc +bytes : List(U8) +bytes = "hello".to_utf8() + +expect bytes == [104, 101, 108, 108, 111] +~~~ +# EXPECTED +NIL +# PROBLEMS +NIL +# TOKENS +~~~zig +LowerIdent,OpColon,UpperIdent,NoSpaceOpenRound,UpperIdent,CloseRound, +LowerIdent,OpAssign,StringStart,StringPart,StringEnd,NoSpaceDotLowerIdent,NoSpaceOpenRound,CloseRound, +KwExpect,LowerIdent,OpEquals,OpenSquare,Int,Comma,Int,Comma,Int,Comma,Int,Comma,Int,CloseSquare, +EndOfFile, +~~~ +# PARSE +~~~clojure +(file + (type-module) + (statements + (s-type-anno (name "bytes") + (ty-apply + (ty (name "List")) + (ty (name "U8")))) + (s-decl + (p-ident (raw "bytes")) + (e-field-access + (e-string + (e-string-part (raw "hello"))) + (e-apply + (e-ident (raw "to_utf8"))))) + (s-expect + (e-binop (op "==") + (e-ident (raw "bytes")) + (e-list + (e-int (raw "104")) + (e-int (raw "101")) + (e-int (raw "108")) + (e-int (raw "108")) + (e-int (raw "111"))))))) +~~~ +# FORMATTED +~~~roc +NO CHANGE +~~~ +# CANONICALIZE +~~~clojure +(can-ir + (d-let + (p-assign (ident "bytes")) + (e-dot-access (field "to_utf8") + (receiver + (e-string + (e-literal (string "hello")))) + (args)) + (annotation + (ty-apply (name "List") (builtin) + (ty-lookup (name "U8") (builtin))))) + (s-expect + (e-binop (op "eq") + (e-lookup-local + (p-assign (ident "bytes"))) + (e-list + (elems + (e-num (value "104")) + (e-num (value "101")) + (e-num (value "108")) + (e-num (value "108")) + (e-num (value "111"))))))) +~~~ +# TYPES +~~~clojure +(inferred-types + (defs + (patt (type "List(U8)"))) + (expressions + (expr (type "List(U8)")))) +~~~