goscript 0.0.58 → 0.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -33
- package/compiler/analysis.go +184 -43
- package/compiler/assignment.go +163 -217
- package/compiler/compiler.go +35 -31
- package/compiler/composite-lit.go +233 -196
- package/compiler/constraint.go +88 -0
- package/compiler/decl.go +82 -24
- package/compiler/expr-call-async.go +20 -34
- package/compiler/expr-call-builtins.go +19 -0
- package/compiler/expr-call-helpers.go +0 -28
- package/compiler/expr-call-make.go +93 -343
- package/compiler/expr-call-type-conversion.go +221 -249
- package/compiler/expr-call.go +70 -69
- package/compiler/expr-selector.go +21 -24
- package/compiler/expr.go +3 -60
- package/compiler/protobuf.go +180 -36
- package/compiler/spec-value.go +132 -24
- package/compiler/spec.go +14 -55
- package/compiler/stmt-assign.go +338 -356
- package/compiler/stmt-range.go +4 -24
- package/compiler/stmt.go +92 -203
- package/compiler/type-utils.go +185 -0
- package/compiler/type.go +26 -80
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js +3 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +8 -2
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/fmt/fmt.js +113 -16
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/runtime/runtime.d.ts +1 -1
- package/dist/gs/runtime/runtime.js +1 -1
- package/dist/gs/slices/slices.d.ts +23 -0
- package/dist/gs/slices/slices.js +61 -0
- package/dist/gs/slices/slices.js.map +1 -1
- package/go.mod +10 -10
- package/go.sum +22 -14
- package/gs/builtin/slice.ts +5 -2
- package/gs/builtin/type.ts +13 -6
- package/gs/fmt/fmt.test.ts +176 -0
- package/gs/fmt/fmt.ts +109 -18
- package/gs/runtime/runtime.ts +1 -1
- package/gs/slices/slices.ts +68 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## What is GoScript?
|
|
11
11
|
|
|
12
|
-
GoScript is
|
|
12
|
+
GoScript is an experimental **Go to TypeScript compiler** that translates Go code to TypeScript at the AST level. The goal is to enable sharing algorithms and business logic between Go backends and TypeScript frontends.
|
|
13
13
|
|
|
14
14
|
> Right now goscript looks pretty cool if you problem is "I want this self-sufficient algorithm be available in Go and JS runtimes". gopherjs's ambition, however, has always been "any valid Go program can run in a browser". There is a lot that goes on in gopherjs that is necessary for supporting the standard library, which goes beyond cross-language translation.
|
|
15
15
|
>
|
|
@@ -17,33 +17,46 @@ GoScript is a **Go to TypeScript compiler** that translates Go code to TypeScrip
|
|
|
17
17
|
|
|
18
18
|
### 🎯 Why GoScript?
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Write once, run everywhere. Share your Go algorithms, business logic, and data structures seamlessly between your backend and frontend without maintaining two codebases.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
🔬 **Experimental features being developed:**
|
|
23
23
|
- Sharing business logic between Go services and web apps
|
|
24
24
|
- Porting Go algorithms to run in browsers
|
|
25
25
|
- Building TypeScript libraries from existing Go code
|
|
26
|
-
- Full-stack teams that love Go's simplicity
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
GoScript compiles a powerful subset of Go:
|
|
30
|
-
- Structs, interfaces, methods, and functions
|
|
31
|
-
- Channels and goroutines (translated to async/await)
|
|
32
|
-
- Slices, maps, and most built-in types
|
|
33
|
-
- Basic reflection support
|
|
34
|
-
- Standard control flow (if, for, switch, etc.)
|
|
27
|
+
Go has powerful concurrency support and an excellent standard library. GoScript brings these capabilities to TypeScript with as simple and readable of a translation as possible.
|
|
35
28
|
|
|
36
|
-
**Current
|
|
29
|
+
⚠️ **Current development status:**
|
|
30
|
+
GoScript is working on compiling a subset of Go:
|
|
31
|
+
- ✅ Basic structs, interfaces, methods, and functions
|
|
32
|
+
- ✅ Channels and goroutines (translating to async/await)
|
|
33
|
+
- ✅ Slice semantics, maps, and built-in types
|
|
34
|
+
- ✅ Standard control flow (if, for, switch, select, range, etc.)
|
|
35
|
+
- 🚧 Basic reflection support
|
|
36
|
+
- 🚧 Standard library support
|
|
37
|
+
|
|
38
|
+
**Known limitations in this preview:**
|
|
37
39
|
- Uses JavaScript `number` type (64-bit float, not Go's int types)
|
|
38
40
|
- No pointer arithmetic (`uintptr`) or `unsafe` package
|
|
39
41
|
- No complex numbers
|
|
40
|
-
- Limited standard library (
|
|
42
|
+
- Limited standard library (working on it)
|
|
43
|
+
- Performance not yet optimized
|
|
44
|
+
|
|
45
|
+
**This is a prototype!** Expect bugs and missing features. Please contribute!
|
|
46
|
+
|
|
47
|
+
### ⚠️ Development Preview
|
|
48
|
+
|
|
49
|
+
**This project is currently in active development and should be considered experimental.** GoScript is a work-in-progress prototype that may have bugs, incomplete features, and breaking changes. We're actively iterating on the compiler and welcome your feedback!
|
|
50
|
+
|
|
51
|
+
🐛 **Found an issue?** Please [open an issue](https://github.com/aperturerobotics/goscript/issues) and we'll fix it.
|
|
41
52
|
|
|
42
|
-
|
|
53
|
+
🤖 **AI** This prototype is heavily AI-written, but I plan to manually rewrite the codebase by hand once it reaches a working state for advanced use cases. AI Producer, human Reducer.
|
|
43
54
|
|
|
44
55
|
📖 **Learn more:** [Design document](./design/DESIGN.md) | [Compliance tests](./compliance/COMPLIANCE.md)
|
|
45
56
|
|
|
46
|
-
## 🚀
|
|
57
|
+
## 🚀 Try It
|
|
58
|
+
|
|
59
|
+
> **Warning:** This is experimental software. Features may be incomplete or broken. Please report any issues!
|
|
47
60
|
|
|
48
61
|
### Installation
|
|
49
62
|
|
|
@@ -52,18 +65,20 @@ If you're building algorithms, business logic, or data processing code, GoScript
|
|
|
52
65
|
go install github.com/aperturerobotics/goscript/cmd/goscript@latest
|
|
53
66
|
```
|
|
54
67
|
|
|
55
|
-
**Option 2: NPM**
|
|
68
|
+
**Option 2: NPM** (if available)
|
|
56
69
|
```bash
|
|
57
70
|
npm install -g goscript
|
|
58
71
|
```
|
|
59
72
|
|
|
60
|
-
###
|
|
73
|
+
### Compilation
|
|
61
74
|
|
|
62
75
|
```bash
|
|
63
|
-
#
|
|
76
|
+
# Try compiling your Go package to TypeScript
|
|
64
77
|
goscript compile --package . --output ./dist
|
|
65
78
|
```
|
|
66
79
|
|
|
80
|
+
**Note:** Many Go packages may not compile successfully yet. Start with simple code and gradually test more complex features.
|
|
81
|
+
|
|
67
82
|
## 📦 Using Generated Code in Your Project
|
|
68
83
|
|
|
69
84
|
After compiling your Go code to TypeScript, you'll need to set up your project appropriately.
|
|
@@ -168,6 +183,8 @@ const searchUser = (email: string) => {
|
|
|
168
183
|
|
|
169
184
|
## 💡 See It In Action
|
|
170
185
|
|
|
186
|
+
> **Disclaimer:** These examples represent the target functionality. Your mileage may vary with the current development preview.
|
|
187
|
+
|
|
171
188
|
### Example: User Management
|
|
172
189
|
|
|
173
190
|
**Go Code** (`user.go`):
|
|
@@ -203,7 +220,7 @@ func FindUserByEmail(users []*User, email string) *User {
|
|
|
203
220
|
goscript compile --package . --output ./dist
|
|
204
221
|
```
|
|
205
222
|
|
|
206
|
-
**Generated TypeScript** (`user.ts`):
|
|
223
|
+
**Generated TypeScript** (`user.gs.ts`):
|
|
207
224
|
```typescript
|
|
208
225
|
export class User {
|
|
209
226
|
public ID: number = 0
|
|
@@ -298,21 +315,11 @@ async function handleMessages() {
|
|
|
298
315
|
}
|
|
299
316
|
```
|
|
300
317
|
|
|
301
|
-
##
|
|
302
|
-
|
|
303
|
-
**Current Status:**
|
|
304
|
-
- ✅ Core language features (structs, methods, interfaces)
|
|
305
|
-
- ✅ Async/await for goroutines and channels
|
|
306
|
-
- ✅ Basic reflection support
|
|
307
|
-
- ✅ Most control flow and data types
|
|
308
|
-
|
|
309
|
-
**Coming Soon:**
|
|
310
|
-
- 📦 Expanded standard library
|
|
311
|
-
- 🧪 Go test → TypeScript test conversion
|
|
312
|
-
- ⚡ Performance optimizations
|
|
313
|
-
- 🔧 Better tooling integration
|
|
318
|
+
## 🤝 How You Can Help
|
|
314
319
|
|
|
315
|
-
|
|
320
|
+
- Try GoScript on your code and [report issues](https://github.com/aperturerobotics/goscript/issues)
|
|
321
|
+
- Check the [compliance tests](./compliance/COMPLIANCE.md) for current progress
|
|
322
|
+
- Contribute test cases for edge cases you discover
|
|
316
323
|
|
|
317
324
|
## License
|
|
318
325
|
|
package/compiler/analysis.go
CHANGED
|
@@ -2,7 +2,6 @@ package compiler
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"encoding/json"
|
|
5
|
-
"fmt"
|
|
6
5
|
"go/ast"
|
|
7
6
|
"go/token"
|
|
8
7
|
"go/types"
|
|
@@ -641,6 +640,22 @@ func (v *analysisVisitor) visitFuncDecl(n *ast.FuncDecl) ast.Visitor {
|
|
|
641
640
|
funcInfo := v.analysis.ensureFunctionData(obj)
|
|
642
641
|
funcInfo.ReceiverUsed = receiverUsed
|
|
643
642
|
}
|
|
643
|
+
|
|
644
|
+
// If receiver is used, mark all identifiers that refer to the receiver variable
|
|
645
|
+
if receiverUsed && n.Body != nil {
|
|
646
|
+
recvName := ident.Name
|
|
647
|
+
ast.Inspect(n.Body, func(nn ast.Node) bool {
|
|
648
|
+
id, ok := nn.(*ast.Ident)
|
|
649
|
+
if !ok {
|
|
650
|
+
return true
|
|
651
|
+
}
|
|
652
|
+
if obj := v.pkg.TypesInfo.Uses[id]; obj != nil && obj == vr {
|
|
653
|
+
ni := v.analysis.ensureNodeData(id)
|
|
654
|
+
ni.IdentifierMapping = recvName
|
|
655
|
+
}
|
|
656
|
+
return true
|
|
657
|
+
})
|
|
658
|
+
}
|
|
644
659
|
}
|
|
645
660
|
}
|
|
646
661
|
}
|
|
@@ -759,9 +774,92 @@ func (v *analysisVisitor) visitCallExpr(n *ast.CallExpr) ast.Visitor {
|
|
|
759
774
|
// Track interface implementations from function call arguments
|
|
760
775
|
v.trackInterfaceCallArguments(n)
|
|
761
776
|
|
|
777
|
+
// Check for implicit address-taking in method calls with pointer receivers
|
|
778
|
+
v.checkImplicitAddressTaking(n)
|
|
779
|
+
|
|
762
780
|
return v
|
|
763
781
|
}
|
|
764
782
|
|
|
783
|
+
// checkImplicitAddressTaking detects when a method call with a pointer receiver
|
|
784
|
+
// is called on a non-pointer variable, which requires implicit address-taking.
|
|
785
|
+
// Example: var s MySlice; s.Add(10) where Add has receiver *MySlice
|
|
786
|
+
// This is equivalent to (&s).Add(10), so s needs to be marked as NeedsVarRef
|
|
787
|
+
func (v *analysisVisitor) checkImplicitAddressTaking(callExpr *ast.CallExpr) {
|
|
788
|
+
// Check if this is a method call (selector expression)
|
|
789
|
+
selExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
|
|
790
|
+
if !ok {
|
|
791
|
+
return
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Get the selection information
|
|
795
|
+
selection := v.pkg.TypesInfo.Selections[selExpr]
|
|
796
|
+
if selection == nil || selection.Kind() != types.MethodVal {
|
|
797
|
+
return
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Get the method object
|
|
801
|
+
methodObj := selection.Obj()
|
|
802
|
+
if methodObj == nil {
|
|
803
|
+
return
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Get the method's signature to check the receiver type
|
|
807
|
+
methodFunc, ok := methodObj.(*types.Func)
|
|
808
|
+
if !ok {
|
|
809
|
+
return
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
sig := methodFunc.Type().(*types.Signature)
|
|
813
|
+
recv := sig.Recv()
|
|
814
|
+
if recv == nil {
|
|
815
|
+
return
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Check if the method has a pointer receiver
|
|
819
|
+
recvType := recv.Type()
|
|
820
|
+
_, hasPointerReceiver := recvType.(*types.Pointer)
|
|
821
|
+
if !hasPointerReceiver {
|
|
822
|
+
return
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Get the type of the receiver expression (the thing before the dot)
|
|
826
|
+
exprType := v.pkg.TypesInfo.TypeOf(selExpr.X)
|
|
827
|
+
if exprType == nil {
|
|
828
|
+
return
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Check if the receiver expression is NOT already a pointer
|
|
832
|
+
_, exprIsPointer := exprType.(*types.Pointer)
|
|
833
|
+
if exprIsPointer {
|
|
834
|
+
// Expression is already a pointer, no implicit address-taking needed
|
|
835
|
+
return
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// At this point, we have:
|
|
839
|
+
// - A method with a pointer receiver
|
|
840
|
+
// - Being called on a non-pointer expression
|
|
841
|
+
// This means Go will implicitly take the address
|
|
842
|
+
|
|
843
|
+
// Check if the receiver expression is an identifier (variable)
|
|
844
|
+
ident, ok := selExpr.X.(*ast.Ident)
|
|
845
|
+
if !ok {
|
|
846
|
+
return
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Get the variable object
|
|
850
|
+
obj := v.pkg.TypesInfo.ObjectOf(ident)
|
|
851
|
+
if obj == nil {
|
|
852
|
+
return
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Mark this variable as needing VarRef (its address is being taken)
|
|
856
|
+
usageInfo := v.getOrCreateUsageInfo(obj)
|
|
857
|
+
usageInfo.Destinations = append(usageInfo.Destinations, AssignmentInfo{
|
|
858
|
+
Object: nil, // No specific destination for method calls
|
|
859
|
+
Type: AddressOfAssignment,
|
|
860
|
+
})
|
|
861
|
+
}
|
|
862
|
+
|
|
765
863
|
// visitSelectorExpr handles selector expression analysis
|
|
766
864
|
func (v *analysisVisitor) visitSelectorExpr(n *ast.SelectorExpr) ast.Visitor {
|
|
767
865
|
// Check if this is a method value (method being used as a value, not called immediately)
|
|
@@ -1373,6 +1471,14 @@ func (a *Analysis) loadGsMetadata(metaFilePath string) *GsMetadata {
|
|
|
1373
1471
|
return &metadata
|
|
1374
1472
|
}
|
|
1375
1473
|
|
|
1474
|
+
// isHandwrittenPackage checks if a package path corresponds to a handwritten package in gs/
|
|
1475
|
+
func (a *Analysis) isHandwrittenPackage(pkgPath string) bool {
|
|
1476
|
+
// Check if the package exists in the embedded gs/ directory
|
|
1477
|
+
metaFilePath := filepath.Join("gs", pkgPath, "meta.json")
|
|
1478
|
+
_, err := goscript.GsOverrides.ReadFile(metaFilePath)
|
|
1479
|
+
return err == nil
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1376
1482
|
// IsMethodAsync checks if a method call is async based on package metadata
|
|
1377
1483
|
func (a *Analysis) IsMethodAsync(pkgPath, typeName, methodName string) bool {
|
|
1378
1484
|
// First, check pre-computed method async status
|
|
@@ -2147,13 +2253,49 @@ func (v *analysisVisitor) analyzeAllMethodsAsync() {
|
|
|
2147
2253
|
// Initialize visitingMethods map
|
|
2148
2254
|
v.visitingMethods = make(map[MethodKey]bool)
|
|
2149
2255
|
|
|
2150
|
-
//
|
|
2151
|
-
|
|
2256
|
+
// Fixed-point iteration: keep analyzing until nothing changes
|
|
2257
|
+
// This handles cases where method A calls method B, but B is analyzed after A
|
|
2258
|
+
maxIterations := 10
|
|
2259
|
+
for iteration := 0; iteration < maxIterations; iteration++ {
|
|
2260
|
+
// Clear visitingMethods map for this iteration
|
|
2261
|
+
v.visitingMethods = make(map[MethodKey]bool)
|
|
2152
2262
|
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2263
|
+
// Track if anything changed in this iteration
|
|
2264
|
+
changed := false
|
|
2265
|
+
|
|
2266
|
+
// Save previous state
|
|
2267
|
+
previousState := make(map[MethodKey]bool)
|
|
2268
|
+
for k, v := range v.analysis.MethodAsyncStatus {
|
|
2269
|
+
previousState[k] = v
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
// Re-analyze methods in current package
|
|
2273
|
+
v.analyzePackageMethodsAsync(v.pkg)
|
|
2274
|
+
|
|
2275
|
+
// Re-analyze methods in all dependency packages
|
|
2276
|
+
for _, pkg := range v.analysis.AllPackages {
|
|
2277
|
+
if pkg != v.pkg {
|
|
2278
|
+
v.analyzePackageMethodsAsync(pkg)
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
// Check if anything changed
|
|
2283
|
+
for k, newValue := range v.analysis.MethodAsyncStatus {
|
|
2284
|
+
oldValue, existed := previousState[k]
|
|
2285
|
+
if !existed {
|
|
2286
|
+
// New method added - check if it's async (if sync, no need to re-analyze dependents)
|
|
2287
|
+
if newValue {
|
|
2288
|
+
changed = true
|
|
2289
|
+
}
|
|
2290
|
+
} else if oldValue != newValue {
|
|
2291
|
+
// Method changed from sync to async (or vice versa)
|
|
2292
|
+
changed = true
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
// If nothing changed, we've reached a fixed point
|
|
2297
|
+
if !changed {
|
|
2298
|
+
break
|
|
2157
2299
|
}
|
|
2158
2300
|
}
|
|
2159
2301
|
|
|
@@ -2212,11 +2354,6 @@ func (v *analysisVisitor) analyzeFunctionLiteralAsync(funcLit *ast.FuncLit, pkg
|
|
|
2212
2354
|
func (v *analysisVisitor) analyzeMethodAsync(funcDecl *ast.FuncDecl, pkg *packages.Package) {
|
|
2213
2355
|
methodKey := v.getMethodKey(funcDecl, pkg)
|
|
2214
2356
|
|
|
2215
|
-
// Check if already analyzed
|
|
2216
|
-
if _, exists := v.analysis.MethodAsyncStatus[methodKey]; exists {
|
|
2217
|
-
return
|
|
2218
|
-
}
|
|
2219
|
-
|
|
2220
2357
|
// Check for cycles
|
|
2221
2358
|
if v.visitingMethods[methodKey] {
|
|
2222
2359
|
// Cycle detected, assume sync to break recursion
|
|
@@ -2230,18 +2367,32 @@ func (v *analysisVisitor) analyzeMethodAsync(funcDecl *ast.FuncDecl, pkg *packag
|
|
|
2230
2367
|
// Determine if method is async
|
|
2231
2368
|
isAsync := false
|
|
2232
2369
|
|
|
2233
|
-
// Determine if this is a
|
|
2234
|
-
|
|
2370
|
+
// Determine if this is a handwritten package (from gs/ directory)
|
|
2371
|
+
// Handwritten packages should not have their bodies analyzed
|
|
2372
|
+
isHandwrittenPackage := v.analysis.isHandwrittenPackage(methodKey.PackagePath)
|
|
2235
2373
|
|
|
2236
|
-
if
|
|
2237
|
-
//
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2374
|
+
if isHandwrittenPackage {
|
|
2375
|
+
// For handwritten packages, check if we have pre-loaded metadata
|
|
2376
|
+
metadataKey := MethodKey{
|
|
2377
|
+
PackagePath: methodKey.PackagePath,
|
|
2378
|
+
ReceiverType: methodKey.ReceiverType,
|
|
2379
|
+
MethodName: methodKey.MethodName,
|
|
2380
|
+
}
|
|
2381
|
+
metadataIsAsync, hasMetadata := v.analysis.MethodAsyncStatus[metadataKey]
|
|
2382
|
+
|
|
2383
|
+
if hasMetadata {
|
|
2384
|
+
// Use explicit metadata from handwritten packages (gs/)
|
|
2385
|
+
isAsync = metadataIsAsync
|
|
2386
|
+
} else {
|
|
2387
|
+
// Handwritten package but no explicit metadata: assume sync
|
|
2388
|
+
isAsync = false
|
|
2243
2389
|
}
|
|
2390
|
+
} else if funcDecl.Body != nil {
|
|
2391
|
+
// Not a handwritten package and has body: always analyze for async operations
|
|
2392
|
+
// This allows fixed-point iteration to update results
|
|
2393
|
+
isAsync = v.containsAsyncOperationsComplete(funcDecl.Body, pkg)
|
|
2244
2394
|
}
|
|
2395
|
+
// Otherwise leave isAsync as false
|
|
2245
2396
|
|
|
2246
2397
|
// Store result in MethodAsyncStatus
|
|
2247
2398
|
v.analysis.MethodAsyncStatus[methodKey] = isAsync
|
|
@@ -2319,16 +2470,8 @@ func (v *analysisVisitor) containsAsyncOperationsComplete(node ast.Node, pkg *pa
|
|
|
2319
2470
|
|
|
2320
2471
|
case *ast.CallExpr:
|
|
2321
2472
|
// Check if we're calling a function known to be async
|
|
2322
|
-
|
|
2323
|
-
if isCallAsyncResult {
|
|
2473
|
+
if v.isCallAsync(s, pkg) {
|
|
2324
2474
|
hasAsync = true
|
|
2325
|
-
callName := ""
|
|
2326
|
-
if ident, ok := s.Fun.(*ast.Ident); ok {
|
|
2327
|
-
callName = ident.Name
|
|
2328
|
-
} else if sel, ok := s.Fun.(*ast.SelectorExpr); ok {
|
|
2329
|
-
callName = sel.Sel.Name
|
|
2330
|
-
}
|
|
2331
|
-
asyncReasons = append(asyncReasons, fmt.Sprintf("async call: %s", callName))
|
|
2332
2475
|
return false
|
|
2333
2476
|
}
|
|
2334
2477
|
}
|
|
@@ -2459,21 +2602,19 @@ func (v *analysisVisitor) isMethodAsyncFromSelection(selExpr *ast.SelectorExpr,
|
|
|
2459
2602
|
return status
|
|
2460
2603
|
}
|
|
2461
2604
|
|
|
2462
|
-
//
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
if key.PackagePath == methodPkgPath {
|
|
2470
|
-
hasMetadata = true
|
|
2471
|
-
break
|
|
2605
|
+
// Check if this is a method in the same package we're currently analyzing
|
|
2606
|
+
if methodPkgPath == v.pkg.Types.Path() {
|
|
2607
|
+
// This is a method in the same package - we should analyze it if we haven't yet
|
|
2608
|
+
if funcDecl := v.findMethodDecl(receiverType, methodObj.Name(), v.pkg); funcDecl != nil {
|
|
2609
|
+
v.analyzeMethodAsync(funcDecl, v.pkg)
|
|
2610
|
+
if status, exists := v.analysis.MethodAsyncStatus[methodKey]; exists {
|
|
2611
|
+
return status
|
|
2472
2612
|
}
|
|
2473
2613
|
}
|
|
2474
|
-
|
|
2475
|
-
//
|
|
2476
|
-
if
|
|
2614
|
+
} else {
|
|
2615
|
+
// For methods in other packages that we're compiling together
|
|
2616
|
+
if targetPkg := v.analysis.AllPackages[methodPkgPath]; targetPkg != nil {
|
|
2617
|
+
// Try to analyze the method if we haven't already
|
|
2477
2618
|
if funcDecl := v.findMethodDecl(receiverType, methodObj.Name(), targetPkg); funcDecl != nil {
|
|
2478
2619
|
v.analyzeMethodAsync(funcDecl, targetPkg)
|
|
2479
2620
|
if status, exists := v.analysis.MethodAsyncStatus[methodKey]; exists {
|