Skip to content

Commit

Permalink
Fix copying TypeParams (#5)
Browse files Browse the repository at this point in the history
There was a bug where the TypeParams weren't being properly copied but
rather continuing the use the source value.

The code:

```
cp := *x
if typeParams := typeparams.ForFuncType(x); typeParams != nil {
	*typeparams.ForFuncType(&cp) = *FieldList(typeParams)
}
```

cp.TypeParams which typeparams.ForFyncType returns is still
x.TypeParams. Then the `*typeparams.ForFuncType(&cp)` overwrites it a
copy thus modifying the original slice.

This issue causes a data race which showed up in golangci-lint and often
caused a panic.

The only way around this I found was to have copies of the function for
different versions of Go since the typeparam package doesn't have a way
to set the TypeParams field.
  • Loading branch information
samuel authored Jan 21, 2023
1 parent 6984600 commit a4c4beb
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 32 deletions.
32 changes: 0 additions & 32 deletions astcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,21 +346,6 @@ func FieldList(x *ast.FieldList) *ast.FieldList {
return &cp
}

// FuncType returns x deep copy.
// Copy of nil argument is nil.
func FuncType(x *ast.FuncType) *ast.FuncType {
if x == nil {
return nil
}
cp := *x
cp.Params = FieldList(x.Params)
cp.Results = FieldList(x.Results)
if typeParams := typeparams.ForFuncType(x); typeParams != nil {
*typeparams.ForFuncType(&cp) = *FieldList(typeParams)
}
return &cp
}

// InterfaceType returns x deep copy.
// Copy of nil argument is nil.
func InterfaceType(x *ast.InterfaceType) *ast.InterfaceType {
Expand Down Expand Up @@ -435,23 +420,6 @@ func ValueSpec(x *ast.ValueSpec) *ast.ValueSpec {
return &cp
}

// TypeSpec returns x deep copy.
// Copy of nil argument is nil.
func TypeSpec(x *ast.TypeSpec) *ast.TypeSpec {
if x == nil {
return nil
}
cp := *x
cp.Name = Ident(x.Name)
cp.Type = copyExpr(x.Type)
cp.Doc = CommentGroup(x.Doc)
cp.Comment = CommentGroup(x.Comment)
if typeParams := typeparams.ForTypeSpec(x); typeParams != nil {
*typeparams.ForTypeSpec(&cp) = *FieldList(typeParams)
}
return &cp
}

// Spec returns x deep copy.
// Copy of nil argument is nil.
func Spec(x ast.Spec) ast.Spec {
Expand Down
30 changes: 30 additions & 0 deletions astcopy_go117.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//go:build !go1.18
// +build !go1.18

package astcopy

// FuncType returns x deep copy.
// Copy of nil argument is nil.
func FuncType(x *ast.FuncType) *ast.FuncType {
if x == nil {
return nil
}
cp := *x
cp.Params = FieldList(x.Params)
cp.Results = FieldList(x.Results)
return &cp
}

// TypeSpec returns x deep copy.
// Copy of nil argument is nil.
func TypeSpec(x *ast.TypeSpec) *ast.TypeSpec {
if x == nil {
return nil
}
cp := *x
cp.Name = Ident(x.Name)
cp.Type = copyExpr(x.Type)
cp.Doc = CommentGroup(x.Doc)
cp.Comment = CommentGroup(x.Comment)
return &cp
}
36 changes: 36 additions & 0 deletions astcopy_go118.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//go:build go1.18
// +build go1.18

package astcopy

import (
"go/ast"
)

// FuncType returns x deep copy.
// Copy of nil argument is nil.
func FuncType(x *ast.FuncType) *ast.FuncType {
if x == nil {
return nil
}
cp := *x
cp.Params = FieldList(x.Params)
cp.Results = FieldList(x.Results)
cp.TypeParams = FieldList(x.TypeParams)
return &cp
}

// TypeSpec returns x deep copy.
// Copy of nil argument is nil.
func TypeSpec(x *ast.TypeSpec) *ast.TypeSpec {
if x == nil {
return nil
}
cp := *x
cp.Name = Ident(x.Name)
cp.Type = copyExpr(x.Type)
cp.Doc = CommentGroup(x.Doc)
cp.Comment = CommentGroup(x.Comment)
cp.TypeParams = FieldList(x.TypeParams)
return &cp
}

0 comments on commit a4c4beb

Please sign in to comment.