Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ func matchRcast(pkg *Package, fn *internal.Elem, m types.Object, typ types.Type,
return nil, fmt.Errorf("TODO: %v should return %d results", m, n)
}
if types.Identical(results.At(0).Type(), typ) {
return pkg.cb.Val(fn).MemberVal(m.Name()).CallWith(0, lhs, flags).stk.Pop(), nil
return pkg.cb.Val(fn).MemberVal(m.Name(), 0).CallWith(0, lhs, flags).stk.Pop(), nil
}
return nil, &MatchError{
Src: fn.Src, Arg: fn.Type, Param: typ, At: "XGo_Rcast",
Expand Down
11 changes: 1 addition & 10 deletions builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ retry:
// TODO: refactor
cb := pkg.cb
cb.stk.Push(elemNone)
kind := cb.findMember(typ, "XGo_Add", "", MemberFlagVal, &Element{}, nil, nil)
kind := cb.findMember(typ, "XGo_Add", "", 0, MemberFlagVal, &Element{}, nil, nil)
if kind != 0 {
cb.stk.PopN(1)
if kind == MemberMethod {
Expand Down Expand Up @@ -1499,7 +1499,6 @@ func (p *BuiltinTI) lookupByName(name string) mthdSignature {
}

var (
tyMap types.Type = types.NewMap(types.Typ[types.Invalid], types.Typ[types.Invalid])
tyChan types.Type = types.NewChan(0, types.Typ[types.Invalid])
tySlice types.Type = types.NewSlice(types.Typ[types.Invalid])
)
Expand Down Expand Up @@ -1629,12 +1628,6 @@ func initBuiltinTIs(pkg *Package) {
{"Cap", btoCap, nil},
},
},
{
typ: tyMap,
methods: []*BuiltinMethod{
{"Len", btoLen, nil},
},
},
{
typ: tyChan,
methods: []*BuiltinMethod{
Expand All @@ -1658,8 +1651,6 @@ func (p *CodeBuilder) getBuiltinTI(typ types.Type) *BuiltinTI {
if t.Elem() != types.Typ[types.String] {
typ = tySlice
}
case *types.Map:
typ = tyMap
case *types.Chan:
typ = tyChan
}
Expand Down
52 changes: 42 additions & 10 deletions codebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ func (p *CodeBuilder) UntypedBigInt(v *big.Int, src ...ast.Node) *CodeBuilder {
p.NewClosure(nil, types.NewTuple(ret), false).BodyStart(pkg).
DefineVarStart(token.NoPos, "v", "_").
Val(pkg.builtin.Ref("new")).Typ(typ).Call(1).
MemberVal("SetString").Val(v.String()).Val(10).Call(2).EndInit(1).
MemberVal("SetString", 0).Val(v.String()).Val(10).Call(2).EndInit(1).
Val(p.Scope().Lookup("v")).Return(1).
End().Call(0)
}
Expand All @@ -1426,7 +1426,7 @@ func (p *CodeBuilder) UntypedBigRat(v *big.Rat, src ...ast.Node) *CodeBuilder {
} else {
// new(big.Rat).SetFrac(a, b)
p.Val(p.pkg.builtin.Ref("new")).Typ(bigPkg.Ref("Rat").Type()).Call(1).
MemberVal("SetFrac").UntypedBigInt(a).UntypedBigInt(b).Call(2)
MemberVal("SetFrac", 0).UntypedBigInt(a).UntypedBigInt(b).Call(2)
}
ret := p.stk.Get(-1)
ret.Type, ret.CVal, ret.Src = pkg.utBigRat, constant.Make(v), getSrc(src)
Expand Down Expand Up @@ -1525,8 +1525,8 @@ func (p *CodeBuilder) ElemRef(src ...ast.Node) *CodeBuilder {
}

// MemberVal func
func (p *CodeBuilder) MemberVal(name string, src ...ast.Node) *CodeBuilder {
_, err := p.Member(name, MemberFlagVal, src...)
func (p *CodeBuilder) MemberVal(name string, lhs int, src ...ast.Node) *CodeBuilder {
_, err := p.Member(name, lhs, MemberFlagVal, src...)
if err != nil {
panic(err)
}
Expand All @@ -1535,7 +1535,7 @@ func (p *CodeBuilder) MemberVal(name string, src ...ast.Node) *CodeBuilder {

// MemberRef func
func (p *CodeBuilder) MemberRef(name string, src ...ast.Node) *CodeBuilder {
_, err := p.Member(name, MemberFlagRef, src...)
_, err := p.Member(name, 0, MemberFlagRef, src...)
if err != nil {
panic(err)
}
Expand All @@ -1554,6 +1554,19 @@ func (p *CodeBuilder) refMember(typ types.Type, name string, argVal ast.Expr, sr
if p.fieldRef(argVal, o, name, src, visited) {
return MemberField
}
case *types.Map:
// Map member access provides syntactic sugar: m.key is converted to m["key"]
// This allows more concise map access when keys are valid identifiers.
// Note: Only works with string-keyed maps.
if key, ok := o.Key().(*types.Basic); !ok || (key.Info()&types.IsString) == 0 {
break
}
tyRet := &refType{typ: o.Elem()}
elem := &internal.Elem{
Val: &ast.IndexExpr{X: argVal, Index: stringLit(name)}, Type: tyRet, Src: src,
}
p.stk.Ret(1, elem)
return MemberField
}
return MemberInvalid
}
Expand Down Expand Up @@ -1647,7 +1660,7 @@ func aliasNameOf(name string, flag MemberFlag) (string, MemberFlag) {

// Member access member by its name.
// src should point to the full source node `x.sel`
func (p *CodeBuilder) Member(name string, flag MemberFlag, src ...ast.Node) (kind MemberKind, err error) {
func (p *CodeBuilder) Member(name string, lhs int, flag MemberFlag, src ...ast.Node) (kind MemberKind, err error) {
srcExpr := getSrc(src)
arg := p.stk.Get(-1)
if debugInstr {
Expand All @@ -1668,7 +1681,7 @@ func (p *CodeBuilder) Member(name string, flag MemberFlag, src ...ast.Node) (kin
flag = memberFlagMethodToFunc
}
aliasName, flag = aliasNameOf(name, flag)
kind = p.findMember(at, name, aliasName, flag, arg, srcExpr, nil)
kind = p.findMember(at, name, aliasName, lhs, flag, arg, srcExpr, nil)
if isType && kind != MemberMethod {
code, pos, end := p.loadExpr(srcExpr)
return MemberInvalid, p.newCodeError(
Expand Down Expand Up @@ -1716,7 +1729,7 @@ func getUnderlying(pkg *Package, typ types.Type) types.Type {
}

func (p *CodeBuilder) findMember(
typ types.Type, name, aliasName string, flag MemberFlag, arg *Element, srcExpr ast.Node, visited map[*types.Struct]none) MemberKind {
typ types.Type, name, aliasName string, lhs int, flag MemberFlag, arg *Element, srcExpr ast.Node, visited map[*types.Struct]none) MemberKind {
var named *types.Named
retry:
switch o := typ.(type) {
Expand Down Expand Up @@ -1779,7 +1792,26 @@ retry:
}
}
}
case *types.Basic, *types.Slice, *types.Map, *types.Chan:
case *types.Map:
// Map member access provides syntactic sugar: m.key is converted to m["key"]
// This allows more concise map access when keys are valid identifiers.
// Note: Only works with string-keyed maps.
if key, ok := o.Key().(*types.Basic); !ok || (key.Info()&types.IsString) == 0 {
break
}
tyRet := o.Elem()
if lhs == 2 { // two-value assignment
pkg := p.pkg.Types
tyRet = types.NewTuple(
types.NewParam(token.NoPos, pkg, "", tyRet),
types.NewParam(token.NoPos, pkg, "", types.Typ[types.Bool]))
}
elem := &internal.Elem{
Val: &ast.IndexExpr{X: arg.Val, Index: stringLit(name)}, Type: tyRet, Src: srcExpr,
}
p.stk.Ret(1, elem)
return MemberField
case *types.Basic, *types.Slice, *types.Chan:
return p.btiMethod(p.getBuiltinTI(o), name, aliasName, flag, srcExpr)
}
return MemberInvalid
Expand Down Expand Up @@ -1964,7 +1996,7 @@ func (p *CodeBuilder) embeddedField(

for i, n := 0, o.NumFields(); i < n; i++ {
if fld := o.Field(i); fld.Embedded() {
if kind := p.findMember(fld.Type(), name, aliasName, flag, arg, src, visited); kind != MemberInvalid {
if kind := p.findMember(fld.Type(), name, aliasName, 0, flag, arg, src, visited); kind != MemberInvalid {
if kind != memberBad {
return kind
}
Expand Down
6 changes: 3 additions & 3 deletions codebuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ func TestCircularEmbeddedFieldLookup(t *testing.T) {
}, nil))

cb.stk.Push(&Element{Type: typeA})
kind, _ := cb.Member("any", MemberFlagVal)
kind, _ := cb.Member("any", 0, MemberFlagVal)
if kind != MemberInvalid {
t.Fatal("Member should return MemberInvalid for circular embedding")
}
kind, _ = cb.Member("any", MemberFlagRef)
kind, _ = cb.Member("any", 0, MemberFlagRef)
if kind != MemberInvalid {
t.Fatal("Member should return MemberInvalid for circular embedding")
}
Expand Down Expand Up @@ -81,7 +81,7 @@ func TestFindMember(t *testing.T) {
// push an element whose type is the interface
cb.stk.Push(&Element{Type: named2})

kind, _ := cb.Member("step", MemberFlagVal)
kind, _ := cb.Member("step", 0, MemberFlagVal)
if kind != MemberMethod {
t.Fatalf("expected MemberMethod (1), got %v", kind)
}
Expand Down
44 changes: 38 additions & 6 deletions error_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1675,7 +1675,7 @@ func TestErrMember(t *testing.T) {
pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg).
Val(ctxRef(pkg, "T")).
Debug(func(cb *gogen.CodeBuilder) {
_, err := cb.Member("x", gogen.MemberFlagVal, source("T.x", 1, 5))
_, err := cb.Member("x", 0, gogen.MemberFlagVal, source("T.x", 1, 5))
if err != nil {
panic(err)
}
Expand All @@ -1690,7 +1690,7 @@ func TestErrMember(t *testing.T) {
NewVar(types.Typ[types.String], "x").
Val(ctxRef(pkg, "x"), source("x", 1, 5)).
Debug(func(cb *gogen.CodeBuilder) {
_, err := cb.Member("y", gogen.MemberFlagVal, source("x.y", 1, 7))
_, err := cb.Member("y", 0, gogen.MemberFlagVal, source("x.y", 1, 7))
if err != nil {
panic(err)
}
Expand All @@ -1705,7 +1705,39 @@ func TestErrMember(t *testing.T) {
NewVar(types.Typ[types.String], "x").
Val(ctxRef(pkg, "x"), source("x", 1, 5)).
Debug(func(cb *gogen.CodeBuilder) {
_, err := cb.Member("y", gogen.MemberFlagVal, source("x.y", 1, 5))
_, err := cb.Member("y", 0, gogen.MemberFlagVal, source("x.y", 1, 5))
if err != nil {
panic(err)
}
}).
EndStmt().
End()
})
codeErrorTest(t,
`./foo.gop:1:5: x.y undefined (type map[int]int has no field or method y)`,
func(pkg *gogen.Package) {
typ := types.NewMap(types.Typ[types.Int], types.Typ[types.Int])
pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg).
NewVar(typ, "x").
Val(ctxRef(pkg, "x"), source("x", 1, 5)).
Debug(func(cb *gogen.CodeBuilder) {
_, err := cb.Member("y", 0, gogen.MemberFlagVal, source("x.y", 1, 5))
if err != nil {
panic(err)
}
}).
EndStmt().
End()
})
codeErrorTest(t,
`./foo.gop:1:5: x.y undefined (type map[int]int has no field or method y)`,
func(pkg *gogen.Package) {
typ := types.NewMap(types.Typ[types.Int], types.Typ[types.Int])
pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg).
NewVar(typ, "x").
Val(ctxRef(pkg, "x"), source("x", 1, 5)).
Debug(func(cb *gogen.CodeBuilder) {
_, err := cb.Member("y", 0, gogen.MemberFlagRef, source("x.y", 1, 5))
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -1812,7 +1844,7 @@ func TestErrUnsafe(t *testing.T) {
builtin := pkg.Unsafe()
pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg).
NewVar(foo, "a").
Val(builtin.Ref("Offsetof")).VarVal("a").MemberVal("Bar").CallWith(1, 0, 0, source("unsafe.Offsetof(a.Bar)", 14, 2)).EndStmt().
Val(builtin.Ref("Offsetof")).VarVal("a").MemberVal("Bar", 0).CallWith(1, 0, 0, source("unsafe.Offsetof(a.Bar)", 14, 2)).EndStmt().
EndStmt().
End()
})
Expand All @@ -1834,7 +1866,7 @@ func TestErrUnsafe(t *testing.T) {
tyT := pkg.NewType("T").InitType(pkg, typT)
pkg.CB().NewVar(tyT, "t")
pkg.CB().NewConstStart(nil, "c").
Val(builtin.Ref("Offsetof")).Val(ctxRef(pkg, "t"), source("t", 17, 27)).MemberVal("m").CallWith(1, 0, 0, source("unsafe.Offsetof(t.m)", 17, 11)).EndInit(1)
Val(builtin.Ref("Offsetof")).Val(ctxRef(pkg, "t"), source("t", 17, 27)).MemberVal("m", 0).CallWith(1, 0, 0, source("unsafe.Offsetof(t.m)", 17, 11)).EndInit(1)
})
codeErrorTest(t,
`./foo.gop:7:12: cannot use a (type int) as type unsafe.Pointer in argument to unsafe.Add`,
Expand Down Expand Up @@ -2019,7 +2051,7 @@ type M struct {
pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg).
NewVar(tyM, "m").
VarVal("println").VarVal("m").
MemberVal("x", source("m.x", 3, 10)).Call(1).EndStmt().
MemberVal("x", 0, source("m.x", 3, 10)).Call(1).EndStmt().
End()
})
}
Expand Down
Loading
Loading