@@ -51,6 +51,21 @@ const TypeVarProblemKind = enum {
5151 type_var_ending_in_underscore ,
5252};
5353
54+ const ModuleFoundStatus = enum {
55+ module_was_found ,
56+ module_not_found ,
57+ };
58+
59+ const TypeBindingLocation = struct {
60+ scope_index : usize ,
61+ binding : * Scope.TypeBinding ,
62+ };
63+
64+ const TypeBindingLocationConst = struct {
65+ scope_index : usize ,
66+ binding : * const Scope.TypeBinding ,
67+ };
68+
5469const TypeVarProblem = struct {
5570 ident : Ident.Idx ,
5671 problem : TypeVarProblemKind ,
@@ -1376,7 +1391,7 @@ fn createExposedScope(
13761391
13771392 // Use a dummy statement index - we just need to track that it's exposed
13781393 const dummy_idx = @as (Statement .Idx , @enumFromInt (0 ));
1379- try self .exposed_scope .put (gpa , .type_decl , ident_idx , dummy_idx );
1394+ try self .exposed_scope .type_bindings . put (gpa , ident_idx , Scope.TypeBinding { . local_nominal = dummy_idx } );
13801395 }
13811396
13821397 // Store by text in a temporary hash map, since indices may change
@@ -1409,7 +1424,7 @@ fn createExposedScope(
14091424
14101425 // Use a dummy statement index - we just need to track that it's exposed
14111426 const dummy_idx = @as (Statement .Idx , @enumFromInt (0 ));
1412- try self .exposed_scope .put (gpa , .type_decl , ident_idx , dummy_idx );
1427+ try self .exposed_scope .type_bindings . put (gpa , ident_idx , Scope.TypeBinding { . local_nominal = dummy_idx } );
14131428 }
14141429
14151430 // Store by text in a temporary hash map, since indices may change
@@ -5634,12 +5649,56 @@ fn canonicalizeTypeAnnoBasicType(
56345649 .base = .{ .builtin = builtin_type },
56355650 } }, region );
56365651 } else {
5637- // If it's not a builtin, look up in scope
5638- if (self .scopeLookupTypeDecl (type_name_ident )) | type_decl_idx | {
5639- return try self .env .addTypeAnno (CIR.TypeAnno { .lookup = .{
5640- .name = type_name_ident ,
5641- .base = .{ .local = .{ .decl_idx = type_decl_idx } },
5642- } }, region );
5652+ // If it's not a builtin, look up in scope using unified type bindings
5653+ if (self .scopeLookupTypeBinding (type_name_ident )) | binding_location | {
5654+ const binding = binding_location .binding .* ;
5655+ return switch (binding ) {
5656+ .local_nominal = > | stmt | try self .env .addTypeAnno (CIR.TypeAnno { .lookup = .{
5657+ .name = type_name_ident ,
5658+ .base = .{ .local = .{ .decl_idx = stmt } },
5659+ } }, region ),
5660+ .local_alias = > | stmt | try self .env .addTypeAnno (CIR.TypeAnno { .lookup = .{
5661+ .name = type_name_ident ,
5662+ .base = .{ .local = .{ .decl_idx = stmt } },
5663+ } }, region ),
5664+ .associated_nominal = > | stmt | try self .env .addTypeAnno (CIR.TypeAnno { .lookup = .{
5665+ .name = type_name_ident ,
5666+ .base = .{ .local = .{ .decl_idx = stmt } },
5667+ } }, region ),
5668+ .external_nominal = > | external | blk : {
5669+ const import_idx = external .import_idx orelse {
5670+ break :blk try self .env .pushMalformed (TypeAnno .Idx , Diagnostic { .module_not_imported = .{
5671+ .module_name = external .module_ident ,
5672+ .region = type_name_region ,
5673+ } });
5674+ };
5675+
5676+ const target_node_idx = external .target_node_idx orelse {
5677+ // Check if the module was not found
5678+ if (external .module_not_found ) {
5679+ break :blk try self .env .pushMalformed (TypeAnno .Idx , Diagnostic { .type_from_missing_module = .{
5680+ .module_name = external .module_ident ,
5681+ .type_name = type_name_ident ,
5682+ .region = type_name_region ,
5683+ } });
5684+ } else {
5685+ break :blk try self .env .pushMalformed (TypeAnno .Idx , Diagnostic { .type_not_exposed = .{
5686+ .module_name = external .module_ident ,
5687+ .type_name = type_name_ident ,
5688+ .region = type_name_region ,
5689+ } });
5690+ }
5691+ };
5692+
5693+ break :blk try self .env .addTypeAnno (CIR.TypeAnno { .lookup = .{
5694+ .name = type_name_ident ,
5695+ .base = .{ .external = .{
5696+ .module_idx = import_idx ,
5697+ .target_node_idx = target_node_idx ,
5698+ } },
5699+ } }, region );
5700+ },
5701+ };
56435702 }
56445703
56455704 // Check if this is an auto-imported type from module_envs
@@ -7316,12 +7375,14 @@ fn scopeIntroduceTypeDecl(
73167375 while (i > 0 ) {
73177376 i -= 1 ;
73187377 const scope = & self .scopes .items [i ];
7319- switch (scope .lookupTypeDecl (name_ident )) {
7320- .found = > | type_decl_idx | {
7321- shadowed_in_parent = type_decl_idx ;
7322- break ;
7323- },
7324- .not_found = > continue ,
7378+ if (scope .type_bindings .get (name_ident )) | binding | {
7379+ shadowed_in_parent = switch (binding ) {
7380+ .local_nominal = > | stmt | stmt ,
7381+ .local_alias = > | stmt | stmt ,
7382+ .associated_nominal = > | stmt | stmt ,
7383+ .external_nominal = > null ,
7384+ };
7385+ if (shadowed_in_parent ) | _ | break ;
73257386 }
73267387 }
73277388 }
@@ -7427,15 +7488,40 @@ fn scopeLookupTypeDecl(self: *Self, ident_idx: Ident.Idx) ?Statement.Idx {
74277488 i -= 1 ;
74287489 const scope = & self .scopes .items [i ];
74297490
7430- // Check for type aliases (unqualified names in associated blocks)
7431- if (scope .lookupTypeAlias (ident_idx )) | aliased_decl | {
7432- return aliased_decl ;
7491+ // Check unified type bindings
7492+ if (scope .type_bindings .get (ident_idx )) | binding | {
7493+ return switch (binding ) {
7494+ .local_nominal = > | stmt | stmt ,
7495+ .local_alias = > | stmt | stmt ,
7496+ .associated_nominal = > | stmt | stmt ,
7497+ .external_nominal = > null , // External types don't have local Statement.Idx
7498+ };
74337499 }
7500+ }
74347501
7435- // Check regular type declarations
7436- switch (scope .lookupTypeDecl (ident_idx )) {
7437- .found = > | type_decl_idx | return type_decl_idx ,
7438- .not_found = > continue ,
7502+ return null ;
7503+ }
7504+
7505+ fn scopeLookupTypeBinding (self : * Self , ident_idx : Ident.Idx ) ? TypeBindingLocation {
7506+ var i = self .scopes .items .len ;
7507+ while (i > 0 ) {
7508+ i -= 1 ;
7509+ const scope = & self .scopes .items [i ];
7510+ if (scope .type_bindings .getPtr (ident_idx )) | binding_ptr | {
7511+ return TypeBindingLocation { .scope_index = i , .binding = binding_ptr };
7512+ }
7513+ }
7514+
7515+ return null ;
7516+ }
7517+
7518+ fn scopeLookupTypeBindingConst (self : * const Self , ident_idx : Ident.Idx ) ? TypeBindingLocationConst {
7519+ var i = self .scopes .items .len ;
7520+ while (i > 0 ) {
7521+ i -= 1 ;
7522+ const scope = & self .scopes .items [i ];
7523+ if (scope .type_bindings .getPtr (ident_idx )) | binding_ptr | {
7524+ return TypeBindingLocationConst { .scope_index = i , .binding = binding_ptr };
74397525 }
74407526 }
74417527
@@ -7581,6 +7667,30 @@ pub fn scopeIntroduceExposedItem(self: *Self, item_name: Ident.Idx, item_info: S
75817667 }
75827668}
75837669
7670+ /// Set an external type binding for an imported nominal type
7671+ fn setExternalTypeBinding (
7672+ self : * Self ,
7673+ scope : * Scope ,
7674+ local_ident : Ident.Idx ,
7675+ module_ident : Ident.Idx ,
7676+ original_ident : Ident.Idx ,
7677+ target_node_idx : ? u16 ,
7678+ module_import_idx : CIR.Import.Idx ,
7679+ origin_region : Region ,
7680+ module_found_status : ModuleFoundStatus ,
7681+ ) ! void {
7682+ try scope .type_bindings .put (self .env .gpa , local_ident , Scope.TypeBinding {
7683+ .external_nominal = .{
7684+ .module_ident = module_ident ,
7685+ .original_ident = original_ident ,
7686+ .target_node_idx = target_node_idx ,
7687+ .import_idx = module_import_idx ,
7688+ .origin_region = origin_region ,
7689+ .module_not_found = module_found_status == .module_not_found ,
7690+ },
7691+ });
7692+ }
7693+
75847694/// Look up an exposed item in parent scopes (for shadowing detection)
75857695fn scopeLookupExposedItemInParentScopes (self : * const Self , item_name : Ident.Idx ) ? Scope.ExposedItemInfo {
75867696 // Search from second-innermost to outermost scope (excluding current scope)
0 commit comments