@@ -14,9 +14,9 @@ import (
14
14
15
15
"github.com/gopherjs/gopherjs/compiler/analysis"
16
16
"github.com/gopherjs/gopherjs/compiler/astutil"
17
+ "github.com/gopherjs/gopherjs/compiler/typesutil"
17
18
"github.com/neelance/astrewrite"
18
19
"golang.org/x/tools/go/gcexportdata"
19
- "golang.org/x/tools/go/types/typeutil"
20
20
)
21
21
22
22
// pkgContext maintains compiler context for a specific package.
@@ -28,8 +28,7 @@ type pkgContext struct {
28
28
pkgVars map [string ]string
29
29
objectNames map [types.Object ]string
30
30
varPtrNames map [* types.Var ]string
31
- anonTypes []* types.TypeName
32
- anonTypeMap typeutil.Map
31
+ anonTypes typesutil.AnonymousTypes
33
32
escapingVars map [* types.Var ]bool
34
33
indentation int
35
34
dependencies map [types.Object ]bool
@@ -38,6 +37,14 @@ type pkgContext struct {
38
37
errList ErrorList
39
38
}
40
39
40
+ // genericCtx contains compiler context for a generic function or type.
41
+ //
42
+ // It is used to accumulate information about types and objects that depend on
43
+ // type parameters and must be constructed in a generic factory function.
44
+ type genericCtx struct {
45
+ anonTypes typesutil.AnonymousTypes
46
+ }
47
+
41
48
func (p * pkgContext ) SelectionOf (e * ast.SelectorExpr ) (selection , bool ) {
42
49
if sel , ok := p .Selections [e ]; ok {
43
50
return sel , true
@@ -78,6 +85,8 @@ type funcContext struct {
78
85
* analysis.FuncInfo
79
86
// Surrounding package context.
80
87
pkgCtx * pkgContext
88
+ // Surrounding generic function context. nil if non-generic code.
89
+ genericCtx * genericCtx
81
90
// Function context, surrounding this function definition. For package-level
82
91
// functions or methods it is the package-level function context (even though
83
92
// it technically doesn't correspond to a function). nil for the package-level
@@ -597,7 +606,7 @@ func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, impor
597
606
}
598
607
599
608
// anonymous types
600
- for _ , t := range funcCtx .pkgCtx .anonTypes {
609
+ for _ , t := range funcCtx .pkgCtx .anonTypes . Ordered () {
601
610
d := Decl {
602
611
Vars : []string {t .Name ()},
603
612
DceObjectFilter : t .Name (),
@@ -758,6 +767,7 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
758
767
c := & funcContext {
759
768
FuncInfo : info ,
760
769
pkgCtx : outerContext .pkgCtx ,
770
+ genericCtx : outerContext .genericCtx ,
761
771
parent : outerContext ,
762
772
sigTypes : & signatureTypes {Sig : sig },
763
773
allVars : make (map [string ]int , len (outerContext .allVars )),
@@ -769,6 +779,9 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
769
779
for k , v := range outerContext .allVars {
770
780
c .allVars [k ] = v
771
781
}
782
+ if c .sigTypes .IsGeneric () {
783
+ c .genericCtx = & genericCtx {}
784
+ }
772
785
prevEV := c .pkgCtx .escapingVars
773
786
774
787
var params []string
@@ -786,7 +799,7 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
786
799
}
787
800
}
788
801
789
- bodyOutput := string (c .CatchOutput (1 , func () {
802
+ bodyOutput := string (c .CatchOutput (c . bodyIndent () , func () {
790
803
if len (c .Blocking ) != 0 {
791
804
c .pkgCtx .Scopes [body ] = c .pkgCtx .Scopes [typ ]
792
805
c .handleEscapingVars (body )
@@ -888,13 +901,13 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
888
901
}
889
902
890
903
if prefix != "" {
891
- bodyOutput = c .Indentation (1 ) + "/* */" + prefix + "\n " + bodyOutput
904
+ bodyOutput = c .Indentation (c . bodyIndent () ) + "/* */" + prefix + "\n " + bodyOutput
892
905
}
893
906
if suffix != "" {
894
- bodyOutput = bodyOutput + c .Indentation (1 ) + "/* */" + suffix + "\n "
907
+ bodyOutput = bodyOutput + c .Indentation (c . bodyIndent () ) + "/* */" + suffix + "\n "
895
908
}
896
909
if localVarDefs != "" {
897
- bodyOutput = c .Indentation (1 ) + localVarDefs + bodyOutput
910
+ bodyOutput = c .Indentation (c . bodyIndent () ) + localVarDefs + bodyOutput
898
911
}
899
912
900
913
c .pkgCtx .escapingVars = prevEV
@@ -907,14 +920,23 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
907
920
// from the call site.
908
921
// TODO(nevkontakte): Cache function instances for a given combination of type
909
922
// parameters.
910
- // TODO(nevkontakte): Generate type parameter arguments and derive all dependent
911
- // types inside the function.
912
923
typeParams := []string {}
913
924
for i := 0 ; i < c .sigTypes .Sig .TypeParams ().Len (); i ++ {
914
925
typeParam := c .sigTypes .Sig .TypeParams ().At (i )
915
926
typeParams = append (typeParams , c .typeName (typeParam ))
916
927
}
917
928
918
- return params , fmt .Sprintf ("function%s(%s){ return function(%s) {\n %s%s}; }" ,
919
- functionName , strings .Join (typeParams , ", " ), strings .Join (params , ", " ), bodyOutput , c .Indentation (0 ))
929
+ // anonymous types
930
+ typesInit := strings.Builder {}
931
+ for _ , t := range c .genericCtx .anonTypes .Ordered () {
932
+ fmt .Fprintf (& typesInit , "%svar %s = $%sType(%s);\n " , c .Indentation (1 ), t .Name (), strings .ToLower (typeKind (t .Type ())[5 :]), c .initArgs (t .Type ()))
933
+ }
934
+
935
+ code := & strings.Builder {}
936
+ fmt .Fprintf (code , "function%s(%s){\n " , functionName , strings .Join (typeParams , ", " ))
937
+ fmt .Fprintf (code , "%s" , typesInit .String ())
938
+ fmt .Fprintf (code , "%sreturn function(%s) {\n " , c .Indentation (1 ), strings .Join (params , ", " ))
939
+ fmt .Fprintf (code , "%s" , bodyOutput )
940
+ fmt .Fprintf (code , "%s};\n %s}" , c .Indentation (1 ), c .Indentation (0 ))
941
+ return params , code .String ()
920
942
}
0 commit comments