Skip to content

Commit

Permalink
cmd/cloner, cmd/viewer, util/codegen: add support for aliases of clon…
Browse files Browse the repository at this point in the history
…eable types

We have several checked type assertions to *types.Named in both cmd/cloner and cmd/viewer.
As Go 1.23 updates the go/types package to produce Alias type nodes for type aliases,
these type assertions no longer work as expected unless the new behavior is disabled
with gotypesalias=0.

In this PR, we add codegen.NamedTypeOf(t types.Type), which functions like t.(*types.Named)
but also unrolls type aliases. We then use it in place of type assertions in the cmd/cloner and
cmd/viewer packages where appropriate.

We also update type switches to include *types.Alias alongside *types.Named in relevant cases,
remove *types.Struct cases when switching on types.Type.Underlying and update the tests
with more cases where type aliases can be used.

Updates tailscale#13224
Updates tailscale#12912

Signed-off-by: Nick Khyl <[email protected]>
  • Loading branch information
nickkhyl committed Aug 23, 2024
1 parent a9dc6e0 commit 03acab2
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 18 deletions.
4 changes: 2 additions & 2 deletions cmd/cloner/cloner.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func gen(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named) {
if !codegen.ContainsPointers(ft) || codegen.HasNoClone(t.Tag(i)) {
continue
}
if named, _ := ft.(*types.Named); named != nil {
if named, _ := codegen.NamedTypeOf(ft); named != nil {
if codegen.IsViewType(ft) {
writef("dst.%s = src.%s", fname, fname)
continue
Expand Down Expand Up @@ -161,7 +161,7 @@ func gen(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named) {
case *types.Pointer:
base := ft.Elem()
hasPtrs := codegen.ContainsPointers(base)
if named, _ := base.(*types.Named); named != nil && hasPtrs {
if named, _ := codegen.NamedTypeOf(base); named != nil && hasPtrs {
writef("dst.%s = src.%s.Clone()", fname, fname)
continue
}
Expand Down
18 changes: 16 additions & 2 deletions cmd/viewer/tests/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,27 @@ type StructWithContainers struct {
}

type (
StructWithPtrsAlias = StructWithPtrs
StructWithoutPtrsAlias = StructWithoutPtrs
StructWithPtrsAlias = StructWithPtrs
StructWithoutPtrsAlias = StructWithoutPtrs
StructWithPtrsAliasView = StructWithPtrsView
StructWithoutPtrsAliasView = StructWithoutPtrsView
)

type StructWithTypeAliasFields struct {
WithPtr StructWithPtrsAlias
WithoutPtr StructWithoutPtrsAlias

WithPtrByPtr *StructWithPtrsAlias
WithoutPtrByPtr *StructWithoutPtrsAlias

SliceWithPtrs []*StructWithPtrsAlias
SliceWithoutPtrs []*StructWithoutPtrsAlias

MapWithPtrs map[string]*StructWithPtrsAlias
MapWithoutPtrs map[string]*StructWithoutPtrsAlias

MapOfSlicesWithPtrs map[string][]*StructWithPtrsAlias
MapOfSlicesWithoutPtrs map[string][]*StructWithoutPtrsAlias
}

type integer = constraints.Integer
Expand Down
70 changes: 67 additions & 3 deletions cmd/viewer/tests/tests_clone.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 51 additions & 2 deletions cmd/viewer/tests/tests_view.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions cmd/viewer/viewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
writeTemplate("sliceField")
}
continue
case *types.Struct, *types.Named:
case *types.Struct:
strucT := underlying
args.FieldType = it.QualifiedName(fieldType)
if codegen.ContainsPointers(strucT) {
Expand Down Expand Up @@ -262,7 +262,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
mElem := m.Elem()
var template string
switch u := mElem.(type) {
case *types.Struct, *types.Named:
case *types.Struct, *types.Named, *types.Alias:
strucT := u
args.FieldType = it.QualifiedName(fieldType)
if codegen.ContainsPointers(strucT) {
Expand All @@ -281,7 +281,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
slice := u
sElem := slice.Elem()
switch x := sElem.(type) {
case *types.Basic, *types.Named:
case *types.Basic, *types.Named, *types.Alias:
sElem := it.QualifiedName(sElem)
args.MapValueView = fmt.Sprintf("views.Slice[%v]", sElem)
args.MapValueType = sElem
Expand All @@ -292,7 +292,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
template = "unsupportedField"
if _, isIface := pElem.Underlying().(*types.Interface); !isIface {
switch pElem.(type) {
case *types.Struct, *types.Named:
case *types.Struct, *types.Named, *types.Alias:
ptrType := it.QualifiedName(ptr)
viewType := appendNameSuffix(it.QualifiedName(pElem), "View")
args.MapFn = fmt.Sprintf("views.SliceOfViews[%v,%v](t)", ptrType, viewType)
Expand All @@ -313,7 +313,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
pElem := ptr.Elem()
if _, isIface := pElem.Underlying().(*types.Interface); !isIface {
switch pElem.(type) {
case *types.Struct, *types.Named:
case *types.Struct, *types.Named, *types.Alias:
args.MapValueType = it.QualifiedName(ptr)
args.MapValueView = appendNameSuffix(it.QualifiedName(pElem), "View")
args.MapFn = "t.View()"
Expand Down Expand Up @@ -422,7 +422,7 @@ func viewTypeForValueType(typ types.Type) types.Type {
func viewTypeForContainerType(typ types.Type) (*types.Named, *types.Func) {
// The container type should be an instantiated generic type,
// with its first type parameter specifying the element type.
containerType, ok := typ.(*types.Named)
containerType, ok := codegen.NamedTypeOf(typ)
if !ok || containerType.TypeArgs().Len() == 0 {
return nil, nil
}
Expand All @@ -435,7 +435,7 @@ func viewTypeForContainerType(typ types.Type) (*types.Named, *types.Func) {
if !ok {
return nil, nil
}
containerViewGenericType, ok := containerViewTypeObj.Type().(*types.Named)
containerViewGenericType, ok := codegen.NamedTypeOf(containerViewTypeObj.Type())
if !ok || containerViewGenericType.TypeParams().Len() != containerType.TypeArgs().Len()+1 {
return nil, nil
}
Expand All @@ -448,7 +448,7 @@ func viewTypeForContainerType(typ types.Type) (*types.Named, *types.Func) {
}
// ...and add the element view type.
// For that, we need to first determine the named elem type...
elemType, ok := baseType(containerType.TypeArgs().At(containerType.TypeArgs().Len() - 1)).(*types.Named)
elemType, ok := codegen.NamedTypeOf(baseType(containerType.TypeArgs().At(containerType.TypeArgs().Len() - 1)))
if !ok {
return nil, nil
}
Expand All @@ -473,7 +473,7 @@ func viewTypeForContainerType(typ types.Type) (*types.Named, *types.Func) {
}
// If elemType is an instantiated generic type, instantiate the elemViewType as well.
if elemTypeArgs := elemType.TypeArgs(); elemTypeArgs != nil {
elemViewType = must.Get(types.Instantiate(nil, elemViewType, collectTypes(elemTypeArgs), false)).(*types.Named)
elemViewType, _ = codegen.NamedTypeOf(must.Get(types.Instantiate(nil, elemViewType, collectTypes(elemTypeArgs), false)))
}
// And finally set the elemViewType as the last type argument.
containerViewTypeArgs[len(containerViewTypeArgs)-1] = elemViewType
Expand Down
9 changes: 9 additions & 0 deletions util/codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,12 @@ func LookupMethod(t types.Type, name string) *types.Func {
}
return nil
}

// NamedTypeOf is like t.(*types.Named), but also works with type aliases.
func NamedTypeOf(t types.Type) (named *types.Named, ok bool) {
if a, ok := t.(*types.Alias); ok {
return NamedTypeOf(types.Unalias(a))
}
named, ok = t.(*types.Named)
return
}

0 comments on commit 03acab2

Please sign in to comment.