ir: AST-callee param typing pins the callee module's source context

The two not-yet-lowered fn_ast_map paths in resolveCallParamTypes (the
qualified `ns.f(...)` call and the plain free-fn call) resolved each
param type in the CALL SITE's visibility context, so a namespaced
import's param type that is bare-visible only in its own module
diagnosed "type 'X' is not visible" at calls whose caller never names
the type bare. Route both through the E4 source pin
(resolveParamTypeInSource), as the method paths already do.

A generic callee's bare T leaves are not nominal names in that module:
astCalleeParamTypes installs the call's inferred $T -> concrete
bindings (the one binding builder) before resolving, or the pin turns
the unbound leaf into "unknown type 'T'" (regressed examples/0129
through math/scalar.sx's clamp).

Regression: examples/0840 (namespaced fn with a module-bare param
type; failed "not visible" pre-pin).
This commit is contained in:
agra
2026-06-12 07:41:18 +03:00
parent 7f2b8b5cde
commit 5b18048abb
6 changed files with 50 additions and 10 deletions

View File

@@ -0,0 +1,13 @@
// A namespaced import's fn param type (`Failure`) is bare-visible only
// inside its own module. Typing this call's args resolves each param in
// the CALLEE module's context — resolved at the call site, the bare leaf
// is namespaced-only and the call diagnoses "type 'Failure' is not
// visible" even though the caller never names it bare.
#import "modules/std.sx";
m :: #import "0840-modules-imported-fn-param-type-source-pin/m.sx";
main :: () {
f : m.Failure = .{ code = 7, message = "boom" };
print("{}\n", m.describe(f));
}

View File

@@ -0,0 +1,10 @@
#import "modules/std.sx";
Failure :: struct {
code: s64 = 0;
message: string = "";
}
describe :: (f: Failure) -> s64 {
return f.code;
}

View File

@@ -2128,6 +2128,28 @@ pub fn userParamTypes(self: *Lowering, func: *const Function) []TypeId {
return types_list.items;
}
/// Param types of a not-yet-lowered AST callee for arg target-typing,
/// resolved in the callee's own module context (the E4 source pin — see
/// `resolveParamTypeInSource`). A generic callee's bare `T` leaves mean
/// nothing as nominal names in that module: without this call's inferred
/// `$T → concrete` bindings the pin would resolve `T` as an undeclared
/// type in a non-main module and diagnose it unknown.
fn astCalleeParamTypes(self: *Lowering, fd: *const ast.FnDecl, args: []const *const Node) []const TypeId {
const saved_bindings = self.type_bindings;
defer self.type_bindings = saved_bindings;
var gbindings: ?std.StringHashMap(TypeId) = null;
defer if (gbindings) |*gb| gb.deinit();
if (fd.type_params.len > 0) {
gbindings = self.genericResolver().buildTypeBindings(fd, args);
self.type_bindings = gbindings.?;
}
var types_list = std.ArrayList(TypeId).empty;
for (fd.params) |p| {
types_list.append(self.alloc, self.resolveParamTypeInSource(fd.body.source_file, &p)) catch unreachable;
}
return types_list.items;
}
pub fn resolveCallParamTypes(self: *Lowering, c: *const ast.Call, sel_author: ?*SelectedFunc) []const TypeId {
// Method calls: obj.method(args) — resolve param types from the method signature,
// skipping the first param (self) since it's prepended later.
@@ -2155,11 +2177,7 @@ pub fn resolveCallParamTypes(self: *Lowering, c: *const ast.Call, sel_author: ?*
return self.userParamTypes(func);
}
if (self.program_index.fn_ast_map.get(qualified)) |fd| {
var types_list = std.ArrayList(TypeId).empty;
for (fd.params) |p| {
types_list.append(self.alloc, self.resolveParamType(&p)) catch unreachable;
}
return types_list.items;
return astCalleeParamTypes(self, fd, c.args);
}
}
}
@@ -2301,11 +2319,7 @@ pub fn resolveCallParamTypes(self: *Lowering, c: *const ast.Call, sel_author: ?*
// Check AST map for function signatures
if (self.program_index.fn_ast_map.get(name)) |fd| {
var types_list = std.ArrayList(TypeId).empty;
for (fd.params) |p| {
types_list.append(self.alloc, self.resolveParamType(&p)) catch unreachable;
}
return types_list.items;
return astCalleeParamTypes(self, fd, c.args);
}
// Check global function pointer variables (quiet author-aware lookup —