-
Notifications
You must be signed in to change notification settings - Fork 33
pkg.NewTuple #566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pkg.NewTuple #566
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| /* | ||
| Copyright 2026 The XGo Authors (xgo.dev) | ||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| */ | ||
|
|
||
| package gogen | ||
|
|
||
| import ( | ||
| "go/ast" | ||
| "go/types" | ||
| "strconv" | ||
| ) | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| /* | ||
| // vFields defines the interface for virtual fields of a struct type. | ||
| type vFields interface { // virtual fields | ||
| FindField(cb *CodeBuilder, t *types.Struct, name string, arg *Element, src ast.Node) bool | ||
| FieldRef(cb *CodeBuilder, t *types.Struct, name string, x ast.Expr, src ast.Node) bool | ||
| } | ||
| */ | ||
|
|
||
| type vFields = *tupleFields | ||
|
Comment on lines
+24
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The // vFields defines the interface for virtual fields of a struct type.
type vFields interface { // virtual fields
FindField(cb *CodeBuilder, t *types.Struct, name string, arg *Element, src ast.Node) bool
FieldRef(cb *CodeBuilder, t *types.Struct, name string, x ast.Expr, src ast.Node) bool
} |
||
|
|
||
| type vFieldsMgr struct { | ||
| vfts map[*types.Struct]vFields | ||
| } | ||
|
|
||
| func (p *CodeBuilder) refVField(t *types.Struct, name string, x ast.Expr, src ast.Node) bool { | ||
| if vft, ok := p.vfts[t]; ok { | ||
| return vft.FieldRef(p, t, name, x, src) | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| func (p *CodeBuilder) findVField(t *types.Struct, name string, arg *Element, src ast.Node) bool { | ||
| if vft, ok := p.vfts[t]; ok { | ||
| return vft.FindField(p, t, name, arg, src) | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| func (p *Package) setVFields(t *types.Struct, vft vFields) { | ||
| if p.cb.vfts == nil { | ||
| p.cb.vfts = make(map[*types.Struct]vFields) | ||
| } | ||
| p.cb.vfts[t] = vft | ||
| } | ||
|
|
||
| /* | ||
| func (p *Package) vFields(t *types.Struct) (vft vFields, ok bool) { | ||
| vft, ok = p.cb.vfts[t] | ||
| return | ||
| } | ||
| */ | ||
|
Comment on lines
+59
to
+64
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| type tupleFields struct { | ||
| fields []*types.Var | ||
| } | ||
|
|
||
| func (p *tupleFields) FindField(cb *CodeBuilder, t *types.Struct, name string, arg *Element, src ast.Node) bool { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| for i, fld := range p.fields { | ||
| if fld.Name() == name { | ||
| cb.stk.Ret(1, &Element{ | ||
| Val: selector(arg, tupleFieldName(i)), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing nil safety check: The if arg == nil {
return false
}This defensive check would prevent potential nil pointer dereferences. |
||
| Type: fld.Type(), | ||
| Src: src, | ||
| }) | ||
| if cb.rec != nil { | ||
| cb.rec.Member(src, fld) | ||
| } | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| func (p *tupleFields) FieldRef(cb *CodeBuilder, t *types.Struct, name string, x ast.Expr, src ast.Node) bool { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| for i, fld := range p.fields { | ||
| if fld.Name() == name { | ||
| if cb.rec != nil { | ||
| cb.rec.Member(src, fld) | ||
| } | ||
| ordName := tupleFieldName(i) | ||
| cb.stk.Ret(1, &Element{ | ||
| Val: &ast.SelectorExpr{X: x, Sel: ident(ordName)}, | ||
| Type: &refType{typ: fld.Type()}, | ||
| }) | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| // NewTuple creates a tuple type with the given fields. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Documentation clarity: The Godoc should clarify that with Suggested addition: // NewTuple creates a tuple type with the given fields.
// The fields are always accessible by ordinal names: _0, _1, ...
// If withName is true, the fields are ALSO accessible by their original names
// through a virtual fields mechanism. |
||
| // The fields are named as _0, _1, ... | ||
| // If withName is true, the original fields can also be accessed through | ||
| // virtual fields mechanism. | ||
| func (p *Package) NewTuple(withName bool, fields ...*types.Var) *types.Struct { | ||
| ordinals := make([]*types.Var, len(fields)) | ||
| for i, fld := range fields { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Input validation: Consider adding validation for nil fields to make debugging easier: for i, fld := range fields {
if fld == nil {
panic("NewTuple: nil field at index " + strconv.Itoa(i))
}
// ...
}Also consider documenting the behavior when multiple fields have the same name (first match wins). |
||
| name := tupleFieldName(i) | ||
| ordinals[i] = types.NewVar(fld.Pos(), fld.Pkg(), name, fld.Type()) | ||
| } | ||
| ret := types.NewStruct(ordinals, nil) | ||
| if withName { | ||
| p.setVFields(ret, &tupleFields{fields}) | ||
| } | ||
| return ret | ||
| } | ||
|
|
||
| func tupleFieldName(i int) string { | ||
| return "_" + strconv.Itoa(i) | ||
| } | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| /* | ||
| Copyright 2026 The XGo Authors (xgo.dev) | ||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| */ | ||
|
|
||
| package gogen_test | ||
|
|
||
| import ( | ||
| "go/token" | ||
| "go/types" | ||
| "testing" | ||
|
|
||
| "github.com/goplus/gogen" | ||
| ) | ||
|
|
||
| func TestTupleMember(t *testing.T) { | ||
| pkg := newMainPackage() | ||
| x := types.NewField(token.NoPos, pkg.Types, "x", types.Typ[types.Int], false) | ||
| y := types.NewField(token.NoPos, pkg.Types, "y", types.Typ[types.Int], false) | ||
| typ := pkg.NewTuple(true, x, y) | ||
| a := types.NewParam(token.NoPos, pkg.Types, "a", typ) | ||
| pkg.NewFunc(nil, "foo", types.NewTuple(a), nil, false).BodyStart(pkg). | ||
| Val(ctxRef(pkg, "a")). | ||
| MemberRef("x"). | ||
| Val(ctxRef(pkg, "a")). | ||
| MemberVal("y"). | ||
| Assign(1). | ||
| EndStmt(). | ||
| Debug(func(cb *gogen.CodeBuilder) { | ||
| cb.Val(ctxRef(pkg, "a")) | ||
| cb.Member("unknown", gogen.MemberFlagRef) | ||
| cb.Member("unknown", gogen.MemberFlagVal) | ||
| cb.ResetStmt() | ||
| }). | ||
| End() | ||
| domTest(t, pkg, `package main | ||
|
|
||
| func foo(a struct { | ||
| _0 int | ||
| _1 int | ||
| }) { | ||
| a._0 = a._1 | ||
| } | ||
| `) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Virtual field placement issue: Virtual fields are checked after direct fields but before embedded fields. This breaks Go's field resolution semantics where embedded fields are promoted to the same level as direct fields.
If a tuple with virtual field "x" embeds a struct that also has field "x", the virtual field will incorrectly shadow the embedded field.
Recommendation: Move this virtual field check to after embedded field recursion (after the loop at lines 1587-1599) to match Go's semantics.