mirror of
https://github.com/golang/go
synced 2024-11-18 17:54:57 -07:00
go.tools/go/types: report correct type for untyped conversion arguments
Fixes golang/go#5849. R=adonovan CC=golang-dev https://golang.org/cl/11007043
This commit is contained in:
parent
cc52b8b7f8
commit
1aa0484f4b
@ -18,6 +18,8 @@ import (
|
||||
// x is marked as invalid (x.mode == invalid).
|
||||
//
|
||||
func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type) {
|
||||
var final Type // declare before gotos
|
||||
|
||||
// all conversions have one argument
|
||||
if len(conv.Args) != 1 {
|
||||
check.invalidOp(conv.Pos(), "%s conversion requires exactly one argument", conv)
|
||||
@ -62,9 +64,20 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type) {
|
||||
x.mode = value
|
||||
}
|
||||
|
||||
// the conversion argument types are final; for now we just use x.typ
|
||||
// TODO(gri) Fix this. For untyped constants, the type should be typ.
|
||||
check.updateExprType(x.expr, x.typ, true)
|
||||
// The conversion argument types are final. For untyped values the
|
||||
// conversion provides the type, per the spec: "A constant may be
|
||||
// given a type explicitly by a constant declaration or conversion,...".
|
||||
final = x.typ
|
||||
if isUntyped(final) {
|
||||
final = typ
|
||||
// For conversions to interfaces, use the argument type's
|
||||
// default type instead. Keep untyped nil for untyped nil
|
||||
// arguments.
|
||||
if _, ok := typ.Underlying().(*Interface); ok {
|
||||
final = defaultType(x.typ)
|
||||
}
|
||||
}
|
||||
check.updateExprType(x.expr, final, true)
|
||||
|
||||
check.conversions[conv] = true // for cap/len checking
|
||||
x.expr = conv
|
||||
|
@ -7,9 +7,12 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
)
|
||||
|
||||
func TestIssue5770(t *testing.T) {
|
||||
@ -26,3 +29,55 @@ func TestIssue5770(t *testing.T) {
|
||||
t.Errorf("got: %v; want: %s", err, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue5849(t *testing.T) {
|
||||
src := `
|
||||
package p
|
||||
var (
|
||||
s uint
|
||||
_ = uint8(8)
|
||||
_ = uint16(16) << s
|
||||
_ = uint32(32 << s)
|
||||
_ = uint64(64 << s + s)
|
||||
_ = (interface{})("foo")
|
||||
_ = (interface{})(nil)
|
||||
)`
|
||||
f, err := parser.ParseFile(fset, "", src, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
ctxt := Context{
|
||||
Expr: func(x ast.Expr, typ Type, val exact.Value) {
|
||||
var want Type
|
||||
switch x := x.(type) {
|
||||
case *ast.BasicLit:
|
||||
switch x.Value {
|
||||
case `8`:
|
||||
want = Typ[Uint8]
|
||||
case `16`:
|
||||
want = Typ[Uint16]
|
||||
case `32`:
|
||||
want = Typ[Uint32]
|
||||
case `64`:
|
||||
want = Typ[Uint] // because of "+ s", s is of type uint
|
||||
case `"foo"`:
|
||||
want = Typ[String]
|
||||
}
|
||||
case *ast.Ident:
|
||||
if x.Name == "nil" {
|
||||
want = Typ[UntypedNil]
|
||||
}
|
||||
}
|
||||
if want != nil && !IsIdentical(typ, want) {
|
||||
t.Errorf("got %s; want %s", typ, want)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_, err = ctxt.Check(f.Name.Name, fset, f)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
@ -247,16 +247,13 @@ func identicalMethods(a, b []*Func) bool {
|
||||
}
|
||||
|
||||
// defaultType returns the default "typed" type for an "untyped" type;
|
||||
// it returns the incoming type for all other types. If there is no
|
||||
// corresponding untyped type, the result is Typ[Invalid].
|
||||
// it returns the incoming type for all other types. The default type
|
||||
// for untyped nil is untyped nil.
|
||||
//
|
||||
func defaultType(typ Type) Type {
|
||||
if t, ok := typ.(*Basic); ok {
|
||||
k := Invalid
|
||||
k := t.kind
|
||||
switch t.kind {
|
||||
// case UntypedNil:
|
||||
// There is no default type for nil. For a good error message,
|
||||
// catch this case before calling this function.
|
||||
case UntypedBool:
|
||||
k = Bool
|
||||
case UntypedInt:
|
||||
|
8
go/types/testdata/shifts.src
vendored
8
go/types/testdata/shifts.src
vendored
@ -143,13 +143,13 @@ func shifts6() {
|
||||
|
||||
_ = make([]int, 1.0)
|
||||
_ = make([]int, 1.0<<s)
|
||||
_ = make([]int, 1.1 /* ERROR "integer" */ <<s)
|
||||
_ = make([]int, 1.1 /* ERROR "must be integer" */ <<s)
|
||||
|
||||
_ = float32(1)
|
||||
_ = float32(1<<s)
|
||||
_ = float32(1 /* ERROR "must be integer" */ <<s)
|
||||
_ = float32(1.0)
|
||||
_ = float32(1.0 /* ERROR "int" */ <<s)
|
||||
_ = float32(1.1 /* ERROR "int" */ <<s)
|
||||
_ = float32(1.0 /* ERROR "must be integer" */ <<s)
|
||||
_ = float32(1.1 /* ERROR "must be integer" */ <<s)
|
||||
|
||||
var b []int
|
||||
_ = append(b, 1<<s)
|
||||
|
Loading…
Reference in New Issue
Block a user