refactor(ffi-linkage): Phase 9.2b — rename runtime-class fns + state → runtime_* / is_reference
The runtime-class object-model identifiers (Decision 5): parse/lower/find/resolve/ register/stamp fns Foreign→Runtime (parseRuntimeClassDecl, lowerRuntimeMethodCall, findRuntimeMethodInChain, resolveRuntimeMethodReturnType, registerRuntimeClassDecl, runtimeClassStructType, runtimeKindForOffset, …); state foreign_class_map→ runtime_class_map, current_foreign_class/_method→current_runtime_*, the foreign_class_decl union variant→runtime_class_decl, foreign_method/static/instance/ class→runtime_*; and the reference-vs-define flag is_foreign→is_reference (+ is_foreign_eff→is_reference_eff) now that it only lives on RuntimeClassDecl. Snapshot-neutral; suite green (646/444). Remaining 9.2: the foreign_path family (coupled .sx hooks: jni_main_foreign_path_at spans build.sx/bundle.sx/compiler_hooks.zig/specs.md) + the extern-ref validators (checkForeignRefs etc. → Extern, linkage not runtime) + bare 'foreign' comments.
This commit is contained in:
@@ -233,7 +233,7 @@ pub fn lowerJniCall(self: *Lowering, fic: *const ast.FfiIntrinsicCall) Ref {
|
||||
/// JNI runtimes lower directly to `jni_msg_send` with a descriptor derived
|
||||
/// from the method's sx signature; Obj-C / Swift runtimes are deferred to
|
||||
/// Phase 3/4 and currently surface a clear diagnostic.
|
||||
pub fn lowerForeignMethodCall(
|
||||
pub fn lowerRuntimeMethodCall(
|
||||
self: *Lowering,
|
||||
fcd: *const ast.RuntimeClassDecl,
|
||||
method_name: []const u8,
|
||||
@@ -250,7 +250,7 @@ pub fn lowerForeignMethodCall(
|
||||
// still used for `*Self` substitution at the dispatch site
|
||||
// — the inherited method's *Self should resolve to the
|
||||
// child receiver, not the parent.
|
||||
const found = self.findForeignMethodInChain(fcd, method_name) orelse {
|
||||
const found = self.findRuntimeMethodInChain(fcd, method_name) orelse {
|
||||
if (self.diagnostics) |d| {
|
||||
d.addFmt(.err, span, "no method '{s}' on foreign class '{s}' (or any `#extends` ancestor)", .{ method_name, fcd.name });
|
||||
}
|
||||
@@ -270,7 +270,7 @@ pub fn lowerForeignMethodCall(
|
||||
if (fcd.runtime == .objc_class or fcd.runtime == .objc_protocol) {
|
||||
return self.lowerObjcMethodCall(fcd, method, target, method_args, span);
|
||||
}
|
||||
if (!fcd.is_foreign) {
|
||||
if (!fcd.is_reference) {
|
||||
if (self.diagnostics) |d| {
|
||||
d.addFmt(.err, span, "sx-defined classes on non-Obj-C runtimes can't yet be dispatched into (class '{s}', runtime '{s}')", .{ fcd.name, @tagName(fcd.runtime) });
|
||||
}
|
||||
@@ -295,7 +295,7 @@ pub fn lowerForeignMethodCall(
|
||||
// resolve `*Foo` cross-class refs to their foreign paths.
|
||||
var registry = jni_descriptor.ClassRegistry.init(self.alloc);
|
||||
defer registry.deinit();
|
||||
var it = self.program_index.foreign_class_map.iterator();
|
||||
var it = self.program_index.runtime_class_map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
registry.put(entry.key_ptr.*, entry.value_ptr.*.foreign_path) catch {};
|
||||
}
|
||||
@@ -357,33 +357,33 @@ pub fn lowerForeignMethodCall(
|
||||
/// with the foreign class's own struct type. Without this substitution
|
||||
/// chained calls like `Cls.alloc().init()` see the inner result as a
|
||||
/// fictitious `Self` struct and the next dispatch lookup fails.
|
||||
pub fn resolveForeignClassMemberType(
|
||||
pub fn resolveRuntimeClassMemberType(
|
||||
self: *Lowering,
|
||||
fcd: *const ast.RuntimeClassDecl,
|
||||
type_node: *const ast.Node,
|
||||
) TypeId {
|
||||
if (type_node.data == .type_expr and std.mem.eql(u8, type_node.data.type_expr.name, "Self")) {
|
||||
return self.foreignClassStructType(fcd);
|
||||
return self.runtimeClassStructType(fcd);
|
||||
}
|
||||
if (type_node.data == .pointer_type_expr) {
|
||||
const pt = type_node.data.pointer_type_expr;
|
||||
if (pt.pointee_type.data == .type_expr and std.mem.eql(u8, pt.pointee_type.data.type_expr.name, "Self")) {
|
||||
return self.module.types.ptrTo(self.foreignClassStructType(fcd));
|
||||
return self.module.types.ptrTo(self.runtimeClassStructType(fcd));
|
||||
}
|
||||
}
|
||||
return self.resolveType(type_node);
|
||||
}
|
||||
|
||||
pub fn resolveForeignMethodReturnType(
|
||||
pub fn resolveRuntimeMethodReturnType(
|
||||
self: *Lowering,
|
||||
fcd: *const ast.RuntimeClassDecl,
|
||||
method: ast.RuntimeMethodDecl,
|
||||
) TypeId {
|
||||
const rt = method.return_type orelse return .void;
|
||||
return self.resolveForeignClassMemberType(fcd, rt);
|
||||
return self.resolveRuntimeClassMemberType(fcd, rt);
|
||||
}
|
||||
|
||||
pub fn foreignClassStructType(self: *Lowering, fcd: *const ast.RuntimeClassDecl) TypeId {
|
||||
pub fn runtimeClassStructType(self: *Lowering, fcd: *const ast.RuntimeClassDecl) TypeId {
|
||||
const name_id = self.module.types.internString(fcd.name);
|
||||
if (self.module.types.findByName(name_id)) |existing| return existing;
|
||||
return self.module.types.intern(.{ .@"struct" = .{ .name = name_id, .fields = &.{} } });
|
||||
@@ -434,7 +434,7 @@ pub fn lowerObjcMethodCall(
|
||||
}
|
||||
}
|
||||
|
||||
const ret_ty = self.resolveForeignMethodReturnType(fcd, method);
|
||||
const ret_ty = self.resolveRuntimeMethodReturnType(fcd, method);
|
||||
|
||||
// Cache the SEL slot per (selector-string, module) like
|
||||
// `#objc_call` does. The mangling produces the literal selector
|
||||
@@ -489,7 +489,7 @@ pub fn lowerObjcStaticCall(
|
||||
}
|
||||
}
|
||||
|
||||
const ret_ty = self.resolveForeignMethodReturnType(fcd, method);
|
||||
const ret_ty = self.resolveRuntimeMethodReturnType(fcd, method);
|
||||
|
||||
const vptr_ty = self.module.types.ptrTo(.void);
|
||||
|
||||
@@ -505,7 +505,7 @@ pub fn lowerObjcStaticCall(
|
||||
// instead of going through `objc_msgSend` (which would land in the
|
||||
// +alloc IMP and use `__sx_default_context.allocator`). This honors
|
||||
// a surrounding `push Context.{ allocator = ... }`.
|
||||
if (!fcd.is_foreign and
|
||||
if (!fcd.is_reference and
|
||||
fcd.runtime == .objc_class and
|
||||
method_args.len == 0 and
|
||||
std.mem.eql(u8, method.name, "alloc"))
|
||||
@@ -568,7 +568,7 @@ pub fn lowerObjcStaticCall(
|
||||
/// user can use `#jni_static_call(T)(class, "name", sig, args...)`
|
||||
/// for those. Constructor is the common case for #jni_main bodies
|
||||
/// that need to instantiate Android classes (SurfaceView, etc.).
|
||||
pub fn lowerForeignStaticCall(
|
||||
pub fn lowerRuntimeStaticCall(
|
||||
self: *Lowering,
|
||||
fcd: *const ast.RuntimeClassDecl,
|
||||
method: ast.RuntimeMethodDecl,
|
||||
@@ -600,7 +600,7 @@ pub fn lowerForeignStaticCall(
|
||||
// Build class registry snapshot for `*Foo` cross-class refs.
|
||||
var registry = jni_descriptor.ClassRegistry.init(self.alloc);
|
||||
defer registry.deinit();
|
||||
var it = self.program_index.foreign_class_map.iterator();
|
||||
var it = self.program_index.runtime_class_map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
registry.put(entry.key_ptr.*, entry.value_ptr.*.foreign_path) catch {};
|
||||
}
|
||||
@@ -679,7 +679,7 @@ pub fn lowerSuperCall(
|
||||
method_args: []const Ref,
|
||||
span: ast.Span,
|
||||
) Ref {
|
||||
const fcd = self.current_foreign_class orelse {
|
||||
const fcd = self.current_runtime_class orelse {
|
||||
if (self.diagnostics) |d| d.addFmt(.err, span, "'super' is only valid inside a `#jni_class` method body", .{});
|
||||
return Ref.none;
|
||||
};
|
||||
@@ -689,7 +689,7 @@ pub fn lowerSuperCall(
|
||||
var parent_path: []const u8 = "android/app/Activity";
|
||||
for (fcd.members) |m| switch (m) {
|
||||
.extends => |alias| {
|
||||
if (self.program_index.foreign_class_map.get(alias)) |parent_fcd| {
|
||||
if (self.program_index.runtime_class_map.get(alias)) |parent_fcd| {
|
||||
parent_path = parent_fcd.foreign_path;
|
||||
} else {
|
||||
parent_path = alias;
|
||||
@@ -704,14 +704,14 @@ pub fn lowerSuperCall(
|
||||
// the parent class to be declared via `#foreign #jni_class`.
|
||||
var descriptor: []const u8 = "";
|
||||
var resolved_method: ?ast.RuntimeMethodDecl = null;
|
||||
if (self.current_foreign_method) |em| {
|
||||
if (self.current_runtime_method) |em| {
|
||||
if (std.mem.eql(u8, em.name, method_name)) {
|
||||
resolved_method = em;
|
||||
}
|
||||
}
|
||||
if (resolved_method == null) {
|
||||
const parent_fcd = blk: for (fcd.members) |m| switch (m) {
|
||||
.extends => |alias| if (self.program_index.foreign_class_map.get(alias)) |pf| break :blk pf else continue,
|
||||
.extends => |alias| if (self.program_index.runtime_class_map.get(alias)) |pf| break :blk pf else continue,
|
||||
else => {},
|
||||
} else null;
|
||||
if (parent_fcd) |pf| {
|
||||
@@ -733,7 +733,7 @@ pub fn lowerSuperCall(
|
||||
// for `*Self` resolution).
|
||||
var registry = jni_descriptor.ClassRegistry.init(self.alloc);
|
||||
defer registry.deinit();
|
||||
var it = self.program_index.foreign_class_map.iterator();
|
||||
var it = self.program_index.runtime_class_map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
registry.put(entry.key_ptr.*, entry.value_ptr.*.foreign_path) catch {};
|
||||
}
|
||||
@@ -781,7 +781,7 @@ pub fn lowerSuperCall(
|
||||
// ── Foreign-class registration ──────────────────────────────────
|
||||
|
||||
/// Register a foreign-class declaration. The alias goes into
|
||||
/// `foreign_class_map` for method-dispatch lookup. The underlying
|
||||
/// `runtime_class_map` for method-dispatch lookup. The underlying
|
||||
/// type (e.g. `*Activity`) is resolved via the existing struct
|
||||
/// fallback in `type_bridge.resolveTypeName` (which interns unknown
|
||||
/// named types as 0-field structs).
|
||||
@@ -792,9 +792,9 @@ pub fn lowerSuperCall(
|
||||
/// under qualified names `<ClassName>.<methodName>`. Lazy lowering
|
||||
/// then handles the body via the standard path; `*Self` is
|
||||
/// substituted to `*<ClassName>State` during body lowering (M1.2 A.2b).
|
||||
pub fn registerForeignClassDecl(self: *Lowering, fcd: *const ast.RuntimeClassDecl) void {
|
||||
self.program_index.foreign_class_map.put(fcd.name, fcd) catch {};
|
||||
if (!fcd.is_foreign and fcd.runtime == .objc_class) {
|
||||
pub fn registerRuntimeClassDecl(self: *Lowering, fcd: *const ast.RuntimeClassDecl) void {
|
||||
self.program_index.runtime_class_map.put(fcd.name, fcd) catch {};
|
||||
if (!fcd.is_reference and fcd.runtime == .objc_class) {
|
||||
if (self.module.lookupObjcDefinedClass(fcd.name) == null) {
|
||||
self.module.appendObjcDefinedClass(fcd.name, fcd);
|
||||
// M2.3 — resolve the `#extends` alias to the actual
|
||||
@@ -828,8 +828,8 @@ pub fn registerForeignClassDecl(self: *Lowering, fcd: *const ast.RuntimeClassDec
|
||||
pub fn resolveObjcParentName(self: *Lowering, fcd: *const ast.RuntimeClassDecl) []const u8 {
|
||||
for (fcd.members) |m| switch (m) {
|
||||
.extends => |alias| {
|
||||
if (self.program_index.foreign_class_map.get(alias)) |parent_fcd| {
|
||||
if (parent_fcd.is_foreign) return parent_fcd.foreign_path;
|
||||
if (self.program_index.runtime_class_map.get(alias)) |parent_fcd| {
|
||||
if (parent_fcd.is_reference) return parent_fcd.foreign_path;
|
||||
// Sx-defined parent — its alias IS its Obj-C name.
|
||||
return parent_fcd.name;
|
||||
}
|
||||
@@ -883,11 +883,11 @@ pub fn declareObjcDefinedClassGlobal(self: *Lowering, class_name: []const u8) vo
|
||||
/// (M1.2 A.4b.iii). Bodyless declarations are skipped — they
|
||||
/// reference inherited / external methods, not sx-side bodies.
|
||||
pub fn registerObjcDefinedClassMethods(self: *Lowering, fcd: *const ast.RuntimeClassDecl) void {
|
||||
// Set current_foreign_class so `*Self` substitutions in
|
||||
// Set current_runtime_class so `*Self` substitutions in
|
||||
// declareFunction's type resolution find the state struct.
|
||||
const saved = self.current_foreign_class;
|
||||
self.current_foreign_class = fcd;
|
||||
defer self.current_foreign_class = saved;
|
||||
const saved = self.current_runtime_class;
|
||||
self.current_runtime_class = fcd;
|
||||
defer self.current_runtime_class = saved;
|
||||
|
||||
var method_infos = std.ArrayList(Module.ObjcDefinedMethodEntry).empty;
|
||||
|
||||
@@ -969,7 +969,7 @@ pub fn synthesizeFnDeclFromObjcMethod(self: *Lowering, method: ast.RuntimeMethod
|
||||
/// If `name` matches an sx-defined `#objc_class`'s qualified-method
|
||||
/// pattern (`<ClassName>.<methodName>`), return the class's
|
||||
/// RuntimeClassDecl. Used by `lowerFunction` to set
|
||||
/// `current_foreign_class` so `*Self` resolves to the state struct
|
||||
/// `current_runtime_class` so `*Self` resolves to the state struct
|
||||
/// during body lowering.
|
||||
pub fn lookupObjcDefinedClassForMethod(self: *Lowering, name: []const u8) ?*const ast.RuntimeClassDecl {
|
||||
const dot = std.mem.indexOf(u8, name, ".") orelse return null;
|
||||
@@ -1013,15 +1013,15 @@ pub fn getJniEnvTlFids(self: *Lowering) struct { get: FuncId, set: FuncId } {
|
||||
/// scan/lower already handles bare-name registration; this only adds the
|
||||
/// qualified-name entry, so cross-class refs in method signatures
|
||||
/// (`*View` → bare lookup) still work.
|
||||
pub fn registerNamespacedForeignClasses(self: *Lowering, ns: ast.NamespaceDecl) void {
|
||||
pub fn registerNamespacedRuntimeClasses(self: *Lowering, ns: ast.NamespaceDecl) void {
|
||||
for (ns.decls) |inner| {
|
||||
if (inner.data == .foreign_class_decl) {
|
||||
const fcd = &inner.data.foreign_class_decl;
|
||||
if (inner.data == .runtime_class_decl) {
|
||||
const fcd = &inner.data.runtime_class_decl;
|
||||
const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ ns.name, fcd.name }) catch fcd.name;
|
||||
self.program_index.foreign_class_map.put(qualified, fcd) catch {};
|
||||
self.program_index.runtime_class_map.put(qualified, fcd) catch {};
|
||||
} else if (inner.data == .namespace_decl) {
|
||||
// Nested namespaces — qualify with both prefixes.
|
||||
self.registerNamespacedForeignClasses(inner.data.namespace_decl);
|
||||
self.registerNamespacedRuntimeClasses(inner.data.namespace_decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1033,11 +1033,11 @@ pub fn synthesizeJniMainStubs(self: *Lowering) void {
|
||||
var seen = std.StringHashMap(void).init(self.alloc);
|
||||
defer seen.deinit();
|
||||
|
||||
var it = self.program_index.foreign_class_map.iterator();
|
||||
var it = self.program_index.runtime_class_map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const fcd = entry.value_ptr.*;
|
||||
if (!fcd.is_main) continue;
|
||||
if (fcd.is_foreign) continue;
|
||||
if (fcd.is_reference) continue;
|
||||
if (fcd.runtime != .jni_class) continue;
|
||||
if (seen.contains(fcd.foreign_path)) continue;
|
||||
seen.put(fcd.foreign_path, {}) catch continue;
|
||||
@@ -1121,13 +1121,13 @@ pub fn synthesizeJniMainStub(self: *Lowering, fcd: *const ast.RuntimeClassDecl,
|
||||
// Record method context so `super.method(args)` inside the body
|
||||
// can find the parent class (via `#extends`) and the method's
|
||||
// signature.
|
||||
const saved_fcd = self.current_foreign_class;
|
||||
const saved_method = self.current_foreign_method;
|
||||
self.current_foreign_class = fcd;
|
||||
self.current_foreign_method = md;
|
||||
const saved_fcd = self.current_runtime_class;
|
||||
const saved_method = self.current_runtime_method;
|
||||
self.current_runtime_class = fcd;
|
||||
self.current_runtime_method = md;
|
||||
defer {
|
||||
self.current_foreign_class = saved_fcd;
|
||||
self.current_foreign_method = saved_method;
|
||||
self.current_runtime_class = saved_fcd;
|
||||
self.current_runtime_method = saved_method;
|
||||
}
|
||||
|
||||
// JNI native methods are C-callable entry points — install the
|
||||
|
||||
Reference in New Issue
Block a user