Commit 5a4a197d authored by Robert Griesemer's avatar Robert Griesemer

go/types: correct result type for append (bug fix)

Rewrote existing code to prevent similar mistakes.

R=adonovan
CC=golang-dev
https://golang.org/cl/7129046
parent 1a03580e
...@@ -21,8 +21,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -21,8 +21,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
id := bin.id id := bin.id
// declare before goto's // declare before goto's
var arg0 ast.Expr var arg0 ast.Expr // first argument, if present
var typ0 Type
// check argument count // check argument count
n := len(args) n := len(args)
...@@ -42,31 +41,24 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -42,31 +41,24 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
if n > 0 { if n > 0 {
arg0 = args[0] arg0 = args[0]
switch id { switch id {
case _Make, _New: case _Make, _New, _Trace:
// argument must be a type // respective cases below do the work
typ0 = check.typ(arg0, false)
if typ0 == Typ[Invalid] {
goto Error
}
case _Trace:
// _Trace implementation does the work
default: default:
// argument must be an expression // argument must be an expression
check.expr(x, arg0, nil, iota) check.expr(x, arg0, nil, iota)
if x.mode == invalid { if x.mode == invalid {
goto Error goto Error
} }
typ0 = underlying(x.typ)
} }
} }
switch id { switch id {
case _Append: case _Append:
s, ok := typ0.(*Slice) if _, ok := underlying(x.typ).(*Slice); !ok {
if !ok {
check.invalidArg(x.pos(), "%s is not a typed slice", x) check.invalidArg(x.pos(), "%s is not a typed slice", x)
goto Error goto Error
} }
resultTyp := x.typ
for _, arg := range args[1:] { for _, arg := range args[1:] {
check.expr(x, arg, nil, iota) check.expr(x, arg, nil, iota)
if x.mode == invalid { if x.mode == invalid {
...@@ -75,12 +67,12 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -75,12 +67,12 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
// TODO(gri) check assignability // TODO(gri) check assignability
} }
x.mode = value x.mode = value
x.typ = s x.typ = resultTyp
case _Cap, _Len: case _Cap, _Len:
mode := invalid mode := invalid
var val interface{} var val interface{}
switch typ := implicitDeref(typ0).(type) { switch typ := implicitDeref(underlying(x.typ)).(type) {
case *Basic: case *Basic:
if isString(typ) && id == _Len { if isString(typ) && id == _Len {
if x.mode == constant { if x.mode == constant {
...@@ -116,7 +108,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -116,7 +108,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
x.val = val x.val = val
case _Close: case _Close:
ch, ok := typ0.(*Chan) ch, ok := underlying(x.typ).(*Chan)
if !ok { if !ok {
check.invalidArg(x.pos(), "%s is not a channel", x) check.invalidArg(x.pos(), "%s is not a channel", x)
goto Error goto Error
...@@ -182,7 +174,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -182,7 +174,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
} }
var dst, src Type var dst, src Type
if t, ok := typ0.(*Slice); ok { if t, ok := underlying(x.typ).(*Slice); ok {
dst = t.Elt dst = t.Elt
} }
switch t := underlying(y.typ).(type) { switch t := underlying(y.typ).(type) {
...@@ -208,7 +200,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -208,7 +200,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
x.typ = Typ[Int] x.typ = Typ[Int]
case _Delete: case _Delete:
m, ok := typ0.(*Map) m, ok := underlying(x.typ).(*Map)
if !ok { if !ok {
check.invalidArg(x.pos(), "%s is not a map", x) check.invalidArg(x.pos(), "%s is not a map", x)
goto Error goto Error
...@@ -224,7 +216,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -224,7 +216,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
x.mode = novalue x.mode = novalue
case _Imag, _Real: case _Imag, _Real:
if !isComplex(typ0) { if !isComplex(x.typ) {
check.invalidArg(x.pos(), "%s must be a complex number", x) check.invalidArg(x.pos(), "%s must be a complex number", x)
goto Error goto Error
} }
...@@ -242,7 +234,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -242,7 +234,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
x.mode = value x.mode = value
} }
k := Invalid k := Invalid
switch typ0.(*Basic).Kind { switch underlying(x.typ).(*Basic).Kind {
case Complex64: case Complex64:
k = Float32 k = Float32
case Complex128: case Complex128:
...@@ -255,8 +247,12 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -255,8 +247,12 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
x.typ = Typ[k] x.typ = Typ[k]
case _Make: case _Make:
resultTyp := check.typ(arg0, false)
if resultTyp == Typ[Invalid] {
goto Error
}
var min int // minimum number of arguments var min int // minimum number of arguments
switch underlying(typ0).(type) { switch underlying(resultTyp).(type) {
case *Slice: case *Slice:
min = 2 min = 2
case *Map, *Chan: case *Map, *Chan:
...@@ -291,11 +287,15 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -291,11 +287,15 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
// safe to continue // safe to continue
} }
x.mode = variable x.mode = variable
x.typ = typ0 x.typ = resultTyp
case _New: case _New:
resultTyp := check.typ(arg0, false)
if resultTyp == Typ[Invalid] {
goto Error
}
x.mode = variable x.mode = variable
x.typ = &Pointer{Base: typ0} x.typ = &Pointer{Base: resultTyp}
case _Panic, _Print, _Println: case _Panic, _Print, _Println:
for _, arg := range args[1:] { for _, arg := range args[1:] {
...@@ -329,14 +329,14 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota ...@@ -329,14 +329,14 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
case _Sizeof: case _Sizeof:
x.mode = constant x.mode = constant
x.val = sizeof(check.ctxt, x.typ)
x.typ = Typ[Uintptr] x.typ = Typ[Uintptr]
x.val = sizeof(check.ctxt, typ0)
case _Assert: case _Assert:
// assert(pred) causes a typechecker error if pred is false. // assert(pred) causes a typechecker error if pred is false.
// The result of assert is the value of pred if there is no error. // The result of assert is the value of pred if there is no error.
// Note: assert is only available in self-test mode. // Note: assert is only available in self-test mode.
if x.mode != constant || !isBoolean(typ0) { if x.mode != constant || !isBoolean(x.typ) {
check.invalidArg(x.pos(), "%s is not a boolean constant", x) check.invalidArg(x.pos(), "%s is not a boolean constant", x)
goto Error goto Error
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment