Skip to content

Commit 3b4e03d

Browse files
uhthomasmvdan
authored andcommitted
cmd/cue: support type parameters in get go
Go type parameters are represented as their basic types in most cases, but there are some more complicated areas which are not handled yet. These cases are documented clearly as TODOs and may be good candidates for improvement work in future. For now, this should unblock importing some packages. Fixes #2217 Change-Id: I5b4660ed3b8c6a11a1f135fe68ed55e966e371b1 Signed-off-by: Thomas Way <[email protected]> Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1171015 Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 286dfcb commit 3b4e03d

File tree

2 files changed

+169
-7
lines changed

2 files changed

+169
-7
lines changed

cmd/cue/cmd/get_go.go

+78-5
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,8 @@ func (e *extractor) makeField(name string, kind fieldKind, expr types.Type, doc
10231023
}
10241024

10251025
func (e *extractor) makeType(expr types.Type) (result cueast.Expr) {
1026-
if x, ok := expr.(*types.Named); ok {
1026+
switch x := expr.(type) {
1027+
case *types.Named:
10271028
obj := x.Obj()
10281029
if obj.Pkg() == nil {
10291030
return e.ident("_", false)
@@ -1076,10 +1077,52 @@ func (e *extractor) makeType(expr types.Type) (result cueast.Expr) {
10761077
result = cueast.NewSel(p, "#"+obj.Name())
10771078
e.usedPkg(pkg.Path())
10781079
}
1079-
return
1080-
}
10811080

1082-
switch x := expr.(type) {
1081+
// TODO(uhthomas): Fields with type parameters should not be
1082+
// top.
1083+
//
1084+
// For example:
1085+
//
1086+
// type A[T any] struct {
1087+
// SomeField T
1088+
// }
1089+
//
1090+
// type B A[string]
1091+
//
1092+
// Should become:
1093+
//
1094+
// #A: SomeField: _
1095+
//
1096+
// #B: #A & {
1097+
// _#T: string
1098+
// SomeField: _#T
1099+
// }
1100+
//
1101+
// Or maybe:
1102+
//
1103+
// #A: {
1104+
// #T: _
1105+
// SomeField: #T
1106+
// }
1107+
//
1108+
// #B: #A & {
1109+
// #T: string
1110+
// }
1111+
//
1112+
// The values of x.TypeParams() and x.TypeArgs() may be helpful.
1113+
1114+
// params := x.TypeParams()
1115+
// args := x.TypeArgs()
1116+
// if params.Len() > 0 {
1117+
// var fields []any
1118+
// for i := 0; i < params.Len(); i++ {
1119+
// name := params.At(i).Obj().Name()
1120+
// fields = append(fields, e.ident(name, true), e.makeType(args.At(i)))
1121+
// }
1122+
// return cueast.NewBinExpr(cuetoken.AND, result, cueast.NewStruct(fields...))
1123+
// }
1124+
1125+
return result
10831126
case *types.Pointer:
10841127
return &cueast.BinaryExpr{
10851128
X: cueast.NewNull(),
@@ -1148,8 +1191,38 @@ func (e *extractor) makeType(expr types.Type) (result cueast.Expr) {
11481191
return e.ident(x.String(), false)
11491192
}
11501193

1194+
case *types.Union:
1195+
var exprs []cueast.Expr
1196+
for i := 0; i < x.Len(); i++ {
1197+
exprs = append(exprs, e.makeType(x.Term(i).Type()))
1198+
}
1199+
return cueast.NewBinExpr(cuetoken.OR, exprs...)
1200+
11511201
case *types.Interface:
1152-
return e.ident("_", false)
1202+
// TODO(uhthomas): Should interfaces with methods (IsMethodSet)
1203+
// be set to top?
1204+
if !x.IsComparable() {
1205+
return e.ident("_", false)
1206+
}
1207+
1208+
// TODO(uhthomas): Simplify expressions.
1209+
//
1210+
// For example:
1211+
//
1212+
// int | (int | string)
1213+
//
1214+
// Should really become:
1215+
//
1216+
// int | string
1217+
//
1218+
var exprs []cueast.Expr
1219+
for i := 0; i < x.NumEmbeddeds(); i++ {
1220+
exprs = append(exprs, e.makeType(x.EmbeddedType(i)))
1221+
}
1222+
return cueast.NewBinExpr(cuetoken.OR, exprs...)
1223+
1224+
case *types.TypeParam:
1225+
return e.makeType(x.Constraint())
11531226

11541227
default:
11551228
// record error

cmd/cue/cmd/testdata/script/get_go_types.txtar

+91-2
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@ cmp ./pkg1/file1_go_gen.cue ./pkg1/file1_go_gen.cue.golden
1313
cmp ./pkg1/alias_go_gen.cue ./pkg1/alias_go_gen.cue.golden
1414
cmp ./pkg2/pkg2_go_gen.cue ./pkg2/pkg2_go_gen.cue.golden
1515
cmp ./pkg4/pkg4_go_gen.cue ./pkg4/pkg4_go_gen.cue.golden
16+
cmp ./pkg_generics/pkg_generics_go_gen.cue ./pkg_generics/pkg_generics_go_gen.cue.golden
1617

1718
# Verify dependencies did not change
1819
cmp go.mod go.mod.golden
1920

2021
-- go.mod --
2122
module mod.test
2223

23-
go 1.14
24+
go 1.21
2425
-- go.mod.golden --
2526
module mod.test
2627

27-
go 1.14
28+
go 1.21
2829
-- cue.mod --
2930
module: "mod.test"
3031
-- pkg1/alias.go --
@@ -433,3 +434,91 @@ package pkg4
433434
#A: {
434435
UnsafePointer: uint64 @go(,unsafe.Pointer)
435436
}
437+
-- pkg_generics/pkg_generics.go --
438+
package pkg_generics
439+
440+
type SomeUnionInterface interface {
441+
string | int | byte
442+
}
443+
444+
type SomeStructAny[T any] struct {
445+
SomeField T
446+
}
447+
448+
type SomeStructString[T string] struct {
449+
SomeField T
450+
}
451+
452+
type SomeStructSomeInterface[T SomeUnionInterface] struct {
453+
SomeField T
454+
}
455+
456+
type SomeStructMultipleTypeParameters[T string, Z ~int] struct {
457+
SomeField T
458+
SomeOtherField Z
459+
}
460+
461+
type SomeStructComparable[T comparable] struct {
462+
SomeField T
463+
}
464+
465+
type SomeInterfaceWithMethod interface {
466+
int
467+
468+
Do() string
469+
}
470+
471+
type SomeAlias = string
472+
473+
type StructWithAlias[T SomeAlias] struct {
474+
SomeField T
475+
}
476+
477+
type SomeType int
478+
479+
type StructWithType[T SomeType] struct {
480+
SomeField T
481+
}
482+
-- pkg_generics/pkg_generics_go_gen.cue.golden --
483+
// Code generated by cue get go. DO NOT EDIT.
484+
485+
//cue:generate cue get go mod.test/pkg_generics
486+
487+
package pkg_generics
488+
489+
#SomeUnionInterface: string | int | uint8
490+
491+
#SomeStructAny: {
492+
SomeField: _ @go(,T)
493+
}
494+
495+
#SomeStructString: {
496+
SomeField: string @go(,T)
497+
}
498+
499+
#SomeStructSomeInterface: {
500+
SomeField: #SomeUnionInterface @go(,T)
501+
}
502+
503+
#SomeStructMultipleTypeParameters: {
504+
SomeField: string @go(,T)
505+
SomeOtherField: int @go(,Z)
506+
}
507+
508+
#SomeStructComparable: {
509+
SomeField: _ @go(,T)
510+
}
511+
512+
#SomeInterfaceWithMethod: int
513+
514+
#SomeAlias: string
515+
516+
#StructWithAlias: {
517+
SomeField: string @go(,T)
518+
}
519+
520+
#SomeType: int
521+
522+
#StructWithType: {
523+
SomeField: #SomeType @go(,T)
524+
}

0 commit comments

Comments
 (0)