Skip to content

Commit 04fb07c

Browse files
committed
fix: use fully qualified struct and interface names
Signed-off-by: Christian Stewart <christian@aperture.us>
1 parent 6830e4d commit 04fb07c

File tree

121 files changed

+332
-3124
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+332
-3124
lines changed

compiler/expr-call-helpers.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,11 @@ func (c *GoToTSCompiler) writeNamedTypeFor(t types.Type) error {
248248
obj := named.Obj()
249249
pkgPath := ""
250250
if pkg := obj.Pkg(); pkg != nil {
251-
pkgPath = pkg.Path() + "."
251+
if pkg.Name() == "main" {
252+
pkgPath = "main."
253+
} else if pkg.Path() != "" {
254+
pkgPath = pkg.Path() + "."
255+
}
252256
}
253257
typeName := pkgPath + obj.Name()
254258
c.tsw.WriteLiterally("reflect.getInterfaceTypeByName(\"" + typeName + "\")")

compiler/expr-type.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,47 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
134134
c.tsw.WriteLiterally("}")
135135
}
136136
} else {
137-
// For named types, just use the name string
137+
// For named types, use the fully qualified name with package path
138+
if goType != nil {
139+
if namedType, isNamed := goType.(*types.Named); isNamed {
140+
typeName := namedType.Obj().Name()
141+
if pkg := namedType.Obj().Pkg(); pkg != nil {
142+
pkgPath := pkg.Path()
143+
pkgName := pkg.Name()
144+
if pkgPath != "" && pkgName != "main" {
145+
typeName = pkgPath + "." + typeName
146+
} else if pkgName == "main" {
147+
typeName = "main." + typeName
148+
}
149+
}
150+
c.tsw.WriteLiterallyf("'%s'", typeName)
151+
return
152+
}
153+
}
154+
// Fallback to short name if type info unavailable
138155
c.tsw.WriteLiterallyf("'%s'", t.Name)
139156
}
140157
case *ast.SelectorExpr:
141158
if ident, ok := t.X.(*ast.Ident); ok {
159+
// Use type info to get the actual package path
160+
goType := c.pkg.TypesInfo.TypeOf(t)
161+
if goType != nil {
162+
if namedType, isNamed := goType.(*types.Named); isNamed {
163+
typeName := namedType.Obj().Name()
164+
if pkg := namedType.Obj().Pkg(); pkg != nil {
165+
pkgPath := pkg.Path()
166+
pkgName := pkg.Name()
167+
if pkgPath != "" && pkgName != "main" {
168+
typeName = pkgPath + "." + typeName
169+
} else if pkgName == "main" {
170+
typeName = "main." + typeName
171+
}
172+
}
173+
c.tsw.WriteLiterallyf("'%s'", typeName)
174+
return
175+
}
176+
}
177+
// Fallback to using the identifier name (package alias)
142178
c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, t.Sel.Name)
143179
}
144180
case *ast.ArrayType:

compiler/spec-struct.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,19 @@ func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType)
429429
// Add code to register the type with the runtime type system
430430
c.tsw.WriteLine("")
431431
c.tsw.WriteLinef("// Register this type with the runtime type system")
432+
433+
// Build full package path name for registration
434+
structName := className
435+
pkgPath := c.pkg.Types.Path()
436+
pkgName := c.pkg.Types.Name()
437+
if pkgPath != "" && pkgName != "main" {
438+
structName = pkgPath + "." + className
439+
} else if pkgName == "main" {
440+
structName = "main." + className
441+
}
442+
432443
c.tsw.WriteLinef("static __typeInfo = $.registerStructType(")
433-
c.tsw.WriteLinef(" '%s',", className)
444+
c.tsw.WriteLinef(" '%s',", structName)
434445
c.tsw.WriteLinef(" new %s(),", className)
435446
c.tsw.WriteLiterally(" [")
436447
// Collect methods for the struct type

