Skip to content
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

typesutil: update TypeAndValue #1545

Merged
merged 2 commits into from
Nov 16, 2023
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
3 changes: 2 additions & 1 deletion cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/goplus/gop/ast"
"github.com/goplus/gop/ast/fromgo"
"github.com/goplus/gop/cl/internal/typesutil"
"github.com/goplus/gop/token"
"github.com/goplus/gox"
"github.com/goplus/gox/cpackages"
Expand Down Expand Up @@ -220,7 +221,7 @@ type goxRecorder struct {

// Member maps identifiers to the objects they denote.
func (p *goxRecorder) Member(id ast.Node, obj types.Object) {
tv := types.TypeAndValue{Type: obj.Type()}
tv := typesutil.NewTypeAndValueForObject(obj)
switch v := id.(type) {
case *ast.SelectorExpr:
sel := v.Sel
Expand Down
43 changes: 35 additions & 8 deletions cl/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,11 @@ find:
e := ctx.cb.Get(-1)
if oldo != nil && gox.IsTypeEx(e.Type) {
rec.Use(ident, oldo)
rec.Type(ident, typesutil.NewTypeAndValueForObject(oldo))
return
}
rec.Use(ident, o)
typ, _ := gox.DerefType(e.Type)
tv := typesutil.NewTypeAndValue(typ, e.CVal)
rec.Type(ident, tv)
rec.Type(ident, typesutil.NewTypeAndValueForObject(o))
}
return
}
Expand Down Expand Up @@ -199,6 +198,7 @@ func compileExprLHS(ctx *blockCtx, expr ast.Expr) {
compileIndexExprLHS(ctx, v)
case *ast.SelectorExpr:
compileSelectorExprLHS(ctx, v)
recordTypesVariable(ctx, v, -1)
case *ast.StarExpr:
compileStarExprLHS(ctx, v)
default:
Expand All @@ -210,6 +210,21 @@ func twoValue(inFlags []int) bool {
return inFlags != nil && (inFlags[0]&clCallWithTwoValue) != 0
}

func recordTypesValue(ctx *blockCtx, expr ast.Expr, n int) {
if rec := ctx.recorder(); rec != nil {
e := ctx.cb.Get(n)
rec.Type(expr, typesutil.NewTypeAndValueForValue(e.Type, e.CVal))
}
}

func recordTypesVariable(ctx *blockCtx, expr ast.Expr, n int) {
if rec := ctx.recorder(); rec != nil {
e := ctx.cb.Get(n)
t, _ := gox.DerefType(e.Type)
rec.Type(expr, typesutil.NewTypeAndValueForVariable(t))
}
}

func compileExpr(ctx *blockCtx, expr ast.Expr, inFlags ...int) {
switch v := expr.(type) {
case *ast.Ident:
Expand All @@ -220,6 +235,7 @@ func compileExpr(ctx *blockCtx, expr ast.Expr, inFlags ...int) {
compileIdent(ctx, v, flags)
case *ast.BasicLit:
compileBasicLit(ctx, v)
recordTypesValue(ctx, v, -1)
case *ast.CallExpr:
flags := 0
if inFlags != nil {
Expand All @@ -234,8 +250,10 @@ func compileExpr(ctx *blockCtx, expr ast.Expr, inFlags ...int) {
compileSelectorExpr(ctx, v, flags)
case *ast.BinaryExpr:
compileBinaryExpr(ctx, v)
recordTypesValue(ctx, v, -1)
case *ast.UnaryExpr:
compileUnaryExpr(ctx, v, twoValue(inFlags))
recordTypesValue(ctx, v, -1)
case *ast.FuncLit:
compileFuncLit(ctx, v)
case *ast.CompositeLit:
Expand Down Expand Up @@ -359,10 +377,6 @@ func compileSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr) {
}
default:
compileExpr(ctx, v.X)
if rec := ctx.recorder(); rec != nil {
e := ctx.cb.Get(-1)
rec.Type(v.X, typesutil.NewTypeAndValue(e.Type, e.CVal))
}
}
ctx.cb.MemberRef(v.Sel.Name, v)
}
Expand All @@ -383,7 +397,7 @@ func compileSelectorExpr(ctx *blockCtx, v *ast.SelectorExpr, flags int) {
compileExpr(ctx, v.X)
if rec := ctx.recorder(); rec != nil {
e := ctx.cb.Get(-1)
rec.Type(v.X, typesutil.NewTypeAndValue(e.Type, e.CVal))
rec.Type(v.X, typesutil.NewTypeAndValueForType(e.Type))
}
}
if err := compileMember(ctx, v, v.Sel.Name, flags); err != nil {
Expand Down Expand Up @@ -544,6 +558,9 @@ func compileCallExpr(ctx *blockCtx, v *ast.CallExpr, inFlags int) {
for fn != nil {
err := compileCallArgs(fn, fnt, ctx, v, ellipsis, flags)
if err == nil {
if rec := ctx.recorder(); rec != nil {
rec.Type(v, typesutil.NewTypeAndValueForCallResult(ctx.cb.Get(-1).Type))
}
break
}
if fn.next == nil {
Expand Down Expand Up @@ -794,6 +811,9 @@ func compileStructLitInKeyVal(ctx *blockCtx, elts []ast.Expr, t *types.Struct, t
err := ctx.newCodeErrorf(name.Pos(), "%s undefined (type %v has no field or method %s)", src, typ, name.Name)
panic(err)
}
if rec := ctx.recorder(); rec != nil {
rec.Use(name, t.Field(idx))
}
switch expr := kv.Value.(type) {
case *ast.LambdaExpr, *ast.LambdaExpr2:
sig := checkLambdaFuncType(ctx, expr, t.Field(idx).Type(), clLambaField, kv.Key)
Expand Down Expand Up @@ -878,6 +898,9 @@ func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit, expected types.Type
}
if t, ok := underlying.(*types.Struct); ok && kind == compositeLitKeyVal {
compileStructLitInKeyVal(ctx, v.Elts, t, typ, v)
if rec := ctx.recorder(); rec != nil {
rec.Type(v, typesutil.NewTypeAndValueForValue(typ, nil))
}
if hasPtr {
ctx.cb.UnaryOp(gotoken.AND)
}
Expand All @@ -892,6 +915,10 @@ func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit, expected types.Type
ctx.cb.MapLit(nil, n<<1)
return
}
if rec := ctx.recorder(); rec != nil {
rec.Type(v.Type, typesutil.NewTypeAndValueForType(typ))
rec.Type(v, typesutil.NewTypeAndValueForValue(typ, nil))
}
switch underlying.(type) {
case *types.Slice:
ctx.cb.SliceLitEx(typ, n<<kind, kind == compositeLitKeyVal, v)
Expand Down
15 changes: 13 additions & 2 deletions cl/func_type_and_var.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"strconv"

"github.com/goplus/gop/ast"
"github.com/goplus/gop/cl/internal/typesutil"
"github.com/goplus/gop/token"
"github.com/goplus/gox"
)
Expand Down Expand Up @@ -112,7 +113,12 @@ func toParam(ctx *blockCtx, fld *ast.Field, args []*gox.Param) []*gox.Param {

// -----------------------------------------------------------------------------

func toType(ctx *blockCtx, typ ast.Expr) types.Type {
func toType(ctx *blockCtx, typ ast.Expr) (t types.Type) {
if rec := ctx.recorder(); rec != nil {
defer func() {
rec.Type(typ, typesutil.NewTypeAndValueForType(t))
}()
}
switch v := typ.(type) {
case *ast.Ident:
ctx.idents = append(ctx.idents, v)
Expand Down Expand Up @@ -228,6 +234,7 @@ func toIdentType(ctx *blockCtx, ident *ast.Ident) (ret types.Type) {
defer func() {
if obj != nil {
rec.Use(ident, obj)
rec.Type(ident, typesutil.NewTypeAndValueForObject(obj))
}
}()
}
Expand Down Expand Up @@ -341,7 +348,11 @@ func toStructType(ctx *blockCtx, v *ast.StructType) *types.Struct {
}
}
}
return types.NewStruct(fields, tags)
st := types.NewStruct(fields, tags)
if rec != nil {
rec.Type(v, typesutil.NewTypeAndValueForType(st))
}
return st
}

func toFieldTag(v *ast.BasicLit) string {
Expand Down
65 changes: 59 additions & 6 deletions cl/internal/typesutil/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,66 @@ type TypeAndValue struct {
Value constant.Value
}

func NewTypeAndValue(typ types.Type, val constant.Value) (ret types.TypeAndValue) {
if t, ok := typ.(*gox.TypeType); ok {
ret.Type = t.Type()
(*TypeAndValue)(unsafe.Pointer(&ret)).mode = typexpr
func NewTypeAndValueForType(typ types.Type) (ret types.TypeAndValue) {
switch t := typ.(type) {
case *gox.TypeType:
typ = t.Type()
}
ret.Type = types.Default(typ)
(*TypeAndValue)(unsafe.Pointer(&ret)).mode = typexpr
return
}

func NewTypeAndValueForValue(typ types.Type, val constant.Value) (ret types.TypeAndValue) {
var mode operandMode
if val != nil {
mode = constant_
} else {
ret.Type = typ
ret.Value = val
mode = value
}
ret.Type = types.Default(typ)
ret.Value = val
(*TypeAndValue)(unsafe.Pointer(&ret)).mode = mode
return
}

func NewTypeAndValueForVariable(typ types.Type) (ret types.TypeAndValue) {
ret.Type = typ
(*TypeAndValue)(unsafe.Pointer(&ret)).mode = variable
return
}

func NewTypeAndValueForCallResult(typ types.Type) (ret types.TypeAndValue) {
if typ == nil {
ret.Type = &types.Tuple{}
(*TypeAndValue)(unsafe.Pointer(&ret)).mode = novalue
return
}
ret.Type = typ
(*TypeAndValue)(unsafe.Pointer(&ret)).mode = value
return
}

func NewTypeAndValueForObject(obj types.Object) (ret types.TypeAndValue) {
var mode operandMode
var val constant.Value
switch v := obj.(type) {
case *types.Const:
mode = constant_
val = v.Val()
case *types.TypeName:
mode = typexpr
case *types.Var:
mode = variable
case *types.Func:
mode = value
case *types.Builtin:
mode = builtin
case *types.Nil:
mode = value
}
ret.Type = obj.Type()
ret.Value = val
(*TypeAndValue)(unsafe.Pointer(&ret)).mode = mode
return
}
52 changes: 47 additions & 5 deletions cl/internal/typesutil/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,55 @@ import (
)

func TestTypeAndValue(t *testing.T) {
ty := gox.NewTypeType(types.Typ[types.Int])
ret := NewTypeAndValue(ty, nil)
tyInt := types.Typ[types.Int]
ty := gox.NewTypeType(tyInt)
ret := NewTypeAndValueForType(ty)
if !ret.IsType() {
t.Fatal("NewTypeAndValue: not type?")
t.Fatal("NewTypeAndValueForType: not type?")
}
ret = NewTypeAndValue(types.Typ[types.Int], constant.MakeInt64(1))
ret = NewTypeAndValueForValue(tyInt, constant.MakeInt64(1))
if ret.Value == nil {
t.Fatal("NewTypeAndValue: not const?")
t.Fatal("NewTypeAndValueForValue: not const?")
}
ret = NewTypeAndValueForVariable(tyInt)
if !ret.Addressable() {
t.Fatal("NewTypeAndValueForVariable: not variable?")
}
ret = NewTypeAndValueForCallResult(tyInt)
if !ret.IsValue() {
t.Fatal("NewTypeAndValueForCall: not value?")
}
ret = NewTypeAndValueForCallResult(nil)
if !ret.IsVoid() {
t.Fatal("NewTypeAndValueForCall: not void?")
}
pkg := types.NewPackage("main", "main")
ret = NewTypeAndValueForObject(types.NewConst(0, pkg, "v", tyInt, constant.MakeInt64(100)))
if ret.Value == nil {
t.Fatal("NewTypeAndValueForObject: not const?")
}
ret = NewTypeAndValueForObject(types.NewTypeName(0, pkg, "MyInt", tyInt))
if !ret.IsType() {
t.Fatal("NewTypeAndValueForObject: not type?")
}
ret = NewTypeAndValueForObject(types.NewVar(0, pkg, "v", tyInt))
if !ret.Addressable() {
t.Fatal("NewTypeAndValueForObject: not variable?")
}
ret = NewTypeAndValueForObject(types.NewFunc(0, pkg, "fn", types.NewSignature(nil, nil, nil, false)))
if !ret.IsValue() {
t.Fatal("NewTypeAndValueForObject: not value?")
}
ret = NewTypeAndValueForValue(types.Typ[types.UntypedNil], nil)
if !ret.IsNil() {
t.Fatal("NewTypeAndValueForValue: not nil?")
}
ret = NewTypeAndValueForObject(types.Universe.Lookup("nil"))
if !ret.IsNil() {
t.Fatal("NewTypeAndValueForObject: not nil?")
}
ret = NewTypeAndValueForObject(types.Universe.Lookup("len"))
if !ret.IsBuiltin() {
t.Fatal("NewTypeAndValueForObject: not builtin?")
}
}
5 changes: 2 additions & 3 deletions x/typesutil/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ func testInfo(t *testing.T, src interface{}) {
if err != nil {
t.Fatal("parserGoSource error", err)
}
// TODO check types
//testItems(t, "types", typesList(fset, info.Types), goTypesList(fset, goinfo.Types))
testItems(t, "types", typesList(fset, info.Types), goTypesList(fset, goinfo.Types))
testItems(t, "defs", defsList(fset, info.Defs, true), goDefsList(fset, goinfo.Defs, true))
testItems(t, "uses", usesList(fset, info.Uses), goUsesList(fset, goinfo.Uses))
// TODO check selections
Expand Down Expand Up @@ -335,7 +334,7 @@ var v4 *T = &T{100,200};
`)
}

func _TestStruct(t *testing.T) {
func TestStruct(t *testing.T) {
testInfo(t, `package main

type Person struct {
Expand Down