Skip to content

Commit 9243fcd

Browse files
authored
Merge pull request #8360 from roc-lang/jared/push-znxlroqvynwl
let-poly fixes, type check out-of-order defs, + lots more
2 parents de712a4 + 2a2ff8d commit 9243fcd

File tree

225 files changed

+5395
-2149
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

225 files changed

+5395
-2149
lines changed

src/build/builtin_compiler/main.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn transformStrNominalToPrimitive(env: *ModuleEnv) !void {
8686
const var_idx = @as(Var, @enumFromInt(i));
8787

8888
// Skip redirects, only process roots
89-
if (env.types.isRedirect(var_idx)) {
89+
if (!env.types.resolveVar(var_idx).is_root) {
9090
continue;
9191
}
9292

@@ -414,7 +414,7 @@ fn transformListNominalToPrimitive(env: *ModuleEnv) !void {
414414
const var_idx = @as(Var, @enumFromInt(i));
415415

416416
// Skip redirects, only process roots
417-
if (env.types.isRedirect(var_idx)) {
417+
if (!env.types.resolveVar(var_idx).is_root) {
418418
continue;
419419
}
420420

src/canonicalize/Can.zig

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ pub fn populateModuleEnvs(
251251
module_envs_map: *std.AutoHashMap(Ident.Idx, AutoImportedType),
252252
calling_module_env: *ModuleEnv,
253253
builtin_module_env: *const ModuleEnv,
254-
builtin_indices: anytype, // Has fields: bool_type, try_type, dict_type, set_type, str_type, and numeric types
254+
builtin_indices: CIR.BuiltinIndices, // Has fields: bool_type, try_type, dict_type, set_type, str_type, and numeric types
255255
) !void {
256256
const types_to_add = .{
257257
.{ "Bool", builtin_indices.bool_type },
@@ -369,7 +369,7 @@ const Self = @This();
369369
/// If parent_name is provided, creates a qualified name (e.g., "Foo.Bar")
370370
fn processTypeDeclFirstPass(
371371
self: *Self,
372-
type_decl: anytype,
372+
type_decl: std.meta.fieldInfo(AST.Statement, .type_decl).type,
373373
parent_name: ?Ident.Idx,
374374
defer_associated_blocks: bool,
375375
) std.mem.Allocator.Error!void {
@@ -924,6 +924,7 @@ fn processAssociatedItemsSecondPass(
924924
.decl => |decl| {
925925
// Canonicalize the declaration with qualified name
926926
const pattern = self.parse_ir.store.getPattern(decl.pattern);
927+
const pattern_region = self.parse_ir.tokenizedRegionToRegion(pattern.to_tokenized_region());
927928
if (pattern == .ident) {
928929
const pattern_ident_tok = pattern.ident.ident_tok;
929930
if (self.parse_ir.tokens.resolveIdentifier(pattern_ident_tok)) |decl_ident| {
@@ -942,12 +943,11 @@ fn processAssociatedItemsSecondPass(
942943
}
943944
} else {
944945
// Non-identifier patterns are not supported in associated blocks
945-
const region = self.parse_ir.tokenizedRegionToRegion(decl.region);
946946
const feature = try self.env.insertString("non-identifier patterns in associated blocks");
947947
try self.env.pushDiagnostic(Diagnostic{
948948
.not_implemented = .{
949949
.feature = feature,
950-
.region = region,
950+
.region = pattern_region,
951951
},
952952
});
953953
}
@@ -1100,19 +1100,19 @@ fn processAssociatedItemsFirstPass(
11001100
// processAssociatedItemsSecondPass will later use updatePlaceholder to replace these
11011101
const pattern = self.parse_ir.store.getPattern(decl.pattern);
11021102
if (pattern == .ident) {
1103+
const pattern_region = self.parse_ir.tokenizedRegionToRegion(pattern.to_tokenized_region());
11031104
const pattern_ident_tok = pattern.ident.ident_tok;
11041105
if (self.parse_ir.tokens.resolveIdentifier(pattern_ident_tok)) |decl_ident| {
11051106
// Build qualified name (e.g., "Foo.Bar.baz")
11061107
const qualified_idx = try self.env.insertQualifiedIdent(self.env.getIdent(parent_name), self.env.getIdent(decl_ident));
11071108

11081109
// Create placeholder pattern with qualified name
1109-
const region = self.parse_ir.tokenizedRegionToRegion(decl.region);
11101110
const placeholder_pattern = Pattern{
11111111
.assign = .{
11121112
.ident = qualified_idx,
11131113
},
11141114
};
1115-
const placeholder_pattern_idx = try self.env.addPattern(placeholder_pattern, region);
1115+
const placeholder_pattern_idx = try self.env.addPattern(placeholder_pattern, pattern_region);
11161116

11171117
// Also compute type-qualified name (e.g., "List.map")
11181118
// Re-fetch identifiers since insertQualifiedIdent may have reallocated the identifier table
@@ -1274,6 +1274,40 @@ pub fn canonicalizeFile(
12741274
try self.processTypeDeclFirstPass(type_decl, null, true); // defer associated blocks
12751275
}
12761276
},
1277+
.decl => |decl| {
1278+
// Introduce declarations for forawrd/recursive references
1279+
const pattern = self.parse_ir.store.getPattern(decl.pattern);
1280+
if (pattern == .ident) {
1281+
const pattern_region = self.parse_ir.tokenizedRegionToRegion(pattern.to_tokenized_region());
1282+
const pattern_ident_tok = pattern.ident.ident_tok;
1283+
if (self.parse_ir.tokens.resolveIdentifier(pattern_ident_tok)) |decl_ident| {
1284+
// Create placeholder pattern with qualified name
1285+
const placeholder_pattern = Pattern{
1286+
.assign = .{ .ident = decl_ident },
1287+
};
1288+
const placeholder_pattern_idx = try self.env.addPattern(placeholder_pattern, pattern_region);
1289+
1290+
// Introduce the qualified name to scope
1291+
switch (try self.scopeIntroduceInternal(self.env.gpa, .ident, decl_ident, placeholder_pattern_idx, false, true)) {
1292+
.success => {},
1293+
.shadowing_warning => |shadowed_pattern_idx| {
1294+
const original_region = self.env.store.getPatternRegion(shadowed_pattern_idx);
1295+
try self.env.pushDiagnostic(Diagnostic{ .shadowing_warning = .{
1296+
.ident = decl_ident,
1297+
.region = pattern_region,
1298+
.original_region = original_region,
1299+
} });
1300+
},
1301+
.top_level_var_error => {
1302+
// This shouldn't happen for declarations in associated blocks
1303+
},
1304+
.var_across_function_boundary => {
1305+
// This shouldn't happen for declarations in associated blocks
1306+
},
1307+
}
1308+
}
1309+
}
1310+
},
12771311
else => {
12781312
// Skip non-type-declaration statements in first pass
12791313
},
@@ -2872,23 +2906,29 @@ fn canonicalizeDeclWithAnnotation(
28722906
const trace = tracy.trace(@src());
28732907
defer trace.end();
28742908

2875-
const pattern_idx = try self.canonicalizePatternOrMalformed(decl.pattern);
2909+
// Either find the placeholder pattern insert in the first past if ident,
2910+
// otherwise canonicalize the pattern
2911+
const pattern = self.parse_ir.store.getPattern(decl.pattern);
2912+
const pattern_idx = blk: {
2913+
if (pattern == .ident) {
2914+
const pattern_ident_tok = pattern.ident.ident_tok;
2915+
if (self.parse_ir.tokens.resolveIdentifier(pattern_ident_tok)) |decl_ident| {
2916+
// Look up the placeholder pattern that was created in the first pass
2917+
const lookup_result = self.scopeLookup(.ident, decl_ident);
2918+
switch (lookup_result) {
2919+
.found => |pattern_idx| break :blk pattern_idx,
2920+
.not_found => unreachable, // Pattern should have been created in first pass
2921+
}
2922+
} else {
2923+
break :blk try self.canonicalizePatternOrMalformed(decl.pattern);
2924+
}
2925+
} else {
2926+
break :blk try self.canonicalizePatternOrMalformed(decl.pattern);
2927+
}
2928+
};
2929+
28762930
const can_expr = try self.canonicalizeExprOrMalformed(decl.body);
28772931

2878-
// Create the def entry and set def type variable to a flex var
2879-
//
2880-
// We always use a flex variable for the definition, regardless of whether there's
2881-
// an annotation. This is because:
2882-
// 1. If there's no annotation, we need a flex var for normal type inference
2883-
// 2. If there IS an annotation, we still use a flex var to avoid copying the
2884-
// annotation's type content. This is necessary because if the annotation contains
2885-
// an alias (e.g., `empty : ConsList(a)`), that alias expects its type arguments
2886-
// to live at specific memory offsets relative to the alias's own type variable.
2887-
// Copying the alias content to a different type variable would break this assumption.
2888-
// 3. During type checking, the definition's flex var will be unified with the
2889-
// annotation's type (if present) or with the inferred type from the expression
2890-
// 4. Type errors will be caught during unification if the implementation doesn't
2891-
// match the annotation
28922932
const region = self.parse_ir.tokenizedRegionToRegion(decl.region);
28932933
const def_idx = self.env.addDef(.{
28942934
.pattern = pattern_idx,
@@ -2957,7 +2997,7 @@ fn parseSingleQuoteCodepoint(
29572997

29582998
fn canonicalizeStringLike(
29592999
self: *Self,
2960-
e: anytype,
3000+
e: AST.Expr.StringLike,
29613001
is_multiline: bool,
29623002
) std.mem.Allocator.Error!CanonicalizedExpr {
29633003
// Get all the string parts
@@ -8346,6 +8386,9 @@ fn checkScopeForUnusedVariables(self: *Self, scope: *const Scope) std.mem.Alloca
83468386

83478387
// Report unused variables in sorted order
83488388
for (unused_vars.items) |unused| {
8389+
// TODO: Currently, static dispatch functions are marked as "unused"
8390+
// even if they are used. As a tmp workaround, this is commented out
8391+
83498392
try self.env.pushDiagnostic(Diagnostic{ .unused_variable = .{
83508393
.ident = unused.ident,
83518394
.region = unused.region,
@@ -9372,7 +9415,7 @@ fn findMatchingTypeIdent(self: *Self) ?Ident.Idx {
93729415

93739416
/// Expose all associated items of a type declaration (recursively for nested types)
93749417
/// This is used for type modules where all associated items are implicitly exposed
9375-
fn exposeAssociatedItems(self: *Self, parent_name: Ident.Idx, type_decl: anytype) std.mem.Allocator.Error!void {
9418+
fn exposeAssociatedItems(self: *Self, parent_name: Ident.Idx, type_decl: std.meta.fieldInfo(AST.Statement, .type_decl).type) std.mem.Allocator.Error!void {
93769419
if (type_decl.associated) |assoc| {
93779420
for (self.parse_ir.store.statementSlice(assoc.statements)) |assoc_stmt_idx| {
93789421
const assoc_stmt = self.parse_ir.store.getStatement(assoc_stmt_idx);

0 commit comments

Comments
 (0)