Merge pull request #8359 from roc-lang/list-fns

Builtin List functions
This commit is contained in:
Richard Feldman 2025-11-08 22:46:04 -05:00 committed by GitHub
commit 092cf67728
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 2098 additions and 882 deletions

View file

@ -149,11 +149,18 @@ fn replaceStrIsEmptyWithLowLevel(env: *ModuleEnv) !std.ArrayList(CIR.Def.Idx) {
if (env.common.findIdent("Builtin.Str.is_empty")) |str_is_empty_ident| {
try low_level_map.put(str_is_empty_ident, .str_is_empty);
}
if (env.common.findIdent("Builtin.List.len")) |list_len_ident| {
try low_level_map.put(list_len_ident, .list_len);
}
if (env.common.findIdent("Builtin.List.is_empty")) |list_is_empty_ident| {
try low_level_map.put(list_is_empty_ident, .list_is_empty);
}
if (env.common.findIdent("list_get_unsafe")) |list_get_unsafe_ident| {
try low_level_map.put(list_get_unsafe_ident, .list_get_unsafe);
}
if (env.common.findIdent("Builtin.Set.is_empty")) |set_is_empty_ident| {
try low_level_map.put(set_is_empty_ident, .set_is_empty);
}
// Bool operations
if (env.common.findIdent("Builtin.Bool.is_eq")) |bool_is_eq_ident| {
try low_level_map.put(bool_is_eq_ident, .bool_is_eq);
}
@ -637,7 +644,8 @@ fn compileModule(
const box_ident = try module_env.insertIdent(base.Ident.for_text("Box"));
// Use provided bool_stmt and try_stmt if available, otherwise use undefined
const common_idents: Check.CommonIdents = .{
// For Builtin module, these will be found after canonicalization and updated before type checking
var common_idents: Check.CommonIdents = .{
.module_name = module_ident,
.list = list_ident,
.box = box_ident,
@ -668,19 +676,7 @@ fn compileModule(
return error.ParseError;
}
// 4. Create module imports map (for cross-module references)
var module_envs = std.AutoHashMap(base.Ident.Idx, Can.AutoImportedType).init(gpa);
defer module_envs.deinit();
// Add dependencies (e.g., Dict for Set, Bool for Str)
// IMPORTANT: Use the module's own ident store, not a temporary one,
// because auto-import lookups will use the module's ident store
for (deps) |dep| {
const dep_ident = try module_env.insertIdent(base.Ident.for_text(dep.name));
try module_envs.put(dep_ident, .{ .env = dep.env });
}
// 5. Canonicalize
// 4. Canonicalize
try module_env.initCIRFields(gpa, module_name);
var can_result = try gpa.create(Can);
@ -689,7 +685,8 @@ fn compileModule(
gpa.destroy(can_result);
}
can_result.* = try Can.init(module_env, parse_ast, &module_envs);
// When compiling Builtin itself, pass null for module_envs so setupAutoImportedBuiltinTypes doesn't run
can_result.* = try Can.init(module_env, parse_ast, null);
try can_result.canonicalizeFile();
try can_result.validateForChecking();
@ -705,6 +702,10 @@ fn compileModule(
const type_name = module_env.getIdentText(d.name);
std.debug.print(" - Undeclared type: {s}\n", .{type_name});
},
.ident_not_in_scope => |d| {
const ident_name = module_env.getIdentText(d.ident);
std.debug.print(" - Ident not in scope: {s}\n", .{ident_name});
},
.nested_value_not_found => |d| {
const parent = module_env.getIdentText(d.parent_name);
const nested = module_env.getIdentText(d.nested_name);
@ -770,6 +771,22 @@ fn compileModule(
eval_order_ptr.* = eval_order;
module_env.evaluation_order = eval_order_ptr;
}
// Find Bool and Try statements before type checking
// When compiling Builtin, bool_stmt and try_stmt are initially undefined,
// but they must be set before type checking begins
const found_bool_stmt = findTypeDeclaration(module_env, "Bool") catch {
std.debug.print("Error: Could not find Bool type in Builtin module\n", .{});
return error.TypeDeclarationNotFound;
};
const found_try_stmt = findTypeDeclaration(module_env, "Try") catch {
std.debug.print("Error: Could not find Try type in Builtin module\n", .{});
return error.TypeDeclarationNotFound;
};
// Update common_idents with the found statement indices
common_idents.bool_stmt = found_bool_stmt;
common_idents.try_stmt = found_try_stmt;
}
// 6. Type check
@ -782,6 +799,9 @@ fn compileModule(
try imported_envs.append(gpa, dep.env);
}
var module_envs = std.AutoHashMap(base.Ident.Idx, Can.AutoImportedType).init(gpa);
defer module_envs.deinit();
var checker = try Check.init(
gpa,
&module_env.types,

View file

@ -7,14 +7,18 @@ Builtin := [].{
}
List := [ProvidedByCompiler].{
len : List(a) -> U64
len = |_| 0
len : List(_elem) -> U64
is_empty : List(_elem) -> Bool
is_empty : List(a) -> Bool
is_empty = |_| True
first : List(elem) -> Try(elem, [ListWasEmpty])
first = |list| List.get(list, 0)
first : List(a) -> Try(a, [ListWasEmpty])
first = |_| Err(ListWasEmpty)
get : List(elem), U64 -> Try(elem, [ListWasEmpty])
get = |list, index| if index < List.len(list) {
Try.Ok(list_get_unsafe(list, index))
} else {
Try.Err(ListWasEmpty)
}
map : List(a), (a -> b) -> List(b)
map = |_, _| []
@ -335,3 +339,7 @@ Builtin := [].{
}
}
}
# Private top-level function for unsafe list access
# This is a low-level operation that gets replaced by the compiler
list_get_unsafe : List(elem), U64 -> elem

View file

@ -375,6 +375,28 @@ pub fn listIncref(list: RocList, amount: isize, elements_refcounted: bool) callc
list.incref(amount, elements_refcounted);
}
/// Get the number of elements in the list.
pub fn listLen(list: RocList) callconv(.c) usize {
return list.len();
}
/// Check if the list is empty.
pub fn listIsEmpty(list: RocList) callconv(.c) bool {
return list.isEmpty();
}
/// Get a pointer to an element at the given index without bounds checking.
/// UNSAFE: No bounds checking is performed. Index must be < list.len().
/// This is intended for internal use by low-level operations only.
/// Returns a pointer to the element at the given index.
pub fn listGetUnsafe(list: RocList, index: u64, element_width: usize) callconv(.c) ?[*]u8 {
if (list.bytes) |bytes| {
const byte_offset = @as(usize, @intCast(index)) * element_width;
return bytes + byte_offset;
}
return null;
}
/// Decrement reference count and deallocate when no longer shared.
pub fn listDecref(
list: RocList,

File diff suppressed because it is too large Load diff

View file

@ -387,6 +387,11 @@ pub const Expr = union(enum) {
// String operations
str_is_empty,
// List operations
list_len,
list_is_empty,
list_get_unsafe,
// Set operations
set_is_empty,

View file

@ -1587,9 +1587,12 @@ pub const Serialized = struct {
// Overwrite ourself with the deserialized version, and return our pointer after casting it to Self.
const env = @as(*Self, @ptrFromInt(@intFromPtr(self)));
// Deserialize common env first so we can look up identifiers
const common = self.common.deserialize(offset, source).*;
env.* = Self{
.gpa = gpa,
.common = self.common.deserialize(offset, source).*,
.common = common,
.types = self.types.deserialize(offset, gpa).*,
.module_kind = self.module_kind,
.all_defs = self.all_defs,
@ -1604,11 +1607,11 @@ pub const Serialized = struct {
.store = self.store.deserialize(offset, gpa).*,
.evaluation_order = null, // Not serialized, will be recomputed if needed
// Well-known identifiers for type checking - look them up in the deserialized common env
.from_int_digits_ident = env.common.findIdent(Ident.FROM_INT_DIGITS_METHOD_NAME) orelse unreachable,
.from_dec_digits_ident = env.common.findIdent(Ident.FROM_DEC_DIGITS_METHOD_NAME) orelse unreachable,
.try_ident = env.common.findIdent("Try") orelse unreachable,
.out_of_range_ident = env.common.findIdent("OutOfRange") orelse unreachable,
.builtin_module_ident = env.common.findIdent("Builtin") orelse unreachable,
.from_int_digits_ident = common.findIdent(Ident.FROM_INT_DIGITS_METHOD_NAME) orelse unreachable,
.from_dec_digits_ident = common.findIdent(Ident.FROM_DEC_DIGITS_METHOD_NAME) orelse unreachable,
.try_ident = common.findIdent("Try") orelse unreachable,
.out_of_range_ident = common.findIdent("OutOfRange") orelse unreachable,
.builtin_module_ident = common.findIdent("Builtin") orelse unreachable,
};
return env;

View file

@ -339,15 +339,15 @@ test "exposed_items is populated correctly" {
.canonicalizeFile();
// Check that exposed_items contains the correct number of items
// The exposed items were added during canonicalization
// Should have exactly 3 entries (duplicates not stored)
try testing.expectEqual(@as(usize, 3), env.common.exposed_items.count());
// Check that exposed_items contains all exposed items
// Should have exactly 2 value entries (duplicates not stored, types not included)
// Types are not stored in exposed_items - they are handled by the type system
try testing.expectEqual(@as(usize, 2), env.common.exposed_items.count());
// Check that exposed_items contains all exposed values (not types)
const foo_idx = env.common.idents.findByString("foo").?;
const bar_idx = env.common.idents.findByString("bar").?;
const mytype_idx = env.common.idents.findByString("MyType").?;
try testing.expect(env.common.exposed_items.containsById(env.gpa, @bitCast(foo_idx)));
try testing.expect(env.common.exposed_items.containsById(env.gpa, @bitCast(bar_idx)));
try testing.expect(env.common.exposed_items.containsById(env.gpa, @bitCast(mytype_idx)));
// MyType is not in exposed_items because it's a type, not a value
}
test "exposed_items persists after canonicalization" {

View file

@ -591,7 +591,7 @@ fn updateVar(self: *Self, target_var: Var, content: types_mod.Content, rank: typ
// file //
/// Check the types for all defs
/// Copy builtin types (Bool, Result) from their modules into the current module's type store
/// Copy builtin types from their modules into the current module's type store
/// This is necessary because type variables are module-specific - we can't use Vars from
/// other modules directly. The Bool and Result types are used in language constructs like
/// `if` conditions and need to be available in every module's type store.
@ -618,9 +618,6 @@ pub fn checkFile(self: *Self) std.mem.Allocator.Error!void {
try ensureTypeStoreIsFilled(self);
// Copy builtin types (Bool, Result) into this module's type store
try self.copyBuiltinTypes();
// First, iterate over the builtin statements, generating types for each type declaration
const builtin_stmts_slice = self.cir.store.sliceStatements(self.cir.builtin_statements);
for (builtin_stmts_slice) |builtin_stmt_idx| {
@ -638,6 +635,11 @@ pub fn checkFile(self: *Self) std.mem.Allocator.Error!void {
try self.generateStmtTypeDeclType(stmt_idx);
}
// Copy builtin types into this module's type store
// This must happen AFTER type declarations are generated so that when compiling
// Builtin itself, the Bool and Try types have already been created
try self.copyBuiltinTypes();
// First pass: assign placeholder type vars
const defs_slice = self.cir.store.sliceDefs(self.cir.all_defs);
for (defs_slice) |def_idx| {
@ -689,7 +691,7 @@ pub fn checkFile(self: *Self) std.mem.Allocator.Error!void {
pub fn checkExprRepl(self: *Self, expr_idx: CIR.Expr.Idx) std.mem.Allocator.Error!void {
try ensureTypeStoreIsFilled(self);
// Copy builtin types (Bool, Result) into this module's type store
// Copy builtin types into this module's type store
try self.copyBuiltinTypes();
// First, iterate over the statements, generating types for each type declaration
@ -948,7 +950,7 @@ fn generateAnnotationType(self: *Self, annotation_idx: CIR.Annotation.Idx) std.m
try self.generateAnnoTypeInPlace(annotation.anno, .annotation);
// Redirect the root annotation to inner annotation
_ = try self.types.setVarRedirect(ModuleEnv.varFrom(annotation_idx), ModuleEnv.varFrom(annotation.anno));
try self.types.setVarRedirect(ModuleEnv.varFrom(annotation_idx), ModuleEnv.varFrom(annotation.anno));
}
/// Given a where clause, generate static dispatch constraints and add to scratch_static_dispatch_constraints
@ -2453,9 +2455,9 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, rank: types_mod.Rank, expected
// We never instantiate rigid variables
if (resolved_pat.rank == Rank.generalized and resolved_pat.content != .rigid) {
const instantiated = try self.instantiateVar(pat_var, rank, .use_last_var);
_ = try self.types.setVarRedirect(expr_var, instantiated);
try self.types.setVarRedirect(expr_var, instantiated);
} else {
_ = try self.types.setVarRedirect(expr_var, pat_var);
try self.types.setVarRedirect(expr_var, pat_var);
}
// Unify this expression with the referenced pattern
@ -2647,7 +2649,7 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, rank: types_mod.Rank, expected
},
.e_closure => |closure| {
does_fx = try self.checkExpr(closure.lambda_idx, rank, expected) or does_fx;
_ = try self.types.setVarRedirect(expr_var, ModuleEnv.varFrom(closure.lambda_idx));
try self.types.setVarRedirect(expr_var, ModuleEnv.varFrom(closure.lambda_idx));
},
// function calling //
.e_call => |call| {
@ -2796,7 +2798,7 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, rank: types_mod.Rank, expected
}
// Redirect the expr to the function's return type
_ = try self.types.setVarRedirect(expr_var, func.ret);
try self.types.setVarRedirect(expr_var, func.ret);
} else {
// TODO(jared): Better arity difference error message
@ -2813,7 +2815,7 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, rank: types_mod.Rank, expected
try self.var_pool.addVarToRank(call_func_var, rank);
_ = try self.unify(func_var, call_func_var, rank);
_ = try self.types.setVarRedirect(expr_var, call_func_ret);
try self.types.setVarRedirect(expr_var, call_func_ret);
}
} else {
// We get here if the type of expr being called
@ -2841,7 +2843,7 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, rank: types_mod.Rank, expected
// Then, we set the root expr to redirect to the return
// type of that function, since a call expr ultimate
// resolve to the returned type
_ = try self.types.setVarRedirect(expr_var, call_func_ret);
try self.types.setVarRedirect(expr_var, call_func_ret);
}
}
},
@ -2966,7 +2968,7 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, rank: types_mod.Rank, expected
},
.e_dbg => |dbg| {
does_fx = try self.checkExpr(dbg.expr, rank, expected) or does_fx;
_ = try self.types.setVarRedirect(expr_var, ModuleEnv.varFrom(dbg.expr));
try self.types.setVarRedirect(expr_var, ModuleEnv.varFrom(dbg.expr));
},
.e_expect => |expect| {
does_fx = try self.checkExpr(expect.body, rank, expected) or does_fx;
@ -2979,14 +2981,14 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, rank: types_mod.Rank, expected
// For annotation-only expressions, the type comes from the annotation.
// This case should only occur when the expression has an annotation (which is
// enforced during canonicalization), so the expected type should be set.
// The type will be unified with the expected type in the code below.
switch (expected) {
.no_expectation => {
// This shouldn't happen since we always create e_anno_only with an annotation
try self.updateVar(expr_var, .err, rank);
},
.expected => {
// The expr_var will be unified with the annotation var below
.expected => |expected_type| {
// Redirect expr_var to the annotation var so that lookups get the correct type
try self.types.setVarRedirect(expr_var, expected_type.var_);
},
}
},

View file

@ -40,4 +40,5 @@ test "check tests" {
std.testing.refAllDecls(@import("test/let_polymorphism_integration_test.zig"));
std.testing.refAllDecls(@import("test/num_type_inference_test.zig"));
std.testing.refAllDecls(@import("test/num_type_requirements_test.zig"));
std.testing.refAllDecls(@import("test/builtin_scope_test.zig"));
}

View file

@ -215,21 +215,21 @@ pub fn initWithImport(module_name: []const u8, source: []const u8, other_module_
.builtin_module = other_test_env.builtin_module.env,
};
// Build imported_envs array dynamically based on module_env.imports order
// This matches the production approach in compile_package.zig
const import_count = module_env.imports.imports.items.items.len;
var imported_envs = try std.ArrayList(*const ModuleEnv).initCapacity(gpa, import_count);
// Build imported_envs array
// Always include the builtin module for auto-imported types (Bool, Str, etc.)
var imported_envs = try std.ArrayList(*const ModuleEnv).initCapacity(gpa, 2);
defer imported_envs.deinit(gpa);
// Add builtin module unconditionally (needed for auto-imported types)
try imported_envs.append(gpa, other_test_env.builtin_module.env);
// Process explicit imports
const import_count = module_env.imports.imports.items.items.len;
for (module_env.imports.imports.items.items[0..import_count]) |str_idx| {
const import_name = module_env.getString(str_idx);
if (std.mem.eql(u8, import_name, "Builtin")) {
try imported_envs.append(gpa, other_test_env.builtin_module.env);
} else if (std.mem.eql(u8, import_name, other_module_name)) {
if (std.mem.eql(u8, import_name, other_module_name)) {
// Cross-module import - append the other test module's env
try imported_envs.append(gpa, other_test_env.module_env);
} else {
std.debug.print("WARNING: Unknown import in test: {s}\n", .{import_name});
}
}
@ -331,22 +331,13 @@ pub fn init(module_name: []const u8, source: []const u8) !TestEnv {
.builtin_module = builtin_module.env,
};
// Build imported_envs array dynamically based on module_env.imports order
// This matches the production approach in compile_package.zig
const import_count = module_env.imports.imports.items.items.len;
var imported_envs = try std.ArrayList(*const ModuleEnv).initCapacity(gpa, import_count);
// Build imported_envs array
// Always include the builtin module for auto-imported types (Bool, Str, etc.)
var imported_envs = try std.ArrayList(*const ModuleEnv).initCapacity(gpa, 2);
defer imported_envs.deinit(gpa);
for (module_env.imports.imports.items.items[0..import_count]) |str_idx| {
const import_name = module_env.getString(str_idx);
// For tests, all imports are to the Builtin module
if (std.mem.eql(u8, import_name, "Builtin")) {
try imported_envs.append(gpa, builtin_module.env);
} else {
// If there are other imports in the future, handle them here
std.debug.print("WARNING: Unknown import in test: {s}\n", .{import_name});
}
}
// Add builtin module unconditionally (needed for auto-imported types)
try imported_envs.append(gpa, builtin_module.env);
// Type Check - Pass the imported modules in other_modules parameter
var checker = try Check.init(

View file

@ -0,0 +1,98 @@
//! Tests verifying that "Builtin" is not in scope and cannot be imported,
//! but that nested types like Str, List, etc. are available.
const TestEnv = @import("./TestEnv.zig");
const testing = @import("std").testing;
const std = @import("std");
test "cannot import Builtin module" {
const src =
\\import Builtin
\\
\\x = 5
;
var test_env = try TestEnv.init("Test", src);
defer test_env.deinit();
// Should have a canonicalization problem because Builtin is not a module that can be imported
const diagnostics = try test_env.module_env.getDiagnostics();
defer test_env.module_env.gpa.free(diagnostics);
// Expect at least one diagnostic (module not found error)
try testing.expect(diagnostics.len > 0);
}
test "can define userspace type named Builtin" {
const src =
\\Test := [A, B, C]
\\
\\Builtin := [D, E, F]
\\
\\x : Builtin
\\x = D
;
var test_env = try TestEnv.init("Test", src);
defer test_env.deinit();
// Should have no problems - Builtin is a valid userspace name
try test_env.assertDefType("x", "Builtin");
}
test "builtin types are still available without import" {
const src =
\\Test := [Whatever]
\\
\\x : Str
\\x = "hello"
\\
\\y : List(U64)
\\y = [1, 2, 3]
;
var test_env = try TestEnv.init("Test", src);
defer test_env.deinit();
// Builtin types like Str and List should work without importing Builtin
try test_env.assertDefType("x", "Str");
try test_env.assertDefType("y", "List(Num(Int(Unsigned64)))");
}
test "can import userspace Builtin module" {
const builtin_module_src =
\\Builtin := [D, E, F]
\\
\\value : Builtin
\\value = D
;
var builtin_module = try TestEnv.init("Builtin", builtin_module_src);
defer builtin_module.deinit();
const main_src =
\\Main := [Whatever]
\\
\\import Builtin
\\
\\x : Builtin
\\x = Builtin.value
;
var main_module = try TestEnv.initWithImport("Main", main_src, "Builtin", &builtin_module);
defer main_module.deinit();
// Should successfully import the userspace Builtin module without "module not found" error
const diagnostics = try main_module.module_env.getDiagnostics();
defer main_module.module_env.gpa.free(diagnostics);
// Check that there's no "module not found" error for "Builtin"
for (diagnostics) |diag| {
if (diag == .module_not_found) {
const module_name = main_module.module_env.getIdent(diag.module_not_found.module_name);
if (std.mem.eql(u8, module_name, "Builtin")) {
try testing.expect(false); // Should not have module_not_found for Builtin
}
}
}
}

View file

@ -2109,16 +2109,97 @@ pub const Interpreter = struct {
switch (op) {
.str_is_empty => {
// Str.is_empty : Str -> Bool
if (args.len != 1) return error.TypeMismatch;
std.debug.assert(args.len == 1); // low-level .str_is_empty expects 1 argument
const str_arg = args[0];
if (str_arg.ptr == null) return error.TypeMismatch;
std.debug.assert(str_arg.ptr != null); // low-level .str_is_empty expects non-null string pointer
const roc_str: *const RocStr = @ptrCast(@alignCast(str_arg.ptr.?));
const result = builtins.str.isEmpty(roc_str.*);
return try self.makeSimpleBoolValue(result);
},
.list_len => {
// List.len : List(a) -> U64
// Note: listLen returns usize, but List.len always returns U64.
// We need to cast usize -> u64 for 32-bit targets (e.g. wasm32).
std.debug.assert(args.len == 1); // low-level .list_len expects 1 argument
const list_arg = args[0];
std.debug.assert(list_arg.ptr != null); // low-level .list_len expects non-null list pointer
const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(list_arg.ptr.?));
const len_usize = builtins.list.listLen(roc_list.*);
const len_u64: u64 = @intCast(len_usize);
const result_layout = layout.Layout.int(.u64);
var out = try self.pushRaw(result_layout, 0);
out.is_initialized = false;
out.setInt(@intCast(len_u64));
out.is_initialized = true;
return out;
},
.list_is_empty => {
// List.is_empty : List(a) -> Bool
std.debug.assert(args.len == 1); // low-level .list_is_empty expects 1 argument
const list_arg = args[0];
std.debug.assert(list_arg.ptr != null); // low-level .list_is_empty expects non-null list pointer
const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(list_arg.ptr.?));
const result = builtins.list.listIsEmpty(roc_list.*);
return try self.makeSimpleBoolValue(result);
},
.list_get_unsafe => {
// Internal operation: Get element at index without bounds checking
// Args: List(a), U64 (index)
// Returns: a (the element)
std.debug.assert(args.len == 2); // low-level .list_get_unsafe expects 2 arguments
const list_arg = args[0];
const index_arg = args[1];
std.debug.assert(list_arg.ptr != null); // low-level .list_get_unsafe expects non-null list pointer
// Extract element layout from List(a)
std.debug.assert(list_arg.layout.tag == .list or list_arg.layout.tag == .list_of_zst); // low-level .list_get_unsafe expects list layout
const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(list_arg.ptr.?));
const index = index_arg.asI128(); // U64 stored as i128
// Get element layout
const elem_layout_idx = list_arg.layout.data.list;
const elem_layout = self.runtime_layout_store.getLayout(elem_layout_idx);
const elem_size = self.runtime_layout_store.layoutSize(elem_layout);
if (elem_size == 0) {
// ZST element - return zero-sized value
return StackValue{
.layout = elem_layout,
.ptr = null,
.is_initialized = true,
};
}
// Get pointer to element (no bounds checking!)
const elem_ptr = builtins.list.listGetUnsafe(roc_list.*, @intCast(index), elem_size);
if (elem_ptr == null) {
self.triggerCrash("list_get_unsafe: null pointer returned", false, roc_ops);
return error.Crash;
}
// Create StackValue pointing to the element
const elem_value = StackValue{
.layout = elem_layout,
.ptr = @ptrCast(elem_ptr.?),
.is_initialized = true,
};
// Copy to new location and increment refcount
return try self.pushCopy(elem_value, roc_ops);
},
.set_is_empty => {
// TODO: implement Set.is_empty
self.triggerCrash("Set.is_empty not yet implemented", false, roc_ops);
@ -2128,7 +2209,7 @@ pub const Interpreter = struct {
// Bool operations
.bool_is_eq => {
// Bool.is_eq : Bool, Bool -> Bool
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .bool_is_eq expects 2 arguments
const lhs = args[0].asBool();
const rhs = args[1].asBool();
const result = lhs == rhs;
@ -2136,7 +2217,7 @@ pub const Interpreter = struct {
},
.bool_is_ne => {
// Bool.is_ne : Bool, Bool -> Bool
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .bool_is_ne expects 2 arguments
const lhs = args[0].asBool();
const rhs = args[1].asBool();
const result = lhs != rhs;
@ -2146,7 +2227,7 @@ pub const Interpreter = struct {
// Numeric type checking operations
.num_is_zero => {
// num.is_zero : num -> Bool
if (args.len != 1) return error.TypeMismatch;
std.debug.assert(args.len == 1); // low-level .num_is_zero expects 1 argument
const num_val = try self.extractNumericValue(args[0]);
const result = switch (num_val) {
.int => |i| i == 0,
@ -2158,7 +2239,7 @@ pub const Interpreter = struct {
},
.num_is_negative => {
// num.is_negative : num -> Bool (signed types only)
if (args.len != 1) return error.TypeMismatch;
std.debug.assert(args.len == 1); // low-level .num_is_negative expects 1 argument
const num_val = try self.extractNumericValue(args[0]);
const result = switch (num_val) {
.int => |i| i < 0,
@ -2170,7 +2251,7 @@ pub const Interpreter = struct {
},
.num_is_positive => {
// num.is_positive : num -> Bool (signed types only)
if (args.len != 1) return error.TypeMismatch;
std.debug.assert(args.len == 1); // low-level .num_is_positive expects 1 argument
const num_val = try self.extractNumericValue(args[0]);
const result = switch (num_val) {
.int => |i| i > 0,
@ -2184,7 +2265,7 @@ pub const Interpreter = struct {
// Numeric comparison operations
.num_is_eq => {
// num.is_eq : num, num -> Bool (all integer types + Dec, NOT F32/F64)
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_is_eq expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result = switch (lhs) {
@ -2199,7 +2280,7 @@ pub const Interpreter = struct {
},
.num_is_ne => {
// num.is_ne : num, num -> Bool (Dec only)
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_is_ne expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result = switch (lhs) {
@ -2213,7 +2294,7 @@ pub const Interpreter = struct {
},
.num_is_gt => {
// num.is_gt : num, num -> Bool
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_is_gt expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result = switch (lhs) {
@ -2226,7 +2307,7 @@ pub const Interpreter = struct {
},
.num_is_gte => {
// num.is_gte : num, num -> Bool
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_is_gte expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result = switch (lhs) {
@ -2239,7 +2320,7 @@ pub const Interpreter = struct {
},
.num_is_lt => {
// num.is_lt : num, num -> Bool
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_is_lt expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result = switch (lhs) {
@ -2252,7 +2333,7 @@ pub const Interpreter = struct {
},
.num_is_lte => {
// num.is_lte : num, num -> Bool
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_is_lte expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result = switch (lhs) {
@ -2267,7 +2348,7 @@ pub const Interpreter = struct {
// Numeric arithmetic operations
.num_negate => {
// num.negate : num -> num (signed types only)
if (args.len != 1) return error.TypeMismatch;
std.debug.assert(args.len == 1); // low-level .num_negate expects 1 argument
const num_val = try self.extractNumericValue(args[0]);
const result_layout = args[0].layout;
@ -2284,7 +2365,7 @@ pub const Interpreter = struct {
return out;
},
.num_plus => {
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_plus expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result_layout = args[0].layout;
@ -2302,7 +2383,7 @@ pub const Interpreter = struct {
return out;
},
.num_minus => {
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_minus expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result_layout = args[0].layout;
@ -2320,7 +2401,7 @@ pub const Interpreter = struct {
return out;
},
.num_times => {
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_times expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result_layout = args[0].layout;
@ -2338,7 +2419,7 @@ pub const Interpreter = struct {
return out;
},
.num_div_by => {
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_div_by expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result_layout = args[0].layout;
@ -2369,7 +2450,7 @@ pub const Interpreter = struct {
return out;
},
.num_rem_by => {
if (args.len != 2) return error.TypeMismatch;
std.debug.assert(args.len == 2); // low-level .num_rem_by expects 2 arguments
const lhs = try self.extractNumericValue(args[0]);
const rhs = try self.extractNumericValue(args[1]);
const result_layout = args[0].layout;

View file

@ -210,3 +210,110 @@ test "e_anno_only - value only crashes when accessed (False branch)" {
try testing.expectEqual(@as(u32, 2), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}
test "List.first on nonempty list" {
const src =
\\result = List.first([1, 2, 3])
;
var result = try parseCheckAndEvalModule(src);
defer cleanupEvalModule(&result);
const summary = try result.evaluator.evalAll();
// Should evaluate 1 declaration with 0 crashes (List.first should succeed)
try testing.expectEqual(@as(u32, 1), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}
test "List.get with valid index returns Ok" {
const src =
\\result = List.get([1, 2, 3], 1)
;
var result = try parseCheckAndEvalModule(src);
defer cleanupEvalModule(&result);
const summary = try result.evaluator.evalAll();
// Should evaluate 1 declaration with 0 crashes (List.get should succeed)
try testing.expectEqual(@as(u32, 1), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}
test "List.get with invalid index returns Err" {
const src =
\\result = List.get([1, 2, 3], 10)
;
var result = try parseCheckAndEvalModule(src);
defer cleanupEvalModule(&result);
const summary = try result.evaluator.evalAll();
// Should evaluate 1 declaration with 0 crashes (List.get should return Err but not crash)
try testing.expectEqual(@as(u32, 1), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}
test "List.get on empty list returns Err" {
const src =
\\empty : List(U64)
\\empty = []
\\result = List.get(empty, 0)
;
var result = try parseCheckAndEvalModule(src);
defer cleanupEvalModule(&result);
const summary = try result.evaluator.evalAll();
// Should evaluate 2 declarations with 0 crashes (List.get should return Err but not crash)
try testing.expectEqual(@as(u32, 2), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}
test "List.get with different element types - Str" {
const src =
\\result = List.get(["foo", "bar", "baz"], 1)
;
var result = try parseCheckAndEvalModule(src);
defer cleanupEvalModule(&result);
const summary = try result.evaluator.evalAll();
// Should evaluate 1 declaration with 0 crashes
try testing.expectEqual(@as(u32, 1), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}
test "List.get with different element types - Bool" {
const src =
\\result = List.get([True, False, True], 2)
;
var result = try parseCheckAndEvalModule(src);
defer cleanupEvalModule(&result);
const summary = try result.evaluator.evalAll();
// Should evaluate 1 declaration with 0 crashes
try testing.expectEqual(@as(u32, 1), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}
test "List.get with nested lists" {
const src =
\\result = List.get([[1, 2], [3, 4], [5, 6]], 1)
;
var result = try parseCheckAndEvalModule(src);
defer cleanupEvalModule(&result);
const summary = try result.evaluator.evalAll();
// Should evaluate 1 declaration with 0 crashes
try testing.expectEqual(@as(u32, 1), summary.evaluated);
try testing.expectEqual(@as(u32, 0), summary.crashed);
}

View file

@ -19,13 +19,19 @@ const ModuleEnv = can.ModuleEnv;
const testing = std.testing;
const test_allocator = testing.allocator;
/// Helper to parse, canonicalize, type-check, and run comptime evaluation on a full module
fn parseCheckAndEvalModule(src: []const u8) !struct {
const EvalModuleResult = struct {
module_env: *ModuleEnv,
evaluator: ComptimeEvaluator,
problems: *check.problem.Store,
builtin_module: builtin_loading.LoadedModule,
} {
};
/// Helper to parse, canonicalize, type-check, and run comptime evaluation on a full module
fn parseCheckAndEvalModule(src: []const u8) !EvalModuleResult {
return parseCheckAndEvalModuleWithName(src, "TestModule");
}
fn parseCheckAndEvalModuleWithName(src: []const u8, module_name: []const u8) !EvalModuleResult {
const gpa = test_allocator;
const module_env = try gpa.create(ModuleEnv);
@ -34,7 +40,7 @@ fn parseCheckAndEvalModule(src: []const u8) !struct {
errdefer module_env.deinit();
module_env.common.source = src;
module_env.module_name = "TestModule";
module_env.module_name = module_name;
try module_env.common.calcLineStarts(module_env.gpa);
// Parse the source code
@ -51,9 +57,9 @@ fn parseCheckAndEvalModule(src: []const u8) !struct {
errdefer builtin_module.deinit();
// Initialize CIR fields in ModuleEnv
try module_env.initCIRFields(gpa, "test");
try module_env.initCIRFields(gpa, module_name);
const common_idents: Check.CommonIdents = .{
.module_name = try module_env.insertIdent(base.Ident.for_text("test")),
.module_name = try module_env.insertIdent(base.Ident.for_text(module_name)),
.list = try module_env.insertIdent(base.Ident.for_text("List")),
.box = try module_env.insertIdent(base.Ident.for_text("Box")),
.bool_stmt = builtin_indices.bool_type,
@ -91,14 +97,16 @@ fn parseCheckAndEvalModule(src: []const u8) !struct {
};
}
/// Helper to parse, canonicalize, type-check, and run comptime evaluation with imported modules
fn parseCheckAndEvalModuleWithImport(src: []const u8, import_name: []const u8, imported_module: *const ModuleEnv) !struct {
const EvalModuleWithImportResult = struct {
module_env: *ModuleEnv,
evaluator: ComptimeEvaluator,
problems: *check.problem.Store,
other_envs: []const *const ModuleEnv,
builtin_module: builtin_loading.LoadedModule,
} {
};
/// Helper to parse, canonicalize, type-check, and run comptime evaluation with imported modules
fn parseCheckAndEvalModuleWithImport(src: []const u8, import_name: []const u8, imported_module: *const ModuleEnv) !EvalModuleWithImportResult {
const gpa = test_allocator;
const module_env = try gpa.create(ModuleEnv);
@ -138,6 +146,9 @@ fn parseCheckAndEvalModuleWithImport(src: []const u8, import_name: []const u8, i
var module_envs = std.AutoHashMap(base.Ident.Idx, Can.AutoImportedType).init(gpa);
defer module_envs.deinit();
// Populate module_envs with builtin types (like production does)
try Can.populateModuleEnvs(&module_envs, module_env, builtin_module.env, builtin_indices);
// Convert import name to Ident.Idx using the MODULE's ident store (not a temporary one!)
// This is important because the canonicalizer will look up identifiers in this same store
const import_ident = try module_env.insertIdent(base.Ident.for_text(import_name));
@ -382,7 +393,7 @@ test "comptime eval - cross-module crash is detected" {
\\}
;
var result_a = try parseCheckAndEvalModule(src_a);
var result_a = try parseCheckAndEvalModuleWithName(src_a, "A");
defer cleanupEvalModule(&result_a);
const summary_a = try result_a.evaluator.evalAll();

View file

@ -137,9 +137,9 @@ foo = Json.parse(data)
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "Str"))
(patt (type "Error")))
(expressions
(expr (type "Error"))
(expr (type "Str"))
(expr (type "Error"))))
~~~

View file

@ -840,7 +840,7 @@ h = |x, y| {
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "e -> e"))
(patt (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c")))
(type_decls
(alias (type "A(a)")
@ -866,6 +866,6 @@ h = |x, y| {
(alias (type "F")
(ty-header (name "F"))))
(expressions
(expr (type "Error"))
(expr (type "e -> e"))
(expr (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c"))))
~~~

View file

@ -76,6 +76,13 @@ NO CHANGE
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -85,7 +92,9 @@ NO CHANGE
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -93,6 +93,13 @@ NO CHANGE
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -102,7 +109,9 @@ NO CHANGE
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -197,11 +197,11 @@ PARSE ERROR - everything.md:56:37:56:38
PARSE ERROR - everything.md:56:38:56:39
PARSE ERROR - everything.md:56:39:56:40
PARSE ERROR - everything.md:56:40:56:42
MALFORMED WHERE CLAUSE - everything.md:56:12:56:17
WHERE CLAUSE NOT ALLOWED IN TYPE DECLARATION - everything.md:12:1:13:7
UNDECLARED TYPE - everything.md:43:5:43:6
MODULE NOT FOUND - everything.md:2:1:5:2
MODULE NOT FOUND - everything.md:6:1:9:2
MALFORMED WHERE CLAUSE - everything.md:56:12:56:17
UNUSED VARIABLE - everything.md:88:5:88:6
UNUSED VARIABLE - everything.md:93:4:93:5
UNUSED VARIABLE - everything.md:98:5:98:6
@ -1174,6 +1174,17 @@ g : e -> e where module(e).A, module(e).B
^^
**MALFORMED WHERE CLAUSE**
This where clause could not be parsed correctly.
**everything.md:56:12:56:17:**
```roc
g : e -> e where module(e).A, module(e).B
```
^^^^^
Check the syntax of your where clause.
**WHERE CLAUSE NOT ALLOWED IN TYPE DECLARATION**
You cannot define a `where` clause inside a type declaration.
@ -1222,17 +1233,6 @@ import I2 exposing [
```
**MALFORMED WHERE CLAUSE**
This where clause could not be parsed correctly.
**everything.md:56:12:56:17:**
```roc
g : e -> e where module(e).A, module(e).B
```
^^^^^
Check the syntax of your where clause.
**UNUSED VARIABLE**
Variable `b` is not used anywhere in your code.
@ -1904,7 +1904,7 @@ h = |x, y| {
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "e -> e"))
(patt (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c")))
(type_decls
(alias (type "A(a)")
@ -1921,6 +1921,6 @@ h = |x, y| {
(alias (type "F")
(ty-header (name "F"))))
(expressions
(expr (type "Error"))
(expr (type "e -> e"))
(expr (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c"))))
~~~

View file

@ -82,6 +82,13 @@ b! : Str => Str
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -91,7 +98,9 @@ b! : Str => Str
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -104,6 +104,13 @@ b! : Str => Str
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -113,7 +120,9 @@ b! : Str => Str
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -528,7 +528,7 @@ NO CHANGE
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "e -> e"))
(patt (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c")))
(type_decls
(alias (type "A(a)")
@ -554,6 +554,6 @@ NO CHANGE
(alias (type "F")
(ty-header (name "F"))))
(expressions
(expr (type "Error"))
(expr (type "e -> e"))
(expr (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c"))))
~~~

View file

@ -70,6 +70,13 @@ NO CHANGE
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -79,7 +86,9 @@ NO CHANGE
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -77,6 +77,13 @@ NO CHANGE
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -86,7 +93,9 @@ NO CHANGE
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -641,7 +641,7 @@ h = |
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "e -> e"))
(patt (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c")))
(type_decls
(alias (type "A(a)")
@ -667,6 +667,6 @@ h = |
(alias (type "F")
(ty-header (name "F"))))
(expressions
(expr (type "Error"))
(expr (type "e -> e"))
(expr (type "[Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j, [Z1((c, d)), Z2(c, f), Z3({ a: c, b: i }), Z4(List(c))]j -> c"))))
~~~

View file

@ -76,6 +76,13 @@ b! : Str => Str
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -85,7 +92,9 @@ b! : Str => Str
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -88,6 +88,13 @@ b! : Str => Str
(d-let
(p-assign (ident "a!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "b!"))
(e-anno-only)
(annotation
(ty-fn (effectful true)
(ty-lookup (name "Str") (builtin))
@ -97,7 +104,9 @@ b! : Str => Str
~~~clojure
(inferred-types
(defs
(patt (type "Error")))
(patt (type "Str => Str"))
(patt (type "Str => Str")))
(expressions
(expr (type "Error"))))
(expr (type "Str => Str"))
(expr (type "Str => Str"))))
~~~

View file

@ -287,11 +287,18 @@ modu :
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "modu"))
(e-anno-only)
(annotation
(ty-malformed))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Error")))
(expressions
(expr (type "Error"))))
~~~

View file

@ -83,11 +83,18 @@ b : S
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "b"))
(e-anno-only)
(annotation
(ty-malformed))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Error")))
(expressions
(expr (type "Error"))))
~~~

View file

@ -2007,14 +2007,14 @@ expect {
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "()"))
(patt (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(patt (type "Error"))
(patt (type "Bool -> Error"))
(patt (type "[Blue]_others, [Tb]_others2 -> Error"))
(patt (type "Error"))
(patt (type "_arg -> [Stdo!(Error)]_others"))
(patt (type "Error"))
(patt (type "{ }"))
(patt (type "{}"))
(patt (type "Error")))
(type_decls
@ -2044,14 +2044,14 @@ expect {
(ty-args
(ty-rigid-var (name "a"))))))
(expressions
(expr (type "Error"))
(expr (type "()"))
(expr (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(expr (type "Error"))
(expr (type "Bool -> Error"))
(expr (type "[Blue]_others, [Tb]_others2 -> Error"))
(expr (type "Error"))
(expr (type "_arg -> [Stdo!(Error)]_others"))
(expr (type "Error"))
(expr (type "{ }"))
(expr (type "{}"))
(expr (type "Error"))))
~~~

View file

@ -1986,14 +1986,14 @@ expect {
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "()"))
(patt (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(patt (type "Error"))
(patt (type "[Rum]_others -> Error"))
(patt (type "[Blue]_others -> Error"))
(patt (type "Error"))
(patt (type "_arg -> [Stdo!(Error)]_others"))
(patt (type "Error"))
(patt (type "{ }"))
(patt (type "{}"))
(patt (type "Error")))
(type_decls
@ -2023,14 +2023,14 @@ expect {
(ty-args
(ty-rigid-var (name "a"))))))
(expressions
(expr (type "Error"))
(expr (type "()"))
(expr (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(expr (type "Error"))
(expr (type "[Rum]_others -> Error"))
(expr (type "[Blue]_others -> Error"))
(expr (type "Error"))
(expr (type "_arg -> [Stdo!(Error)]_others"))
(expr (type "Error"))
(expr (type "{ }"))
(expr (type "{}"))
(expr (type "Error"))))
~~~

View file

@ -245,7 +245,7 @@ ain! = |_| getUser(900)
(inferred-types
(defs
(patt (type "Error"))
(patt (type "Error"))
(patt (type "UserId -> Str"))
(patt (type "_arg -> Error"))
(patt (type "_arg -> Error")))
(type_decls
@ -253,7 +253,7 @@ ain! = |_| getUser(900)
(ty-header (name "UserId"))))
(expressions
(expr (type "Error"))
(expr (type "Error"))
(expr (type "UserId -> Str"))
(expr (type "_arg -> Error"))
(expr (type "_arg -> Error"))))
~~~

View file

@ -269,6 +269,7 @@ DOES NOT EXIST - fuzz_crash_023.md:193:4:193:13
UNUSED VARIABLE - fuzz_crash_023.md:164:2:164:18
UNUSED VARIABLE - fuzz_crash_023.md:165:2:165:14
UNUSED VARIABLE - fuzz_crash_023.md:178:2:178:8
UNUSED VARIABLE - fuzz_crash_023.md:178:47:178:71
UNUSED VARIABLE - fuzz_crash_023.md:180:2:180:17
UNUSED VARIABLE - fuzz_crash_023.md:188:2:188:15
UNUSED VARIABLE - fuzz_crash_023.md:189:2:189:23
@ -846,6 +847,18 @@ The unused variable is declared here:
^^^^^^
**UNUSED VARIABLE**
Variable `qux` is not used anywhere in your code.
If you don't need this variable, prefix it with an underscore like `_qux` to suppress this warning.
The unused variable is declared here:
**fuzz_crash_023.md:178:47:178:71:**
```roc
record = { foo: 123, bar: "Hello", ;az: tag, qux: Ok(world), punned }
```
^^^^^^^^^^^^^^^^^^^^^^^^
**UNUSED VARIABLE**
Variable `multiline_tuple` is not used anywhere in your code.
@ -2211,6 +2224,11 @@ expect {
(p-applied-tag)))
(value
(e-num (value "1000"))))))))))
(d-let
(p-assign (ident "qux"))
(e-anno-only)
(annotation
(ty-malformed)))
(d-let
(p-assign (ident "main!"))
(e-closure
@ -2310,6 +2328,9 @@ expect {
(p-assign (ident "tag"))))
(s-expr
(e-runtime-error (tag "expr_not_canonicalized")))
(s-let
(p-assign (ident "qux"))
(e-anno-only))
(s-let
(p-assign (ident "tuple"))
(e-tuple
@ -2554,6 +2575,7 @@ expect {
(patt (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(patt (type "Num(Int(Unsigned64)) -> Num(Int(Unsigned64))"))
(patt (type "[Red][Blue, Green]_others, _arg -> Error"))
(patt (type "Error"))
(patt (type "List(Error) -> Error"))
(patt (type "{}"))
(patt (type "Error")))
@ -2600,6 +2622,7 @@ expect {
(expr (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(expr (type "Num(Int(Unsigned64)) -> Num(Int(Unsigned64))"))
(expr (type "[Red][Blue, Green]_others, _arg -> Error"))
(expr (type "Error"))
(expr (type "List(Error) -> Error"))
(expr (type "{}"))
(expr (type "Error"))))

View file

@ -2249,7 +2249,7 @@ expect {
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "(Error, Error)"))
(patt (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(patt (type "Num(Int(Unsigned64)) -> Num(Int(Unsigned64))"))
(patt (type "[Red, Blue]_others, _arg -> Error"))
@ -2286,7 +2286,7 @@ expect {
(ty-args
(ty-rigid-var (name "a"))))))
(expressions
(expr (type "Error"))
(expr (type "(Error, Error)"))
(expr (type "Bool -> num where [num.from_int_digits : List(U8) -> Try(num, [OutOfRange])]"))
(expr (type "Num(Int(Unsigned64)) -> Num(Int(Unsigned64))"))
(expr (type "[Red, Blue]_others, _arg -> Error"))

View file

@ -455,11 +455,18 @@ pkg :
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "pkg"))
(e-anno-only)
(annotation
(ty-malformed))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Error")))
(expressions
(expr (type "Error"))))
~~~

View file

@ -89,11 +89,18 @@ o :
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "o"))
(e-anno-only)
(annotation
(ty-malformed))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Error")))
(expressions
(expr (type "Error"))))
~~~

View file

@ -9,8 +9,8 @@ import u.R}g:r->R.a.E
~~~
# EXPECTED
PARSE ERROR - fuzz_crash_042.md:1:11:1:12
MODULE NOT FOUND - fuzz_crash_042.md:1:1:1:11
MODULE NOT IMPORTED - fuzz_crash_042.md:1:17:1:22
MODULE NOT FOUND - fuzz_crash_042.md:1:1:1:11
# PROBLEMS
**PARSE ERROR**
A parsing error occurred: `statement_unexpected_token`
@ -23,17 +23,6 @@ import u.R}g:r->R.a.E
^
**MODULE NOT FOUND**
The module `u.R` was not found in this Roc project.
You're attempting to use this module here:
**fuzz_crash_042.md:1:1:1:11:**
```roc
import u.R}g:r->R.a.E
```
^^^^^^^^^^
**MODULE NOT IMPORTED**
There is no module with the name `R.a` imported into this Roc file.
@ -45,6 +34,17 @@ import u.R}g:r->R.a.E
^^^^^
**MODULE NOT FOUND**
The module `u.R` was not found in this Roc project.
You're attempting to use this module here:
**fuzz_crash_042.md:1:1:1:11:**
```roc
import u.R}g:r->R.a.E
```
^^^^^^^^^^
# TOKENS
~~~zig
KwImport,LowerIdent,NoSpaceDotUpperIdent,CloseCurly,LowerIdent,OpColon,LowerIdent,OpArrow,UpperIdent,NoSpaceDotLowerIdent,NoSpaceDotUpperIdent,
@ -70,12 +70,21 @@ g : r -> R.a.E
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "g"))
(e-anno-only)
(annotation
(ty-fn (effectful false)
(ty-rigid-var (name "r"))
(ty-malformed))))
(s-import (module "u.R")
(exposes)))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "r -> Error")))
(expressions
(expr (type "r -> Error"))))
~~~

View file

@ -102,11 +102,18 @@ o :
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "o"))
(e-anno-only)
(annotation
(ty-malformed))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Error")))
(expressions
(expr (type "Error"))))
~~~

View file

@ -157,21 +157,28 @@ tag_tuple : Value((a, b, c))
(ty-malformed))
(ty-apply (name "Result") (builtin)
(ty-record)
(ty-underscore))))))
(ty-underscore)))))
(d-let
(p-assign (ident "tag_tuple"))
(e-anno-only)
(annotation
(ty-malformed))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs
(patt (type "Num(Int(Unsigned64))"))
(patt (type "Error"))
(patt (type "Error"))
(patt (type "Error"))
(patt (type "Error"))
(patt (type "(a, b, c)"))
(patt (type "Num(Int(Unsigned8)), Num(Int(Unsigned16)) -> Num(Int(Unsigned32))"))
(patt (type "List(Error) -> Try({ }, _d)"))
(patt (type "Error")))
(expressions
(expr (type "Num(Int(Unsigned64))"))
(expr (type "Error"))
(expr (type "Error"))
(expr (type "Error"))
(expr (type "Error"))
(expr (type "(a, b, c)"))
(expr (type "Num(Int(Unsigned8)), Num(Int(Unsigned16)) -> Num(Int(Unsigned32))"))
(expr (type "List(Error) -> Try({ }, _d)"))
(expr (type "Error"))))
~~~

View file

@ -45,11 +45,18 @@ b : r
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "b"))
(e-anno-only)
(annotation
(ty-rigid-var (name "r")))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "r")))
(expressions
(expr (type "r"))))
~~~

View file

@ -85,15 +85,15 @@ external = Foo.defaultBaz
~~~clojure
(can-ir
(d-let
(p-assign (ident "external"))
(e-lookup-local
(p-assign (ident "Foo.defaultBaz")))
(p-assign (ident "nominal_associated_alias_within_block.Foo.defaultBaz"))
(e-nominal (nominal "nominal_associated_alias_within_block.Foo.Bar")
(e-tag (name "X")))
(annotation
(ty-lookup (name "Foo.Baz") (local))))
(d-let
(p-assign (ident "Foo.defaultBaz"))
(e-nominal (nominal "Foo.Bar")
(e-tag (name "X")))
(p-assign (ident "external"))
(e-lookup-local
(p-assign (ident "nominal_associated_alias_within_block.Foo.defaultBaz")))
(annotation
(ty-lookup (name "Foo.Baz") (local))))
(s-nominal-decl
@ -101,29 +101,29 @@ external = Foo.defaultBaz
(ty-tag-union
(ty-tag-name (name "Whatever"))))
(s-nominal-decl
(ty-header (name "Foo.Bar"))
(ty-header (name "nominal_associated_alias_within_block.Foo.Bar"))
(ty-tag-union
(ty-tag-name (name "X"))
(ty-tag-name (name "Y"))
(ty-tag-name (name "Z"))))
(s-alias-decl
(ty-header (name "Foo.Baz"))
(ty-header (name "nominal_associated_alias_within_block.Foo.Baz"))
(ty-lookup (name "Foo.Bar") (local))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Baz"))
(patt (type "Foo.Baz")))
(patt (type "nominal_associated_alias_within_block.Foo.Baz"))
(patt (type "nominal_associated_alias_within_block.Foo.Baz")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar")))
(alias (type "Foo.Baz")
(ty-header (name "Foo.Baz"))))
(nominal (type "nominal_associated_alias_within_block.Foo.Bar")
(ty-header (name "nominal_associated_alias_within_block.Foo.Bar")))
(alias (type "nominal_associated_alias_within_block.Foo.Baz")
(ty-header (name "nominal_associated_alias_within_block.Foo.Baz"))))
(expressions
(expr (type "Foo.Baz"))
(expr (type "Foo.Baz"))))
(expr (type "nominal_associated_alias_within_block.Foo.Baz"))
(expr (type "nominal_associated_alias_within_block.Foo.Baz"))))
~~~

View file

@ -110,6 +110,9 @@ deepType = C
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "Foo.Level1.Level2.Level3.value"))
(e-num (value "42")))
(d-let
(p-assign (ident "deepValue"))
(e-lookup-local
@ -121,9 +124,6 @@ deepType = C
(e-tag (name "C"))
(annotation
(ty-lookup (name "Foo.Level1.Level2.Level3") (local))))
(d-let
(p-assign (ident "Foo.Level1.Level2.Level3.value"))
(e-num (value "42")))
(s-nominal-decl
(ty-header (name "Foo"))
(ty-tag-union
@ -146,8 +146,8 @@ deepType = C
(inferred-types
(defs
(patt (type "Num(Int(Unsigned64))"))
(patt (type "Foo.Level1.Level2.Level3"))
(patt (type "Num(Int(Unsigned64))")))
(patt (type "Num(Int(Unsigned64))"))
(patt (type "Foo.Level1.Level2.Level3")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
@ -159,6 +159,6 @@ deepType = C
(ty-header (name "Foo.Level1.Level2.Level3"))))
(expressions
(expr (type "Num(Int(Unsigned64))"))
(expr (type "Foo.Level1.Level2.Level3"))
(expr (type "Num(Int(Unsigned64))"))))
(expr (type "Num(Int(Unsigned64))"))
(expr (type "Foo.Level1.Level2.Level3"))))
~~~

View file

@ -58,15 +58,15 @@ useBar = Foo.bar
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "Foo.bar"))
(e-num (value "42")))
(d-let
(p-assign (ident "useBar"))
(e-lookup-local
(p-assign (ident "Foo.bar")))
(annotation
(ty-lookup (name "U64") (builtin))))
(d-let
(p-assign (ident "Foo.bar"))
(e-num (value "42")))
(s-nominal-decl
(ty-header (name "Foo"))
(ty-tag-union

View file

@ -89,15 +89,6 @@ result = Foo.transform(Foo.defaultBar)
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "result"))
(e-call
(e-lookup-local
(p-assign (ident "Foo.transform")))
(e-lookup-local
(p-assign (ident "Foo.defaultBar"))))
(annotation
(ty-lookup (name "Foo.Bar") (local))))
(d-let
(p-assign (ident "Foo.defaultBar"))
(e-nominal (nominal "Foo.Bar")
@ -113,6 +104,15 @@ result = Foo.transform(Foo.defaultBar)
(ty-fn (effectful false)
(ty-lookup (name "Foo.Bar") (local))
(ty-lookup (name "Foo.Bar") (local)))))
(d-let
(p-assign (ident "result"))
(e-call
(e-lookup-local
(p-assign (ident "Foo.transform")))
(e-lookup-local
(p-assign (ident "Foo.defaultBar"))))
(annotation
(ty-lookup (name "Foo.Bar") (local))))
(s-nominal-decl
(ty-header (name "Foo"))
(ty-tag-union
@ -129,8 +129,8 @@ result = Foo.transform(Foo.defaultBar)
(inferred-types
(defs
(patt (type "Foo.Bar"))
(patt (type "Foo.Bar"))
(patt (type "Foo.Bar -> Foo.Bar")))
(patt (type "Foo.Bar -> Foo.Bar"))
(patt (type "Foo.Bar")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
@ -138,6 +138,6 @@ result = Foo.transform(Foo.defaultBar)
(ty-header (name "Foo.Bar"))))
(expressions
(expr (type "Foo.Bar"))
(expr (type "Foo.Bar"))
(expr (type "Foo.Bar -> Foo.Bar"))))
(expr (type "Foo.Bar -> Foo.Bar"))
(expr (type "Foo.Bar"))))
~~~

View file

@ -84,6 +84,9 @@ myNum = Foo.Bar.baz
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "Foo.Bar.baz"))
(e-num (value "5")))
(d-let
(p-assign (ident "myType"))
(e-tag (name "Something"))
@ -95,9 +98,6 @@ myNum = Foo.Bar.baz
(p-assign (ident "Foo.Bar.baz")))
(annotation
(ty-lookup (name "U64") (builtin))))
(d-let
(p-assign (ident "Foo.Bar.baz"))
(e-num (value "5")))
(s-nominal-decl
(ty-header (name "Foo"))
(ty-tag-union
@ -111,8 +111,8 @@ myNum = Foo.Bar.baz
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Bar"))
(patt (type "Num(Int(Unsigned64))"))
(patt (type "Foo.Bar"))
(patt (type "Num(Int(Unsigned64))")))
(type_decls
(nominal (type "Foo")
@ -120,7 +120,7 @@ myNum = Foo.Bar.baz
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar"))))
(expressions
(expr (type "Foo.Bar"))
(expr (type "Num(Int(Unsigned64))"))
(expr (type "Foo.Bar"))
(expr (type "Num(Int(Unsigned64))"))))
~~~

View file

@ -101,12 +101,6 @@ external = Foo.defaultBar
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "external"))
(e-lookup-local
(p-assign (ident "Foo.defaultBar")))
(annotation
(ty-lookup (name "Foo.Bar") (local))))
(d-let
(p-assign (ident "Foo.defaultBar"))
(e-tag (name "X"))
@ -130,6 +124,12 @@ external = Foo.defaultBar
(p-assign (ident "Foo.transform")))
(e-lookup-local
(p-assign (ident "Foo.defaultBar")))))
(d-let
(p-assign (ident "external"))
(e-lookup-local
(p-assign (ident "Foo.defaultBar")))
(annotation
(ty-lookup (name "Foo.Bar") (local))))
(s-nominal-decl
(ty-header (name "Foo"))
(ty-tag-union
@ -145,9 +145,9 @@ external = Foo.defaultBar
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Bar"))
(patt (type "Foo.Bar"))
(patt (type "Foo.Bar -> Foo.Bar"))
(patt (type "Foo.Bar"))
(patt (type "Foo.Bar")))
(type_decls
(nominal (type "Foo")
@ -155,8 +155,8 @@ external = Foo.defaultBar
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar"))))
(expressions
(expr (type "Foo.Bar"))
(expr (type "Foo.Bar"))
(expr (type "Foo.Bar -> Foo.Bar"))
(expr (type "Foo.Bar"))
(expr (type "Foo.Bar"))))
~~~

View file

@ -76,7 +76,7 @@ useMyBar = Foo.Bar.X
(can-ir
(d-let
(p-assign (ident "useMyBar"))
(e-nominal (nominal "Foo.Bar")
(e-nominal (nominal "nominal_associated_type_alias.Foo.Bar")
(e-tag (name "X")))
(annotation
(ty-lookup (name "MyBar") (local))))
@ -85,7 +85,7 @@ useMyBar = Foo.Bar.X
(ty-tag-union
(ty-tag-name (name "Whatever"))))
(s-nominal-decl
(ty-header (name "Foo.Bar"))
(ty-header (name "nominal_associated_type_alias.Foo.Bar"))
(ty-tag-union
(ty-tag-name (name "X"))
(ty-tag-name (name "Y"))
@ -102,8 +102,8 @@ useMyBar = Foo.Bar.X
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar")))
(nominal (type "nominal_associated_type_alias.Foo.Bar")
(ty-header (name "nominal_associated_type_alias.Foo.Bar")))
(alias (type "MyBar")
(ty-header (name "MyBar"))))
(expressions

View file

@ -73,10 +73,13 @@ result = myBar
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "nominal_associated_value_alias.Foo.bar"))
(e-num (value "42")))
(d-let
(p-assign (ident "myBar"))
(e-lookup-local
(p-assign (ident "Foo.bar")))
(p-assign (ident "nominal_associated_value_alias.Foo.bar")))
(annotation
(ty-lookup (name "U64") (builtin))))
(d-let
@ -85,9 +88,6 @@ result = myBar
(p-assign (ident "myBar")))
(annotation
(ty-lookup (name "U64") (builtin))))
(d-let
(p-assign (ident "Foo.bar"))
(e-num (value "42")))
(s-nominal-decl
(ty-header (name "Foo"))
(ty-tag-union

View file

@ -93,7 +93,7 @@ useBar = Something
(ty-tag-union
(ty-tag-name (name "Whatever"))))
(s-nominal-decl
(ty-header (name "Foo.Bar"))
(ty-header (name "nominal_associated_vs_module.Foo.Bar"))
(ty-tag-union
(ty-tag-name (name "Something")))))
~~~
@ -101,12 +101,12 @@ useBar = Something
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Bar")))
(patt (type "nominal_associated_vs_module.Foo.Bar")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar"))))
(nominal (type "nominal_associated_vs_module.Foo.Bar")
(ty-header (name "nominal_associated_vs_module.Foo.Bar"))))
(expressions
(expr (type "Foo.Bar"))))
(expr (type "nominal_associated_vs_module.Foo.Bar"))))
~~~

View file

@ -59,7 +59,7 @@ Foo := [A, B, C].{
~~~clojure
(can-ir
(d-let
(p-assign (ident "Foo.x"))
(p-assign (ident "nominal_associated_with_final_expression.Foo.x"))
(e-num (value "5")))
(s-nominal-decl
(ty-header (name "Foo"))

View file

@ -78,7 +78,7 @@ x = Foo.Bar.Baz.X
(can-ir
(d-let
(p-assign (ident "x"))
(e-nominal (nominal "Foo.Bar.Baz")
(e-nominal (nominal "nominal_deeply_nested_tag.Foo.Bar.Baz")
(e-tag (name "X")))
(annotation
(ty-lookup (name "Foo.Bar.Baz") (local))))
@ -87,11 +87,11 @@ x = Foo.Bar.Baz.X
(ty-tag-union
(ty-tag-name (name "Whatever"))))
(s-nominal-decl
(ty-header (name "Foo.Bar"))
(ty-header (name "nominal_deeply_nested_tag.Foo.Bar"))
(ty-tag-union
(ty-tag-name (name "Something"))))
(s-nominal-decl
(ty-header (name "Foo.Bar.Baz"))
(ty-header (name "nominal_deeply_nested_tag.Foo.Bar.Baz"))
(ty-tag-union
(ty-tag-name (name "X"))
(ty-tag-name (name "Y"))
@ -101,14 +101,14 @@ x = Foo.Bar.Baz.X
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Bar.Baz")))
(patt (type "nominal_deeply_nested_tag.Foo.Bar.Baz")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar")))
(nominal (type "Foo.Bar.Baz")
(ty-header (name "Foo.Bar.Baz"))))
(nominal (type "nominal_deeply_nested_tag.Foo.Bar")
(ty-header (name "nominal_deeply_nested_tag.Foo.Bar")))
(nominal (type "nominal_deeply_nested_tag.Foo.Bar.Baz")
(ty-header (name "nominal_deeply_nested_tag.Foo.Bar.Baz"))))
(expressions
(expr (type "Foo.Bar.Baz"))))
(expr (type "nominal_deeply_nested_tag.Foo.Bar.Baz"))))
~~~

View file

@ -91,7 +91,7 @@ value = Foo.Bar.Baz.Qux.Y
(can-ir
(d-let
(p-assign (ident "value"))
(e-nominal (nominal "Foo.Bar.Baz.Qux")
(e-nominal (nominal "nominal_four_level_nested_tag.Foo.Bar.Baz.Qux")
(e-tag (name "Y")))
(annotation
(ty-lookup (name "Foo.Bar.Baz.Qux") (local))))
@ -100,15 +100,15 @@ value = Foo.Bar.Baz.Qux.Y
(ty-tag-union
(ty-tag-name (name "A"))))
(s-nominal-decl
(ty-header (name "Foo.Bar"))
(ty-header (name "nominal_four_level_nested_tag.Foo.Bar"))
(ty-tag-union
(ty-tag-name (name "B"))))
(s-nominal-decl
(ty-header (name "Foo.Bar.Baz"))
(ty-header (name "nominal_four_level_nested_tag.Foo.Bar.Baz"))
(ty-tag-union
(ty-tag-name (name "C"))))
(s-nominal-decl
(ty-header (name "Foo.Bar.Baz.Qux"))
(ty-header (name "nominal_four_level_nested_tag.Foo.Bar.Baz.Qux"))
(ty-tag-union
(ty-tag-name (name "X"))
(ty-tag-name (name "Y"))
@ -118,16 +118,16 @@ value = Foo.Bar.Baz.Qux.Y
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Bar.Baz.Qux")))
(patt (type "nominal_four_level_nested_tag.Foo.Bar.Baz.Qux")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar")))
(nominal (type "Foo.Bar.Baz")
(ty-header (name "Foo.Bar.Baz")))
(nominal (type "Foo.Bar.Baz.Qux")
(ty-header (name "Foo.Bar.Baz.Qux"))))
(nominal (type "nominal_four_level_nested_tag.Foo.Bar")
(ty-header (name "nominal_four_level_nested_tag.Foo.Bar")))
(nominal (type "nominal_four_level_nested_tag.Foo.Bar.Baz")
(ty-header (name "nominal_four_level_nested_tag.Foo.Bar.Baz")))
(nominal (type "nominal_four_level_nested_tag.Foo.Bar.Baz.Qux")
(ty-header (name "nominal_four_level_nested_tag.Foo.Bar.Baz.Qux"))))
(expressions
(expr (type "Foo.Bar.Baz.Qux"))))
(expr (type "nominal_four_level_nested_tag.Foo.Bar.Baz.Qux"))))
~~~

View file

@ -65,7 +65,7 @@ x = Foo.Bar.X
(can-ir
(d-let
(p-assign (ident "x"))
(e-nominal (nominal "Foo.Bar")
(e-nominal (nominal "nominal_nested_type_ref.Foo.Bar")
(e-tag (name "X")))
(annotation
(ty-lookup (name "Foo.Bar") (local))))
@ -74,7 +74,7 @@ x = Foo.Bar.X
(ty-tag-union
(ty-tag-name (name "Whatever"))))
(s-nominal-decl
(ty-header (name "Foo.Bar"))
(ty-header (name "nominal_nested_type_ref.Foo.Bar"))
(ty-tag-union
(ty-tag-name (name "X"))
(ty-tag-name (name "Y"))
@ -84,12 +84,12 @@ x = Foo.Bar.X
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Bar")))
(patt (type "nominal_nested_type_ref.Foo.Bar")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar"))))
(nominal (type "nominal_nested_type_ref.Foo.Bar")
(ty-header (name "nominal_nested_type_ref.Foo.Bar"))))
(expressions
(expr (type "Foo.Bar"))))
(expr (type "nominal_nested_type_ref.Foo.Bar"))))
~~~

View file

@ -60,14 +60,14 @@ x = Foo.Bar.X
(can-ir
(d-let
(p-assign (ident "x"))
(e-nominal (nominal "Foo.Bar")
(e-nominal (nominal "nominal_simple_nested_tag.Foo.Bar")
(e-tag (name "X"))))
(s-nominal-decl
(ty-header (name "Foo"))
(ty-tag-union
(ty-tag-name (name "Whatever"))))
(s-nominal-decl
(ty-header (name "Foo.Bar"))
(ty-header (name "nominal_simple_nested_tag.Foo.Bar"))
(ty-tag-union
(ty-tag-name (name "X"))
(ty-tag-name (name "Y"))
@ -77,12 +77,12 @@ x = Foo.Bar.X
~~~clojure
(inferred-types
(defs
(patt (type "Foo.Bar")))
(patt (type "nominal_simple_nested_tag.Foo.Bar")))
(type_decls
(nominal (type "Foo")
(ty-header (name "Foo")))
(nominal (type "Foo.Bar")
(ty-header (name "Foo.Bar"))))
(nominal (type "nominal_simple_nested_tag.Foo.Bar")
(ty-header (name "nominal_simple_nested_tag.Foo.Bar"))))
(expressions
(expr (type "Foo.Bar"))))
(expr (type "nominal_simple_nested_tag.Foo.Bar"))))
~~~

View file

@ -63,11 +63,21 @@ multiplyInts : I64, I64 -> I64
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "multiplyInts"))
(e-anno-only)
(annotation
(ty-fn (effectful false)
(ty-lookup (name "I64") (builtin))
(ty-lookup (name "I64") (builtin))
(ty-lookup (name "I64") (builtin))))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Num(Int(Signed64)), Num(Int(Signed64)) -> Num(Int(Signed64))")))
(expressions
(expr (type "Num(Int(Signed64)), Num(Int(Signed64)) -> Num(Int(Signed64))"))))
~~~

View file

@ -61,11 +61,20 @@ processString : Str -> Str
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "processString"))
(e-anno-only)
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin))))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Str -> Str")))
(expressions
(expr (type "Str -> Str"))))
~~~

View file

@ -317,6 +317,80 @@ main = {
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "Adv.to_str"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Adv.to_u64"))
(e-closure
(captures
(capture (ident "u")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "u")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "U64") (builtin)))))
(d-let
(p-assign (ident "Adv.update_str"))
(e-closure
(captures
(capture (ident "u64")))
(e-lambda
(args
(p-nominal
(p-applied-tag))
(p-assign (ident "next_str")))
(e-nominal (nominal "Adv")
(e-tag (name "Val")
(args
(e-lookup-local
(p-assign (ident "u64")))
(e-lookup-local
(p-assign (ident "next_str"))))))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Adv") (local)))))
(d-let
(p-assign (ident "Adv.update_u64"))
(e-closure
(captures
(capture (ident "str")))
(e-lambda
(args
(p-nominal
(p-applied-tag))
(p-assign (ident "next_u64")))
(e-nominal (nominal "Adv")
(e-tag (name "Val")
(args
(e-lookup-local
(p-assign (ident "next_u64")))
(e-lookup-local
(p-assign (ident "str"))))))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "U64") (builtin))
(ty-lookup (name "Adv") (local)))))
(d-let
(p-assign (ident "mismatch"))
(e-block
@ -411,80 +485,6 @@ main = {
(ty-tuple
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "U64") (builtin)))))
(d-let
(p-assign (ident "Adv.to_str"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Adv.to_u64"))
(e-closure
(captures
(capture (ident "u")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "u")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "U64") (builtin)))))
(d-let
(p-assign (ident "Adv.update_str"))
(e-closure
(captures
(capture (ident "u64")))
(e-lambda
(args
(p-nominal
(p-applied-tag))
(p-assign (ident "next_str")))
(e-nominal (nominal "Adv")
(e-tag (name "Val")
(args
(e-lookup-local
(p-assign (ident "u64")))
(e-lookup-local
(p-assign (ident "next_str"))))))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Adv") (local)))))
(d-let
(p-assign (ident "Adv.update_u64"))
(e-closure
(captures
(capture (ident "str")))
(e-lambda
(args
(p-nominal
(p-applied-tag))
(p-assign (ident "next_u64")))
(e-nominal (nominal "Adv")
(e-tag (name "Val")
(args
(e-lookup-local
(p-assign (ident "next_u64")))
(e-lookup-local
(p-assign (ident "str"))))))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Adv") (local))
(ty-lookup (name "U64") (builtin))
(ty-lookup (name "Adv") (local)))))
(s-nominal-decl
(ty-header (name "Adv"))
(ty-tag-union
@ -496,24 +496,24 @@ main = {
~~~clojure
(inferred-types
(defs
(patt (type "_a"))
(patt (type "_a"))
(patt (type "_a"))
(patt (type "(Str, Num(Int(Unsigned64)))"))
(patt (type "Adv -> Str"))
(patt (type "Adv -> Num(Int(Unsigned64))"))
(patt (type "Adv, Str -> Adv"))
(patt (type "Adv, Num(Int(Unsigned64)) -> Adv")))
(patt (type "Adv, Num(Int(Unsigned64)) -> Adv"))
(patt (type "_a"))
(patt (type "_a"))
(patt (type "_a"))
(patt (type "(Str, Num(Int(Unsigned64)))")))
(type_decls
(nominal (type "Adv")
(ty-header (name "Adv"))))
(expressions
(expr (type "_a"))
(expr (type "_a"))
(expr (type "_a"))
(expr (type "(Str, Num(Int(Unsigned64)))"))
(expr (type "Adv -> Str"))
(expr (type "Adv -> Num(Int(Unsigned64))"))
(expr (type "Adv, Str -> Adv"))
(expr (type "Adv, Num(Int(Unsigned64)) -> Adv"))))
(expr (type "Adv, Num(Int(Unsigned64)) -> Adv"))
(expr (type "_a"))
(expr (type "_a"))
(expr (type "_a"))
(expr (type "(Str, Num(Int(Unsigned64)))"))))
~~~

View file

@ -167,6 +167,35 @@ main = (helper1(val), helper2(val))
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "Basic.to_str"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Basic") (local))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Basic.to_str2"))
(e-lambda
(args
(p-assign (ident "test")))
(e-dot-access (field "to_str")
(receiver
(e-lookup-local
(p-assign (ident "test"))))
(args)))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Basic") (local))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "helper1"))
(e-lambda
@ -232,35 +261,6 @@ main = (helper1(val), helper2(val))
(ty-tuple
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Basic.to_str"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Basic") (local))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Basic.to_str2"))
(e-lambda
(args
(p-assign (ident "test")))
(e-dot-access (field "to_str")
(receiver
(e-lookup-local
(p-assign (ident "test"))))
(args)))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Basic") (local))
(ty-lookup (name "Str") (builtin)))))
(s-nominal-decl
(ty-header (name "Basic"))
(ty-tag-union
@ -271,20 +271,20 @@ main = (helper1(val), helper2(val))
~~~clojure
(inferred-types
(defs
(patt (type "Basic -> Str"))
(patt (type "Basic -> Str"))
(patt (type "a -> b where [a.to_str : a -> b]"))
(patt (type "a -> b where [a.to_str2 : a -> b]"))
(patt (type "Basic"))
(patt (type "(Str, Str)"))
(patt (type "Basic -> Str"))
(patt (type "Basic -> Str")))
(patt (type "(Str, Str)")))
(type_decls
(nominal (type "Basic")
(ty-header (name "Basic"))))
(expressions
(expr (type "Basic -> Str"))
(expr (type "Basic -> Str"))
(expr (type "a -> b where [a.to_str : a -> b]"))
(expr (type "a -> b where [a.to_str2 : a -> b]"))
(expr (type "Basic"))
(expr (type "(Str, Str)"))
(expr (type "Basic -> Str"))
(expr (type "Basic -> Str"))))
(expr (type "(Str, Str)"))))
~~~

View file

@ -124,6 +124,27 @@ main = (helper1(val), helper2(val))
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "BasicNoAnno.to_str"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s"))))))
(d-let
(p-assign (ident "BasicNoAnno.to_str2"))
(e-lambda
(args
(p-assign (ident "test")))
(e-dot-access (field "to_str")
(receiver
(e-lookup-local
(p-assign (ident "test"))))
(args))))
(d-let
(p-assign (ident "helper1"))
(e-lambda
@ -169,27 +190,6 @@ main = (helper1(val), helper2(val))
(ty-tuple
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "BasicNoAnno.to_str"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s"))))))
(d-let
(p-assign (ident "BasicNoAnno.to_str2"))
(e-lambda
(args
(p-assign (ident "test")))
(e-dot-access (field "to_str")
(receiver
(e-lookup-local
(p-assign (ident "test"))))
(args))))
(s-nominal-decl
(ty-header (name "BasicNoAnno"))
(ty-tag-union
@ -200,20 +200,20 @@ main = (helper1(val), helper2(val))
~~~clojure
(inferred-types
(defs
(patt (type "BasicNoAnno -> Str"))
(patt (type "a -> b where [a.to_str : a -> b]"))
(patt (type "a -> b where [a.to_str : a -> b]"))
(patt (type "a -> b where [a.to_str2 : a -> b]"))
(patt (type "BasicNoAnno"))
(patt (type "(Str, Str)"))
(patt (type "BasicNoAnno -> Str"))
(patt (type "a -> b where [a.to_str : a -> b]")))
(patt (type "(Str, Str)")))
(type_decls
(nominal (type "BasicNoAnno")
(ty-header (name "BasicNoAnno"))))
(expressions
(expr (type "BasicNoAnno -> Str"))
(expr (type "a -> b where [a.to_str : a -> b]"))
(expr (type "a -> b where [a.to_str : a -> b]"))
(expr (type "a -> b where [a.to_str2 : a -> b]"))
(expr (type "BasicNoAnno"))
(expr (type "(Str, Str)"))
(expr (type "BasicNoAnno -> Str"))
(expr (type "a -> b where [a.to_str : a -> b]"))))
(expr (type "(Str, Str)"))))
~~~

View file

@ -231,6 +231,47 @@ NO CHANGE
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "Container.get_value"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Container") (local))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Container.transform"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag))
(p-assign (ident "fn")))
(e-nominal (nominal "Container")
(e-tag (name "Box")
(args
(e-call
(e-lookup-local
(p-assign (ident "fn")))
(e-lookup-local
(p-assign (ident "s")))))))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Container") (local))
(ty-parens
(ty-fn (effectful false)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin))))
(ty-lookup (name "Container") (local)))))
(d-let
(p-assign (ident "extract"))
(e-lambda
@ -351,47 +392,6 @@ NO CHANGE
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Container.get_value"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag)))
(e-lookup-local
(p-assign (ident "s")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Container") (local))
(ty-lookup (name "Str") (builtin)))))
(d-let
(p-assign (ident "Container.transform"))
(e-closure
(captures
(capture (ident "s")))
(e-lambda
(args
(p-nominal
(p-applied-tag))
(p-assign (ident "fn")))
(e-nominal (nominal "Container")
(e-tag (name "Box")
(args
(e-call
(e-lookup-local
(p-assign (ident "fn")))
(e-lookup-local
(p-assign (ident "s")))))))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "Container") (local))
(ty-parens
(ty-fn (effectful false)
(ty-lookup (name "Str") (builtin))
(ty-lookup (name "Str") (builtin))))
(ty-lookup (name "Container") (local)))))
(s-nominal-decl
(ty-header (name "Container"))
(ty-tag-union
@ -402,6 +402,8 @@ NO CHANGE
~~~clojure
(inferred-types
(defs
(patt (type "Container -> Str"))
(patt (type "Container, Str -> Str -> Container"))
(patt (type "a -> Str where [a.get_value : a -> Str]"))
(patt (type "a, Str -> Str -> a where [a.transform : a, Str -> Str -> aa.transform : a, Str -> Str -> a]"))
(patt (type "Container"))
@ -409,13 +411,13 @@ NO CHANGE
(patt (type "Str"))
(patt (type "Str"))
(patt (type "Container"))
(patt (type "(Str, Str, Str)"))
(patt (type "Container -> Str"))
(patt (type "Container, Str -> Str -> Container")))
(patt (type "(Str, Str, Str)")))
(type_decls
(nominal (type "Container")
(ty-header (name "Container"))))
(expressions
(expr (type "Container -> Str"))
(expr (type "Container, Str -> Str -> Container"))
(expr (type "a -> Str where [a.get_value : a -> Str]"))
(expr (type "a, Str -> Str -> a where [a.transform : a, Str -> Str -> aa.transform : a, Str -> Str -> a]"))
(expr (type "Container"))
@ -423,7 +425,5 @@ NO CHANGE
(expr (type "Str"))
(expr (type "Str"))
(expr (type "Container"))
(expr (type "(Str, Str, Str)"))
(expr (type "Container -> Str"))
(expr (type "Container, Str -> Str -> Container"))))
(expr (type "(Str, Str, Str)"))))
~~~

View file

@ -9,6 +9,7 @@ nums : List U8
~~~
# EXPECTED
PARSE ERROR - type_annotation_missing_parens.md:2:1:2:1
TOO FEW ARGS - type_annotation_missing_parens.md:1:8:1:12
# PROBLEMS
**PARSE ERROR**
Type applications require parentheses around their type arguments.
@ -33,6 +34,16 @@ Other valid examples:
^
**TOO FEW ARGS**
The type _List_ expects argument, but got instead.
**type_annotation_missing_parens.md:1:8:1:12:**
```roc
nums : List U8
```
^^^^
# TOKENS
~~~zig
LowerIdent,OpColon,UpperIdent,UpperIdent,
@ -53,11 +64,18 @@ nums : List
~~~
# CANONICALIZE
~~~clojure
(can-ir (empty true))
(can-ir
(d-let
(p-assign (ident "nums"))
(e-anno-only)
(annotation
(ty-lookup (name "List") (builtin)))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "Error")))
(expressions
(expr (type "Error"))))
~~~

View file

@ -143,21 +143,28 @@ NO CHANGE
(ty-malformed))
(ty-apply (name "Result") (builtin)
(ty-record)
(ty-underscore))))))
(ty-underscore)))))
(d-let
(p-assign (ident "tag_tuple"))
(e-anno-only)
(annotation
(ty-malformed))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs
(patt (type "Num(Int(Unsigned64))"))
(patt (type "Error"))
(patt (type "Error"))
(patt (type "Error"))
(patt (type "Error"))
(patt (type "(_a, _b, _c)"))
(patt (type "Num(Int(Unsigned8)), Num(Int(Unsigned16)) -> Num(Int(Unsigned32))"))
(patt (type "List(Error) -> Try({ }, _a)"))
(patt (type "Error")))
(expressions
(expr (type "Num(Int(Unsigned64))"))
(expr (type "Error"))
(expr (type "Error"))
(expr (type "Error"))
(expr (type "Error"))
(expr (type "(_a, _b, _c)"))
(expr (type "Num(Int(Unsigned8)), Num(Int(Unsigned16)) -> Num(Int(Unsigned32))"))
(expr (type "List(Error) -> Try({ }, _a)"))
(expr (type "Error"))))
~~~

View file

@ -71,6 +71,18 @@ decode_things # After member name
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "decode_things"))
(e-anno-only)
(annotation
(ty-fn (effectful false)
(ty-apply (name "List") (builtin)
(ty-apply (name "List") (builtin)
(ty-lookup (name "U8") (builtin))))
(ty-apply (name "List") (builtin)
(ty-rigid-var (name "a"))))
(where
(alias (ty-rigid-var-lookup (ty-rigid-var (name "a"))) (name "Decode")))))
(s-import (module "Decode")
(exposes
(exposed (name "Decode") (wildcard false)))))
@ -78,6 +90,8 @@ decode_things # After member name
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
(defs
(patt (type "List(List(Num(Int(Unsigned8)))) -> List(a)")))
(expressions
(expr (type "List(List(Num(Int(Unsigned8)))) -> List(a)"))))
~~~

View file

@ -194,15 +194,29 @@ broken_fn3 : a -> b
(ty-rigid-var (name "a"))
(ty-rigid-var (name "b")))
(where
(malformed)))))
(malformed))))
(d-let
(p-assign (ident "broken_fn3"))
(e-anno-only)
(annotation
(ty-fn (effectful false)
(ty-rigid-var (name "a"))
(ty-rigid-var (name "b")))
(where
(method (ty-rigid-var (name "c")) (name "method")
(args
(ty-rigid-var-lookup (ty-rigid-var (name "c"))))
(ty-rigid-var (name "d")))))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs
(patt (type "Error"))
(patt (type "Error")))
(patt (type "a -> b"))
(patt (type "a -> b"))
(patt (type "a -> b")))
(expressions
(expr (type "Error"))
(expr (type "Error"))))
(expr (type "a -> b"))
(expr (type "a -> b"))
(expr (type "a -> b"))))
~~~