go/types: modify Eval, EvalNode to return a TypeAndValue
The new interface makes the functions more useful by allowing clients to check the various properties that TypeAndValue provides. Change-Id: I8b41a27316081bea24a18ffe6fa1812e809d6f67 Reviewed-on: https://go-review.googlesource.com/2134 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
c1ef9c75bf
commit
6370cd3a8e
|
@ -248,13 +248,14 @@ func doOneInput(input, filename string) bool {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mainFileScope := mainpkg.Object.Scope().Child(0)
|
mainFileScope := mainpkg.Object.Scope().Child(0)
|
||||||
t, _, err = types.EvalNode(prog.Fset, texpr, mainpkg.Object, mainFileScope)
|
tv, err := types.EvalNode(prog.Fset, texpr, mainpkg.Object, mainFileScope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ok = false
|
ok = false
|
||||||
// Don't print err since its location is bad.
|
// Don't print err since its location is bad.
|
||||||
e.errorf("'%s' is not a valid type: %s", typstr, err)
|
e.errorf("'%s' is not a valid type: %s", typstr, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
t = tv.Type
|
||||||
}
|
}
|
||||||
e.types = append(e.types, t)
|
e.types = append(e.types, t)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,6 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
|
||||||
"golang.org/x/tools/go/exact"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// New is a convenience function to create a new type from a given
|
// New is a convenience function to create a new type from a given
|
||||||
|
@ -22,11 +20,11 @@ import (
|
||||||
// Position info for objects in the result type is undefined.
|
// Position info for objects in the result type is undefined.
|
||||||
//
|
//
|
||||||
func New(str string) Type {
|
func New(str string) Type {
|
||||||
typ, _, err := Eval(str, nil, nil)
|
tv, err := Eval(str, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return typ
|
return tv.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eval returns the type and, if constant, the value for the
|
// Eval returns the type and, if constant, the value for the
|
||||||
|
@ -50,10 +48,10 @@ func New(str string) Type {
|
||||||
// level untyped constants will return an untyped type rather then the
|
// level untyped constants will return an untyped type rather then the
|
||||||
// respective context-specific type.
|
// respective context-specific type.
|
||||||
//
|
//
|
||||||
func Eval(str string, pkg *Package, scope *Scope) (typ Type, val exact.Value, err error) {
|
func Eval(str string, pkg *Package, scope *Scope) (TypeAndValue, error) {
|
||||||
node, err := parser.ParseExpr(str)
|
node, err := parser.ParseExpr(str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return TypeAndValue{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a file set that looks structurally identical to the
|
// Create a file set that looks structurally identical to the
|
||||||
|
@ -70,7 +68,7 @@ func Eval(str string, pkg *Package, scope *Scope) (typ Type, val exact.Value, er
|
||||||
// An error is returned if the scope is incorrect
|
// An error is returned if the scope is incorrect
|
||||||
// if the node cannot be evaluated in the scope.
|
// if the node cannot be evaluated in the scope.
|
||||||
//
|
//
|
||||||
func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (typ Type, val exact.Value, err error) {
|
func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (tv TypeAndValue, err error) {
|
||||||
// verify package/scope relationship
|
// verify package/scope relationship
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
scope = Universe
|
scope = Universe
|
||||||
|
@ -81,7 +79,7 @@ func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (t
|
||||||
}
|
}
|
||||||
// s == nil || s == pkg.scope
|
// s == nil || s == pkg.scope
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil, nil, fmt.Errorf("scope does not belong to package %s", pkg.name)
|
return TypeAndValue{}, fmt.Errorf("scope does not belong to package %s", pkg.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,18 +90,6 @@ func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (t
|
||||||
|
|
||||||
// evaluate node
|
// evaluate node
|
||||||
var x operand
|
var x operand
|
||||||
check.exprOrType(&x, node)
|
check.rawExpr(&x, node, nil)
|
||||||
switch x.mode {
|
return TypeAndValue{x.mode, x.typ, x.val}, nil
|
||||||
case invalid, novalue:
|
|
||||||
fallthrough
|
|
||||||
default:
|
|
||||||
unreachable() // or bailed out with error
|
|
||||||
case constant:
|
|
||||||
val = x.val
|
|
||||||
fallthrough
|
|
||||||
case typexpr, variable, mapindex, value, commaok:
|
|
||||||
typ = x.typ
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, typStr, valStr string) {
|
func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, typStr, valStr string) {
|
||||||
gotTyp, gotVal, err := Eval(str, pkg, scope)
|
gotTv, err := Eval(str, pkg, scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Eval(%q) failed: %s", str, err)
|
t.Errorf("Eval(%q) failed: %s", str, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if gotTyp == nil {
|
if gotTv.Type == nil {
|
||||||
t.Errorf("Eval(%q) got nil type but no error", str)
|
t.Errorf("Eval(%q) got nil type but no error", str)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,13 @@ func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, ty
|
||||||
// compare types
|
// compare types
|
||||||
if typ != nil {
|
if typ != nil {
|
||||||
// we have a type, check identity
|
// we have a type, check identity
|
||||||
if !Identical(gotTyp, typ) {
|
if !Identical(gotTv.Type, typ) {
|
||||||
t.Errorf("Eval(%q) got type %s, want %s", str, gotTyp, typ)
|
t.Errorf("Eval(%q) got type %s, want %s", str, gotTv.Type, typ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// we have a string, compare type string
|
// we have a string, compare type string
|
||||||
gotStr := gotTyp.String()
|
gotStr := gotTv.Type.String()
|
||||||
if gotStr != typStr {
|
if gotStr != typStr {
|
||||||
t.Errorf("Eval(%q) got type %s, want %s", str, gotStr, typStr)
|
t.Errorf("Eval(%q) got type %s, want %s", str, gotStr, typStr)
|
||||||
return
|
return
|
||||||
|
@ -46,8 +46,8 @@ func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, ty
|
||||||
|
|
||||||
// compare values
|
// compare values
|
||||||
gotStr := ""
|
gotStr := ""
|
||||||
if gotVal != nil {
|
if gotTv.Value != nil {
|
||||||
gotStr = gotVal.String()
|
gotStr = gotTv.Value.String()
|
||||||
}
|
}
|
||||||
if gotStr != valStr {
|
if gotStr != valStr {
|
||||||
t.Errorf("Eval(%q) got value %s, want %s", str, gotStr, valStr)
|
t.Errorf("Eval(%q) got value %s, want %s", str, gotStr, valStr)
|
||||||
|
|
Loading…
Reference in New Issue