compiler/spec.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,11 @@ func (c *GoToTSCompiler) WriteInterfaceTypeSpec(a *ast.TypeSpec, t *ast.Interfac
536536
// Build full package path name for registration
537537
interfaceName := a.Name.Name
538538
pkgPath := c.pkg.Types.Path()
539-
if pkgPath != "" {
539+
pkgName := c.pkg.Types.Name()
540+
if pkgPath != "" && pkgName != "main" {
540541
interfaceName = pkgPath + "." + interfaceName
542+
} else if pkgName == "main" {
543+
interfaceName = "main." + interfaceName
541544
}
542545
c.tsw.WriteLine("")
543546
c.tsw.WriteLinef("$.registerInterfaceType(")

compliance/WIP.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# interface_to_interface_type_assertion
2+
3+
## Problem
4+
5+
Type assertion from one interface to another is failing because the compiler generates an incomplete type name.
6+
7+
**Root Cause:**
8+
In `/Users/cjs/repos/aperture/goscript/compiler/expr-type.go`, the `writeTypeDescription` function handles `*ast.Ident` cases (line 76-139). For non-primitive named types, it just writes `'%s'` with `t.Name` (line 138), which produces the short name `'MyOtherInterface'`.
9+
10+
However, interfaces are registered with their fully qualified names like:
11+
12+
```
13+
'github.com/.../MyOtherInterface'
14+
```
15+
16+
This causes the runtime type assertion to fail because it can't find the type in the registry.
17+
18+
## Solution
19+
20+
Modify `writeTypeDescription` in `expr-type.go` to use the fully qualified type name from `types.TypeString()` for named types, similar to how interface registration works.
21+
22+
For the `case *ast.Ident:` non-primitive path (line 136-139), we should:
23+
24+
1. Get the type info: `goType := c.pkg.TypesInfo.TypeOf(t)`
25+
2. If it's a named type, use `types.TypeString(namedType.Obj().Type(), c.makeTypeStringQualifier())` to get the full package path
26+
3. Write that instead of just `t.Name`
27+
28+
This will make the generated code:
29+
30+
```typescript
31+
$.typeAssert<MyOtherInterface>(i, 'github.com/.../MyOtherInterface')
32+
```
33+
34+
Which matches the registered type name.

compliance/deps/encoding/base64/base64.gs.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ export class Encoding {
422422

423423
// Register this type with the runtime type system
424424
static __typeInfo = $.registerStructType(
425-
'Encoding',
425+
'encoding/base64.Encoding',
426426
new Encoding(),
427427
[{ name: "WithPadding", args: [{ name: "padding", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Pointer, elemType: "Encoding" } }] }, { name: "Strict", args: [], returns: [{ type: { kind: $.TypeKind.Pointer, elemType: "Encoding" } }] }, { name: "Encode", args: [{ name: "dst", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "src", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [] }, { name: "AppendEncode", args: [{ name: "dst", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "src", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }] }, { name: "EncodeToString", args: [{ name: "src", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "string" } }] }, { name: "EncodedLen", args: [{ name: "n", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "decodeQuantum", args: [{ name: "dst", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "src", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "si", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "AppendDecode", args: [{ name: "dst", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "src", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "DecodeString", args: [{ name: "s", type: { kind: $.TypeKind.Basic, name: "string" } }], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "Decode", args: [{ name: "dst", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "src", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "DecodedLen", args: [{ name: "n", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }],
428428
Encoding,
@@ -610,7 +610,7 @@ export class decoder {
610610

611611
// Register this type with the runtime type system
612612
static __typeInfo = $.registerStructType(
613-
'decoder',
613+
'encoding/base64.decoder',
614614
new decoder(),
615615
[{ name: "Read", args: [{ name: "p", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }],
616616
decoder,
@@ -769,7 +769,7 @@ export class encoder {
769769

770770
// Register this type with the runtime type system
771771
static __typeInfo = $.registerStructType(
772-
'encoder',
772+
'encoding/base64.encoder',
773773
new encoder(),
774774
[{ name: "Write", args: [{ name: "p", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "Close", args: [], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }],
775775
encoder,
@@ -830,7 +830,7 @@ export class newlineFilteringReader {
830830

831831
// Register this type with the runtime type system
832832
static __typeInfo = $.registerStructType(
833-
'newlineFilteringReader',
833+
'encoding/base64.newlineFilteringReader',
834834
new newlineFilteringReader(),
835835
[{ name: "Read", args: [{ name: "p", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }],
836836
newlineFilteringReader,

compliance/deps/encoding/json/decode.gs.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export class InvalidUnmarshalError {
6767

6868
// Register this type with the runtime type system
6969
static __typeInfo = $.registerStructType(
70-
'InvalidUnmarshalError',
70+
'encoding/json.InvalidUnmarshalError',
7171
new InvalidUnmarshalError(),
7272
[{ name: "Error", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "string" } }] }],
7373
InvalidUnmarshalError,
@@ -143,7 +143,7 @@ export class UnmarshalFieldError {
143143

144144
// Register this type with the runtime type system
145145
static __typeInfo = $.registerStructType(
146-
'UnmarshalFieldError',
146+
'encoding/json.UnmarshalFieldError',
147147
new UnmarshalFieldError(),
148148
[{ name: "Error", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "string" } }] }],
149149
UnmarshalFieldError,
@@ -232,7 +232,7 @@ export class UnmarshalTypeError {
232232

233233
// Register this type with the runtime type system
234234
static __typeInfo = $.registerStructType(
235-
'UnmarshalTypeError',
235+
'encoding/json.UnmarshalTypeError',
236236
new UnmarshalTypeError(),
237237
[{ name: "Error", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "string" } }] }],
238238
UnmarshalTypeError,
@@ -395,7 +395,7 @@ export class decodeState {
395395
public addErrorContext(err: $.GoError): $.GoError {
396396
const d = this
397397
if (d.errorContext != null && (d.errorContext!.Struct != null || $.len(d.errorContext!.FieldStack) > 0)) {
398-
$.typeSwitch(err, [{ types: [{kind: $.TypeKind.Pointer, elemType: 'UnmarshalTypeError'}], body: (err) => {
398+
$.typeSwitch(err, [{ types: [{kind: $.TypeKind.Pointer, elemType: 'encoding/json.UnmarshalTypeError'}], body: (err) => {
399399
err!.Struct = d.errorContext!.Struct!.Name()
400400
let fieldStack = d.errorContext!.FieldStack
401401
if (err!.Field != "") {
@@ -1464,7 +1464,7 @@ export class decodeState {
14641464

14651465
// Register this type with the runtime type system
14661466
static __typeInfo = $.registerStructType(
1467-
'decodeState',
1467+
'encoding/json.decodeState',
14681468
new decodeState(),
14691469
[{ name: "unmarshal", args: [{ name: "v", type: { kind: $.TypeKind.Interface, methods: [] } }], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "readIndex", args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: "number" } }] }, { name: "init", args: [{ name: "data", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }], returns: [{ type: { kind: $.TypeKind.Pointer, elemType: "decodeState" } }] }, { name: "saveError", args: [{ name: "err", type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }], returns: [] }, { name: "addErrorContext", args: [{ name: "err", type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "skip", args: [], returns: [] }, { name: "scanNext", args: [], returns: [] }, { name: "scanWhile", args: [{ name: "op", type: { kind: $.TypeKind.Basic, name: "number" } }], returns: [] }, { name: "rescanLiteral", args: [], returns: [] }, { name: "value", args: [{ name: "v", type: "Value" }], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "valueQuoted", args: [], returns: [{ type: { kind: $.TypeKind.Interface, methods: [] } }] }, { name: "array", args: [{ name: "v", type: "Value" }], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "object", args: [{ name: "v", type: "Value" }], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "convertNumber", args: [{ name: "s", type: { kind: $.TypeKind.Basic, name: "string" } }], returns: [{ type: { kind: $.TypeKind.Interface, methods: [] } }, { type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "literalStore", args: [{ name: "item", type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Basic, name: "number" } } }, { name: "v", type: "Value" }, { name: "fromQuoted", type: { kind: $.TypeKind.Basic, name: "boolean" } }], returns: [{ type: { kind: $.TypeKind.Interface, name: 'GoError', methods: [{ name: 'Error', args: [], returns: [{ type: { kind: $.TypeKind.Basic, name: 'string' } }] }] } }] }, { name: "valueInterface", args: [], returns: [{ type: { kind: $.TypeKind.Interface, methods: [] } }] }, { name: "arrayInterface", args: [], returns: [{ type: { kind: $.TypeKind.Slice, elemType: { kind: $.TypeKind.Interface, methods: [] } } }] }, { name: "objectInterface", args: [], returns: [{ type: { kind: $.TypeKind.Map, keyType: { kind: $.TypeKind.Basic, name: "string" }, elemType: { kind: $.TypeKind.Interface, methods: [] } } }] }, { name: "literalInterface", args: [], returns: [{ type: { kind: $.TypeKind.Interface, methods: [] } }] }],
14701470
decodeState,
@@ -1510,7 +1510,7 @@ export class errorContext {
15101510

15111511
// Register this type with the runtime type system
15121512
static __typeInfo = $.registerStructType(
1513-
'errorContext',
1513+
'encoding/json.errorContext',
15141514
new errorContext(),
15151515
[],
15161516
errorContext,
@@ -1535,7 +1535,7 @@ export class unquotedValue {
15351535

15361536
// Register this type with the runtime type system
15371537
static __typeInfo = $.registerStructType(
1538-
'unquotedValue',
1538+
'encoding/json.unquotedValue',
15391539
new unquotedValue(),
15401540
[],
15411541
unquotedValue,
@@ -1708,7 +1708,7 @@ export function indirect(v: reflect.Value, decodingNull: boolean): [Unmarshaler,
17081708
}
17091709
if (v.Type()!.NumMethod() > 0 && v.CanInterface()) {
17101710
{
1711-
let { value: u, ok: ok } = $.typeAssert<Unmarshaler>(v.Interface(), 'Unmarshaler')
1711+
let { value: u, ok: ok } = $.typeAssert<Unmarshaler>(v.Interface(), 'encoding/json.Unmarshaler')
17121712
if (ok) {
17131713
return [u, null, $.markAsStructValue(new reflect.Value({}))]
17141714
}

0 commit comments

Comments
 (0)