Skip to content

Commit 1d82a7c

Browse files
committed
fix: restore remaining compliance suite
1 parent 3fede9d commit 1d82a7c

141 files changed

Lines changed: 972 additions & 673 deletions

File tree

Some content is hidden

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

compiler/analysis.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,6 @@ func (v *analysisVisitor) visitTypeAssertExpr(typeAssert *ast.TypeAssertExpr) as
11961196

11971197
// For each method in the interface, check if the struct implements it
11981198
for interfaceMethod := range interfaceType.ExplicitMethods() {
1199-
interfaceMethod := interfaceMethod
12001199

12011200
// Find the corresponding method in the struct type
12021201
structMethod := v.findStructMethod(namedType, interfaceMethod.Name())
@@ -1465,7 +1464,6 @@ func (a *Analysis) addImportsForPromotedMethods(pkg *packages.Package) {
14651464

14661465
// Look for embedded fields
14671466
for field := range structType.Fields() {
1468-
field := field
14691467
if !field.Embedded() {
14701468
continue
14711469
}
@@ -1490,7 +1488,6 @@ func (a *Analysis) addImportsForPromotedMethods(pkg *packages.Package) {
14901488

14911489
// Scan all methods in the method set
14921490
for selection := range embeddedMethodSet.Methods() {
1493-
selection := selection
14941491
method := selection.Obj()
14951492
sig, ok := method.Type().(*types.Signature)
14961493
if !ok {
@@ -1500,15 +1497,13 @@ func (a *Analysis) addImportsForPromotedMethods(pkg *packages.Package) {
15001497
// Scan parameters
15011498
if sig.Params() != nil {
15021499
for param := range sig.Params().Variables() {
1503-
param := param
15041500
a.collectPackageFromType(param.Type(), pkg.Types, packagesToAdd)
15051501
}
15061502
}
15071503

15081504
// Scan results
15091505
if sig.Results() != nil {
15101506
for result := range sig.Results().Variables() {
1511-
result := result
15121507
a.collectPackageFromType(result.Type(), pkg.Types, packagesToAdd)
15131508
}
15141509
}
@@ -1551,7 +1546,6 @@ func (a *Analysis) collectPackageFromType(t types.Type, currentPkg *types.Packag
15511546
a.collectPackageFromType(etyp, currentPkg, packagesToAdd)
15521547
}
15531548
for method := range typ.ExplicitMethods() {
1554-
method := method
15551549
a.collectPackageFromType(method.Type(), currentPkg, packagesToAdd)
15561550
}
15571551
case *types.Pointer:
@@ -2430,7 +2424,6 @@ func (a *Analysis) GetIdentifierMapping(ident *ast.Ident) string {
24302424
func (v *analysisVisitor) findStructMethod(namedType *types.Named, methodName string) *types.Func {
24312425
// Check methods directly on the type
24322426
for method := range namedType.Methods() {
2433-
method := method
24342427
if method.Name() == methodName {
24352428
return method
24362429
}
@@ -2534,7 +2527,6 @@ func (v *analysisVisitor) trackInterfaceAssignments(assignStmt *ast.AssignStmt)
25342527

25352528
// Track implementations for all interface methods
25362529
for interfaceMethod := range interfaceType.ExplicitMethods() {
2537-
interfaceMethod := interfaceMethod
25382530

25392531
structMethod := v.findStructMethod(namedType, interfaceMethod.Name())
25402532
if structMethod != nil {
@@ -2593,7 +2585,6 @@ func (v *analysisVisitor) trackInterfaceCallArguments(callExpr *ast.CallExpr) {
25932585

25942586
// Track implementations for all interface methods
25952587
for interfaceMethod := range interfaceType.ExplicitMethods() {
2596-
interfaceMethod := interfaceMethod
25972588

25982589
structMethod := v.findStructMethod(namedType, interfaceMethod.Name())
25992590
if structMethod != nil {
@@ -2738,7 +2729,6 @@ func (v *interfaceImplementationVisitor) findImplementationsInPackage(interfaceT
27382729
func (v *interfaceImplementationVisitor) trackImplementation(interfaceType *types.Interface, namedType *types.Named) {
27392730
// For each method in the interface, find the corresponding implementation
27402731
for interfaceMethod := range interfaceType.ExplicitMethods() {
2741-
interfaceMethod := interfaceMethod
27422732

27432733
// Find the method in the implementing type
27442734
structMethod := v.findMethodInType(namedType, interfaceMethod.Name())
@@ -2751,7 +2741,6 @@ func (v *interfaceImplementationVisitor) trackImplementation(interfaceType *type
27512741
// findMethodInType finds a method with the given name in a named type
27522742
func (v *interfaceImplementationVisitor) findMethodInType(namedType *types.Named, methodName string) *types.Func {
27532743
for method := range namedType.Methods() {
2754-
method := method
27552744
if method.Name() == methodName {
27562745
return method
27572746
}

compiler/analysis_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"go/token"
77
"go/types"
88
"os"
9+
"slices"
910
"testing"
1011

1112
"golang.org/x/tools/go/packages"
@@ -329,13 +330,7 @@ func TestDiscoverGsPackages(t *testing.T) {
329330
// Check for some known packages that should exist
330331
expectedPackages := []string{"sync", "bytes", "strings"}
331332
for _, expected := range expectedPackages {
332-
found := false
333-
for _, pkg := range packages {
334-
if pkg == expected {
335-
found = true
336-
break
337-
}
338-
}
333+
found := slices.Contains(packages, expected)
339334
if !found {
340335
t.Logf("Expected package '%s' not found in discovered packages: %v", expected, packages)
341336
}

compiler/code-writer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ func (w *TSCodeWriter) WriteImport(symbolName, importPath string) {
5959

6060
// WriteCommentLine writes a comment as a // line.
6161
func (w *TSCodeWriter) WriteCommentLine(commentText string) {
62-
lines := strings.Split(commentText, "\n")
63-
for _, line := range lines {
62+
lines := strings.SplitSeq(commentText, "\n")
63+
for line := range lines {
6464
w.WriteLinef("// %s", line)
6565
}
6666
}

compiler/compiler.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,9 @@ func (c *PackageCompiler) Compile(ctx context.Context) error {
414414

415415
// Check if this is a .pb.go file that should be skipped
416416
baseFileName := filepath.Base(fileName)
417-
if strings.HasSuffix(baseFileName, ".pb.go") {
417+
if before, ok := strings.CutSuffix(baseFileName, ".pb.go"); ok {
418418
// Check if there's a corresponding .pb.ts file
419-
pbTsFileName := strings.TrimSuffix(baseFileName, ".pb.go") + ".pb.ts"
419+
pbTsFileName := before + ".pb.ts"
420420
packageDir := filepath.Dir(fileName)
421421
pbTsPath := filepath.Join(packageDir, pbTsFileName)
422422

@@ -1131,10 +1131,10 @@ func (c *GoToTSCompiler) WriteDoc(doc *ast.CommentGroup) {
11311131
// Preserve original comment style (// or /*)
11321132
if strings.HasPrefix(comment.Text, "//") {
11331133
c.tsw.WriteLine(comment.Text)
1134-
} else if strings.HasPrefix(comment.Text, "/*") {
1134+
} else if after, ok := strings.CutPrefix(comment.Text, "/*"); ok {
11351135
// Write block comments potentially spanning multiple lines
11361136
// Remove /* and */, then split by newline
1137-
content := strings.TrimSuffix(strings.TrimPrefix(comment.Text, "/*"), "*/")
1137+
content := strings.TrimSuffix(after, "*/")
11381138
lines := strings.Split(content, "\n") // Use \n as Split expects a separator string
11391139

11401140
if len(lines) == 1 && !strings.Contains(lines[0], "\n") { // Check again for internal newlines just in case

compiler/composite-lit.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func (c *GoToTSCompiler) WriteCompositeLit(exp *ast.CompositeLit) error {
107107
// Use type info to get array length and element type
108108
var arrayLen int
109109
var elemType ast.Expr
110-
var goElemType interface{}
110+
var goElemType any
111111
if typ := c.pkg.TypesInfo.TypeOf(exp.Type); typ != nil {
112112
if at, ok := typ.Underlying().(*types.Array); ok {
113113
arrayLen = int(at.Len())
@@ -534,7 +534,7 @@ func (c *GoToTSCompiler) WriteVarRefedValue(expr ast.Expr) error {
534534
// evaluateConstantExpr attempts to evaluate a Go expression as a compile-time constant.
535535
// It returns the constant value if successful, or nil if the expression is not a constant.
536536
// This is used for evaluating array literal keys that are constant expressions.
537-
func (c *GoToTSCompiler) evaluateConstantExpr(expr ast.Expr) interface{} {
537+
func (c *GoToTSCompiler) evaluateConstantExpr(expr ast.Expr) any {
538538
// Use the type checker's constant evaluation
539539
if tv, ok := c.pkg.TypesInfo.Types[expr]; ok && tv.Value != nil {
540540
// The expression has a constant value
@@ -575,8 +575,7 @@ func (c *GoToTSCompiler) categorizeStructFields(
575575
explicitEmbedded = make(map[string]ast.Expr)
576576

577577
// Pre-populate embeddedFields map keys using the correct property name
578-
for i := 0; i < structType.NumFields(); i++ {
579-
field := structType.Field(i)
578+
for field := range structType.Fields() {
580579
if field.Anonymous() {
581580
fieldType := field.Type()
582581
if ptr, ok := fieldType.(*types.Pointer); ok {
@@ -611,8 +610,7 @@ func (c *GoToTSCompiler) categorizeStructFields(
611610
}
612611

613612
isDirectField := false
614-
for i := range structType.NumFields() {
615-
field := structType.Field(i)
613+
for field := range structType.Fields() {
616614
if field.Name() == keyName {
617615
isDirectField = true
618616
directFields[keyName] = kv.Value

compiler/constraint.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@ type ConstraintInfo struct {
1616
func analyzeConstraint(iface *types.Interface) ConstraintInfo {
1717
info := ConstraintInfo{}
1818

19-
for i := 0; i < iface.NumEmbeddeds(); i++ {
20-
embedded := iface.EmbeddedType(i)
19+
for embedded := range iface.EmbeddedTypes() {
2120
if union, ok := embedded.(*types.Union); ok {
22-
for j := 0; j < union.Len(); j++ {
23-
term := union.Term(j)
21+
for term := range union.Terms() {
2422
checkType(term.Type(), &info)
2523
}
2624
} else {

compiler/expr-call-async.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ func (c *GoToTSCompiler) addNonNullAssertion(expFun ast.Expr) {
169169
c.tsw.WriteLiterally("!")
170170
}
171171
}
172+
} else if _, isParenExpr := expFun.(*ast.ParenExpr); isParenExpr {
173+
// Parenthesized function expressions often come from pointer dereferences
174+
// like (*rel)(), which remain nullable in TypeScript.
175+
c.tsw.WriteLiterally("!")
172176
} else if _, isNamed := funType.(*types.Named); isNamed {
173177
c.tsw.WriteLiterally("!")
174178
}

compiler/expr-call-helpers.go

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import (
88
)
99

1010
// writeByteSliceCreation handles the creation of []byte slices with proper Uint8Array handling
11-
func (c *GoToTSCompiler) writeByteSliceCreation(lengthArg, capacityArg interface{}) error {
11+
func (c *GoToTSCompiler) writeByteSliceCreation(lengthArg, capacityArg any) error {
1212
return c.writeSliceCreationForType(lengthArg, capacityArg, true)
1313
}
1414

1515
// writeSliceCreationForType handles slice creation with special handling for byte slices
16-
func (c *GoToTSCompiler) writeSliceCreationForType(lengthArg, capacityArg interface{}, isByteSlice bool) error {
16+
func (c *GoToTSCompiler) writeSliceCreationForType(lengthArg, capacityArg any, isByteSlice bool) error {
1717
hasCapacity := capacityArg != nil
1818

1919
if isByteSlice && !hasCapacity {
@@ -52,7 +52,7 @@ func (c *GoToTSCompiler) writeSliceCreationForType(lengthArg, capacityArg interf
5252
}
5353

5454
// writeGenericSliceCreation handles the creation of generic slices with proper type hints
55-
func (c *GoToTSCompiler) writeGenericSliceCreation(elemType types.Type, lengthArg, capacityArg interface{}) error {
55+
func (c *GoToTSCompiler) writeGenericSliceCreation(elemType types.Type, lengthArg, capacityArg any) error {
5656
hasCapacity := capacityArg != nil
5757

5858
c.tsw.WriteLiterally("$.makeSlice<")
@@ -90,7 +90,7 @@ func (c *GoToTSCompiler) writeSliceTypeHint(elemType types.Type, hasCapacity boo
9090
}
9191

9292
// writeExprOrDefault writes an expression if it's not nil, otherwise writes a default value
93-
func (c *GoToTSCompiler) writeExprOrDefault(expr interface{}, defaultValue string) error {
93+
func (c *GoToTSCompiler) writeExprOrDefault(expr any, defaultValue string) error {
9494
if expr == nil {
9595
c.tsw.WriteLiterally(defaultValue)
9696
return nil
@@ -149,6 +149,14 @@ func (c *GoToTSCompiler) writeReflectTypeFor(exp *ast.CallExpr, selectorExpr *as
149149
typeArg := instance.TypeArgs.At(0)
150150
// fmt.Printf("DEBUG: Type argument: %v\n", typeArg)
151151

152+
if named, ok := typeArg.(*types.Named); ok {
153+
if _, isInterface := named.Underlying().(*types.Interface); isInterface {
154+
typeName := qualifiedTypeName(named)
155+
c.tsw.WriteLiterally("reflect.getInterfaceLiteralTypeByName(\"" + typeName + "\")")
156+
return true, nil
157+
}
158+
}
159+
152160
// Generate TypeScript code to create a Type for this type
153161
if err := c.writeTypeForTypeArg(typeArg); err != nil {
154162
return true, err
@@ -157,6 +165,54 @@ func (c *GoToTSCompiler) writeReflectTypeFor(exp *ast.CallExpr, selectorExpr *as
157165
return true, nil
158166
}
159167

168+
// writeReflectTypeAssert handles reflect.TypeAssert[T](v) calls.
169+
func (c *GoToTSCompiler) writeReflectTypeAssert(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
170+
if selectorExpr.Sel.Name != "TypeAssert" {
171+
return false, nil
172+
}
173+
174+
xIdent, ok := selectorExpr.X.(*ast.Ident)
175+
if !ok {
176+
return false, nil
177+
}
178+
179+
obj := c.objectOfIdent(xIdent)
180+
if obj == nil {
181+
return false, nil
182+
}
183+
184+
pkgName, ok := obj.(*types.PkgName)
185+
if !ok || pkgName.Imported().Path() != "reflect" {
186+
return false, nil
187+
}
188+
189+
if len(exp.Args) != 1 {
190+
return false, errors.New("reflect.TypeAssert called with unexpected argument count")
191+
}
192+
193+
if c.pkg.TypesInfo.Instances == nil {
194+
return false, errors.New("reflect.TypeAssert called but no type instances available")
195+
}
196+
197+
instance, hasInstance := c.pkg.TypesInfo.Instances[selectorExpr.Sel]
198+
if !hasInstance || instance.TypeArgs == nil || instance.TypeArgs.Len() == 0 {
199+
return false, errors.New("reflect.TypeAssert called without type arguments")
200+
}
201+
202+
typeArg := instance.TypeArgs.At(0)
203+
204+
c.tsw.WriteLiterally("$.typeAssertTuple<")
205+
c.WriteGoType(typeArg, GoTypeContextGeneral)
206+
c.tsw.WriteLiterally(">(")
207+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
208+
return true, err
209+
}
210+
c.tsw.WriteLiterally(".Interface(), ")
211+
c.writeTypeInfoObject(typeArg)
212+
c.tsw.WriteLiterally(")")
213+
return true, nil
214+
}
215+
160216
// writeTypeForTypeArg generates TypeScript code to create a reflect.Type for the given Go type
161217
func (c *GoToTSCompiler) writeTypeForTypeArg(t types.Type) error {
162218
// Handle basic types
@@ -175,12 +231,46 @@ func (c *GoToTSCompiler) writeTypeForTypeArg(t types.Type) error {
175231
c.tsw.WriteLiterally(")")
176232
return nil
177233
case *types.Slice:
178-
// For slice types, use TypeOf with an empty slice
179-
c.tsw.WriteLiterally("reflect.TypeOf([])")
234+
c.tsw.WriteLiterally("reflect.SliceOf(")
235+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
236+
return err
237+
}
238+
c.tsw.WriteLiterally(")")
180239
return nil
181240
case *types.Array:
182-
// For array types, use TypeOf with an empty array
183-
c.tsw.WriteLiterally("reflect.TypeOf([])")
241+
c.tsw.WriteLiterally("reflect.ArrayOf(")
242+
c.tsw.WriteLiterallyf("%d, ", underlying.Len())
243+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
244+
return err
245+
}
246+
c.tsw.WriteLiterally(")")
247+
return nil
248+
case *types.Map:
249+
c.tsw.WriteLiterally("reflect.MapOf(")
250+
if err := c.writeTypeForTypeArg(underlying.Key()); err != nil {
251+
return err
252+
}
253+
c.tsw.WriteLiterally(", ")
254+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
255+
return err
256+
}
257+
c.tsw.WriteLiterally(")")
258+
return nil
259+
case *types.Chan:
260+
c.tsw.WriteLiterally("reflect.ChanOf(")
261+
switch underlying.Dir() {
262+
case types.RecvOnly:
263+
c.tsw.WriteLiterally("reflect.RecvDir")
264+
case types.SendOnly:
265+
c.tsw.WriteLiterally("reflect.SendDir")
266+
default:
267+
c.tsw.WriteLiterally("reflect.BothDir")
268+
}
269+
c.tsw.WriteLiterally(", ")
270+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
271+
return err
272+
}
273+
c.tsw.WriteLiterally(")")
184274
return nil
185275
case *types.Struct:
186276
// For struct types, use TypeOf with zero value

compiler/expr-call-make.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (c *GoToTSCompiler) writeMakeSlice(sliceType *types.Slice, exp *ast.CallExp
7979

8080
// Check if it's []byte
8181
if c.isByteSliceType(sliceType) {
82-
var lengthArg, capacityArg interface{}
82+
var lengthArg, capacityArg any
8383
if len(exp.Args) >= 2 {
8484
lengthArg = exp.Args[1]
8585
}
@@ -90,7 +90,7 @@ func (c *GoToTSCompiler) writeMakeSlice(sliceType *types.Slice, exp *ast.CallExp
9090
}
9191

9292
// Handle other slice types
93-
var lengthArg, capacityArg interface{}
93+
var lengthArg, capacityArg any
9494
if len(exp.Args) >= 2 {
9595
lengthArg = exp.Args[1]
9696
}
@@ -193,7 +193,7 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
193193
if elemType != nil {
194194
// Check if it's make(S, ...) where S constrains to []byte
195195
if c.isByteSliceType(types.NewSlice(elemType)) {
196-
var lengthArg, capacityArg interface{}
196+
var lengthArg, capacityArg any
197197
if len(exp.Args) >= 2 {
198198
lengthArg = exp.Args[1]
199199
}
@@ -203,7 +203,7 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
203203
return c.writeByteSliceCreation(lengthArg, capacityArg)
204204
}
205205

206-
var lengthArg, capacityArg interface{}
206+
var lengthArg, capacityArg any
207207
if len(exp.Args) >= 2 {
208208
lengthArg = exp.Args[1]
209209
}

0 commit comments

Comments
 (0)