Skip to content

Commit 6a1190c

Browse files
authored
fix: detect if wrapper type receiver has a pointer type and unwrap (#97)
See #91 and 4e3fc0 and 142201 ``` go test -timeout 30s -run ^TestCompliance/wrapper_slice_append$ ./compiler ``` Fixes: #96 Signed-off-by: Christian Stewart <christian@aperture.us>
1 parent 142201c commit 6a1190c

File tree

12 files changed

+91
-294
lines changed

12 files changed

+91
-294
lines changed

compiler/expr-call.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,47 @@ func (c *GoToTSCompiler) writeWrapperTypeMethodCall(exp *ast.CallExpr, selectorE
349349
c.tsw.WriteLiterally(selectorExpr.Sel.Name)
350350
c.tsw.WriteLiterally("(")
351351

352-
// First argument is the receiver
353-
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
354-
return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
352+
// Write the receiver (the object the method is called on)
353+
// For pointer receiver methods, we need to pass the VarRef instead of the value
354+
receiverNeedsVarRef := false
355+
356+
// Check if the method has a pointer receiver by looking at the method signature
357+
if selection := c.pkg.TypesInfo.Selections[selectorExpr]; selection != nil {
358+
if methodObj := selection.Obj(); methodObj != nil {
359+
if methodFunc, ok := methodObj.(*types.Func); ok {
360+
if sig, ok := methodFunc.Type().(*types.Signature); ok && sig != nil {
361+
if recv := sig.Recv(); recv != nil {
362+
if _, isPointer := recv.Type().(*types.Pointer); isPointer {
363+
receiverNeedsVarRef = true
364+
}
365+
}
366+
}
367+
}
368+
}
369+
}
370+
371+
if receiverNeedsVarRef {
372+
// For pointer receivers, we need to pass the VarRef
373+
// Convert p.field to p._fields.field
374+
if selExpr, ok := selectorExpr.X.(*ast.SelectorExpr); ok {
375+
if baseIdent, ok := selExpr.X.(*ast.Ident); ok {
376+
c.tsw.WriteLiterally(baseIdent.Name)
377+
c.tsw.WriteLiterally("._fields.")
378+
c.tsw.WriteLiterally(selExpr.Sel.Name)
379+
} else {
380+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
381+
return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
382+
}
383+
}
384+
} else {
385+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
386+
return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
387+
}
388+
}
389+
} else {
390+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
391+
return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
392+
}
355393
}
356394

357395
// Add other arguments

compiler/spec.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,10 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
376376
}
377377
recvField := funcDecl.Recv.List[0]
378378
recvType := recvField.Type
379+
isPointerReceiver := false
379380
if starExpr, ok := recvType.(*ast.StarExpr); ok {
380381
recvType = starExpr.X
382+
isPointerReceiver = true
381383
}
382384

383385
// Check for both simple identifiers (FileMode) and generic types (FileMode[T])
@@ -391,12 +393,7 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
391393
}
392394

393395
if recvTypeName == className {
394-
if !isInsideFunction {
395-
c.tsw.WriteLiterally("export ")
396-
}
397-
398-
// Generate function signature: export function TypeName_MethodName(receiver: TypeName, ...args): ReturnType
399-
c.tsw.WriteLiterally("function ")
396+
c.tsw.WriteLiterally("export function ")
400397
c.tsw.WriteLiterally(className)
401398
c.tsw.WriteLiterally("_")
402399
c.tsw.WriteLiterally(funcDecl.Name.Name)
@@ -413,7 +410,15 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
413410
}
414411
c.tsw.WriteLiterally(receiverParamName)
415412
c.tsw.WriteLiterally(": ")
416-
c.tsw.WriteLiterally(className)
413+
414+
// For pointer receivers, use VarRef<T>
415+
if isPointerReceiver {
416+
c.tsw.WriteLiterally("$.VarRef<")
417+
c.tsw.WriteLiterally(className)
418+
c.tsw.WriteLiterally(">")
419+
} else {
420+
c.tsw.WriteLiterally(className)
421+
}
417422

418423
// Add other parameters
419424
if funcDecl.Type.Params != nil && len(funcDecl.Type.Params.List) > 0 {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export { ByName_Len, ByName_Less, ByName_Swap } from "./named_slice_wrapper.gs.js"
12
export type { ByName } from "./named_slice_wrapper.gs.js"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
export { MyFileMode_String } from "./named_type_wrapper.gs.js"
12
export { FileStatus } from "./named_type_wrapper.gs.js"
23
export type { MyFileMode } from "./named_type_wrapper.gs.js"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export { CustomString_Length, CustomString_Upper, FileMode_Add, FileMode_IsZero, FileMode_String } from "./type_declaration_receiver.gs.js"
12
export type { CustomString, FileMode } from "./type_declaration_receiver.gs.js"

compliance/tests/wrapper_slice_append/actual.log

Lines changed: 0 additions & 1 deletion
This file was deleted.

compliance/tests/wrapper_slice_append/errlist/errlist.gs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as $ from "@goscript/builtin/index.js";
55

66
export type ErrorList = $.Slice<string>;
77

8-
export function ErrorList_Add(p: ErrorList, msg: string): void {
8+
export function ErrorList_Add(p: $.VarRef<ErrorList>, msg: string): void {
99
p!.value = $.append(p!.value, msg)
1010
}
1111

compliance/tests/wrapper_slice_append/skip-test

Whitespace-only changes.

compliance/tests/wrapper_slice_append/wrapper_slice_append.gs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class parser {
5454
export async function main(): Promise<void> {
5555
let p: parser = new parser()
5656
// this Add method does not work:
57-
errlist.ErrorList_Add(p.errors, "error")
57+
errlist.ErrorList_Add(p._fields.errors, "error")
5858
console.log(p.errors![0])
5959

6060
// but it does work for a struct type:
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export { TestFileMode, TestMyMode } from "./wrapper_type_args.gs.js"
1+
export { MyMode_IsExecutable, MyMode_String, TestFileMode, TestMyMode } from "./wrapper_type_args.gs.js"
22
export { MyDir } from "./wrapper_type_args.gs.js"
33
export type { DirInterface, MyMode } from "./wrapper_type_args.gs.js"

0 commit comments

Comments
 (0)