Make Builtin itself un-importable

This commit is contained in:
Richard Feldman 2025-11-07 23:49:31 -05:00
parent 7bd9d645b9
commit 2a0410ec1d
No known key found for this signature in database
4 changed files with 79 additions and 36 deletions

View file

@ -305,27 +305,17 @@ pub fn setupAutoImportedBuiltinTypes(
if (envs_map.get(type_ident)) |type_entry| {
const module_env = type_entry.env;
// Create an import for the parent Builtin module (only once, shared across all types)
// Create an import entry for the parent Builtin module
// This is needed for type bindings to reference, but we do NOT add it to
// import_indices or scope - "Builtin" should not be directly importable!
const builtin_module_name = module_env.module_name;
// Check if we already have this import in our indices
const is_new_import = !self.import_indices.contains(builtin_module_name);
const module_import_idx = try self.env.imports.getOrPut(
gpa,
self.env.common.getStringStore(),
builtin_module_name,
);
if (is_new_import) {
// Add to import_indices so getOrCreateAutoImport can find it
try self.import_indices.put(gpa, builtin_module_name, module_import_idx);
// Also add to current scope so scopeLookupImportedModule can find it
// This ensures consistency with getOrCreateAutoImport
_ = try current_scope.introduceImportedModule(gpa, builtin_module_name, module_import_idx);
}
// Get target_node_idx from statement_idx
const target_node_idx = if (type_entry.statement_idx) |stmt_idx|
module_env.getExposedNodeIndexByStatementIdx(stmt_idx)

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

@ -216,21 +216,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});
}
}
@ -332,22 +332,14 @@ 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,60 @@
//! 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)))");
}