]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, go/exact: "vendor" go/types into std repo
authorRobert Griesemer <gri@golang.org>
Tue, 7 Apr 2015 01:23:51 +0000 (18:23 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 8 Apr 2015 03:40:04 +0000 (03:40 +0000)
This is a first step towards moving go/types from the tools
repo into the std repo. The files were brought over via the
added src/go/types.bash script for reproducability. The
script can be removed once all dependencies on go/types
have moved to the std repo go/types.

The script moved packages as follows:

- x/tools/go/types => go/types (type-checker)
- x/tools/go/exact => go/exact (constants)
- x/tools/go/gcimporter => go/types/internal/gcimporter

The gcimporter is needed to be able to run tests. go/types
should probably have some factory function to provide an
appropriate importer.

Some of the go/types tests fail for a handful of platforms
(windows and nacl). In order to keep this change "clean"
from manual changes, the next change will disable those
tests for now so we can move forward.

Change-Id: I448d8f7faa39ad2e04811911b699f7682627c224
Reviewed-on: https://go-review.googlesource.com/8530
Reviewed-by: Rob Pike <r@golang.org>
91 files changed:
src/go/exact/exact.go [new file with mode: 0644]
src/go/exact/exact_test.go [new file with mode: 0644]
src/go/exact/go13.go [new file with mode: 0644]
src/go/exact/go14.go [new file with mode: 0644]
src/go/types.bash [new file with mode: 0644]
src/go/types/api.go [new file with mode: 0644]
src/go/types/api_test.go [new file with mode: 0644]
src/go/types/assignments.go [new file with mode: 0644]
src/go/types/builtins.go [new file with mode: 0644]
src/go/types/builtins_test.go [new file with mode: 0644]
src/go/types/call.go [new file with mode: 0644]
src/go/types/check.go [new file with mode: 0644]
src/go/types/check_test.go [new file with mode: 0644]
src/go/types/conversions.go [new file with mode: 0644]
src/go/types/decl.go [new file with mode: 0644]
src/go/types/errors.go [new file with mode: 0644]
src/go/types/eval.go [new file with mode: 0644]
src/go/types/eval_test.go [new file with mode: 0644]
src/go/types/expr.go [new file with mode: 0644]
src/go/types/exprstring.go [new file with mode: 0644]
src/go/types/exprstring_test.go [new file with mode: 0644]
src/go/types/go11.go [new file with mode: 0644]
src/go/types/go12.go [new file with mode: 0644]
src/go/types/hilbert_test.go [new file with mode: 0644]
src/go/types/initorder.go [new file with mode: 0644]
src/go/types/internal/gcimporter/exportdata.go [new file with mode: 0644]
src/go/types/internal/gcimporter/gcimporter.go [new file with mode: 0644]
src/go/types/internal/gcimporter/gcimporter_test.go [new file with mode: 0644]
src/go/types/internal/gcimporter/testdata/exports.go [new file with mode: 0644]
src/go/types/issues_test.go [new file with mode: 0644]
src/go/types/labels.go [new file with mode: 0644]
src/go/types/lookup.go [new file with mode: 0644]
src/go/types/methodset.go [new file with mode: 0644]
src/go/types/methodsetcache.go [new file with mode: 0644]
src/go/types/object.go [new file with mode: 0644]
src/go/types/objset.go [new file with mode: 0644]
src/go/types/operand.go [new file with mode: 0644]
src/go/types/ordering.go [new file with mode: 0644]
src/go/types/package.go [new file with mode: 0644]
src/go/types/predicates.go [new file with mode: 0644]
src/go/types/resolver.go [new file with mode: 0644]
src/go/types/resolver_test.go [new file with mode: 0644]
src/go/types/return.go [new file with mode: 0644]
src/go/types/scope.go [new file with mode: 0644]
src/go/types/selection.go [new file with mode: 0644]
src/go/types/self_test.go [new file with mode: 0644]
src/go/types/sizes.go [new file with mode: 0644]
src/go/types/stdlib_test.go [new file with mode: 0644]
src/go/types/stmt.go [new file with mode: 0644]
src/go/types/testdata/blank.src [new file with mode: 0644]
src/go/types/testdata/builtins.src [new file with mode: 0644]
src/go/types/testdata/const0.src [new file with mode: 0644]
src/go/types/testdata/const1.src [new file with mode: 0644]
src/go/types/testdata/constdecl.src [new file with mode: 0644]
src/go/types/testdata/conversions.src [new file with mode: 0644]
src/go/types/testdata/cycles.src [new file with mode: 0644]
src/go/types/testdata/cycles1.src [new file with mode: 0644]
src/go/types/testdata/cycles2.src [new file with mode: 0644]
src/go/types/testdata/cycles3.src [new file with mode: 0644]
src/go/types/testdata/cycles4.src [new file with mode: 0644]
src/go/types/testdata/decls0.src [new file with mode: 0644]
src/go/types/testdata/decls1.src [new file with mode: 0644]
src/go/types/testdata/decls2a.src [new file with mode: 0644]
src/go/types/testdata/decls2b.src [new file with mode: 0644]
src/go/types/testdata/decls3.src [new file with mode: 0644]
src/go/types/testdata/errors.src [new file with mode: 0644]
src/go/types/testdata/expr0.src [new file with mode: 0644]
src/go/types/testdata/expr1.src [new file with mode: 0644]
src/go/types/testdata/expr2.src [new file with mode: 0644]
src/go/types/testdata/expr3.src [new file with mode: 0644]
src/go/types/testdata/gotos.src [new file with mode: 0644]
src/go/types/testdata/importdecl0a.src [new file with mode: 0644]
src/go/types/testdata/importdecl0b.src [new file with mode: 0644]
src/go/types/testdata/importdecl1a.src [new file with mode: 0644]
src/go/types/testdata/importdecl1b.src [new file with mode: 0644]
src/go/types/testdata/init0.src [new file with mode: 0644]
src/go/types/testdata/init1.src [new file with mode: 0644]
src/go/types/testdata/init2.src [new file with mode: 0644]
src/go/types/testdata/issues.src [new file with mode: 0644]
src/go/types/testdata/labels.src [new file with mode: 0644]
src/go/types/testdata/methodsets.src [new file with mode: 0644]
src/go/types/testdata/shifts.src [new file with mode: 0644]
src/go/types/testdata/stmt0.src [new file with mode: 0644]
src/go/types/testdata/stmt1.src [new file with mode: 0644]
src/go/types/testdata/vardecl.src [new file with mode: 0644]
src/go/types/token_test.go [new file with mode: 0644]
src/go/types/type.go [new file with mode: 0644]
src/go/types/typestring.go [new file with mode: 0644]
src/go/types/typestring_test.go [new file with mode: 0644]
src/go/types/typexpr.go [new file with mode: 0644]
src/go/types/universe.go [new file with mode: 0644]

diff --git a/src/go/exact/exact.go b/src/go/exact/exact.go
new file mode 100644 (file)
index 0000000..e3ceff3
--- /dev/null
@@ -0,0 +1,920 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package exact implements Values representing untyped
+// Go constants and the corresponding operations. Values
+// and operations have unlimited precision.
+//
+// A special Unknown value may be used when a value
+// is unknown due to an error. Operations on unknown
+// values produce unknown values unless specified
+// otherwise.
+//
+package exact // import "go/exact"
+
+import (
+       "fmt"
+       "go/token"
+       "math/big"
+       "strconv"
+)
+
+// Kind specifies the kind of value represented by a Value.
+type Kind int
+
+// Implementation note: Kinds must be enumerated in
+// order of increasing "complexity" (used by match).
+
+const (
+       // unknown values
+       Unknown Kind = iota
+
+       // non-numeric values
+       Bool
+       String
+
+       // numeric values
+       Int
+       Float
+       Complex
+)
+
+// A Value represents a mathematically exact value of a given Kind.
+type Value interface {
+       // Kind returns the value kind; it is always the smallest
+       // kind in which the value can be represented exactly.
+       Kind() Kind
+
+       // String returns a human-readable form of the value.
+       String() string
+
+       // Prevent external implementations.
+       implementsValue()
+}
+
+// ----------------------------------------------------------------------------
+// Implementations
+
+type (
+       unknownVal struct{}
+       boolVal    bool
+       stringVal  string
+       int64Val   int64
+       intVal     struct{ val *big.Int }
+       floatVal   struct{ val *big.Rat }
+       complexVal struct{ re, im *big.Rat }
+)
+
+func (unknownVal) Kind() Kind { return Unknown }
+func (boolVal) Kind() Kind    { return Bool }
+func (stringVal) Kind() Kind  { return String }
+func (int64Val) Kind() Kind   { return Int }
+func (intVal) Kind() Kind     { return Int }
+func (floatVal) Kind() Kind   { return Float }
+func (complexVal) Kind() Kind { return Complex }
+
+func (unknownVal) String() string   { return "unknown" }
+func (x boolVal) String() string    { return fmt.Sprintf("%v", bool(x)) }
+func (x stringVal) String() string  { return strconv.Quote(string(x)) }
+func (x int64Val) String() string   { return strconv.FormatInt(int64(x), 10) }
+func (x intVal) String() string     { return x.val.String() }
+func (x floatVal) String() string   { return x.val.String() }
+func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) }
+
+func (unknownVal) implementsValue() {}
+func (boolVal) implementsValue()    {}
+func (stringVal) implementsValue()  {}
+func (int64Val) implementsValue()   {}
+func (intVal) implementsValue()     {}
+func (floatVal) implementsValue()   {}
+func (complexVal) implementsValue() {}
+
+// int64 bounds
+var (
+       minInt64 = big.NewInt(-1 << 63)
+       maxInt64 = big.NewInt(1<<63 - 1)
+)
+
+func normInt(x *big.Int) Value {
+       if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
+               return int64Val(x.Int64())
+       }
+       return intVal{x}
+}
+
+func normFloat(x *big.Rat) Value {
+       if x.IsInt() {
+               return normInt(x.Num())
+       }
+       return floatVal{x}
+}
+
+func normComplex(re, im *big.Rat) Value {
+       if im.Sign() == 0 {
+               return normFloat(re)
+       }
+       return complexVal{re, im}
+}
+
+// ----------------------------------------------------------------------------
+// Factories
+
+// MakeUnknown returns the Unknown value.
+func MakeUnknown() Value { return unknownVal{} }
+
+// MakeBool returns the Bool value for x.
+func MakeBool(b bool) Value { return boolVal(b) }
+
+// MakeString returns the String value for x.
+func MakeString(s string) Value { return stringVal(s) }
+
+// MakeInt64 returns the Int value for x.
+func MakeInt64(x int64) Value { return int64Val(x) }
+
+// MakeUint64 returns the Int value for x.
+func MakeUint64(x uint64) Value { return normInt(new(big.Int).SetUint64(x)) }
+
+// MakeFloat64 returns the numeric value for x.
+// If x is not finite, the result is unknown.
+func MakeFloat64(x float64) Value {
+       if f := new(big.Rat).SetFloat64(x); f != nil {
+               return normFloat(f)
+       }
+       return unknownVal{}
+}
+
+// MakeFromLiteral returns the corresponding integer, floating-point,
+// imaginary, character, or string value for a Go literal string. The
+// result is nil if the literal string is invalid.
+func MakeFromLiteral(lit string, tok token.Token) Value {
+       switch tok {
+       case token.INT:
+               if x, err := strconv.ParseInt(lit, 0, 64); err == nil {
+                       return int64Val(x)
+               }
+               if x, ok := new(big.Int).SetString(lit, 0); ok {
+                       return intVal{x}
+               }
+
+       case token.FLOAT:
+               if x, ok := new(big.Rat).SetString(lit); ok {
+                       return normFloat(x)
+               }
+
+       case token.IMAG:
+               if n := len(lit); n > 0 && lit[n-1] == 'i' {
+                       if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok {
+                               return normComplex(big.NewRat(0, 1), im)
+                       }
+               }
+
+       case token.CHAR:
+               if n := len(lit); n >= 2 {
+                       if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil {
+                               return int64Val(code)
+                       }
+               }
+
+       case token.STRING:
+               if s, err := strconv.Unquote(lit); err == nil {
+                       return stringVal(s)
+               }
+       }
+
+       return nil
+}
+
+// ----------------------------------------------------------------------------
+// Accessors
+//
+// For unknown arguments the result is the zero value for the respective
+// accessor type, except for Sign, where the result is 1.
+
+// BoolVal returns the Go boolean value of x, which must be a Bool or an Unknown.
+// If x is Unknown, the result is false.
+func BoolVal(x Value) bool {
+       switch x := x.(type) {
+       case boolVal:
+               return bool(x)
+       case unknownVal:
+               return false
+       }
+       panic(fmt.Sprintf("%v not a Bool", x))
+}
+
+// StringVal returns the Go string value of x, which must be a String or an Unknown.
+// If x is Unknown, the result is "".
+func StringVal(x Value) string {
+       switch x := x.(type) {
+       case stringVal:
+               return string(x)
+       case unknownVal:
+               return ""
+       }
+       panic(fmt.Sprintf("%v not a String", x))
+}
+
+// Int64Val returns the Go int64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Int64Val(x Value) (int64, bool) {
+       switch x := x.(type) {
+       case int64Val:
+               return int64(x), true
+       case intVal:
+               return x.val.Int64(), x.val.BitLen() <= 63
+       case unknownVal:
+               return 0, false
+       }
+       panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Uint64Val returns the Go uint64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Uint64Val(x Value) (uint64, bool) {
+       switch x := x.(type) {
+       case int64Val:
+               return uint64(x), x >= 0
+       case intVal:
+               return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64
+       case unknownVal:
+               return 0, false
+       }
+       panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Float32Val is like Float64Val but for float32 instead of float64.
+func Float32Val(x Value) (float32, bool) {
+       switch x := x.(type) {
+       case int64Val:
+               f := float32(x)
+               return f, int64Val(f) == x
+       case intVal:
+               return ratToFloat32(new(big.Rat).SetFrac(x.val, int1))
+       case floatVal:
+               return ratToFloat32(x.val)
+       case unknownVal:
+               return 0, false
+       }
+       panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// Float64Val returns the nearest Go float64 value of x and whether the result is exact;
+// x must be numeric but not Complex, or Unknown. For values too small (too close to 0)
+// to represent as float64, Float64Val silently underflows to 0. The result sign always
+// matches the sign of x, even for 0.
+// If x is Unknown, the result is (0, false).
+func Float64Val(x Value) (float64, bool) {
+       switch x := x.(type) {
+       case int64Val:
+               f := float64(int64(x))
+               return f, int64Val(f) == x
+       case intVal:
+               return new(big.Rat).SetFrac(x.val, int1).Float64()
+       case floatVal:
+               return x.val.Float64()
+       case unknownVal:
+               return 0, false
+       }
+       panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// BitLen returns the number of bits required to represent
+// the absolute value x in binary representation; x must be an Int or an Unknown.
+// If x is Unknown, the result is 0.
+func BitLen(x Value) int {
+       switch x := x.(type) {
+       case int64Val:
+               return new(big.Int).SetInt64(int64(x)).BitLen()
+       case intVal:
+               return x.val.BitLen()
+       case unknownVal:
+               return 0
+       }
+       panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0;
+// x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0,
+// otherwise it is != 0. If x is Unknown, the result is 1.
+func Sign(x Value) int {
+       switch x := x.(type) {
+       case int64Val:
+               switch {
+               case x < 0:
+                       return -1
+               case x > 0:
+                       return 1
+               }
+               return 0
+       case intVal:
+               return x.val.Sign()
+       case floatVal:
+               return x.val.Sign()
+       case complexVal:
+               return x.re.Sign() | x.im.Sign()
+       case unknownVal:
+               return 1 // avoid spurious division by zero errors
+       }
+       panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for serializing/deserializing integers
+
+const (
+       // Compute the size of a Word in bytes.
+       _m       = ^big.Word(0)
+       _log     = _m>>8&1 + _m>>16&1 + _m>>32&1
+       wordSize = 1 << _log
+)
+
+// Bytes returns the bytes for the absolute value of x in little-
+// endian binary representation; x must be an Int.
+func Bytes(x Value) []byte {
+       var val *big.Int
+       switch x := x.(type) {
+       case int64Val:
+               val = new(big.Int).SetInt64(int64(x))
+       case intVal:
+               val = x.val
+       default:
+               panic(fmt.Sprintf("%v not an Int", x))
+       }
+
+       words := val.Bits()
+       bytes := make([]byte, len(words)*wordSize)
+
+       i := 0
+       for _, w := range words {
+               for j := 0; j < wordSize; j++ {
+                       bytes[i] = byte(w)
+                       w >>= 8
+                       i++
+               }
+       }
+       // remove leading 0's
+       for i > 0 && bytes[i-1] == 0 {
+               i--
+       }
+
+       return bytes[:i]
+}
+
+// MakeFromBytes returns the Int value given the bytes of its little-endian
+// binary representation. An empty byte slice argument represents 0.
+func MakeFromBytes(bytes []byte) Value {
+       words := make([]big.Word, (len(bytes)+(wordSize-1))/wordSize)
+
+       i := 0
+       var w big.Word
+       var s uint
+       for _, b := range bytes {
+               w |= big.Word(b) << s
+               if s += 8; s == wordSize*8 {
+                       words[i] = w
+                       i++
+                       w = 0
+                       s = 0
+               }
+       }
+       // store last word
+       if i < len(words) {
+               words[i] = w
+               i++
+       }
+       // remove leading 0's
+       for i > 0 && words[i-1] == 0 {
+               i--
+       }
+
+       return normInt(new(big.Int).SetBits(words[:i]))
+}
+
+// ----------------------------------------------------------------------------
+// Support for disassembling fractions
+
+// Num returns the numerator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int
+// with the same sign as x.
+func Num(x Value) Value {
+       switch x := x.(type) {
+       case unknownVal, int64Val, intVal:
+               return x
+       case floatVal:
+               return normInt(x.val.Num())
+       }
+       panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// Denom returns the denominator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int >= 1.
+func Denom(x Value) Value {
+       switch x := x.(type) {
+       case unknownVal:
+               return x
+       case int64Val, intVal:
+               return int64Val(1)
+       case floatVal:
+               return normInt(x.val.Denom())
+       }
+       panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for assembling/disassembling complex numbers
+
+// MakeImag returns the numeric value x*i (possibly 0);
+// x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown.
+func MakeImag(x Value) Value {
+       var im *big.Rat
+       switch x := x.(type) {
+       case unknownVal:
+               return x
+       case int64Val:
+               im = big.NewRat(int64(x), 1)
+       case intVal:
+               im = new(big.Rat).SetFrac(x.val, int1)
+       case floatVal:
+               im = x.val
+       default:
+               panic(fmt.Sprintf("%v not Int or Float", x))
+       }
+       return normComplex(rat0, im)
+}
+
+// Real returns the real part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Real(x Value) Value {
+       switch x := x.(type) {
+       case unknownVal, int64Val, intVal, floatVal:
+               return x
+       case complexVal:
+               return normFloat(x.re)
+       }
+       panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// Imag returns the imaginary part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Imag(x Value) Value {
+       switch x := x.(type) {
+       case unknownVal:
+               return x
+       case int64Val, intVal, floatVal:
+               return int64Val(0)
+       case complexVal:
+               return normFloat(x.im)
+       }
+       panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Operations
+
+// is32bit reports whether x can be represented using 32 bits.
+func is32bit(x int64) bool {
+       const s = 32
+       return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// is63bit reports whether x can be represented using 63 bits.
+func is63bit(x int64) bool {
+       const s = 63
+       return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// UnaryOp returns the result of the unary expression op y.
+// The operation must be defined for the operand.
+// If size >= 0 it specifies the ^ (xor) result size in bytes.
+// If y is Unknown, the result is Unknown.
+//
+func UnaryOp(op token.Token, y Value, size int) Value {
+       switch op {
+       case token.ADD:
+               switch y.(type) {
+               case unknownVal, int64Val, intVal, floatVal, complexVal:
+                       return y
+               }
+
+       case token.SUB:
+               switch y := y.(type) {
+               case unknownVal:
+                       return y
+               case int64Val:
+                       if z := -y; z != y {
+                               return z // no overflow
+                       }
+                       return normInt(new(big.Int).Neg(big.NewInt(int64(y))))
+               case intVal:
+                       return normInt(new(big.Int).Neg(y.val))
+               case floatVal:
+                       return normFloat(new(big.Rat).Neg(y.val))
+               case complexVal:
+                       return normComplex(new(big.Rat).Neg(y.re), new(big.Rat).Neg(y.im))
+               }
+
+       case token.XOR:
+               var z big.Int
+               switch y := y.(type) {
+               case unknownVal:
+                       return y
+               case int64Val:
+                       z.Not(big.NewInt(int64(y)))
+               case intVal:
+                       z.Not(y.val)
+               default:
+                       goto Error
+               }
+               // For unsigned types, the result will be negative and
+               // thus "too large": We must limit the result size to
+               // the type's size.
+               if size >= 0 {
+                       s := uint(size) * 8
+                       z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), s)) // z &^= (-1)<<s
+               }
+               return normInt(&z)
+
+       case token.NOT:
+               switch y := y.(type) {
+               case unknownVal:
+                       return y
+               case boolVal:
+                       return !y
+               }
+       }
+
+Error:
+       panic(fmt.Sprintf("invalid unary operation %s%v", op, y))
+}
+
+var (
+       int1 = big.NewInt(1)
+       rat0 = big.NewRat(0, 1)
+)
+
+func ord(x Value) int {
+       switch x.(type) {
+       default:
+               return 0
+       case boolVal, stringVal:
+               return 1
+       case int64Val:
+               return 2
+       case intVal:
+               return 3
+       case floatVal:
+               return 4
+       case complexVal:
+               return 5
+       }
+}
+
+// match returns the matching representation (same type) with the
+// smallest complexity for two values x and y. If one of them is
+// numeric, both of them must be numeric. If one of them is Unknown,
+// both results are Unknown.
+//
+func match(x, y Value) (_, _ Value) {
+       if ord(x) > ord(y) {
+               y, x = match(y, x)
+               return x, y
+       }
+       // ord(x) <= ord(y)
+
+       switch x := x.(type) {
+       case unknownVal:
+               return x, x
+
+       case boolVal, stringVal, complexVal:
+               return x, y
+
+       case int64Val:
+               switch y := y.(type) {
+               case int64Val:
+                       return x, y
+               case intVal:
+                       return intVal{big.NewInt(int64(x))}, y
+               case floatVal:
+                       return floatVal{big.NewRat(int64(x), 1)}, y
+               case complexVal:
+                       return complexVal{big.NewRat(int64(x), 1), rat0}, y
+               }
+
+       case intVal:
+               switch y := y.(type) {
+               case intVal:
+                       return x, y
+               case floatVal:
+                       return floatVal{new(big.Rat).SetFrac(x.val, int1)}, y
+               case complexVal:
+                       return complexVal{new(big.Rat).SetFrac(x.val, int1), rat0}, y
+               }
+
+       case floatVal:
+               switch y := y.(type) {
+               case floatVal:
+                       return x, y
+               case complexVal:
+                       return complexVal{x.val, rat0}, y
+               }
+       }
+
+       panic("unreachable")
+}
+
+// BinaryOp returns the result of the binary expression x op y.
+// The operation must be defined for the operands. If one of the
+// operands is Unknown, the result is Unknown.
+// To force integer division of Int operands, use op == token.QUO_ASSIGN
+// instead of token.QUO; the result is guaranteed to be Int in this case.
+// Division by zero leads to a run-time panic.
+//
+func BinaryOp(x Value, op token.Token, y Value) Value {
+       x, y = match(x, y)
+
+       switch x := x.(type) {
+       case unknownVal:
+               return x
+
+       case boolVal:
+               y := y.(boolVal)
+               switch op {
+               case token.LAND:
+                       return x && y
+               case token.LOR:
+                       return x || y
+               }
+
+       case int64Val:
+               a := int64(x)
+               b := int64(y.(int64Val))
+               var c int64
+               switch op {
+               case token.ADD:
+                       if !is63bit(a) || !is63bit(b) {
+                               return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b)))
+                       }
+                       c = a + b
+               case token.SUB:
+                       if !is63bit(a) || !is63bit(b) {
+                               return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b)))
+                       }
+                       c = a - b
+               case token.MUL:
+                       if !is32bit(a) || !is32bit(b) {
+                               return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b)))
+                       }
+                       c = a * b
+               case token.QUO:
+                       return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b)))
+               case token.QUO_ASSIGN: // force integer division
+                       c = a / b
+               case token.REM:
+                       c = a % b
+               case token.AND:
+                       c = a & b
+               case token.OR:
+                       c = a | b
+               case token.XOR:
+                       c = a ^ b
+               case token.AND_NOT:
+                       c = a &^ b
+               default:
+                       goto Error
+               }
+               return int64Val(c)
+
+       case intVal:
+               a := x.val
+               b := y.(intVal).val
+               var c big.Int
+               switch op {
+               case token.ADD:
+                       c.Add(a, b)
+               case token.SUB:
+                       c.Sub(a, b)
+               case token.MUL:
+                       c.Mul(a, b)
+               case token.QUO:
+                       return normFloat(new(big.Rat).SetFrac(a, b))
+               case token.QUO_ASSIGN: // force integer division
+                       c.Quo(a, b)
+               case token.REM:
+                       c.Rem(a, b)
+               case token.AND:
+                       c.And(a, b)
+               case token.OR:
+                       c.Or(a, b)
+               case token.XOR:
+                       c.Xor(a, b)
+               case token.AND_NOT:
+                       c.AndNot(a, b)
+               default:
+                       goto Error
+               }
+               return normInt(&c)
+
+       case floatVal:
+               a := x.val
+               b := y.(floatVal).val
+               var c big.Rat
+               switch op {
+               case token.ADD:
+                       c.Add(a, b)
+               case token.SUB:
+                       c.Sub(a, b)
+               case token.MUL:
+                       c.Mul(a, b)
+               case token.QUO:
+                       c.Quo(a, b)
+               default:
+                       goto Error
+               }
+               return normFloat(&c)
+
+       case complexVal:
+               y := y.(complexVal)
+               a, b := x.re, x.im
+               c, d := y.re, y.im
+               var re, im big.Rat
+               switch op {
+               case token.ADD:
+                       // (a+c) + i(b+d)
+                       re.Add(a, c)
+                       im.Add(b, d)
+               case token.SUB:
+                       // (a-c) + i(b-d)
+                       re.Sub(a, c)
+                       im.Sub(b, d)
+               case token.MUL:
+                       // (ac-bd) + i(bc+ad)
+                       var ac, bd, bc, ad big.Rat
+                       ac.Mul(a, c)
+                       bd.Mul(b, d)
+                       bc.Mul(b, c)
+                       ad.Mul(a, d)
+                       re.Sub(&ac, &bd)
+                       im.Add(&bc, &ad)
+               case token.QUO:
+                       // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
+                       var ac, bd, bc, ad, s, cc, dd big.Rat
+                       ac.Mul(a, c)
+                       bd.Mul(b, d)
+                       bc.Mul(b, c)
+                       ad.Mul(a, d)
+                       cc.Mul(c, c)
+                       dd.Mul(d, d)
+                       s.Add(&cc, &dd)
+                       re.Add(&ac, &bd)
+                       re.Quo(&re, &s)
+                       im.Sub(&bc, &ad)
+                       im.Quo(&im, &s)
+               default:
+                       goto Error
+               }
+               return normComplex(&re, &im)
+
+       case stringVal:
+               if op == token.ADD {
+                       return x + y.(stringVal)
+               }
+       }
+
+Error:
+       panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y))
+}
+
+// Shift returns the result of the shift expression x op s
+// with op == token.SHL or token.SHR (<< or >>). x must be
+// an Int or an Unknown. If x is Unknown, the result is x.
+//
+func Shift(x Value, op token.Token, s uint) Value {
+       switch x := x.(type) {
+       case unknownVal:
+               return x
+
+       case int64Val:
+               if s == 0 {
+                       return x
+               }
+               switch op {
+               case token.SHL:
+                       z := big.NewInt(int64(x))
+                       return normInt(z.Lsh(z, s))
+               case token.SHR:
+                       return x >> s
+               }
+
+       case intVal:
+               if s == 0 {
+                       return x
+               }
+               var z big.Int
+               switch op {
+               case token.SHL:
+                       return normInt(z.Lsh(x.val, s))
+               case token.SHR:
+                       return normInt(z.Rsh(x.val, s))
+               }
+       }
+
+       panic(fmt.Sprintf("invalid shift %v %s %d", x, op, s))
+}
+
+func cmpZero(x int, op token.Token) bool {
+       switch op {
+       case token.EQL:
+               return x == 0
+       case token.NEQ:
+               return x != 0
+       case token.LSS:
+               return x < 0
+       case token.LEQ:
+               return x <= 0
+       case token.GTR:
+               return x > 0
+       case token.GEQ:
+               return x >= 0
+       }
+       panic("unreachable")
+}
+
+// Compare returns the result of the comparison x op y.
+// The comparison must be defined for the operands.
+// If one of the operands is Unknown, the result is
+// false.
+//
+func Compare(x Value, op token.Token, y Value) bool {
+       x, y = match(x, y)
+
+       switch x := x.(type) {
+       case unknownVal:
+               return false
+
+       case boolVal:
+               y := y.(boolVal)
+               switch op {
+               case token.EQL:
+                       return x == y
+               case token.NEQ:
+                       return x != y
+               }
+
+       case int64Val:
+               y := y.(int64Val)
+               switch op {
+               case token.EQL:
+                       return x == y
+               case token.NEQ:
+                       return x != y
+               case token.LSS:
+                       return x < y
+               case token.LEQ:
+                       return x <= y
+               case token.GTR:
+                       return x > y
+               case token.GEQ:
+                       return x >= y
+               }
+
+       case intVal:
+               return cmpZero(x.val.Cmp(y.(intVal).val), op)
+
+       case floatVal:
+               return cmpZero(x.val.Cmp(y.(floatVal).val), op)
+
+       case complexVal:
+               y := y.(complexVal)
+               re := x.re.Cmp(y.re)
+               im := x.im.Cmp(y.im)
+               switch op {
+               case token.EQL:
+                       return re == 0 && im == 0
+               case token.NEQ:
+                       return re != 0 || im != 0
+               }
+
+       case stringVal:
+               y := y.(stringVal)
+               switch op {
+               case token.EQL:
+                       return x == y
+               case token.NEQ:
+                       return x != y
+               case token.LSS:
+                       return x < y
+               case token.LEQ:
+                       return x <= y
+               case token.GTR:
+                       return x > y
+               case token.GEQ:
+                       return x >= y
+               }
+       }
+
+       panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y))
+}
diff --git a/src/go/exact/exact_test.go b/src/go/exact/exact_test.go
new file mode 100644 (file)
index 0000000..aa38a89
--- /dev/null
@@ -0,0 +1,375 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exact
+
+import (
+       "go/token"
+       "strings"
+       "testing"
+)
+
+// TODO(gri) expand this test framework
+
+var opTests = []string{
+       // unary operations
+       `+ 0 = 0`,
+       `+ ? = ?`,
+       `- 1 = -1`,
+       `- ? = ?`,
+       `^ 0 = -1`,
+       `^ ? = ?`,
+
+       `! true = false`,
+       `! false = true`,
+       `! ? = ?`,
+
+       // etc.
+
+       // binary operations
+       `"" + "" = ""`,
+       `"foo" + "" = "foo"`,
+       `"" + "bar" = "bar"`,
+       `"foo" + "bar" = "foobar"`,
+
+       `0 + 0 = 0`,
+       `0 + 0.1 = 0.1`,
+       `0 + 0.1i = 0.1i`,
+       `0.1 + 0.9 = 1`,
+       `1e100 + 1e100 = 2e100`,
+       `? + 0 = ?`,
+       `0 + ? = ?`,
+
+       `0 - 0 = 0`,
+       `0 - 0.1 = -0.1`,
+       `0 - 0.1i = -0.1i`,
+       `1e100 - 1e100 = 0`,
+       `? - 0 = ?`,
+       `0 - ? = ?`,
+
+       `0 * 0 = 0`,
+       `1 * 0.1 = 0.1`,
+       `1 * 0.1i = 0.1i`,
+       `1i * 1i = -1`,
+       `? * 0 = ?`,
+       `0 * ? = ?`,
+
+       `0 / 0 = "division_by_zero"`,
+       `10 / 2 = 5`,
+       `5 / 3 = 5/3`,
+       `5i / 3i = 5/3`,
+       `? / 0 = ?`,
+       `0 / ? = ?`,
+
+       `0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
+       `10 % 3 = 1`,
+       `? % 0 = ?`,
+       `0 % ? = ?`,
+
+       `0 & 0 = 0`,
+       `12345 & 0 = 0`,
+       `0xff & 0xf = 0xf`,
+       `? & 0 = ?`,
+       `0 & ? = ?`,
+
+       `0 | 0 = 0`,
+       `12345 | 0 = 12345`,
+       `0xb | 0xa0 = 0xab`,
+       `? | 0 = ?`,
+       `0 | ? = ?`,
+
+       `0 ^ 0 = 0`,
+       `1 ^ -1 = -2`,
+       `? ^ 0 = ?`,
+       `0 ^ ? = ?`,
+
+       `0 &^ 0 = 0`,
+       `0xf &^ 1 = 0xe`,
+       `1 &^ 0xf = 0`,
+       // etc.
+
+       // shifts
+       `0 << 0 = 0`,
+       `1 << 10 = 1024`,
+       `0 >> 0 = 0`,
+       `1024 >> 10 == 1`,
+       `? << 0 == ?`,
+       `? >> 10 == ?`,
+       // etc.
+
+       // comparisons
+       `false == false = true`,
+       `false == true = false`,
+       `true == false = false`,
+       `true == true = true`,
+
+       `false != false = false`,
+       `false != true = true`,
+       `true != false = true`,
+       `true != true = false`,
+
+       `"foo" == "bar" = false`,
+       `"foo" != "bar" = true`,
+       `"foo" < "bar" = false`,
+       `"foo" <= "bar" = false`,
+       `"foo" > "bar" = true`,
+       `"foo" >= "bar" = true`,
+
+       `0 == 0 = true`,
+       `0 != 0 = false`,
+       `0 < 10 = true`,
+       `10 <= 10 = true`,
+       `0 > 10 = false`,
+       `10 >= 10 = true`,
+
+       `1/123456789 == 1/123456789 == true`,
+       `1/123456789 != 1/123456789 == false`,
+       `1/123456789 < 1/123456788 == true`,
+       `1/123456788 <= 1/123456789 == false`,
+       `0.11 > 0.11 = false`,
+       `0.11 >= 0.11 = true`,
+
+       `? == 0 = false`,
+       `? != 0 = false`,
+       `? < 10 = false`,
+       `? <= 10 = false`,
+       `? > 10 = false`,
+       `? >= 10 = false`,
+
+       `0 == ? = false`,
+       `0 != ? = false`,
+       `0 < ? = false`,
+       `10 <= ? = false`,
+       `0 > ? = false`,
+       `10 >= ? = false`,
+
+       // etc.
+}
+
+func TestOps(t *testing.T) {
+       for _, test := range opTests {
+               a := strings.Split(test, " ")
+               i := 0 // operator index
+
+               var x, x0 Value
+               switch len(a) {
+               case 4:
+                       // unary operation
+               case 5:
+                       // binary operation
+                       x, x0 = val(a[0]), val(a[0])
+                       i = 1
+               default:
+                       t.Errorf("invalid test case: %s", test)
+                       continue
+               }
+
+               op, ok := optab[a[i]]
+               if !ok {
+                       panic("missing optab entry for " + a[i])
+               }
+
+               y, y0 := val(a[i+1]), val(a[i+1])
+
+               got := doOp(x, op, y)
+               want := val(a[i+3])
+               if !eql(got, want) {
+                       t.Errorf("%s: got %s; want %s", test, got, want)
+               }
+               if x0 != nil && !eql(x, x0) {
+                       t.Errorf("%s: x changed to %s", test, x)
+               }
+               if !eql(y, y0) {
+                       t.Errorf("%s: y changed to %s", test, y)
+               }
+       }
+}
+
+func eql(x, y Value) bool {
+       _, ux := x.(unknownVal)
+       _, uy := y.(unknownVal)
+       if ux || uy {
+               return ux == uy
+       }
+       return Compare(x, token.EQL, y)
+}
+
+// ----------------------------------------------------------------------------
+// Support functions
+
+func val(lit string) Value {
+       if len(lit) == 0 {
+               return MakeUnknown()
+       }
+
+       switch lit {
+       case "?":
+               return MakeUnknown()
+       case "true":
+               return MakeBool(true)
+       case "false":
+               return MakeBool(false)
+       }
+
+       tok := token.INT
+       switch first, last := lit[0], lit[len(lit)-1]; {
+       case first == '"' || first == '`':
+               tok = token.STRING
+               lit = strings.Replace(lit, "_", " ", -1)
+       case first == '\'':
+               tok = token.CHAR
+       case last == 'i':
+               tok = token.IMAG
+       default:
+               if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
+                       tok = token.FLOAT
+               }
+       }
+
+       return MakeFromLiteral(lit, tok)
+}
+
+var optab = map[string]token.Token{
+       "!": token.NOT,
+
+       "+": token.ADD,
+       "-": token.SUB,
+       "*": token.MUL,
+       "/": token.QUO,
+       "%": token.REM,
+
+       "<<": token.SHL,
+       ">>": token.SHR,
+
+       "&":  token.AND,
+       "|":  token.OR,
+       "^":  token.XOR,
+       "&^": token.AND_NOT,
+
+       "==": token.EQL,
+       "!=": token.NEQ,
+       "<":  token.LSS,
+       "<=": token.LEQ,
+       ">":  token.GTR,
+       ">=": token.GEQ,
+}
+
+func panicHandler(v *Value) {
+       switch p := recover().(type) {
+       case nil:
+               // nothing to do
+       case string:
+               *v = MakeString(p)
+       case error:
+               *v = MakeString(p.Error())
+       default:
+               panic(p)
+       }
+}
+
+func doOp(x Value, op token.Token, y Value) (z Value) {
+       defer panicHandler(&z)
+
+       if x == nil {
+               return UnaryOp(op, y, -1)
+       }
+
+       switch op {
+       case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+               return MakeBool(Compare(x, op, y))
+       case token.SHL, token.SHR:
+               s, _ := Int64Val(y)
+               return Shift(x, op, uint(s))
+       default:
+               return BinaryOp(x, op, y)
+       }
+}
+
+// ----------------------------------------------------------------------------
+// Other tests
+
+var fracTests = []string{
+       "0 0 1",
+       "1 1 1",
+       "-1 -1 1",
+       "1.2 6 5",
+       "-0.991 -991 1000",
+       "1e100 1e100 1",
+}
+
+func TestFractions(t *testing.T) {
+       for _, test := range fracTests {
+               a := strings.Split(test, " ")
+               if len(a) != 3 {
+                       t.Errorf("invalid test case: %s", test)
+                       continue
+               }
+
+               x := val(a[0])
+               n := val(a[1])
+               d := val(a[2])
+
+               if got := Num(x); !eql(got, n) {
+                       t.Errorf("%s: got num = %s; want %s", test, got, n)
+               }
+
+               if got := Denom(x); !eql(got, d) {
+                       t.Errorf("%s: got denom = %s; want %s", test, got, d)
+               }
+       }
+}
+
+var bytesTests = []string{
+       "0",
+       "1",
+       "123456789",
+       "123456789012345678901234567890123456789012345678901234567890",
+}
+
+func TestBytes(t *testing.T) {
+       for _, test := range bytesTests {
+               x := val(test)
+               bytes := Bytes(x)
+
+               // special case 0
+               if Sign(x) == 0 && len(bytes) != 0 {
+                       t.Errorf("%s: got %v; want empty byte slice", test, bytes)
+               }
+
+               if n := len(bytes); n > 0 && bytes[n-1] == 0 {
+                       t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
+               }
+
+               if got := MakeFromBytes(bytes); !eql(got, x) {
+                       t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
+               }
+       }
+}
+
+func TestUnknown(t *testing.T) {
+       u := MakeUnknown()
+       var values = []Value{
+               u,
+               MakeBool(false), // token.ADD ok below, operation is never considered
+               MakeString(""),
+               MakeInt64(1),
+               MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT),
+               MakeFloat64(1.2),
+               MakeImag(MakeFloat64(1.2)),
+       }
+       for _, val := range values {
+               x, y := val, u
+               for i := range [2]int{} {
+                       if i == 1 {
+                               x, y = y, x
+                       }
+                       if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
+                               t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
+                       }
+                       if got := Compare(x, token.EQL, y); got {
+                               t.Errorf("%s == %s: got true; want false", x, y)
+                       }
+               }
+       }
+}
diff --git a/src/go/exact/go13.go b/src/go/exact/go13.go
new file mode 100644 (file)
index 0000000..1016c14
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2014 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.4
+
+package exact
+
+import (
+       "math"
+       "math/big"
+)
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+       // Before 1.4, there's no Rat.Float32.
+       // Emulate it, albeit at the cost of
+       // imprecision in corner cases.
+       x64, exact := x.Float64()
+       x32 := float32(x64)
+       if math.IsInf(float64(x32), 0) {
+               exact = false
+       }
+       return x32, exact
+}
diff --git a/src/go/exact/go14.go b/src/go/exact/go14.go
new file mode 100644 (file)
index 0000000..b86e5d2
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.4
+
+package exact
+
+import "math/big"
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+       return x.Float32()
+}
diff --git a/src/go/types.bash b/src/go/types.bash
new file mode 100644 (file)
index 0000000..f39bd7e
--- /dev/null
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+# Copyright 2015 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Run this script to update the packages ./exact and ./types
+# in the $GOROOT/src/go directory. They are vendored from the
+# original sources in x/tools. Imports are renamed as needed.
+#
+# Delete this script once go/exact and go/types don't exist anymore in x/tools.
+
+set -e
+
+### Safety first.
+if [ ! -d "$GOPATH" ]; then
+       echo 2>&1 '$GOPATH must be set.'
+       exit 1
+fi
+if [ ! -d "$GOROOT" ]; then
+       echo 2>&1 '$GOROOT must be set.'
+       exit 1
+fi
+
+GODIR=$GOROOT/src/go
+
+function vendor() (
+       SRCDIR=$GOPATH/src/golang.org/x/tools/$1
+       DSTDIR=$GODIR/$2
+
+       echo 2>&1 "vendoring $SRCDIR => $DSTDIR"
+
+       # create directory
+       rm -rf $DSTDIR
+       mkdir -p $DSTDIR
+       cd $DSTDIR
+
+       # copy go sources and update import paths
+       for f in $SRCDIR/*.go; do
+               # copy $f and update imports
+               sed -e 's|"golang.org/x/tools/go/exact"|"go/exact"|' \
+                   -e 's|"golang.org/x/tools/go/types"|"go/types"|' \
+                   -e 's|"golang.org/x/tools/go/gcimporter"|"go/types/internal/gcimporter"|' \
+                   $f | gofmt > tmp.go
+               mv -f tmp.go `basename $f`
+       done
+
+       # copy testdata, if any
+       if [ -e $SRCDIR/testdata ]; then
+               cp -R $SRCDIR/testdata/ $DSTDIR/testdata/
+       fi
+)
+
+function install() (
+       PKG=$GODIR/$1
+
+       echo 2>&1 "installing $PKG"
+       cd $PKG
+       go install
+)
+
+function test() (
+       PKG=$GODIR/$1
+
+       echo 2>&1 "testing $PKG"
+       cd $PKG
+       if ! go test; then
+               echo 2>&1 "TESTING $PKG FAILED"
+               exit 1
+       fi
+)
+
+### go/exact
+vendor go/exact exact
+test exact
+install exact
+
+### go/types
+vendor go/types types
+# cannot test w/o gcimporter
+install types
+
+### go/gcimporter
+vendor go/gcimporter types/internal/gcimporter
+test types/internal/gcimporter
+install types/internal/gcimporter
+
+### test go/types (requires gcimporter)
+test types
+
+# All done.
+echo 2>&1 "DONE"
+exit 0
diff --git a/src/go/types/api.go b/src/go/types/api.go
new file mode 100644 (file)
index 0000000..c3681e9
--- /dev/null
@@ -0,0 +1,365 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package types declares the data types and implements
+// the algorithms for type-checking of Go packages.
+// Use Check and Config.Check to invoke the type-checker.
+//
+// Type-checking consists of several interdependent phases:
+//
+// Name resolution maps each identifier (ast.Ident) in the program to the
+// language object (Object) it denotes.
+// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
+//
+// Constant folding computes the exact constant value (exact.Value) for
+// every expression (ast.Expr) that is a compile-time constant.
+// Use Info.Types[expr].Value for the results of constant folding.
+//
+// Type inference computes the type (Type) of every expression (ast.Expr)
+// and checks for compliance with the language specification.
+// Use Info.Types[expr].Type for the results of type inference.
+//
+package types // import "go/types"
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/token"
+
+       "go/exact"
+)
+
+// Check type-checks a package and returns the resulting complete package
+// object, or a nil package and the first error. The package is specified
+// by a list of *ast.Files and corresponding file set, and the import path
+// the package is identified with. The clean path must not be empty or dot (".").
+//
+// For more control over type-checking and results, use Config.Check.
+func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
+       var conf Config
+       pkg, err := conf.Check(path, fset, files, nil)
+       if err != nil {
+               return nil, err
+       }
+       return pkg, nil
+}
+
+// An Error describes a type-checking error; it implements the error interface.
+// A "soft" error is an error that still permits a valid interpretation of a
+// package (such as "unused variable"); "hard" errors may lead to unpredictable
+// behavior if ignored.
+type Error struct {
+       Fset *token.FileSet // file set for interpretation of Pos
+       Pos  token.Pos      // error position
+       Msg  string         // error message
+       Soft bool           // if set, error is "soft"
+}
+
+// Error returns an error string formatted as follows:
+// filename:line:column: message
+func (err Error) Error() string {
+       return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
+}
+
+// An importer resolves import paths to Packages.
+// The imports map records packages already known,
+// indexed by package path. The type-checker
+// will invoke Import with Config.Packages.
+// An importer must determine the canonical package path and
+// check imports to see if it is already present in the map.
+// If so, the Importer can return the map entry.  Otherwise,
+// the importer must load the package data for the given path
+// into a new *Package, record it in imports map, and return
+// the package.
+// TODO(gri) Need to be clearer about requirements of completeness.
+type Importer func(map[string]*Package, string) (*Package, error)
+
+// A Config specifies the configuration for type checking.
+// The zero value for Config is a ready-to-use default configuration.
+type Config struct {
+       // If IgnoreFuncBodies is set, function bodies are not
+       // type-checked.
+       IgnoreFuncBodies bool
+
+       // If FakeImportC is set, `import "C"` (for packages requiring Cgo)
+       // declares an empty "C" package and errors are omitted for qualified
+       // identifiers referring to package C (which won't find an object).
+       // This feature is intended for the standard library cmd/api tool.
+       //
+       // Caution: Effects may be unpredictable due to follow-up errors.
+       //          Do not use casually!
+       FakeImportC bool
+
+       // Packages is used to look up (and thus canonicalize) packages by
+       // package path. If Packages is nil, it is set to a new empty map.
+       // During type-checking, imported packages are added to the map.
+       Packages map[string]*Package
+
+       // If Error != nil, it is called with each error found
+       // during type checking; err has dynamic type Error.
+       // Secondary errors (for instance, to enumerate all types
+       // involved in an invalid recursive type declaration) have
+       // error strings that start with a '\t' character.
+       // If Error == nil, type-checking stops with the first
+       // error found.
+       Error func(err error)
+
+       // If Import != nil, it is called for each imported package.
+       // Otherwise, DefaultImport is called.
+       Import Importer
+
+       // If Sizes != nil, it provides the sizing functions for package unsafe.
+       // Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
+       Sizes Sizes
+
+       // If DisableUnusedImportCheck is set, packages are not checked
+       // for unused imports.
+       DisableUnusedImportCheck bool
+}
+
+// DefaultImport is the default importer invoked if Config.Import == nil.
+// The declaration:
+//
+//     import _ "go/types/internal/gcimporter"
+//
+// in a client of go/types will initialize DefaultImport to gcimporter.Import.
+var DefaultImport Importer
+
+// Info holds result type information for a type-checked package.
+// Only the information for which a map is provided is collected.
+// If the package has type errors, the collected information may
+// be incomplete.
+type Info struct {
+       // Types maps expressions to their types, and for constant
+       // expressions, their values. Invalid expressions are omitted.
+       //
+       // For (possibly parenthesized) identifiers denoting built-in
+       // functions, the recorded signatures are call-site specific:
+       // if the call result is not a constant, the recorded type is
+       // an argument-specific signature. Otherwise, the recorded type
+       // is invalid.
+       //
+       // Identifiers on the lhs of declarations (i.e., the identifiers
+       // which are being declared) are collected in the Defs map.
+       // Identifiers denoting packages are collected in the Uses maps.
+       Types map[ast.Expr]TypeAndValue
+
+       // Defs maps identifiers to the objects they define (including
+       // package names, dots "." of dot-imports, and blank "_" identifiers).
+       // For identifiers that do not denote objects (e.g., the package name
+       // in package clauses, or symbolic variables t in t := x.(type) of
+       // type switch headers), the corresponding objects are nil.
+       //
+       // For an anonymous field, Defs returns the field *Var it defines.
+       //
+       // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
+       Defs map[*ast.Ident]Object
+
+       // Uses maps identifiers to the objects they denote.
+       //
+       // For an anonymous field, Uses returns the *TypeName it denotes.
+       //
+       // Invariant: Uses[id].Pos() != id.Pos()
+       Uses map[*ast.Ident]Object
+
+       // Implicits maps nodes to their implicitly declared objects, if any.
+       // The following node and object types may appear:
+       //
+       //      node               declared object
+       //
+       //      *ast.ImportSpec    *PkgName for dot-imports and imports without renames
+       //      *ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
+       //      *ast.Field         anonymous struct field or parameter *Var
+       //
+       Implicits map[ast.Node]Object
+
+       // Selections maps selector expressions (excluding qualified identifiers)
+       // to their corresponding selections.
+       Selections map[*ast.SelectorExpr]*Selection
+
+       // Scopes maps ast.Nodes to the scopes they define. Package scopes are not
+       // associated with a specific node but with all files belonging to a package.
+       // Thus, the package scope can be found in the type-checked Package object.
+       // Scopes nest, with the Universe scope being the outermost scope, enclosing
+       // the package scope, which contains (one or more) files scopes, which enclose
+       // function scopes which in turn enclose statement and function literal scopes.
+       // Note that even though package-level functions are declared in the package
+       // scope, the function scopes are embedded in the file scope of the file
+       // containing the function declaration.
+       //
+       // The following node types may appear in Scopes:
+       //
+       //      *ast.File
+       //      *ast.FuncType
+       //      *ast.BlockStmt
+       //      *ast.IfStmt
+       //      *ast.SwitchStmt
+       //      *ast.TypeSwitchStmt
+       //      *ast.CaseClause
+       //      *ast.CommClause
+       //      *ast.ForStmt
+       //      *ast.RangeStmt
+       //
+       Scopes map[ast.Node]*Scope
+
+       // InitOrder is the list of package-level initializers in the order in which
+       // they must be executed. Initializers referring to variables related by an
+       // initialization dependency appear in topological order, the others appear
+       // in source order. Variables without an initialization expression do not
+       // appear in this list.
+       InitOrder []*Initializer
+}
+
+// TypeOf returns the type of expression e, or nil if not found.
+// Precondition: the Types, Uses and Defs maps are populated.
+//
+func (info *Info) TypeOf(e ast.Expr) Type {
+       if t, ok := info.Types[e]; ok {
+               return t.Type
+       }
+       if id, _ := e.(*ast.Ident); id != nil {
+               if obj := info.ObjectOf(id); obj != nil {
+                       return obj.Type()
+               }
+       }
+       return nil
+}
+
+// ObjectOf returns the object denoted by the specified id,
+// or nil if not found.
+//
+// If id is an anonymous struct field, ObjectOf returns the field (*Var)
+// it uses, not the type (*TypeName) it defines.
+//
+// Precondition: the Uses and Defs maps are populated.
+//
+func (info *Info) ObjectOf(id *ast.Ident) Object {
+       if obj, _ := info.Defs[id]; obj != nil {
+               return obj
+       }
+       return info.Uses[id]
+}
+
+// TypeAndValue reports the type and value (for constants)
+// of the corresponding expression.
+type TypeAndValue struct {
+       mode  operandMode
+       Type  Type
+       Value exact.Value
+}
+
+// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
+// "void" values as regular values but with the empty tuple type.
+
+// IsVoid reports whether the corresponding expression
+// is a function call without results.
+func (tv TypeAndValue) IsVoid() bool {
+       return tv.mode == novalue
+}
+
+// IsType reports whether the corresponding expression specifies a type.
+func (tv TypeAndValue) IsType() bool {
+       return tv.mode == typexpr
+}
+
+// IsBuiltin reports whether the corresponding expression denotes
+// a (possibly parenthesized) built-in function.
+func (tv TypeAndValue) IsBuiltin() bool {
+       return tv.mode == builtin
+}
+
+// IsValue reports whether the corresponding expression is a value.
+// Builtins are not considered values. Constant values have a non-
+// nil Value.
+func (tv TypeAndValue) IsValue() bool {
+       switch tv.mode {
+       case constant, variable, mapindex, value, commaok:
+               return true
+       }
+       return false
+}
+
+// IsNil reports whether the corresponding expression denotes the
+// predeclared value nil.
+func (tv TypeAndValue) IsNil() bool {
+       return tv.mode == value && tv.Type == Typ[UntypedNil]
+}
+
+// Addressable reports whether the corresponding expression
+// is addressable (http://golang.org/ref/spec#Address_operators).
+func (tv TypeAndValue) Addressable() bool {
+       return tv.mode == variable
+}
+
+// Assignable reports whether the corresponding expression
+// is assignable to (provided a value of the right type).
+func (tv TypeAndValue) Assignable() bool {
+       return tv.mode == variable || tv.mode == mapindex
+}
+
+// HasOk reports whether the corresponding expression may be
+// used on the lhs of a comma-ok assignment.
+func (tv TypeAndValue) HasOk() bool {
+       return tv.mode == commaok || tv.mode == mapindex
+}
+
+// An Initializer describes a package-level variable, or a list of variables in case
+// of a multi-valued initialization expression, and the corresponding initialization
+// expression.
+type Initializer struct {
+       Lhs []*Var // var Lhs = Rhs
+       Rhs ast.Expr
+}
+
+func (init *Initializer) String() string {
+       var buf bytes.Buffer
+       for i, lhs := range init.Lhs {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               buf.WriteString(lhs.Name())
+       }
+       buf.WriteString(" = ")
+       WriteExpr(&buf, init.Rhs)
+       return buf.String()
+}
+
+// Check type-checks a package and returns the resulting package object,
+// the first error if any, and if info != nil, additional type information.
+// The package is marked as complete if no errors occurred, otherwise it is
+// incomplete. See Config.Error for controlling behavior in the presence of
+// errors.
+//
+// The package is specified by a list of *ast.Files and corresponding
+// file set, and the package path the package is identified with.
+// The clean path must not be empty or dot (".").
+func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
+       pkg := NewPackage(path, "")
+       return pkg, NewChecker(conf, fset, pkg, info).Files(files)
+}
+
+// AssertableTo reports whether a value of type V can be asserted to have type T.
+func AssertableTo(V *Interface, T Type) bool {
+       m, _ := assertableTo(V, T)
+       return m == nil
+}
+
+// AssignableTo reports whether a value of type V is assignable to a variable of type T.
+func AssignableTo(V, T Type) bool {
+       x := operand{mode: value, typ: V}
+       return x.assignableTo(nil, T) // config not needed for non-constant x
+}
+
+// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
+func ConvertibleTo(V, T Type) bool {
+       x := operand{mode: value, typ: V}
+       return x.convertibleTo(nil, T) // config not needed for non-constant x
+}
+
+// Implements reports whether type V implements interface T.
+func Implements(V Type, T *Interface) bool {
+       f, _ := MissingMethod(V, T, true)
+       return f == nil
+}
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
new file mode 100644 (file)
index 0000000..9808768
--- /dev/null
@@ -0,0 +1,936 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "strings"
+       "testing"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+func pkgFor(path, source string, info *Info) (*Package, error) {
+       fset := token.NewFileSet()
+       f, err := parser.ParseFile(fset, path, source, 0)
+       if err != nil {
+               return nil, err
+       }
+
+       var conf Config
+       return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
+}
+
+func mustTypecheck(t *testing.T, path, source string, info *Info) string {
+       pkg, err := pkgFor(path, source, info)
+       if err != nil {
+               name := path
+               if pkg != nil {
+                       name = "package " + pkg.Name()
+               }
+               t.Fatalf("%s: didn't type-check (%s)", name, err)
+       }
+       return pkg.Name()
+}
+
+func TestValuesInfo(t *testing.T) {
+       var tests = []struct {
+               src  string
+               expr string // constant expression
+               typ  string // constant type
+               val  string // constant value
+       }{
+               {`package a0; const _ = false`, `false`, `untyped bool`, `false`},
+               {`package a1; const _ = 0`, `0`, `untyped int`, `0`},
+               {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
+               {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
+               {`package a4; const _ = 0i`, `0i`, `untyped complex`, `0`},
+               {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
+
+               {`package b0; var _ = false`, `false`, `bool`, `false`},
+               {`package b1; var _ = 0`, `0`, `int`, `0`},
+               {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
+               {`package b3; var _ = 0.`, `0.`, `float64`, `0`},
+               {`package b4; var _ = 0i`, `0i`, `complex128`, `0`},
+               {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
+
+               {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
+               {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`},
+               {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`},
+
+               {`package c1a; var _ = int(0)`, `0`, `int`, `0`},
+               {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`},
+               {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`},
+
+               {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`},
+               {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`},
+               {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`},
+
+               {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`},
+               {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
+               {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
+
+               {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `0`},
+               {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `0`},
+               {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `0`},
+
+               {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
+               {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
+               {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`},
+
+               {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
+               {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
+               {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
+               {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
+
+               {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
+               {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
+               {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
+               {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
+               {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`},
+               {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`},
+               {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`},
+               {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`},
+
+               {`package f0 ; var _ float32 =  1e-200`, `1e-200`, `float32`, `0`},
+               {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
+               {`package f2a; var _ float64 =  1e-2000`, `1e-2000`, `float64`, `0`},
+               {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
+               {`package f2b; var _         =  1e-2000`, `1e-2000`, `float64`, `0`},
+               {`package f3b; var _         = -1e-2000`, `-1e-2000`, `float64`, `0`},
+               {`package f4 ; var _ complex64  =  1e-200 `, `1e-200`, `complex64`, `0`},
+               {`package f5 ; var _ complex64  = -1e-200 `, `-1e-200`, `complex64`, `0`},
+               {`package f6a; var _ complex128 =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
+               {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+               {`package f6b; var _            =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
+               {`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+       }
+
+       for _, test := range tests {
+               info := Info{
+                       Types: make(map[ast.Expr]TypeAndValue),
+               }
+               name := mustTypecheck(t, "ValuesInfo", test.src, &info)
+
+               // look for constant expression
+               var expr ast.Expr
+               for e := range info.Types {
+                       if ExprString(e) == test.expr {
+                               expr = e
+                               break
+                       }
+               }
+               if expr == nil {
+                       t.Errorf("package %s: no expression found for %s", name, test.expr)
+                       continue
+               }
+               tv := info.Types[expr]
+
+               // check that type is correct
+               if got := tv.Type.String(); got != test.typ {
+                       t.Errorf("package %s: got type %s; want %s", name, got, test.typ)
+                       continue
+               }
+
+               // check that value is correct
+               if got := tv.Value.String(); got != test.val {
+                       t.Errorf("package %s: got value %s; want %s", name, got, test.val)
+               }
+       }
+}
+
+func TestTypesInfo(t *testing.T) {
+       var tests = []struct {
+               src  string
+               expr string // expression
+               typ  string // value type
+       }{
+               // single-valued expressions of untyped constants
+               {`package b0; var x interface{} = false`, `false`, `bool`},
+               {`package b1; var x interface{} = 0`, `0`, `int`},
+               {`package b2; var x interface{} = 0.`, `0.`, `float64`},
+               {`package b3; var x interface{} = 0i`, `0i`, `complex128`},
+               {`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
+
+               // comma-ok expressions
+               {`package p0; var x interface{}; var _, _ = x.(int)`,
+                       `x.(int)`,
+                       `(int, bool)`,
+               },
+               {`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
+                       `x.(int)`,
+                       `(int, bool)`,
+               },
+               // TODO(gri): uncomment if we accept issue 8189.
+               // {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
+               //      `m["foo"]`,
+               //      `(complex128, p2.mybool)`,
+               // },
+               // TODO(gri): remove if we accept issue 8189.
+               {`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
+                       `m["foo"]`,
+                       `(complex128, bool)`,
+               },
+               {`package p3; var c chan string; var _, _ = <-c`,
+                       `<-c`,
+                       `(string, bool)`,
+               },
+
+               // issue 6796
+               {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
+                       `x.(int)`,
+                       `(int, bool)`,
+               },
+               {`package issue6796_b; var c chan string; var _, _ = (<-c)`,
+                       `(<-c)`,
+                       `(string, bool)`,
+               },
+               {`package issue6796_c; var c chan string; var _, _ = (<-c)`,
+                       `<-c`,
+                       `(string, bool)`,
+               },
+               {`package issue6796_d; var c chan string; var _, _ = ((<-c))`,
+                       `(<-c)`,
+                       `(string, bool)`,
+               },
+               {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`,
+                       `(<-c)`,
+                       `(string, bool)`,
+               },
+
+               // issue 7060
+               {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
+                       `m[0]`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`,
+                       `m[0]`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`,
+                       `m[0]`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`,
+                       `<-ch`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`,
+                       `<-ch`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`,
+                       `<-ch`,
+                       `(string, bool)`,
+               },
+       }
+
+       for _, test := range tests {
+               info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+               name := mustTypecheck(t, "TypesInfo", test.src, &info)
+
+               // look for expression type
+               var typ Type
+               for e, tv := range info.Types {
+                       if ExprString(e) == test.expr {
+                               typ = tv.Type
+                               break
+                       }
+               }
+               if typ == nil {
+                       t.Errorf("package %s: no type found for %s", name, test.expr)
+                       continue
+               }
+
+               // check that type is correct
+               if got := typ.String(); got != test.typ {
+                       t.Errorf("package %s: got %s; want %s", name, got, test.typ)
+               }
+       }
+}
+
+func predString(tv TypeAndValue) string {
+       var buf bytes.Buffer
+       pred := func(b bool, s string) {
+               if b {
+                       if buf.Len() > 0 {
+                               buf.WriteString(", ")
+                       }
+                       buf.WriteString(s)
+               }
+       }
+
+       pred(tv.IsVoid(), "void")
+       pred(tv.IsType(), "type")
+       pred(tv.IsBuiltin(), "builtin")
+       pred(tv.IsValue() && tv.Value != nil, "const")
+       pred(tv.IsValue() && tv.Value == nil, "value")
+       pred(tv.IsNil(), "nil")
+       pred(tv.Addressable(), "addressable")
+       pred(tv.Assignable(), "assignable")
+       pred(tv.HasOk(), "hasOk")
+
+       if buf.Len() == 0 {
+               return "invalid"
+       }
+       return buf.String()
+}
+
+func TestPredicatesInfo(t *testing.T) {
+       var tests = []struct {
+               src  string
+               expr string
+               pred string
+       }{
+               // void
+               {`package n0; func f() { f() }`, `f()`, `void`},
+
+               // types
+               {`package t0; type _ int`, `int`, `type`},
+               {`package t1; type _ []int`, `[]int`, `type`},
+               {`package t2; type _ func()`, `func()`, `type`},
+
+               // built-ins
+               {`package b0; var _ = len("")`, `len`, `builtin`},
+               {`package b1; var _ = (len)("")`, `(len)`, `builtin`},
+
+               // constants
+               {`package c0; var _ = 42`, `42`, `const`},
+               {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`},
+               {`package c2; const (i = 1i; _ = i)`, `i`, `const`},
+
+               // values
+               {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
+               {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`},
+               {`package v2; var _ = func(){}`, `(func() literal)`, `value`},
+               {`package v4; func f() { _ = f }`, `f`, `value`},
+               {`package v3; var _ *int = nil`, `nil`, `value, nil`},
+               {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`},
+
+               // addressable (and thus assignable) operands
+               {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`},
+               {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`},
+               {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`},
+               {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`},
+               {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`},
+               {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`},
+               {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`},
+               {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`},
+               // composite literals are not addressable
+
+               // assignable but not addressable values
+               {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+               {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+
+               // hasOk expressions
+               {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`},
+               {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`},
+
+               // missing entries
+               // - package names are collected in the Uses map
+               // - identifiers being declared are collected in the Defs map
+               {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`},
+               {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`},
+               {`package m2; const c = 0`, `c`, `<missing>`},
+               {`package m3; type T int`, `T`, `<missing>`},
+               {`package m4; var v int`, `v`, `<missing>`},
+               {`package m5; func f() {}`, `f`, `<missing>`},
+               {`package m6; func _(x int) {}`, `x`, `<missing>`},
+               {`package m6; func _()(x int) { return }`, `x`, `<missing>`},
+               {`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`},
+       }
+
+       for _, test := range tests {
+               info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+               name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
+
+               // look for expression predicates
+               got := "<missing>"
+               for e, tv := range info.Types {
+                       //println(name, ExprString(e))
+                       if ExprString(e) == test.expr {
+                               got = predString(tv)
+                               break
+                       }
+               }
+
+               if got != test.pred {
+                       t.Errorf("package %s: got %s; want %s", name, got, test.pred)
+               }
+       }
+}
+
+func TestScopesInfo(t *testing.T) {
+       var tests = []struct {
+               src    string
+               scopes []string // list of scope descriptors of the form kind:varlist
+       }{
+               {`package p0`, []string{
+                       "file:",
+               }},
+               {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
+                       "file:fmt m",
+               }},
+               {`package p2; func _() {}`, []string{
+                       "file:", "func:",
+               }},
+               {`package p3; func _(x, y int) {}`, []string{
+                       "file:", "func:x y",
+               }},
+               {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
+                       "file:", "func:x y z", // redeclaration of x
+               }},
+               {`package p5; func _(x, y int) (u, _ int) { return }`, []string{
+                       "file:", "func:u x y",
+               }},
+               {`package p6; func _() { { var x int; _ = x } }`, []string{
+                       "file:", "func:", "block:x",
+               }},
+               {`package p7; func _() { if true {} }`, []string{
+                       "file:", "func:", "if:", "block:",
+               }},
+               {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
+                       "file:", "func:", "if:x", "block:y",
+               }},
+               {`package p9; func _() { switch x := 0; x {} }`, []string{
+                       "file:", "func:", "switch:x",
+               }},
+               {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
+                       "file:", "func:", "switch:x", "case:y", "case:",
+               }},
+               {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
+                       "file:", "func:t", "type switch:",
+               }},
+               {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
+                       "file:", "func:t", "type switch:t",
+               }},
+               {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
+                       "file:", "func:t", "type switch:", "case:x", // x implicitly declared
+               }},
+               {`package p14; func _() { select{} }`, []string{
+                       "file:", "func:",
+               }},
+               {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
+                       "file:", "func:c", "comm:",
+               }},
+               {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
+                       "file:", "func:c", "comm:i x",
+               }},
+               {`package p17; func _() { for{} }`, []string{
+                       "file:", "func:", "for:", "block:",
+               }},
+               {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
+                       "file:", "func:n", "for:i", "block:",
+               }},
+               {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
+                       "file:", "func:a", "range:i", "block:",
+               }},
+               {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
+                       "file:", "func:a", "range:i x", "block:",
+               }},
+       }
+
+       for _, test := range tests {
+               info := Info{Scopes: make(map[ast.Node]*Scope)}
+               name := mustTypecheck(t, "ScopesInfo", test.src, &info)
+
+               // number of scopes must match
+               if len(info.Scopes) != len(test.scopes) {
+                       t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
+               }
+
+               // scope descriptions must match
+               for node, scope := range info.Scopes {
+                       kind := "<unknown node kind>"
+                       switch node.(type) {
+                       case *ast.File:
+                               kind = "file"
+                       case *ast.FuncType:
+                               kind = "func"
+                       case *ast.BlockStmt:
+                               kind = "block"
+                       case *ast.IfStmt:
+                               kind = "if"
+                       case *ast.SwitchStmt:
+                               kind = "switch"
+                       case *ast.TypeSwitchStmt:
+                               kind = "type switch"
+                       case *ast.CaseClause:
+                               kind = "case"
+                       case *ast.CommClause:
+                               kind = "comm"
+                       case *ast.ForStmt:
+                               kind = "for"
+                       case *ast.RangeStmt:
+                               kind = "range"
+                       }
+
+                       // look for matching scope description
+                       desc := kind + ":" + strings.Join(scope.Names(), " ")
+                       found := false
+                       for _, d := range test.scopes {
+                               if desc == d {
+                                       found = true
+                                       break
+                               }
+                       }
+                       if !found {
+                               t.Errorf("package %s: no matching scope found for %s", name, desc)
+                       }
+               }
+       }
+}
+
+func TestInitOrderInfo(t *testing.T) {
+       var tests = []struct {
+               src   string
+               inits []string
+       }{
+               {`package p0; var (x = 1; y = x)`, []string{
+                       "x = 1", "y = x",
+               }},
+               {`package p1; var (a = 1; b = 2; c = 3)`, []string{
+                       "a = 1", "b = 2", "c = 3",
+               }},
+               {`package p2; var (a, b, c = 1, 2, 3)`, []string{
+                       "a = 1", "b = 2", "c = 3",
+               }},
+               {`package p3; var _ = f(); func f() int { return 1 }`, []string{
+                       "_ = f()", // blank var
+               }},
+               {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
+                       "a = 0", "z = 0", "y = z", "x = y",
+               }},
+               {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
+                       "a, _ = m[0]", // blank var
+               }},
+               {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
+                       "z = 0", "a, b = f()",
+               }},
+               {`package p7; var (a = func() int { return b }(); b = 1)`, []string{
+                       "b = 1", "a = (func() int literal)()",
+               }},
+               {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
+                       "c = 1", "a, b = (func() (_, _ int) literal)()",
+               }},
+               {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
+                       "y = 1", "x = T.m",
+               }},
+               {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{
+                       "a = 0", "b = 0", "c = 0", "d = c + b",
+               }},
+               {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{
+                       "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c",
+               }},
+               // emit an initializer for n:1 initializations only once (not for each node
+               // on the lhs which may appear in different order in the dependency graph)
+               {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{
+                       "b = 0", "x, y = m[0]", "a = x",
+               }},
+               // test case from spec section on package initialization
+               {`package p12
+
+               var (
+                       a = c + b
+                       b = f()
+                       c = f()
+                       d = 3
+               )
+
+               func f() int {
+                       d++
+                       return d
+               }`, []string{
+                       "d = 3", "b = f()", "c = f()", "a = c + b",
+               }},
+               // test case for issue 7131
+               {`package main
+
+               var counter int
+               func next() int { counter++; return counter }
+
+               var _ = makeOrder()
+               func makeOrder() []int { return []int{f, b, d, e, c, a} }
+
+               var a       = next()
+               var b, c    = next(), next()
+               var d, e, f = next(), next(), next()
+               `, []string{
+                       "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
+               }},
+       }
+
+       for _, test := range tests {
+               info := Info{}
+               name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
+
+               // number of initializers must match
+               if len(info.InitOrder) != len(test.inits) {
+                       t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
+                       continue
+               }
+
+               // initializers must match
+               for i, want := range test.inits {
+                       got := info.InitOrder[i].String()
+                       if got != want {
+                               t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
+                               continue
+                       }
+               }
+       }
+}
+
+func TestMultiFileInitOrder(t *testing.T) {
+       fset := token.NewFileSet()
+       mustParse := func(src string) *ast.File {
+               f, err := parser.ParseFile(fset, "main", src, 0)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               return f
+       }
+
+       fileA := mustParse(`package main; var a = 1`)
+       fileB := mustParse(`package main; var b = 2`)
+
+       // The initialization order must not depend on the parse
+       // order of the files, only on the presentation order to
+       // the type-checker.
+       for _, test := range []struct {
+               files []*ast.File
+               want  string
+       }{
+               {[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"},
+               {[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"},
+       } {
+               var info Info
+               if _, err := new(Config).Check("main", fset, test.files, &info); err != nil {
+                       t.Fatal(err)
+               }
+               if got := fmt.Sprint(info.InitOrder); got != test.want {
+                       t.Fatalf("got %s; want %s", got, test.want)
+               }
+       }
+}
+
+func TestFiles(t *testing.T) {
+       var sources = []string{
+               "package p; type T struct{}; func (T) m1() {}",
+               "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}",
+               "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}",
+               "package p",
+       }
+
+       var conf Config
+       fset := token.NewFileSet()
+       pkg := NewPackage("p", "p")
+       var info Info
+       check := NewChecker(&conf, fset, pkg, &info)
+
+       for i, src := range sources {
+               filename := fmt.Sprintf("sources%d", i)
+               f, err := parser.ParseFile(fset, filename, src, 0)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if err := check.Files([]*ast.File{f}); err != nil {
+                       t.Error(err)
+               }
+       }
+
+       // check InitOrder is [x y]
+       var vars []string
+       for _, init := range info.InitOrder {
+               for _, v := range init.Lhs {
+                       vars = append(vars, v.Name())
+               }
+       }
+       if got, want := fmt.Sprint(vars), "[x y]"; got != want {
+               t.Errorf("InitOrder == %s, want %s", got, want)
+       }
+}
+
+func TestSelection(t *testing.T) {
+       selections := make(map[*ast.SelectorExpr]*Selection)
+
+       fset := token.NewFileSet()
+       conf := Config{
+               Packages: make(map[string]*Package),
+               Import: func(imports map[string]*Package, path string) (*Package, error) {
+                       return imports[path], nil
+               },
+       }
+       makePkg := func(path, src string) {
+               f, err := parser.ParseFile(fset, path+".go", src, 0)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections})
+               if err != nil {
+                       t.Fatal(err)
+               }
+               conf.Packages[path] = pkg
+       }
+
+       const libSrc = `
+package lib
+type T float64
+const C T = 3
+var V T
+func F() {}
+func (T) M() {}
+`
+       const mainSrc = `
+package main
+import "lib"
+
+type A struct {
+       *B
+       C
+}
+
+type B struct {
+       b int
+}
+
+func (B) f(int)
+
+type C struct {
+       c int
+}
+
+func (C) g()
+func (*C) h()
+
+func main() {
+       // qualified identifiers
+       var _ lib.T
+        _ = lib.C
+        _ = lib.F
+        _ = lib.V
+       _ = lib.T.M
+
+       // fields
+       _ = A{}.B
+       _ = new(A).B
+
+       _ = A{}.C
+       _ = new(A).C
+
+       _ = A{}.b
+       _ = new(A).b
+
+       _ = A{}.c
+       _ = new(A).c
+
+       // methods
+        _ = A{}.f
+        _ = new(A).f
+        _ = A{}.g
+        _ = new(A).g
+        _ = new(A).h
+
+        _ = B{}.f
+        _ = new(B).f
+
+        _ = C{}.g
+        _ = new(C).g
+        _ = new(C).h
+
+       // method expressions
+        _ = A.f
+        _ = (*A).f
+        _ = B.f
+        _ = (*B).f
+}`
+
+       wantOut := map[string][2]string{
+               "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"},
+
+               "A{}.B":    {"field (main.A) B *main.B", ".[0]"},
+               "new(A).B": {"field (*main.A) B *main.B", "->[0]"},
+               "A{}.C":    {"field (main.A) C main.C", ".[1]"},
+               "new(A).C": {"field (*main.A) C main.C", "->[1]"},
+               "A{}.b":    {"field (main.A) b int", "->[0 0]"},
+               "new(A).b": {"field (*main.A) b int", "->[0 0]"},
+               "A{}.c":    {"field (main.A) c int", ".[1 0]"},
+               "new(A).c": {"field (*main.A) c int", "->[1 0]"},
+
+               "A{}.f":    {"method (main.A) f(int)", "->[0 0]"},
+               "new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
+               "A{}.g":    {"method (main.A) g()", ".[1 0]"},
+               "new(A).g": {"method (*main.A) g()", "->[1 0]"},
+               "new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ?
+               "B{}.f":    {"method (main.B) f(int)", ".[0]"},
+               "new(B).f": {"method (*main.B) f(int)", "->[0]"},
+               "C{}.g":    {"method (main.C) g()", ".[0]"},
+               "new(C).g": {"method (*main.C) g()", "->[0]"},
+               "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ?
+
+               "A.f":    {"method expr (main.A) f(main.A, int)", "->[0 0]"},
+               "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
+               "B.f":    {"method expr (main.B) f(main.B, int)", ".[0]"},
+               "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
+       }
+
+       makePkg("lib", libSrc)
+       makePkg("main", mainSrc)
+
+       for e, sel := range selections {
+               sel.String() // assertion: must not panic
+
+               start := fset.Position(e.Pos()).Offset
+               end := fset.Position(e.End()).Offset
+               syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
+
+               direct := "."
+               if sel.Indirect() {
+                       direct = "->"
+               }
+               got := [2]string{
+                       sel.String(),
+                       fmt.Sprintf("%s%v", direct, sel.Index()),
+               }
+               want := wantOut[syntax]
+               if want != got {
+                       t.Errorf("%s: got %q; want %q", syntax, got, want)
+               }
+               delete(wantOut, syntax)
+
+               // We must explicitly assert properties of the
+               // Signature's receiver since it doesn't participate
+               // in Identical() or String().
+               sig, _ := sel.Type().(*Signature)
+               if sel.Kind() == MethodVal {
+                       got := sig.Recv().Type()
+                       want := sel.Recv()
+                       if !Identical(got, want) {
+                               t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
+                       }
+               } else if sig != nil && sig.Recv() != nil {
+                       t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
+               }
+       }
+       // Assert that all wantOut entries were used exactly once.
+       for syntax := range wantOut {
+               t.Errorf("no ast.Selection found with syntax %q", syntax)
+       }
+}
+
+func TestIssue8518(t *testing.T) {
+       fset := token.NewFileSet()
+       conf := Config{
+               Packages: make(map[string]*Package),
+               Error:    func(err error) { t.Log(err) }, // don't exit after first error
+               Import: func(imports map[string]*Package, path string) (*Package, error) {
+                       return imports[path], nil
+               },
+       }
+       makePkg := func(path, src string) {
+               f, err := parser.ParseFile(fset, path, src, 0)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error
+               conf.Packages[path] = pkg
+       }
+
+       const libSrc = `
+package a 
+import "missing"
+const C1 = foo
+const C2 = missing.C
+`
+
+       const mainSrc = `
+package main
+import "a"
+var _ = a.C1
+var _ = a.C2
+`
+
+       makePkg("a", libSrc)
+       makePkg("main", mainSrc) // don't crash when type-checking this package
+}
+
+func TestLookupFieldOrMethod(t *testing.T) {
+       // Test cases assume a lookup of the form a.f or x.f, where a stands for an
+       // addressable value, and x for a non-addressable value (even though a variable
+       // for ease of test case writing).
+       var tests = []struct {
+               src      string
+               found    bool
+               index    []int
+               indirect bool
+       }{
+               // field lookups
+               {"var x T; type T struct{}", false, nil, false},
+               {"var x T; type T struct{ f int }", true, []int{0}, false},
+               {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
+
+               // method lookups
+               {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
+               {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
+               {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
+               {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
+
+               // collisions
+               {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
+               {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
+
+               // outside methodset
+               // (*T).f method exists, but value of type T is not addressable
+               {"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
+       }
+
+       for _, test := range tests {
+               pkg, err := pkgFor("test", "package p;"+test.src, nil)
+               if err != nil {
+                       t.Errorf("%s: incorrect test case: %s", test.src, err)
+                       continue
+               }
+
+               obj := pkg.Scope().Lookup("a")
+               if obj == nil {
+                       if obj = pkg.Scope().Lookup("x"); obj == nil {
+                               t.Errorf("%s: incorrect test case - no object a or x", test.src)
+                               continue
+                       }
+               }
+
+               f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f")
+               if (f != nil) != test.found {
+                       if f == nil {
+                               t.Errorf("%s: got no object; want one", test.src)
+                       } else {
+                               t.Errorf("%s: got object = %v; want none", test.src, f)
+                       }
+               }
+               if !sameSlice(index, test.index) {
+                       t.Errorf("%s: got index = %v; want %v", test.src, index, test.index)
+               }
+               if indirect != test.indirect {
+                       t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect)
+               }
+       }
+}
+
+func sameSlice(a, b []int) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i, x := range a {
+               if x != b[i] {
+                       return false
+               }
+       }
+       return true
+}
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
new file mode 100644 (file)
index 0000000..14ee286
--- /dev/null
@@ -0,0 +1,323 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements initialization and assignment checks.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+)
+
+// assignment reports whether x can be assigned to a variable of type T,
+// if necessary by attempting to convert untyped values to the appropriate
+// type. If x.mode == invalid upon return, then assignment has already
+// issued an error message and the caller doesn't have to report another.
+// Use T == nil to indicate assignment to an untyped blank identifier.
+//
+// TODO(gri) Should find a better way to handle in-band errors.
+//
+func (check *Checker) assignment(x *operand, T Type) bool {
+       switch x.mode {
+       case invalid:
+               return true // error reported before
+       case constant, variable, mapindex, value, commaok:
+               // ok
+       default:
+               unreachable()
+       }
+
+       // x must be a single value
+       // (tuple types are never named - no need for underlying type)
+       if t, _ := x.typ.(*Tuple); t != nil {
+               assert(t.Len() > 1)
+               check.errorf(x.pos(), "%d-valued expression %s used as single value", t.Len(), x)
+               x.mode = invalid
+               return false
+       }
+
+       if isUntyped(x.typ) {
+               target := T
+               // spec: "If an untyped constant is assigned to a variable of interface
+               // type or the blank identifier, the constant is first converted to type
+               // bool, rune, int, float64, complex128 or string respectively, depending
+               // on whether the value is a boolean, rune, integer, floating-point, complex,
+               // or string constant."
+               if T == nil || IsInterface(T) {
+                       if T == nil && x.typ == Typ[UntypedNil] {
+                               check.errorf(x.pos(), "use of untyped nil")
+                               x.mode = invalid
+                               return false
+                       }
+                       target = defaultType(x.typ)
+               }
+               check.convertUntyped(x, target)
+               if x.mode == invalid {
+                       return false
+               }
+       }
+
+       // spec: "If a left-hand side is the blank identifier, any typed or
+       // non-constant value except for the predeclared identifier nil may
+       // be assigned to it."
+       return T == nil || x.assignableTo(check.conf, T)
+}
+
+func (check *Checker) initConst(lhs *Const, x *operand) {
+       if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+               if lhs.typ == nil {
+                       lhs.typ = Typ[Invalid]
+               }
+               return
+       }
+
+       // rhs must be a constant
+       if x.mode != constant {
+               check.errorf(x.pos(), "%s is not constant", x)
+               if lhs.typ == nil {
+                       lhs.typ = Typ[Invalid]
+               }
+               return
+       }
+       assert(isConstType(x.typ))
+
+       // If the lhs doesn't have a type yet, use the type of x.
+       if lhs.typ == nil {
+               lhs.typ = x.typ
+       }
+
+       if !check.assignment(x, lhs.typ) {
+               if x.mode != invalid {
+                       check.errorf(x.pos(), "cannot define constant %s (type %s) as %s", lhs.Name(), lhs.typ, x)
+               }
+               return
+       }
+
+       lhs.val = x.val
+}
+
+// If result is set, lhs is a function result parameter and x is a return result.
+func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type {
+       if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+               if lhs.typ == nil {
+                       lhs.typ = Typ[Invalid]
+               }
+               return nil
+       }
+
+       // If the lhs doesn't have a type yet, use the type of x.
+       if lhs.typ == nil {
+               typ := x.typ
+               if isUntyped(typ) {
+                       // convert untyped types to default types
+                       if typ == Typ[UntypedNil] {
+                               check.errorf(x.pos(), "use of untyped nil")
+                               lhs.typ = Typ[Invalid]
+                               return nil
+                       }
+                       typ = defaultType(typ)
+               }
+               lhs.typ = typ
+       }
+
+       if !check.assignment(x, lhs.typ) {
+               if x.mode != invalid {
+                       if result {
+                               // don't refer to lhs.name because it may be an anonymous result parameter
+                               check.errorf(x.pos(), "cannot return %s as value of type %s", x, lhs.typ)
+                       } else {
+                               check.errorf(x.pos(), "cannot initialize %s with %s", lhs, x)
+                       }
+               }
+               return nil
+       }
+
+       return x.typ
+}
+
+func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
+       if x.mode == invalid || x.typ == Typ[Invalid] {
+               return nil
+       }
+
+       // Determine if the lhs is a (possibly parenthesized) identifier.
+       ident, _ := unparen(lhs).(*ast.Ident)
+
+       // Don't evaluate lhs if it is the blank identifier.
+       if ident != nil && ident.Name == "_" {
+               check.recordDef(ident, nil)
+               if !check.assignment(x, nil) {
+                       assert(x.mode == invalid)
+                       x.typ = nil
+               }
+               return x.typ
+       }
+
+       // If the lhs is an identifier denoting a variable v, this assignment
+       // is not a 'use' of v. Remember current value of v.used and restore
+       // after evaluating the lhs via check.expr.
+       var v *Var
+       var v_used bool
+       if ident != nil {
+               if _, obj := check.scope.LookupParent(ident.Name); obj != nil {
+                       v, _ = obj.(*Var)
+                       if v != nil {
+                               v_used = v.used
+                       }
+               }
+       }
+
+       var z operand
+       check.expr(&z, lhs)
+       if v != nil {
+               v.used = v_used // restore v.used
+       }
+
+       if z.mode == invalid || z.typ == Typ[Invalid] {
+               return nil
+       }
+
+       // spec: "Each left-hand side operand must be addressable, a map index
+       // expression, or the blank identifier. Operands may be parenthesized."
+       switch z.mode {
+       case invalid:
+               return nil
+       case variable, mapindex:
+               // ok
+       default:
+               check.errorf(z.pos(), "cannot assign to %s", &z)
+               return nil
+       }
+
+       if !check.assignment(x, z.typ) {
+               if x.mode != invalid {
+                       check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
+               }
+               return nil
+       }
+
+       return x.typ
+}
+
+// If returnPos is valid, initVars is called to type-check the assignment of
+// return expressions, and returnPos is the position of the return statement.
+func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
+       l := len(lhs)
+       get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
+       if get == nil || l != r {
+               // invalidate lhs and use rhs
+               for _, obj := range lhs {
+                       if obj.typ == nil {
+                               obj.typ = Typ[Invalid]
+                       }
+               }
+               if get == nil {
+                       return // error reported by unpack
+               }
+               check.useGetter(get, r)
+               if returnPos.IsValid() {
+                       check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
+                       return
+               }
+               check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+               return
+       }
+
+       var x operand
+       if commaOk {
+               var a [2]Type
+               for i := range a {
+                       get(&x, i)
+                       a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
+               }
+               check.recordCommaOkTypes(rhs[0], a)
+               return
+       }
+
+       for i, lhs := range lhs {
+               get(&x, i)
+               check.initVar(lhs, &x, returnPos.IsValid())
+       }
+}
+
+func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
+       l := len(lhs)
+       get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2)
+       if get == nil {
+               return // error reported by unpack
+       }
+       if l != r {
+               check.useGetter(get, r)
+               check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+               return
+       }
+
+       var x operand
+       if commaOk {
+               var a [2]Type
+               for i := range a {
+                       get(&x, i)
+                       a[i] = check.assignVar(lhs[i], &x)
+               }
+               check.recordCommaOkTypes(rhs[0], a)
+               return
+       }
+
+       for i, lhs := range lhs {
+               get(&x, i)
+               check.assignVar(lhs, &x)
+       }
+}
+
+func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
+       scope := check.scope
+
+       // collect lhs variables
+       var newVars []*Var
+       var lhsVars = make([]*Var, len(lhs))
+       for i, lhs := range lhs {
+               var obj *Var
+               if ident, _ := lhs.(*ast.Ident); ident != nil {
+                       // Use the correct obj if the ident is redeclared. The
+                       // variable's scope starts after the declaration; so we
+                       // must use Scope.Lookup here and call Scope.Insert
+                       // (via check.declare) later.
+                       name := ident.Name
+                       if alt := scope.Lookup(name); alt != nil {
+                               // redeclared object must be a variable
+                               if alt, _ := alt.(*Var); alt != nil {
+                                       obj = alt
+                               } else {
+                                       check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
+                               }
+                               check.recordUse(ident, alt)
+                       } else {
+                               // declare new variable, possibly a blank (_) variable
+                               obj = NewVar(ident.Pos(), check.pkg, name, nil)
+                               if name != "_" {
+                                       newVars = append(newVars, obj)
+                               }
+                               check.recordDef(ident, obj)
+                       }
+               } else {
+                       check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+               }
+               if obj == nil {
+                       obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+               }
+               lhsVars[i] = obj
+       }
+
+       check.initVars(lhsVars, rhs, token.NoPos)
+
+       // declare new variables
+       if len(newVars) > 0 {
+               for _, obj := range newVars {
+                       check.declare(scope, nil, obj) // recordObject already called
+               }
+       } else {
+               check.softErrorf(pos, "no new variables on left side of :=")
+       }
+}
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
new file mode 100644 (file)
index 0000000..ac8647e
--- /dev/null
@@ -0,0 +1,628 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements typechecking of builtin function calls.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+
+       "go/exact"
+)
+
+// builtin type-checks a call to the built-in specified by id and
+// returns true if the call is valid, with *x holding the result;
+// but x.expr is not set. If the call is invalid, the result is
+// false, and *x is undefined.
+//
+func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) {
+       // append is the only built-in that permits the use of ... for the last argument
+       bin := predeclaredFuncs[id]
+       if call.Ellipsis.IsValid() && id != _Append {
+               check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name)
+               check.use(call.Args...)
+               return
+       }
+
+       // For len(x) and cap(x) we need to know if x contains any function calls or
+       // receive operations. Save/restore current setting and set hasCallOrRecv to
+       // false for the evaluation of x so that we can check it afterwards.
+       // Note: We must do this _before_ calling unpack because unpack evaluates the
+       //       first argument before we even call arg(x, 0)!
+       if id == _Len || id == _Cap {
+               defer func(b bool) {
+                       check.hasCallOrRecv = b
+               }(check.hasCallOrRecv)
+               check.hasCallOrRecv = false
+       }
+
+       // determine actual arguments
+       var arg getter
+       nargs := len(call.Args)
+       switch id {
+       default:
+               // make argument getter
+               arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
+               if arg == nil {
+                       return
+               }
+               // evaluate first argument, if present
+               if nargs > 0 {
+                       arg(x, 0)
+                       if x.mode == invalid {
+                               return
+                       }
+               }
+       case _Make, _New, _Offsetof, _Trace:
+               // arguments require special handling
+       }
+
+       // check argument count
+       {
+               msg := ""
+               if nargs < bin.nargs {
+                       msg = "not enough"
+               } else if !bin.variadic && nargs > bin.nargs {
+                       msg = "too many"
+               }
+               if msg != "" {
+                       check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
+                       return
+               }
+       }
+
+       switch id {
+       case _Append:
+               // append(s S, x ...T) S, where T is the element type of S
+               // spec: "The variadic function append appends zero or more values x to s of type
+               // S, which must be a slice type, and returns the resulting slice, also of type S.
+               // The values x are passed to a parameter of type ...T where T is the element type
+               // of S and the respective parameter passing rules apply."
+               S := x.typ
+               var T Type
+               if s, _ := S.Underlying().(*Slice); s != nil {
+                       T = s.elem
+               } else {
+                       check.invalidArg(x.pos(), "%s is not a slice", x)
+                       return
+               }
+
+               // remember arguments that have been evaluated already
+               alist := []operand{*x}
+
+               // spec: "As a special case, append also accepts a first argument assignable
+               // to type []byte with a second argument of string type followed by ... .
+               // This form appends the bytes of the string.
+               if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(UniverseByte)) {
+                       arg(x, 1)
+                       if x.mode == invalid {
+                               return
+                       }
+                       if isString(x.typ) {
+                               if check.Types != nil {
+                                       sig := makeSig(S, S, x.typ)
+                                       sig.variadic = true
+                                       check.recordBuiltinType(call.Fun, sig)
+                               }
+                               x.mode = value
+                               x.typ = S
+                               break
+                       }
+                       alist = append(alist, *x)
+                       // fallthrough
+               }
+
+               // check general case by creating custom signature
+               sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
+               sig.variadic = true
+               check.arguments(x, call, sig, func(x *operand, i int) {
+                       // only evaluate arguments that have not been evaluated before
+                       if i < len(alist) {
+                               *x = alist[i]
+                               return
+                       }
+                       arg(x, i)
+               }, nargs)
+               // ok to continue even if check.arguments reported errors
+
+               x.mode = value
+               x.typ = S
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, sig)
+               }
+
+       case _Cap, _Len:
+               // cap(x)
+               // len(x)
+               mode := invalid
+               var typ Type
+               var val exact.Value
+               switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) {
+               case *Basic:
+                       if isString(t) && id == _Len {
+                               if x.mode == constant {
+                                       mode = constant
+                                       val = exact.MakeInt64(int64(len(exact.StringVal(x.val))))
+                               } else {
+                                       mode = value
+                               }
+                       }
+
+               case *Array:
+                       mode = value
+                       // spec: "The expressions len(s) and cap(s) are constants
+                       // if the type of s is an array or pointer to an array and
+                       // the expression s does not contain channel receives or
+                       // function calls; in this case s is not evaluated."
+                       if !check.hasCallOrRecv {
+                               mode = constant
+                               val = exact.MakeInt64(t.len)
+                       }
+
+               case *Slice, *Chan:
+                       mode = value
+
+               case *Map:
+                       if id == _Len {
+                               mode = value
+                       }
+               }
+
+               if mode == invalid {
+                       check.invalidArg(x.pos(), "%s for %s", x, bin.name)
+                       return
+               }
+
+               x.mode = mode
+               x.typ = Typ[Int]
+               x.val = val
+               if check.Types != nil && mode != constant {
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
+               }
+
+       case _Close:
+               // close(c)
+               c, _ := x.typ.Underlying().(*Chan)
+               if c == nil {
+                       check.invalidArg(x.pos(), "%s is not a channel", x)
+                       return
+               }
+               if c.dir == RecvOnly {
+                       check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
+                       return
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, c))
+               }
+
+       case _Complex:
+               // complex(x, y realT) complexT
+               if !check.complexArg(x) {
+                       return
+               }
+
+               var y operand
+               arg(&y, 1)
+               if y.mode == invalid {
+                       return
+               }
+               if !check.complexArg(&y) {
+                       return
+               }
+
+               check.convertUntyped(x, y.typ)
+               if x.mode == invalid {
+                       return
+               }
+               check.convertUntyped(&y, x.typ)
+               if y.mode == invalid {
+                       return
+               }
+
+               if !Identical(x.typ, y.typ) {
+                       check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+                       return
+               }
+
+               if x.mode == constant && y.mode == constant {
+                       x.val = exact.BinaryOp(x.val, token.ADD, exact.MakeImag(y.val))
+               } else {
+                       x.mode = value
+               }
+
+               realT := x.typ
+               complexT := Typ[Invalid]
+               switch realT.Underlying().(*Basic).kind {
+               case Float32:
+                       complexT = Typ[Complex64]
+               case Float64:
+                       complexT = Typ[Complex128]
+               case UntypedInt, UntypedRune, UntypedFloat:
+                       if x.mode == constant {
+                               realT = defaultType(realT).(*Basic)
+                               complexT = Typ[UntypedComplex]
+                       } else {
+                               // untyped but not constant; probably because one
+                               // operand is a non-constant shift of untyped lhs
+                               realT = Typ[Float64]
+                               complexT = Typ[Complex128]
+                       }
+               default:
+                       check.invalidArg(x.pos(), "float32 or float64 arguments expected")
+                       return
+               }
+
+               x.typ = complexT
+               if check.Types != nil && x.mode != constant {
+                       check.recordBuiltinType(call.Fun, makeSig(complexT, realT, realT))
+               }
+
+               if x.mode != constant {
+                       // The arguments have now their final types, which at run-
+                       // time will be materialized. Update the expression trees.
+                       // If the current types are untyped, the materialized type
+                       // is the respective default type.
+                       // (If the result is constant, the arguments are never
+                       // materialized and there is nothing to do.)
+                       check.updateExprType(x.expr, realT, true)
+                       check.updateExprType(y.expr, realT, true)
+               }
+
+       case _Copy:
+               // copy(x, y []T) int
+               var dst Type
+               if t, _ := x.typ.Underlying().(*Slice); t != nil {
+                       dst = t.elem
+               }
+
+               var y operand
+               arg(&y, 1)
+               if y.mode == invalid {
+                       return
+               }
+               var src Type
+               switch t := y.typ.Underlying().(type) {
+               case *Basic:
+                       if isString(y.typ) {
+                               src = UniverseByte
+                       }
+               case *Slice:
+                       src = t.elem
+               }
+
+               if dst == nil || src == nil {
+                       check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
+                       return
+               }
+
+               if !Identical(dst, src) {
+                       check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+                       return
+               }
+
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ))
+               }
+               x.mode = value
+               x.typ = Typ[Int]
+
+       case _Delete:
+               // delete(m, k)
+               m, _ := x.typ.Underlying().(*Map)
+               if m == nil {
+                       check.invalidArg(x.pos(), "%s is not a map", x)
+                       return
+               }
+               arg(x, 1) // k
+               if x.mode == invalid {
+                       return
+               }
+
+               if !x.assignableTo(check.conf, m.key) {
+                       check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
+                       return
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key))
+               }
+
+       case _Imag, _Real:
+               // imag(complexT) realT
+               // real(complexT) realT
+               if !isComplex(x.typ) {
+                       check.invalidArg(x.pos(), "%s must be a complex number", x)
+                       return
+               }
+               if x.mode == constant {
+                       if id == _Real {
+                               x.val = exact.Real(x.val)
+                       } else {
+                               x.val = exact.Imag(x.val)
+                       }
+               } else {
+                       x.mode = value
+               }
+               var k BasicKind
+               switch x.typ.Underlying().(*Basic).kind {
+               case Complex64:
+                       k = Float32
+               case Complex128:
+                       k = Float64
+               case UntypedComplex:
+                       k = UntypedFloat
+               default:
+                       unreachable()
+               }
+
+               if check.Types != nil && x.mode != constant {
+                       check.recordBuiltinType(call.Fun, makeSig(Typ[k], x.typ))
+               }
+               x.typ = Typ[k]
+
+       case _Make:
+               // make(T, n)
+               // make(T, n, m)
+               // (no argument evaluated yet)
+               arg0 := call.Args[0]
+               T := check.typ(arg0)
+               if T == Typ[Invalid] {
+                       return
+               }
+
+               var min int // minimum number of arguments
+               switch T.Underlying().(type) {
+               case *Slice:
+                       min = 2
+               case *Map, *Chan:
+                       min = 1
+               default:
+                       check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
+                       return
+               }
+               if nargs < min || min+1 < nargs {
+                       check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs)
+                       return
+               }
+               var sizes []int64 // constant integer arguments, if any
+               for _, arg := range call.Args[1:] {
+                       if s, ok := check.index(arg, -1); ok && s >= 0 {
+                               sizes = append(sizes, s)
+                       }
+               }
+               if len(sizes) == 2 && sizes[0] > sizes[1] {
+                       check.invalidArg(call.Args[1].Pos(), "length and capacity swapped")
+                       // safe to continue
+               }
+               x.mode = value
+               x.typ = T
+               if check.Types != nil {
+                       params := [...]Type{T, Typ[Int], Typ[Int]}
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ, params[:1+len(sizes)]...))
+               }
+
+       case _New:
+               // new(T)
+               // (no argument evaluated yet)
+               T := check.typ(call.Args[0])
+               if T == Typ[Invalid] {
+                       return
+               }
+
+               x.mode = value
+               x.typ = &Pointer{base: T}
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
+               }
+
+       case _Panic:
+               // panic(x)
+               T := new(Interface)
+               if !check.assignment(x, T) {
+                       assert(x.mode == invalid)
+                       return
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, T))
+               }
+
+       case _Print, _Println:
+               // print(x, y, ...)
+               // println(x, y, ...)
+               var params []Type
+               if nargs > 0 {
+                       params = make([]Type, nargs)
+                       for i := 0; i < nargs; i++ {
+                               if i > 0 {
+                                       arg(x, i) // first argument already evaluated
+                               }
+                               if !check.assignment(x, nil) {
+                                       assert(x.mode == invalid)
+                                       return
+                               }
+                               params[i] = x.typ
+                       }
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, params...))
+               }
+
+       case _Recover:
+               // recover() interface{}
+               x.mode = value
+               x.typ = new(Interface)
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ))
+               }
+
+       case _Alignof:
+               // unsafe.Alignof(x T) uintptr
+               if !check.assignment(x, nil) {
+                       assert(x.mode == invalid)
+                       return
+               }
+
+               x.mode = constant
+               x.val = exact.MakeInt64(check.conf.alignof(x.typ))
+               x.typ = Typ[Uintptr]
+               // result is constant - no need to record signature
+
+       case _Offsetof:
+               // unsafe.Offsetof(x T) uintptr, where x must be a selector
+               // (no argument evaluated yet)
+               arg0 := call.Args[0]
+               selx, _ := unparen(arg0).(*ast.SelectorExpr)
+               if selx == nil {
+                       check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
+                       check.use(arg0)
+                       return
+               }
+
+               check.expr(x, selx.X)
+               if x.mode == invalid {
+                       return
+               }
+
+               base := derefStructPtr(x.typ)
+               sel := selx.Sel.Name
+               obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
+               switch obj.(type) {
+               case nil:
+                       check.invalidArg(x.pos(), "%s has no single field %s", base, sel)
+                       return
+               case *Func:
+                       // TODO(gri) Using derefStructPtr may result in methods being found
+                       // that don't actually exist. An error either way, but the error
+                       // message is confusing. See: http://play.golang.org/p/al75v23kUy ,
+                       // but go/types reports: "invalid argument: x.m is a method value".
+                       check.invalidArg(arg0.Pos(), "%s is a method value", arg0)
+                       return
+               }
+               if indirect {
+                       check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
+                       return
+               }
+
+               // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)?
+               check.recordSelection(selx, FieldVal, base, obj, index, false)
+
+               offs := check.conf.offsetof(base, index)
+               x.mode = constant
+               x.val = exact.MakeInt64(offs)
+               x.typ = Typ[Uintptr]
+               // result is constant - no need to record signature
+
+       case _Sizeof:
+               // unsafe.Sizeof(x T) uintptr
+               if !check.assignment(x, nil) {
+                       assert(x.mode == invalid)
+                       return
+               }
+
+               x.mode = constant
+               x.val = exact.MakeInt64(check.conf.sizeof(x.typ))
+               x.typ = Typ[Uintptr]
+               // result is constant - no need to record signature
+
+       case _Assert:
+               // assert(pred) causes a typechecker error if pred is false.
+               // The result of assert is the value of pred if there is no error.
+               // Note: assert is only available in self-test mode.
+               if x.mode != constant || !isBoolean(x.typ) {
+                       check.invalidArg(x.pos(), "%s is not a boolean constant", x)
+                       return
+               }
+               if x.val.Kind() != exact.Bool {
+                       check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
+                       return
+               }
+               if !exact.BoolVal(x.val) {
+                       check.errorf(call.Pos(), "%s failed", call)
+                       // compile-time assertion failure - safe to continue
+               }
+               // result is constant - no need to record signature
+
+       case _Trace:
+               // trace(x, y, z, ...) dumps the positions, expressions, and
+               // values of its arguments. The result of trace is the value
+               // of the first argument.
+               // Note: trace is only available in self-test mode.
+               // (no argument evaluated yet)
+               if nargs == 0 {
+                       check.dump("%s: trace() without arguments", call.Pos())
+                       x.mode = novalue
+                       break
+               }
+               var t operand
+               x1 := x
+               for _, arg := range call.Args {
+                       check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
+                       check.dump("%s: %s", x1.pos(), x1)
+                       x1 = &t // use incoming x only for first argument
+               }
+               // trace is only available in test mode - no need to record signature
+
+       default:
+               unreachable()
+       }
+
+       return true
+}
+
+// makeSig makes a signature for the given argument and result types.
+// Default types are used for untyped arguments, and res may be nil.
+func makeSig(res Type, args ...Type) *Signature {
+       list := make([]*Var, len(args))
+       for i, param := range args {
+               list[i] = NewVar(token.NoPos, nil, "", defaultType(param))
+       }
+       params := NewTuple(list...)
+       var result *Tuple
+       if res != nil {
+               assert(!isUntyped(res))
+               result = NewTuple(NewVar(token.NoPos, nil, "", res))
+       }
+       return &Signature{params: params, results: result}
+}
+
+// implicitArrayDeref returns A if typ is of the form *A and A is an array;
+// otherwise it returns typ.
+//
+func implicitArrayDeref(typ Type) Type {
+       if p, ok := typ.(*Pointer); ok {
+               if a, ok := p.base.Underlying().(*Array); ok {
+                       return a
+               }
+       }
+       return typ
+}
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e ast.Expr) ast.Expr {
+       for {
+               p, ok := e.(*ast.ParenExpr)
+               if !ok {
+                       return e
+               }
+               e = p.X
+       }
+}
+
+func (check *Checker) complexArg(x *operand) bool {
+       t, _ := x.typ.Underlying().(*Basic)
+       if t != nil && (t.info&IsFloat != 0 || t.kind == UntypedInt || t.kind == UntypedRune) {
+               return true
+       }
+       check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
+       return false
+}
diff --git a/src/go/types/builtins_test.go b/src/go/types/builtins_test.go
new file mode 100644 (file)
index 0000000..fa18277
--- /dev/null
@@ -0,0 +1,204 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "testing"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+var builtinCalls = []struct {
+       name, src, sig string
+}{
+       {"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
+       {"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
+       {"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
+       {"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
+       {"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
+       {"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
+       {"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
+
+       {"cap", `var s [10]int; _ = cap(s)`, `invalid type`},  // constant
+       {"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
+       {"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
+       {"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
+
+       {"len", `_ = len("foo")`, `invalid type`}, // constant
+       {"len", `var s string; _ = len(s)`, `func(string) int`},
+       {"len", `var s [10]int; _ = len(s)`, `invalid type`},  // constant
+       {"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant
+       {"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
+       {"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
+       {"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
+
+       {"close", `var c chan int; close(c)`, `func(chan int)`},
+       {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
+
+       {"complex", `_ = complex(1, 0)`, `invalid type`}, // constant
+       {"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
+       {"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
+       {"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
+       {"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
+
+       {"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
+       {"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
+       {"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
+       {"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
+       {"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
+
+       {"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
+       {"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
+
+       {"imag", `_ = imag(1i)`, `invalid type`}, // constant
+       {"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
+       {"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
+       {"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
+       {"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
+
+       {"real", `_ = real(1i)`, `invalid type`}, // constant
+       {"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
+       {"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
+       {"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
+       {"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
+
+       {"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
+       {"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
+
+       {"new", `_ = new(int)`, `func(int) *int`},
+       {"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
+
+       {"panic", `panic(0)`, `func(interface{})`},
+       {"panic", `panic("foo")`, `func(interface{})`},
+
+       {"print", `print()`, `func()`},
+       {"print", `print(0)`, `func(int)`},
+       {"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+       {"println", `println()`, `func()`},
+       {"println", `println(0)`, `func(int)`},
+       {"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+       {"recover", `recover()`, `func() interface{}`},
+       {"recover", `_ = recover()`, `func() interface{}`},
+
+       {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},                 // constant
+       {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
+
+       {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},           // constant
+       {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
+
+       {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},                 // constant
+       {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
+
+       {"assert", `assert(true)`, `invalid type`},                                    // constant
+       {"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
+
+       // no tests for trace since it produces output as a side-effect
+}
+
+func TestBuiltinSignatures(t *testing.T) {
+       DefPredeclaredTestFuncs()
+
+       seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually
+       for _, call := range builtinCalls {
+               testBuiltinSignature(t, call.name, call.src, call.sig)
+               seen[call.name] = true
+       }
+
+       // make sure we didn't miss one
+       for _, name := range Universe.Names() {
+               if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
+                       t.Errorf("missing test for %s", name)
+               }
+       }
+       for _, name := range Unsafe.Scope().Names() {
+               if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
+                       t.Errorf("missing test for unsafe.%s", name)
+               }
+       }
+}
+
+func testBuiltinSignature(t *testing.T, name, src0, want string) {
+       src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
+       f, err := parser.ParseFile(fset, "", src, 0)
+       if err != nil {
+               t.Errorf("%s: %s", src0, err)
+               return
+       }
+
+       var conf Config
+       uses := make(map[*ast.Ident]Object)
+       types := make(map[ast.Expr]TypeAndValue)
+       _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types})
+       if err != nil {
+               t.Errorf("%s: %s", src0, err)
+               return
+       }
+
+       // find called function
+       n := 0
+       var fun ast.Expr
+       for x := range types {
+               if call, _ := x.(*ast.CallExpr); call != nil {
+                       fun = call.Fun
+                       n++
+               }
+       }
+       if n != 1 {
+               t.Errorf("%s: got %d CallExprs; want 1", src0, n)
+               return
+       }
+
+       // check recorded types for fun and descendents (may be parenthesized)
+       for {
+               // the recorded type for the built-in must match the wanted signature
+               typ := types[fun].Type
+               if typ == nil {
+                       t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
+                       return
+               }
+               if got := typ.String(); got != want {
+                       t.Errorf("%s: got type %s; want %s", src0, got, want)
+                       return
+               }
+
+               // called function must be a (possibly parenthesized, qualified)
+               // identifier denoting the expected built-in
+               switch p := fun.(type) {
+               case *ast.Ident:
+                       obj := uses[p]
+                       if obj == nil {
+                               t.Errorf("%s: no object found for %s", src0, p)
+                               return
+                       }
+                       bin, _ := obj.(*Builtin)
+                       if bin == nil {
+                               t.Errorf("%s: %s does not denote a built-in", src0, p)
+                               return
+                       }
+                       if bin.Name() != name {
+                               t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
+                               return
+                       }
+                       return // we're done
+
+               case *ast.ParenExpr:
+                       fun = p.X // unpack
+
+               case *ast.SelectorExpr:
+                       // built-in from package unsafe - ignore details
+                       return // we're done
+
+               default:
+                       t.Errorf("%s: invalid function call", src0)
+                       return
+               }
+       }
+}
diff --git a/src/go/types/call.go b/src/go/types/call.go
new file mode 100644 (file)
index 0000000..7f366a8
--- /dev/null
@@ -0,0 +1,441 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements typechecking of call and selector expressions.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+)
+
+func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
+       check.exprOrType(x, e.Fun)
+
+       switch x.mode {
+       case invalid:
+               check.use(e.Args...)
+               x.mode = invalid
+               x.expr = e
+               return statement
+
+       case typexpr:
+               // conversion
+               T := x.typ
+               x.mode = invalid
+               switch n := len(e.Args); n {
+               case 0:
+                       check.errorf(e.Rparen, "missing argument in conversion to %s", T)
+               case 1:
+                       check.expr(x, e.Args[0])
+                       if x.mode != invalid {
+                               check.conversion(x, T)
+                       }
+               default:
+                       check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
+               }
+               x.expr = e
+               return conversion
+
+       case builtin:
+               id := x.id
+               if !check.builtin(x, e, id) {
+                       x.mode = invalid
+               }
+               x.expr = e
+               // a non-constant result implies a function call
+               if x.mode != invalid && x.mode != constant {
+                       check.hasCallOrRecv = true
+               }
+               return predeclaredFuncs[id].kind
+
+       default:
+               // function/method call
+               sig, _ := x.typ.Underlying().(*Signature)
+               if sig == nil {
+                       check.invalidOp(x.pos(), "cannot call non-function %s", x)
+                       x.mode = invalid
+                       x.expr = e
+                       return statement
+               }
+
+               arg, n, _ := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false)
+               if arg == nil {
+                       x.mode = invalid
+                       x.expr = e
+                       return statement
+               }
+
+               check.arguments(x, e, sig, arg, n)
+
+               // determine result
+               switch sig.results.Len() {
+               case 0:
+                       x.mode = novalue
+               case 1:
+                       x.mode = value
+                       x.typ = sig.results.vars[0].typ // unpack tuple
+               default:
+                       x.mode = value
+                       x.typ = sig.results
+               }
+               x.expr = e
+               check.hasCallOrRecv = true
+
+               return statement
+       }
+}
+
+// use type-checks each argument.
+// Useful to make sure expressions are evaluated
+// (and variables are "used") in the presence of other errors.
+func (check *Checker) use(arg ...ast.Expr) {
+       var x operand
+       for _, e := range arg {
+               check.rawExpr(&x, e, nil)
+       }
+}
+
+// useGetter is like use, but takes a getter instead of a list of expressions.
+// It should be called instead of use if a getter is present to avoid repeated
+// evaluation of the first argument (since the getter was likely obtained via
+// unpack, which may have evaluated the first argument already).
+func (check *Checker) useGetter(get getter, n int) {
+       var x operand
+       for i := 0; i < n; i++ {
+               get(&x, i)
+       }
+}
+
+// A getter sets x as the i'th operand, where 0 <= i < n and n is the total
+// number of operands (context-specific, and maintained elsewhere). A getter
+// type-checks the i'th operand; the details of the actual check are getter-
+// specific.
+type getter func(x *operand, i int)
+
+// unpack takes a getter get and a number of operands n. If n == 1, unpack
+// calls the incoming getter for the first operand. If that operand is
+// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
+// function call, or a comma-ok expression and allowCommaOk is set, the result
+// is a new getter and operand count providing access to the function results,
+// or comma-ok values, respectively. The third result value reports if it
+// is indeed the comma-ok case. In all other cases, the incoming getter and
+// operand count are returned unchanged, and the third result value is false.
+//
+// In other words, if there's exactly one operand that - after type-checking
+// by calling get - stands for multiple operands, the resulting getter provides
+// access to those operands instead.
+//
+// If the returned getter is called at most once for a given operand index i
+// (including i == 0), that operand is guaranteed to cause only one call of
+// the incoming getter with that i.
+//
+func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) {
+       if n == 1 {
+               // possibly result of an n-valued function call or comma,ok value
+               var x0 operand
+               get(&x0, 0)
+               if x0.mode == invalid {
+                       return nil, 0, false
+               }
+
+               if t, ok := x0.typ.(*Tuple); ok {
+                       // result of an n-valued function call
+                       return func(x *operand, i int) {
+                               x.mode = value
+                               x.expr = x0.expr
+                               x.typ = t.At(i).typ
+                       }, t.Len(), false
+               }
+
+               if x0.mode == mapindex || x0.mode == commaok {
+                       // comma-ok value
+                       if allowCommaOk {
+                               a := [2]Type{x0.typ, Typ[UntypedBool]}
+                               return func(x *operand, i int) {
+                                       x.mode = value
+                                       x.expr = x0.expr
+                                       x.typ = a[i]
+                               }, 2, true
+                       }
+                       x0.mode = value
+               }
+
+               // single value
+               return func(x *operand, i int) {
+                       if i != 0 {
+                               unreachable()
+                       }
+                       *x = x0
+               }, 1, false
+       }
+
+       // zero or multiple values
+       return get, n, false
+}
+
+// arguments checks argument passing for the call with the given signature.
+// The arg function provides the operand for the i'th argument.
+func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
+       if call.Ellipsis.IsValid() {
+               // last argument is of the form x...
+               if len(call.Args) == 1 && n > 1 {
+                       // f()... is not permitted if f() is multi-valued
+                       check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0])
+                       check.useGetter(arg, n)
+                       return
+               }
+               if !sig.variadic {
+                       check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+                       check.useGetter(arg, n)
+                       return
+               }
+       }
+
+       // evaluate arguments
+       for i := 0; i < n; i++ {
+               arg(x, i)
+               if x.mode != invalid {
+                       var ellipsis token.Pos
+                       if i == n-1 && call.Ellipsis.IsValid() {
+                               ellipsis = call.Ellipsis
+                       }
+                       check.argument(sig, i, x, ellipsis)
+               }
+       }
+
+       // check argument count
+       if sig.variadic {
+               // a variadic function accepts an "empty"
+               // last argument: count one extra
+               n++
+       }
+       if n < sig.params.Len() {
+               check.errorf(call.Rparen, "too few arguments in call to %s", call.Fun)
+               // ok to continue
+       }
+}
+
+// argument checks passing of argument x to the i'th parameter of the given signature.
+// If ellipsis is valid, the argument is followed by ... at that position in the call.
+func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) {
+       n := sig.params.Len()
+
+       // determine parameter type
+       var typ Type
+       switch {
+       case i < n:
+               typ = sig.params.vars[i].typ
+       case sig.variadic:
+               typ = sig.params.vars[n-1].typ
+               if debug {
+                       if _, ok := typ.(*Slice); !ok {
+                               check.dump("%s: expected unnamed slice type, got %s", sig.params.vars[n-1].Pos(), typ)
+                       }
+               }
+       default:
+               check.errorf(x.pos(), "too many arguments")
+               return
+       }
+
+       if ellipsis.IsValid() {
+               // argument is of the form x...
+               if i != n-1 {
+                       check.errorf(ellipsis, "can only use ... with matching parameter")
+                       return
+               }
+               switch t := x.typ.Underlying().(type) {
+               case *Slice:
+                       // ok
+               case *Tuple:
+                       check.errorf(ellipsis, "cannot use ... with %d-valued expression %s", t.Len(), x)
+                       return
+               default:
+                       check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
+                       return
+               }
+       } else if sig.variadic && i >= n-1 {
+               // use the variadic parameter slice's element type
+               typ = typ.(*Slice).elem
+       }
+
+       if !check.assignment(x, typ) && x.mode != invalid {
+               check.errorf(x.pos(), "cannot pass argument %s to parameter of type %s", x, typ)
+       }
+}
+
+func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
+       // these must be declared before the "goto Error" statements
+       var (
+               obj      Object
+               index    []int
+               indirect bool
+       )
+
+       sel := e.Sel.Name
+       // If the identifier refers to a package, handle everything here
+       // so we don't need a "package" mode for operands: package names
+       // can only appear in qualified identifiers which are mapped to
+       // selector expressions.
+       if ident, ok := e.X.(*ast.Ident); ok {
+               _, obj := check.scope.LookupParent(ident.Name)
+               if pkg, _ := obj.(*PkgName); pkg != nil {
+                       assert(pkg.pkg == check.pkg)
+                       check.recordUse(ident, pkg)
+                       pkg.used = true
+                       exp := pkg.imported.scope.Lookup(sel)
+                       if exp == nil {
+                               if !pkg.imported.fake {
+                                       check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
+                               }
+                               goto Error
+                       }
+                       if !exp.Exported() {
+                               check.errorf(e.Pos(), "%s not exported by package %s", sel, ident)
+                               // ok to continue
+                       }
+                       check.recordUse(e.Sel, exp)
+                       // Simplified version of the code for *ast.Idents:
+                       // - imported objects are always fully initialized
+                       switch exp := exp.(type) {
+                       case *Const:
+                               assert(exp.Val() != nil)
+                               x.mode = constant
+                               x.typ = exp.typ
+                               x.val = exp.val
+                       case *TypeName:
+                               x.mode = typexpr
+                               x.typ = exp.typ
+                       case *Var:
+                               x.mode = variable
+                               x.typ = exp.typ
+                       case *Func:
+                               x.mode = value
+                               x.typ = exp.typ
+                       case *Builtin:
+                               x.mode = builtin
+                               x.typ = exp.typ
+                               x.id = exp.id
+                       default:
+                               unreachable()
+                       }
+                       x.expr = e
+                       return
+               }
+       }
+
+       check.exprOrType(x, e.X)
+       if x.mode == invalid {
+               goto Error
+       }
+
+       obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
+       if obj == nil {
+               switch {
+               case index != nil:
+                       // TODO(gri) should provide actual type where the conflict happens
+                       check.invalidOp(e.Pos(), "ambiguous selector %s", sel)
+               case indirect:
+                       check.invalidOp(e.Pos(), "%s is not in method set of %s", sel, x.typ)
+               default:
+                       check.invalidOp(e.Pos(), "%s has no field or method %s", x, sel)
+               }
+               goto Error
+       }
+
+       if x.mode == typexpr {
+               // method expression
+               m, _ := obj.(*Func)
+               if m == nil {
+                       check.invalidOp(e.Pos(), "%s has no method %s", x, sel)
+                       goto Error
+               }
+
+               check.recordSelection(e, MethodExpr, x.typ, m, index, indirect)
+
+               // the receiver type becomes the type of the first function
+               // argument of the method expression's function type
+               var params []*Var
+               sig := m.typ.(*Signature)
+               if sig.params != nil {
+                       params = sig.params.vars
+               }
+               x.mode = value
+               x.typ = &Signature{
+                       params:   NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...),
+                       results:  sig.results,
+                       variadic: sig.variadic,
+               }
+
+               check.addDeclDep(m)
+
+       } else {
+               // regular selector
+               switch obj := obj.(type) {
+               case *Var:
+                       check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
+                       if x.mode == variable || indirect {
+                               x.mode = variable
+                       } else {
+                               x.mode = value
+                       }
+                       x.typ = obj.typ
+
+               case *Func:
+                       // TODO(gri) If we needed to take into account the receiver's
+                       // addressability, should we report the type &(x.typ) instead?
+                       check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
+
+                       if debug {
+                               // Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
+                               typ := x.typ
+                               if x.mode == variable {
+                                       // If typ is not an (unnamed) pointer or an interface,
+                                       // use *typ instead, because the method set of *typ
+                                       // includes the methods of typ.
+                                       // Variables are addressable, so we can always take their
+                                       // address.
+                                       if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) {
+                                               typ = &Pointer{base: typ}
+                                       }
+                               }
+                               // If we created a synthetic pointer type above, we will throw
+                               // away the method set computed here after use.
+                               // TODO(gri) Method set computation should probably always compute
+                               // both, the value and the pointer receiver method set and represent
+                               // them in a single structure.
+                               // TODO(gri) Consider also using a method set cache for the lifetime
+                               // of checker once we rely on MethodSet lookup instead of individual
+                               // lookup.
+                               mset := NewMethodSet(typ)
+                               if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {
+                                       check.dump("%s: (%s).%v -> %s", e.Pos(), typ, obj.name, m)
+                                       check.dump("%s\n", mset)
+                                       panic("method sets and lookup don't agree")
+                               }
+                       }
+
+                       x.mode = value
+
+                       // remove receiver
+                       sig := *obj.typ.(*Signature)
+                       sig.recv = nil
+                       x.typ = &sig
+
+                       check.addDeclDep(obj)
+
+               default:
+                       unreachable()
+               }
+       }
+
+       // everything went well
+       x.expr = e
+       return
+
+Error:
+       x.mode = invalid
+       x.expr = e
+}
diff --git a/src/go/types/check.go b/src/go/types/check.go
new file mode 100644 (file)
index 0000000..04a6e2c
--- /dev/null
@@ -0,0 +1,363 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the Check function, which drives type-checking.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+
+       "go/exact"
+)
+
+// debugging/development support
+const (
+       debug = false // leave on during development
+       trace = false // turn on for detailed type resolution traces
+)
+
+// If Strict is set, the type-checker enforces additional
+// rules not specified by the Go 1 spec, but which will
+// catch guaranteed run-time errors if the respective
+// code is executed. In other words, programs passing in
+// Strict mode are Go 1 compliant, but not all Go 1 programs
+// will pass in Strict mode. The additional rules are:
+//
+// - A type assertion x.(T) where T is an interface type
+//   is invalid if any (statically known) method that exists
+//   for both x and T have different signatures.
+//
+const strict = false
+
+// exprInfo stores information about an untyped expression.
+type exprInfo struct {
+       isLhs bool // expression is lhs operand of a shift with delayed type-check
+       mode  operandMode
+       typ   *Basic
+       val   exact.Value // constant value; or nil (if not a constant)
+}
+
+// funcInfo stores the information required for type-checking a function.
+type funcInfo struct {
+       name string    // for debugging/tracing only
+       decl *declInfo // for cycle detection
+       sig  *Signature
+       body *ast.BlockStmt
+}
+
+// A context represents the context within which an object is type-checked.
+type context struct {
+       decl          *declInfo   // package-level declaration whose init expression/function body is checked
+       scope         *Scope      // top-most scope for lookups
+       iota          exact.Value // value of iota in a constant declaration; nil otherwise
+       sig           *Signature  // function signature if inside a function; nil otherwise
+       hasLabel      bool        // set if a function makes use of labels (only ~1% of functions); unused outside functions
+       hasCallOrRecv bool        // set if an expression contains a function call or channel receive operation
+}
+
+// A Checker maintains the state of the type checker.
+// It must be created with NewChecker.
+type Checker struct {
+       // package information
+       // (initialized by NewChecker, valid for the life-time of checker)
+       conf *Config
+       fset *token.FileSet
+       pkg  *Package
+       *Info
+       objMap map[Object]*declInfo // maps package-level object to declaration info
+
+       // information collected during type-checking of a set of package files
+       // (initialized by Files, valid only for the duration of check.Files;
+       // maps and lists are allocated on demand)
+       files            []*ast.File                       // package files
+       unusedDotImports map[*Scope]map[*Package]token.Pos // positions of unused dot-imported packages for each file scope
+
+       firstErr error                 // first error encountered
+       methods  map[string][]*Func    // maps type names to associated methods
+       untyped  map[ast.Expr]exprInfo // map of expressions without final type
+       funcs    []funcInfo            // list of functions to type-check
+       delayed  []func()              // delayed checks requiring fully setup types
+
+       // context within which the current object is type-checked
+       // (valid only for the duration of type-checking a specific object)
+       context
+
+       // debugging
+       indent int // indentation for tracing
+}
+
+// addUnusedImport adds the position of a dot-imported package
+// pkg to the map of dot imports for the given file scope.
+func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos token.Pos) {
+       mm := check.unusedDotImports
+       if mm == nil {
+               mm = make(map[*Scope]map[*Package]token.Pos)
+               check.unusedDotImports = mm
+       }
+       m := mm[scope]
+       if m == nil {
+               m = make(map[*Package]token.Pos)
+               mm[scope] = m
+       }
+       m[pkg] = pos
+}
+
+// addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists
+func (check *Checker) addDeclDep(to Object) {
+       from := check.decl
+       if from == nil {
+               return // not in a package-level init expression
+       }
+       if _, found := check.objMap[to]; !found {
+               return // to is not a package-level object
+       }
+       from.addDep(to)
+}
+
+func (check *Checker) assocMethod(tname string, meth *Func) {
+       m := check.methods
+       if m == nil {
+               m = make(map[string][]*Func)
+               check.methods = m
+       }
+       m[tname] = append(m[tname], meth)
+}
+
+func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val exact.Value) {
+       m := check.untyped
+       if m == nil {
+               m = make(map[ast.Expr]exprInfo)
+               check.untyped = m
+       }
+       m[e] = exprInfo{lhs, mode, typ, val}
+}
+
+func (check *Checker) later(name string, decl *declInfo, sig *Signature, body *ast.BlockStmt) {
+       check.funcs = append(check.funcs, funcInfo{name, decl, sig, body})
+}
+
+func (check *Checker) delay(f func()) {
+       check.delayed = append(check.delayed, f)
+}
+
+// NewChecker returns a new Checker instance for a given package.
+// Package files may be added incrementally via checker.Files.
+func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
+       // make sure we have a configuration
+       if conf == nil {
+               conf = new(Config)
+       }
+
+       // make sure we have a package canonicalization map
+       if conf.Packages == nil {
+               conf.Packages = make(map[string]*Package)
+       }
+
+       // make sure we have an info struct
+       if info == nil {
+               info = new(Info)
+       }
+
+       return &Checker{
+               conf:   conf,
+               fset:   fset,
+               pkg:    pkg,
+               Info:   info,
+               objMap: make(map[Object]*declInfo),
+       }
+}
+
+// initFiles initializes the files-specific portion of checker.
+// The provided files must all belong to the same package.
+func (check *Checker) initFiles(files []*ast.File) {
+       // start with a clean slate (check.Files may be called multiple times)
+       check.files = nil
+       check.unusedDotImports = nil
+
+       check.firstErr = nil
+       check.methods = nil
+       check.untyped = nil
+       check.funcs = nil
+       check.delayed = nil
+
+       // determine package name and collect valid files
+       pkg := check.pkg
+       for _, file := range files {
+               switch name := file.Name.Name; pkg.name {
+               case "":
+                       if name != "_" {
+                               pkg.name = name
+                       } else {
+                               check.errorf(file.Name.Pos(), "invalid package name _")
+                       }
+                       fallthrough
+
+               case name:
+                       check.files = append(check.files, file)
+
+               default:
+                       check.errorf(file.Package, "package %s; expected %s", name, pkg.name)
+                       // ignore this file
+               }
+       }
+}
+
+// A bailout panic is used for early termination.
+type bailout struct{}
+
+func (check *Checker) handleBailout(err *error) {
+       switch p := recover().(type) {
+       case nil, bailout:
+               // normal return or early exit
+               *err = check.firstErr
+       default:
+               // re-panic
+               panic(p)
+       }
+}
+
+// Files checks the provided files as part of the checker's package.
+func (check *Checker) Files(files []*ast.File) (err error) {
+       defer check.handleBailout(&err)
+
+       check.initFiles(files)
+
+       check.collectObjects()
+
+       check.packageObjects(check.resolveOrder())
+
+       check.functionBodies()
+
+       check.initOrder()
+
+       if !check.conf.DisableUnusedImportCheck {
+               check.unusedImports()
+       }
+
+       // perform delayed checks
+       for _, f := range check.delayed {
+               f()
+       }
+
+       check.recordUntyped()
+
+       check.pkg.complete = true
+       return
+}
+
+func (check *Checker) recordUntyped() {
+       if !debug && check.Types == nil {
+               return // nothing to do
+       }
+
+       for x, info := range check.untyped {
+               if debug && isTyped(info.typ) {
+                       check.dump("%s: %s (type %s) is typed", x.Pos(), x, info.typ)
+                       unreachable()
+               }
+               check.recordTypeAndValue(x, info.mode, info.typ, info.val)
+       }
+}
+
+func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val exact.Value) {
+       assert(x != nil)
+       assert(typ != nil)
+       if mode == invalid {
+               return // omit
+       }
+       assert(typ != nil)
+       if mode == constant {
+               assert(val != nil)
+               assert(typ == Typ[Invalid] || isConstType(typ))
+       }
+       if m := check.Types; m != nil {
+               m[x] = TypeAndValue{mode, typ, val}
+       }
+}
+
+func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
+       // f must be a (possibly parenthesized) identifier denoting a built-in
+       // (built-ins in package unsafe always produce a constant result and
+       // we don't record their signatures, so we don't see qualified idents
+       // here): record the signature for f and possible children.
+       for {
+               check.recordTypeAndValue(f, builtin, sig, nil)
+               switch p := f.(type) {
+               case *ast.Ident:
+                       return // we're done
+               case *ast.ParenExpr:
+                       f = p.X
+               default:
+                       unreachable()
+               }
+       }
+}
+
+func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
+       assert(x != nil)
+       if a[0] == nil || a[1] == nil {
+               return
+       }
+       assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1]))
+       if m := check.Types; m != nil {
+               for {
+                       tv := m[x]
+                       assert(tv.Type != nil) // should have been recorded already
+                       pos := x.Pos()
+                       tv.Type = NewTuple(
+                               NewVar(pos, check.pkg, "", a[0]),
+                               NewVar(pos, check.pkg, "", a[1]),
+                       )
+                       m[x] = tv
+                       // if x is a parenthesized expression (p.X), update p.X
+                       p, _ := x.(*ast.ParenExpr)
+                       if p == nil {
+                               break
+                       }
+                       x = p.X
+               }
+       }
+}
+
+func (check *Checker) recordDef(id *ast.Ident, obj Object) {
+       assert(id != nil)
+       if m := check.Defs; m != nil {
+               m[id] = obj
+       }
+}
+
+func (check *Checker) recordUse(id *ast.Ident, obj Object) {
+       assert(id != nil)
+       assert(obj != nil)
+       if m := check.Uses; m != nil {
+               m[id] = obj
+       }
+}
+
+func (check *Checker) recordImplicit(node ast.Node, obj Object) {
+       assert(node != nil)
+       assert(obj != nil)
+       if m := check.Implicits; m != nil {
+               m[node] = obj
+       }
+}
+
+func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
+       assert(obj != nil && (recv == nil || len(index) > 0))
+       check.recordUse(x.Sel, obj)
+       // TODO(gri) Should we also call recordTypeAndValue?
+       if m := check.Selections; m != nil {
+               m[x] = &Selection{kind, recv, obj, index, indirect}
+       }
+}
+
+func (check *Checker) recordScope(node ast.Node, scope *Scope) {
+       assert(node != nil)
+       assert(scope != nil)
+       if m := check.Scopes; m != nil {
+               m[node] = scope
+       }
+}
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
new file mode 100644 (file)
index 0000000..edc9c0e
--- /dev/null
@@ -0,0 +1,294 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+//     package p
+//     func f() {
+//             _ = x /* ERROR "not declared" */ + 1
+//     }
+
+// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */
+//           and test against strict mode.
+
+package types_test
+
+import (
+       "flag"
+       "go/ast"
+       "go/parser"
+       "go/scanner"
+       "go/token"
+       "io/ioutil"
+       "regexp"
+       "strings"
+       "testing"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+var (
+       listErrors = flag.Bool("list", false, "list errors")
+       testFiles  = flag.String("files", "", "space-separated list of test files")
+)
+
+// The test filenames do not end in .go so that they are invisible
+// to gofmt since they contain comments that must not change their
+// positions relative to surrounding tokens.
+
+// Each tests entry is list of files belonging to the same package.
+var tests = [][]string{
+       {"testdata/errors.src"},
+       {"testdata/importdecl0a.src", "testdata/importdecl0b.src"},
+       {"testdata/importdecl1a.src", "testdata/importdecl1b.src"},
+       {"testdata/cycles.src"},
+       {"testdata/cycles1.src"},
+       {"testdata/cycles2.src"},
+       {"testdata/cycles3.src"},
+       {"testdata/cycles4.src"},
+       {"testdata/init0.src"},
+       {"testdata/init1.src"},
+       {"testdata/init2.src"},
+       {"testdata/decls0.src"},
+       {"testdata/decls1.src"},
+       {"testdata/decls2a.src", "testdata/decls2b.src"},
+       {"testdata/decls3.src"},
+       {"testdata/const0.src"},
+       {"testdata/const1.src"},
+       {"testdata/constdecl.src"},
+       {"testdata/vardecl.src"},
+       {"testdata/expr0.src"},
+       {"testdata/expr1.src"},
+       {"testdata/expr2.src"},
+       {"testdata/expr3.src"},
+       {"testdata/methodsets.src"},
+       {"testdata/shifts.src"},
+       {"testdata/builtins.src"},
+       {"testdata/conversions.src"},
+       {"testdata/stmt0.src"},
+       {"testdata/stmt1.src"},
+       {"testdata/gotos.src"},
+       {"testdata/labels.src"},
+       {"testdata/issues.src"},
+       {"testdata/blank.src"},
+}
+
+var fset = token.NewFileSet()
+
+// Positioned errors are of the form filename:line:column: message .
+var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`)
+
+// splitError splits an error's error message into a position string
+// and the actual error message. If there's no position information,
+// pos is the empty string, and msg is the entire error message.
+//
+func splitError(err error) (pos, msg string) {
+       msg = err.Error()
+       if m := posMsgRx.FindStringSubmatch(msg); len(m) == 3 {
+               pos = m[1]
+               msg = m[2]
+       }
+       return
+}
+
+func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) {
+       var files []*ast.File
+       var errlist []error
+       for _, filename := range filenames {
+               file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+               if file == nil {
+                       t.Fatalf("%s: %s", filename, err)
+               }
+               files = append(files, file)
+               if err != nil {
+                       if list, _ := err.(scanner.ErrorList); len(list) > 0 {
+                               for _, err := range list {
+                                       errlist = append(errlist, err)
+                               }
+                       } else {
+                               errlist = append(errlist, err)
+                       }
+               }
+       }
+       return files, errlist
+}
+
+// ERROR comments must start with text `ERROR "rx"` or `ERROR rx` where
+// rx is a regular expression that matches the expected error message.
+// Space around "rx" or rx is ignored. Use the form `ERROR HERE "rx"`
+// for error messages that are located immediately after rather than
+// at a token's position.
+//
+var errRx = regexp.MustCompile(`^ *ERROR *(HERE)? *"?([^"]*)"?`)
+
+// errMap collects the regular expressions of ERROR comments found
+// in files and returns them as a map of error positions to error messages.
+//
+func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
+       // map of position strings to lists of error message patterns
+       errmap := make(map[string][]string)
+
+       for _, file := range files {
+               filename := fset.Position(file.Package).Filename
+               src, err := ioutil.ReadFile(filename)
+               if err != nil {
+                       t.Fatalf("%s: could not read %s", testname, filename)
+               }
+
+               var s scanner.Scanner
+               s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments)
+               var prev token.Pos // position of last non-comment, non-semicolon token
+               var here token.Pos // position immediately after the token at position prev
+
+       scanFile:
+               for {
+                       pos, tok, lit := s.Scan()
+                       switch tok {
+                       case token.EOF:
+                               break scanFile
+                       case token.COMMENT:
+                               if lit[1] == '*' {
+                                       lit = lit[:len(lit)-2] // strip trailing */
+                               }
+                               if s := errRx.FindStringSubmatch(lit[2:]); len(s) == 3 {
+                                       pos := prev
+                                       if s[1] == "HERE" {
+                                               pos = here
+                                       }
+                                       p := fset.Position(pos).String()
+                                       errmap[p] = append(errmap[p], strings.TrimSpace(s[2]))
+                               }
+                       case token.SEMICOLON:
+                               // ignore automatically inserted semicolon
+                               if lit == "\n" {
+                                       continue scanFile
+                               }
+                               fallthrough
+                       default:
+                               prev = pos
+                               var l int // token length
+                               if tok.IsLiteral() {
+                                       l = len(lit)
+                               } else {
+                                       l = len(tok.String())
+                               }
+                               here = prev + token.Pos(l)
+                       }
+               }
+       }
+
+       return errmap
+}
+
+func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
+       for _, err := range errlist {
+               pos, gotMsg := splitError(err)
+               list := errmap[pos]
+               index := -1 // list index of matching message, if any
+               // we expect one of the messages in list to match the error at pos
+               for i, wantRx := range list {
+                       rx, err := regexp.Compile(wantRx)
+                       if err != nil {
+                               t.Errorf("%s: %v", pos, err)
+                               continue
+                       }
+                       if rx.MatchString(gotMsg) {
+                               index = i
+                               break
+                       }
+               }
+               if index >= 0 {
+                       // eliminate from list
+                       if n := len(list) - 1; n > 0 {
+                               // not the last entry - swap in last element and shorten list by 1
+                               list[index] = list[n]
+                               errmap[pos] = list[:n]
+                       } else {
+                               // last entry - remove list from map
+                               delete(errmap, pos)
+                       }
+               } else {
+                       t.Errorf("%s: no error expected: %q", pos, gotMsg)
+               }
+       }
+}
+
+func checkFiles(t *testing.T, testfiles []string) {
+       // parse files and collect parser errors
+       files, errlist := parseFiles(t, testfiles)
+
+       pkgName := "<no package>"
+       if len(files) > 0 {
+               pkgName = files[0].Name.Name
+       }
+
+       if *listErrors && len(errlist) > 0 {
+               t.Errorf("--- %s:", pkgName)
+               for _, err := range errlist {
+                       t.Error(err)
+               }
+       }
+
+       // typecheck and collect typechecker errors
+       var conf Config
+       conf.Error = func(err error) {
+               if *listErrors {
+                       t.Error(err)
+                       return
+               }
+               // Ignore secondary error messages starting with "\t";
+               // they are clarifying messages for a primary error.
+               if !strings.Contains(err.Error(), ": \t") {
+                       errlist = append(errlist, err)
+               }
+       }
+       conf.Check(pkgName, fset, files, nil)
+
+       if *listErrors {
+               return
+       }
+
+       // match and eliminate errors;
+       // we are expecting the following errors
+       errmap := errMap(t, pkgName, files)
+       eliminate(t, errmap, errlist)
+
+       // there should be no expected errors left
+       if len(errmap) > 0 {
+               t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", pkgName, len(errmap))
+               for pos, list := range errmap {
+                       for _, rx := range list {
+                               t.Errorf("%s: %q", pos, rx)
+                       }
+               }
+       }
+}
+
+func TestCheck(t *testing.T) {
+       // Declare builtins for testing.
+       DefPredeclaredTestFuncs()
+
+       // If explicit test files are specified, only check those.
+       if files := *testFiles; files != "" {
+               checkFiles(t, strings.Split(files, " "))
+               return
+       }
+
+       // Otherwise, run all the tests.
+       for _, files := range tests {
+               checkFiles(t, files)
+       }
+}
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
new file mode 100644 (file)
index 0000000..256aabe
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements typechecking of conversions.
+
+package types
+
+import "go/exact"
+
+// Conversion type-checks the conversion T(x).
+// The result is in x.
+func (check *Checker) conversion(x *operand, T Type) {
+       constArg := x.mode == constant
+
+       var ok bool
+       switch {
+       case constArg && isConstType(T):
+               // constant conversion
+               switch t := T.Underlying().(*Basic); {
+               case representableConst(x.val, check.conf, t.kind, &x.val):
+                       ok = true
+               case x.isInteger() && isString(t):
+                       codepoint := int64(-1)
+                       if i, ok := exact.Int64Val(x.val); ok {
+                               codepoint = i
+                       }
+                       // If codepoint < 0 the absolute value is too large (or unknown) for
+                       // conversion. This is the same as converting any other out-of-range
+                       // value - let string(codepoint) do the work.
+                       x.val = exact.MakeString(string(codepoint))
+                       ok = true
+               }
+       case x.convertibleTo(check.conf, T):
+               // non-constant conversion
+               x.mode = value
+               ok = true
+       }
+
+       if !ok {
+               check.errorf(x.pos(), "cannot convert %s to %s", x, T)
+               x.mode = invalid
+               return
+       }
+
+       // 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(x.typ) {
+               final = T
+               // - For conversions to interfaces, use the argument's default type.
+               // - For conversions of untyped constants to non-constant types, also
+               //   use the default type (e.g., []byte("foo") should report string
+               //   not []byte as type for the constant "foo").
+               // - Keep untyped nil for untyped nil arguments.
+               if IsInterface(T) || constArg && !isConstType(T) {
+                       final = defaultType(x.typ)
+               }
+               check.updateExprType(x.expr, final, true)
+       }
+
+       x.typ = T
+}
+
+func (x *operand) convertibleTo(conf *Config, T Type) bool {
+       // "x is assignable to T"
+       if x.assignableTo(conf, T) {
+               return true
+       }
+
+       // "x's type and T have identical underlying types"
+       V := x.typ
+       Vu := V.Underlying()
+       Tu := T.Underlying()
+       if Identical(Vu, Tu) {
+               return true
+       }
+
+       // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
+       if V, ok := V.(*Pointer); ok {
+               if T, ok := T.(*Pointer); ok {
+                       if Identical(V.base.Underlying(), T.base.Underlying()) {
+                               return true
+                       }
+               }
+       }
+
+       // "x's type and T are both integer or floating point types"
+       if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
+               return true
+       }
+
+       // "x's type and T are both complex types"
+       if isComplex(V) && isComplex(T) {
+               return true
+       }
+
+       // "x is an integer or a slice of bytes or runes and T is a string type"
+       if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
+               return true
+       }
+
+       // "x is a string and T is a slice of bytes or runes"
+       if isString(V) && isBytesOrRunes(Tu) {
+               return true
+       }
+
+       // package unsafe:
+       // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
+       if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
+               return true
+       }
+       // "and vice versa"
+       if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
+               return true
+       }
+
+       return false
+}
+
+func isUintptr(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.kind == Uintptr
+}
+
+func isUnsafePointer(typ Type) bool {
+       // TODO(gri): Is this (typ.Underlying() instead of just typ) correct?
+       //            The spec does not say so, but gc claims it is. See also
+       //            issue 6326.
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.kind == UnsafePointer
+}
+
+func isPointer(typ Type) bool {
+       _, ok := typ.Underlying().(*Pointer)
+       return ok
+}
+
+func isBytesOrRunes(typ Type) bool {
+       if s, ok := typ.(*Slice); ok {
+               t, ok := s.elem.Underlying().(*Basic)
+               return ok && (t.kind == Byte || t.kind == Rune)
+       }
+       return false
+}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
new file mode 100644 (file)
index 0000000..132de3a
--- /dev/null
@@ -0,0 +1,419 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+
+       "go/exact"
+)
+
+func (check *Checker) reportAltDecl(obj Object) {
+       if pos := obj.Pos(); pos.IsValid() {
+               // We use "other" rather than "previous" here because
+               // the first declaration seen may not be textually
+               // earlier in the source.
+               check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
+       }
+}
+
+func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object) {
+       // spec: "The blank identifier, represented by the underscore
+       // character _, may be used in a declaration like any other
+       // identifier but the declaration does not introduce a new
+       // binding."
+       if obj.Name() != "_" {
+               if alt := scope.Insert(obj); alt != nil {
+                       check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+                       check.reportAltDecl(alt)
+                       return
+               }
+       }
+       if id != nil {
+               check.recordDef(id, obj)
+       }
+}
+
+// objDecl type-checks the declaration of obj in its respective (file) context.
+// See check.typ for the details on def and path.
+func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
+       if obj.Type() != nil {
+               return // already checked - nothing to do
+       }
+
+       if trace {
+               check.trace(obj.Pos(), "-- declaring %s", obj.Name())
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(obj.Pos(), "=> %s", obj)
+               }()
+       }
+
+       d := check.objMap[obj]
+       if d == nil {
+               check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+               unreachable()
+       }
+
+       // save/restore current context and setup object context
+       defer func(ctxt context) {
+               check.context = ctxt
+       }(check.context)
+       check.context = context{
+               scope: d.file,
+       }
+
+       // Const and var declarations must not have initialization
+       // cycles. We track them by remembering the current declaration
+       // in check.decl. Initialization expressions depending on other
+       // consts, vars, or functions, add dependencies to the current
+       // check.decl.
+       switch obj := obj.(type) {
+       case *Const:
+               check.decl = d // new package-level const decl
+               check.constDecl(obj, d.typ, d.init)
+       case *Var:
+               check.decl = d // new package-level var decl
+               check.varDecl(obj, d.lhs, d.typ, d.init)
+       case *TypeName:
+               // invalid recursive types are detected via path
+               check.typeDecl(obj, d.typ, def, path)
+       case *Func:
+               // functions may be recursive - no need to track dependencies
+               check.funcDecl(obj, d)
+       default:
+               unreachable()
+       }
+}
+
+func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
+       assert(obj.typ == nil)
+
+       if obj.visited {
+               obj.typ = Typ[Invalid]
+               return
+       }
+       obj.visited = true
+
+       // use the correct value of iota
+       assert(check.iota == nil)
+       check.iota = obj.val
+       defer func() { check.iota = nil }()
+
+       // provide valid constant value under all circumstances
+       obj.val = exact.MakeUnknown()
+
+       // determine type, if any
+       if typ != nil {
+               t := check.typ(typ)
+               if !isConstType(t) {
+                       check.errorf(typ.Pos(), "invalid constant type %s", t)
+                       obj.typ = Typ[Invalid]
+                       return
+               }
+               obj.typ = t
+       }
+
+       // check initialization
+       var x operand
+       if init != nil {
+               check.expr(&x, init)
+       }
+       check.initConst(obj, &x)
+}
+
+func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
+       assert(obj.typ == nil)
+
+       if obj.visited {
+               obj.typ = Typ[Invalid]
+               return
+       }
+       obj.visited = true
+
+       // var declarations cannot use iota
+       assert(check.iota == nil)
+
+       // determine type, if any
+       if typ != nil {
+               obj.typ = check.typ(typ)
+       }
+
+       // check initialization
+       if init == nil {
+               if typ == nil {
+                       // error reported before by arityMatch
+                       obj.typ = Typ[Invalid]
+               }
+               return
+       }
+
+       if lhs == nil || len(lhs) == 1 {
+               assert(lhs == nil || lhs[0] == obj)
+               var x operand
+               check.expr(&x, init)
+               check.initVar(obj, &x, false)
+               return
+       }
+
+       if debug {
+               // obj must be one of lhs
+               found := false
+               for _, lhs := range lhs {
+                       if obj == lhs {
+                               found = true
+                               break
+                       }
+               }
+               if !found {
+                       panic("inconsistent lhs")
+               }
+       }
+       check.initVars(lhs, []ast.Expr{init}, token.NoPos)
+}
+
+// underlying returns the underlying type of typ; possibly by following
+// forward chains of named types. Such chains only exist while named types
+// are incomplete.
+func underlying(typ Type) Type {
+       for {
+               n, _ := typ.(*Named)
+               if n == nil {
+                       break
+               }
+               typ = n.underlying
+       }
+       return typ
+}
+
+func (n *Named) setUnderlying(typ Type) {
+       if n != nil {
+               n.underlying = typ
+       }
+}
+
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
+       assert(obj.typ == nil)
+
+       // type declarations cannot use iota
+       assert(check.iota == nil)
+
+       named := &Named{obj: obj}
+       def.setUnderlying(named)
+       obj.typ = named // make sure recursive type declarations terminate
+
+       // determine underlying type of named
+       check.typExpr(typ, named, append(path, obj))
+
+       // The underlying type of named may be itself a named type that is
+       // incomplete:
+       //
+       //      type (
+       //              A B
+       //              B *C
+       //              C A
+       //      )
+       //
+       // The type of C is the (named) type of A which is incomplete,
+       // and which has as its underlying type the named type B.
+       // Determine the (final, unnamed) underlying type by resolving
+       // any forward chain (they always end in an unnamed type).
+       named.underlying = underlying(named.underlying)
+
+       // check and add associated methods
+       // TODO(gri) It's easy to create pathological cases where the
+       // current approach is incorrect: In general we need to know
+       // and add all methods _before_ type-checking the type.
+       // See http://play.golang.org/p/WMpE0q2wK8
+       check.addMethodDecls(obj)
+}
+
+func (check *Checker) addMethodDecls(obj *TypeName) {
+       // get associated methods
+       methods := check.methods[obj.name]
+       if len(methods) == 0 {
+               return // no methods
+       }
+       delete(check.methods, obj.name)
+
+       // use an objset to check for name conflicts
+       var mset objset
+
+       // spec: "If the base type is a struct type, the non-blank method
+       // and field names must be distinct."
+       base := obj.typ.(*Named)
+       if t, _ := base.underlying.(*Struct); t != nil {
+               for _, fld := range t.fields {
+                       if fld.name != "_" {
+                               assert(mset.insert(fld) == nil)
+                       }
+               }
+       }
+
+       // Checker.Files may be called multiple times; additional package files
+       // may add methods to already type-checked types. Add pre-existing methods
+       // so that we can detect redeclarations.
+       for _, m := range base.methods {
+               assert(m.name != "_")
+               assert(mset.insert(m) == nil)
+       }
+
+       // type-check methods
+       for _, m := range methods {
+               // spec: "For a base type, the non-blank names of methods bound
+               // to it must be unique."
+               if m.name != "_" {
+                       if alt := mset.insert(m); alt != nil {
+                               switch alt.(type) {
+                               case *Var:
+                                       check.errorf(m.pos, "field and method with the same name %s", m.name)
+                               case *Func:
+                                       check.errorf(m.pos, "method %s already declared for %s", m.name, base)
+                               default:
+                                       unreachable()
+                               }
+                               check.reportAltDecl(alt)
+                               continue
+                       }
+               }
+               check.objDecl(m, nil, nil)
+               // methods with blank _ names cannot be found - don't keep them
+               if m.name != "_" {
+                       base.methods = append(base.methods, m)
+               }
+       }
+}
+
+func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
+       assert(obj.typ == nil)
+
+       // func declarations cannot use iota
+       assert(check.iota == nil)
+
+       sig := new(Signature)
+       obj.typ = sig // guard against cycles
+       fdecl := decl.fdecl
+       check.funcType(sig, fdecl.Recv, fdecl.Type)
+       if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
+               check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
+               // ok to continue
+       }
+
+       // function body must be type-checked after global declarations
+       // (functions implemented elsewhere have no body)
+       if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
+               check.later(obj.name, decl, sig, fdecl.Body)
+       }
+}
+
+func (check *Checker) declStmt(decl ast.Decl) {
+       pkg := check.pkg
+
+       switch d := decl.(type) {
+       case *ast.BadDecl:
+               // ignore
+
+       case *ast.GenDecl:
+               var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+               for iota, spec := range d.Specs {
+                       switch s := spec.(type) {
+                       case *ast.ValueSpec:
+                               switch d.Tok {
+                               case token.CONST:
+                                       // determine which init exprs to use
+                                       switch {
+                                       case s.Type != nil || len(s.Values) > 0:
+                                               last = s
+                                       case last == nil:
+                                               last = new(ast.ValueSpec) // make sure last exists
+                                       }
+
+                                       // declare all constants
+                                       lhs := make([]*Const, len(s.Names))
+                                       for i, name := range s.Names {
+                                               obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
+                                               lhs[i] = obj
+
+                                               var init ast.Expr
+                                               if i < len(last.Values) {
+                                                       init = last.Values[i]
+                                               }
+
+                                               check.constDecl(obj, last.Type, init)
+                                       }
+
+                                       check.arityMatch(s, last)
+
+                                       for i, name := range s.Names {
+                                               check.declare(check.scope, name, lhs[i])
+                                       }
+
+                               case token.VAR:
+                                       lhs0 := make([]*Var, len(s.Names))
+                                       for i, name := range s.Names {
+                                               lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
+                                       }
+
+                                       // initialize all variables
+                                       for i, obj := range lhs0 {
+                                               var lhs []*Var
+                                               var init ast.Expr
+                                               switch len(s.Values) {
+                                               case len(s.Names):
+                                                       // lhs and rhs match
+                                                       init = s.Values[i]
+                                               case 1:
+                                                       // rhs is expected to be a multi-valued expression
+                                                       lhs = lhs0
+                                                       init = s.Values[0]
+                                               default:
+                                                       if i < len(s.Values) {
+                                                               init = s.Values[i]
+                                                       }
+                                               }
+                                               check.varDecl(obj, lhs, s.Type, init)
+                                               if len(s.Values) == 1 {
+                                                       // If we have a single lhs variable we are done either way.
+                                                       // If we have a single rhs expression, it must be a multi-
+                                                       // valued expression, in which case handling the first lhs
+                                                       // variable will cause all lhs variables to have a type
+                                                       // assigned, and we are done as well.
+                                                       if debug {
+                                                               for _, obj := range lhs0 {
+                                                                       assert(obj.typ != nil)
+                                                               }
+                                                       }
+                                                       break
+                                               }
+                                       }
+
+                                       check.arityMatch(s, nil)
+
+                                       // declare all variables
+                                       // (only at this point are the variable scopes (parents) set)
+                                       for i, name := range s.Names {
+                                               check.declare(check.scope, name, lhs0[i])
+                                       }
+
+                               default:
+                                       check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+                               }
+
+                       case *ast.TypeSpec:
+                               obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+                               check.declare(check.scope, s.Name, obj)
+                               check.typeDecl(obj, s.Type, nil, nil)
+
+                       default:
+                               check.invalidAST(s.Pos(), "const, type, or var declaration expected")
+                       }
+               }
+
+       default:
+               check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+       }
+}
diff --git a/src/go/types/errors.go b/src/go/types/errors.go
new file mode 100644 (file)
index 0000000..0a9dd0e
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements various error reporters.
+
+package types
+
+import (
+       "fmt"
+       "go/ast"
+       "go/token"
+       "strings"
+)
+
+func assert(p bool) {
+       if !p {
+               panic("assertion failed")
+       }
+}
+
+func unreachable() {
+       panic("unreachable")
+}
+
+func (check *Checker) sprintf(format string, args ...interface{}) string {
+       for i, arg := range args {
+               switch a := arg.(type) {
+               case nil:
+                       arg = "<nil>"
+               case operand:
+                       panic("internal error: should always pass *operand")
+               case *operand:
+                       arg = operandString(check.pkg, a)
+               case token.Pos:
+                       arg = check.fset.Position(a).String()
+               case ast.Expr:
+                       arg = ExprString(a)
+               case Object:
+                       arg = ObjectString(check.pkg, a)
+               case Type:
+                       arg = TypeString(check.pkg, a)
+               }
+               args[i] = arg
+       }
+       return fmt.Sprintf(format, args...)
+}
+
+func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) {
+       fmt.Printf("%s:\t%s%s\n",
+               check.fset.Position(pos),
+               strings.Repeat(".  ", check.indent),
+               check.sprintf(format, args...),
+       )
+}
+
+// dump is only needed for debugging
+func (check *Checker) dump(format string, args ...interface{}) {
+       fmt.Println(check.sprintf(format, args...))
+}
+
+func (check *Checker) err(pos token.Pos, msg string, soft bool) {
+       err := Error{check.fset, pos, msg, soft}
+       if check.firstErr == nil {
+               check.firstErr = err
+       }
+       f := check.conf.Error
+       if f == nil {
+               panic(bailout{}) // report only first error
+       }
+       f(err)
+}
+
+func (check *Checker) error(pos token.Pos, msg string) {
+       check.err(pos, msg, false)
+}
+
+func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) {
+       check.err(pos, check.sprintf(format, args...), false)
+}
+
+func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) {
+       check.err(pos, check.sprintf(format, args...), true)
+}
+
+func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) {
+       check.errorf(pos, "invalid AST: "+format, args...)
+}
+
+func (check *Checker) invalidArg(pos token.Pos, format string, args ...interface{}) {
+       check.errorf(pos, "invalid argument: "+format, args...)
+}
+
+func (check *Checker) invalidOp(pos token.Pos, format string, args ...interface{}) {
+       check.errorf(pos, "invalid operation: "+format, args...)
+}
diff --git a/src/go/types/eval.go b/src/go/types/eval.go
new file mode 100644 (file)
index 0000000..7fa319e
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements New, Eval and EvalNode.
+
+package types
+
+import (
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/token"
+)
+
+// New is a convenience function to create a new type from a given
+// expression or type literal string evaluated in Universe scope.
+// New(str) is shorthand for Eval(str, nil, nil), but only returns
+// the type result, and panics in case of an error.
+// Position info for objects in the result type is undefined.
+//
+func New(str string) Type {
+       tv, err := Eval(str, nil, nil)
+       if err != nil {
+               panic(err)
+       }
+       return tv.Type
+}
+
+// Eval returns the type and, if constant, the value for the
+// expression or type literal string str evaluated in scope.
+// If the expression contains function literals, the function
+// bodies are ignored (though they must be syntactically correct).
+//
+// If pkg == nil, the Universe scope is used and the provided
+// scope is ignored. Otherwise, the scope must belong to the
+// package (either the package scope, or nested within the
+// package scope).
+//
+// An error is returned if the scope is incorrect, the string
+// has syntax errors, or if it cannot be evaluated in the scope.
+// Position info for objects in the result type is undefined.
+//
+// Note: Eval should not be used instead of running Check to compute
+// types and values, but in addition to Check. Eval will re-evaluate
+// its argument each time, and it also does not know about the context
+// in which an expression is used (e.g., an assignment). Thus, top-
+// level untyped constants will return an untyped type rather then the
+// respective context-specific type.
+//
+func Eval(str string, pkg *Package, scope *Scope) (TypeAndValue, error) {
+       node, err := parser.ParseExpr(str)
+       if err != nil {
+               return TypeAndValue{}, err
+       }
+
+       // Create a file set that looks structurally identical to the
+       // one created by parser.ParseExpr for correct error positions.
+       fset := token.NewFileSet()
+       fset.AddFile("", len(str), fset.Base()).SetLinesForContent([]byte(str))
+
+       return EvalNode(fset, node, pkg, scope)
+}
+
+// EvalNode is like Eval but instead of string it accepts
+// an expression node and respective file set.
+//
+// An error is returned if the scope is incorrect
+// if the node cannot be evaluated in the scope.
+//
+func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (tv TypeAndValue, err error) {
+       // verify package/scope relationship
+       if pkg == nil {
+               scope = Universe
+       } else {
+               s := scope
+               for s != nil && s != pkg.scope {
+                       s = s.parent
+               }
+               // s == nil || s == pkg.scope
+               if s == nil {
+                       return TypeAndValue{}, fmt.Errorf("scope does not belong to package %s", pkg.name)
+               }
+       }
+
+       // initialize checker
+       check := NewChecker(nil, fset, pkg, nil)
+       check.scope = scope
+       defer check.handleBailout(&err)
+
+       // evaluate node
+       var x operand
+       check.rawExpr(&x, node, nil)
+       return TypeAndValue{x.mode, x.typ, x.val}, nil
+}
diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go
new file mode 100644 (file)
index 0000000..de350e0
--- /dev/null
@@ -0,0 +1,148 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for Eval.
+
+package types_test
+
+import (
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "strings"
+       "testing"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+func testEval(t *testing.T, pkg *Package, scope *Scope, str string, typ Type, typStr, valStr string) {
+       gotTv, err := Eval(str, pkg, scope)
+       if err != nil {
+               t.Errorf("Eval(%q) failed: %s", str, err)
+               return
+       }
+       if gotTv.Type == nil {
+               t.Errorf("Eval(%q) got nil type but no error", str)
+               return
+       }
+
+       // compare types
+       if typ != nil {
+               // we have a type, check identity
+               if !Identical(gotTv.Type, typ) {
+                       t.Errorf("Eval(%q) got type %s, want %s", str, gotTv.Type, typ)
+                       return
+               }
+       } else {
+               // we have a string, compare type string
+               gotStr := gotTv.Type.String()
+               if gotStr != typStr {
+                       t.Errorf("Eval(%q) got type %s, want %s", str, gotStr, typStr)
+                       return
+               }
+       }
+
+       // compare values
+       gotStr := ""
+       if gotTv.Value != nil {
+               gotStr = gotTv.Value.String()
+       }
+       if gotStr != valStr {
+               t.Errorf("Eval(%q) got value %s, want %s", str, gotStr, valStr)
+       }
+}
+
+func TestEvalBasic(t *testing.T) {
+       for _, typ := range Typ[Bool : String+1] {
+               testEval(t, nil, nil, typ.Name(), typ, "", "")
+       }
+}
+
+func TestEvalComposite(t *testing.T) {
+       for _, test := range independentTestTypes {
+               testEval(t, nil, nil, test.src, nil, test.str, "")
+       }
+}
+
+func TestEvalArith(t *testing.T) {
+       var tests = []string{
+               `true`,
+               `false == false`,
+               `12345678 + 87654321 == 99999999`,
+               `10 * 20 == 200`,
+               `(1<<1000)*2 >> 100 == 2<<900`,
+               `"foo" + "bar" == "foobar"`,
+               `"abc" <= "bcd"`,
+               `len([10]struct{}{}) == 2*5`,
+       }
+       for _, test := range tests {
+               testEval(t, nil, nil, test, Typ[UntypedBool], "", "true")
+       }
+}
+
+func TestEvalContext(t *testing.T) {
+       src := `
+package p
+import "fmt"
+import m "math"
+const c = 3.0
+type T []int
+func f(a int, s string) float64 {
+       fmt.Println("calling f")
+       _ = m.Pi // use package math
+       const d int = c + 1
+       var x int
+       x = a + len(s)
+       return float64(x)
+}
+`
+       fset := token.NewFileSet()
+       file, err := parser.ParseFile(fset, "p", src, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       pkg, err := Check("p", fset, []*ast.File{file})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       pkgScope := pkg.Scope()
+       if n := pkgScope.NumChildren(); n != 1 {
+               t.Fatalf("got %d file scopes, want 1", n)
+       }
+
+       fileScope := pkgScope.Child(0)
+       if n := fileScope.NumChildren(); n != 1 {
+               t.Fatalf("got %d functions scopes, want 1", n)
+       }
+
+       funcScope := fileScope.Child(0)
+
+       var tests = []string{
+               `true => true, untyped bool`,
+               `fmt.Println => , func(a ...interface{}) (n int, err error)`,
+               `c => 3, untyped float`,
+               `T => , p.T`,
+               `a => , int`,
+               `s => , string`,
+               `d => 4, int`,
+               `x => , int`,
+               `d/c => 1, int`,
+               `c/2 => 3/2, untyped float`,
+               `m.Pi < m.E => false, untyped bool`,
+       }
+       for _, test := range tests {
+               str, typ := split(test, ", ")
+               str, val := split(str, "=>")
+               testEval(t, pkg, funcScope, str, nil, typ, val)
+       }
+}
+
+// split splits string s at the first occurrence of s.
+func split(s, sep string) (string, string) {
+       i := strings.Index(s, sep)
+       return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
+}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
new file mode 100644 (file)
index 0000000..8acdd78
--- /dev/null
@@ -0,0 +1,1483 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements typechecking of expressions.
+
+package types
+
+import (
+       "fmt"
+       "go/ast"
+       "go/token"
+       "math"
+
+       "go/exact"
+)
+
+/*
+Basic algorithm:
+
+Expressions are checked recursively, top down. Expression checker functions
+are generally of the form:
+
+  func f(x *operand, e *ast.Expr, ...)
+
+where e is the expression to be checked, and x is the result of the check.
+The check performed by f may fail in which case x.mode == invalid, and
+related error messages will have been issued by f.
+
+If a hint argument is present, it is the composite literal element type
+of an outer composite literal; it is used to type-check composite literal
+elements that have no explicit type specification in the source
+(e.g.: []T{{...}, {...}}, the hint is the type T in this case).
+
+All expressions are checked via rawExpr, which dispatches according
+to expression kind. Upon returning, rawExpr is recording the types and
+constant values for all expressions that have an untyped type (those types
+may change on the way up in the expression tree). Usually these are constants,
+but the results of comparisons or non-constant shifts of untyped constants
+may also be untyped, but not constant.
+
+Untyped expressions may eventually become fully typed (i.e., not untyped),
+typically when the value is assigned to a variable, or is used otherwise.
+The updateExprType method is used to record this final type and update
+the recorded types: the type-checked expression tree is again traversed down,
+and the new type is propagated as needed. Untyped constant expression values
+that become fully typed must now be representable by the full type (constant
+sub-expression trees are left alone except for their roots). This mechanism
+ensures that a client sees the actual (run-time) type an untyped value would
+have. It also permits type-checking of lhs shift operands "as if the shift
+were not present": when updateExprType visits an untyped lhs shift operand
+and assigns it it's final type, that type must be an integer type, and a
+constant lhs must be representable as an integer.
+
+When an expression gets its final type, either on the way out from rawExpr,
+on the way down in updateExprType, or at the end of the type checker run,
+the type (and constant value, if any) is recorded via Info.Types, if present.
+*/
+
+type opPredicates map[token.Token]func(Type) bool
+
+var unaryOpPredicates = opPredicates{
+       token.ADD: isNumeric,
+       token.SUB: isNumeric,
+       token.XOR: isInteger,
+       token.NOT: isBoolean,
+}
+
+func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
+       if pred := m[op]; pred != nil {
+               if !pred(x.typ) {
+                       check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
+                       return false
+               }
+       } else {
+               check.invalidAST(x.pos(), "unknown operator %s", op)
+               return false
+       }
+       return true
+}
+
+func (check *Checker) unary(x *operand, op token.Token) {
+       switch op {
+       case token.AND:
+               // spec: "As an exception to the addressability
+               // requirement x may also be a composite literal."
+               if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable {
+                       check.invalidOp(x.pos(), "cannot take address of %s", x)
+                       x.mode = invalid
+                       return
+               }
+               x.mode = value
+               x.typ = &Pointer{base: x.typ}
+               return
+
+       case token.ARROW:
+               typ, ok := x.typ.Underlying().(*Chan)
+               if !ok {
+                       check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
+                       x.mode = invalid
+                       return
+               }
+               if typ.dir == SendOnly {
+                       check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
+                       x.mode = invalid
+                       return
+               }
+               x.mode = commaok
+               x.typ = typ.elem
+               check.hasCallOrRecv = true
+               return
+       }
+
+       if !check.op(unaryOpPredicates, x, op) {
+               x.mode = invalid
+               return
+       }
+
+       if x.mode == constant {
+               typ := x.typ.Underlying().(*Basic)
+               size := -1
+               if isUnsigned(typ) {
+                       size = int(check.conf.sizeof(typ))
+               }
+               x.val = exact.UnaryOp(op, x.val, size)
+               // Typed constants must be representable in
+               // their type after each constant operation.
+               if isTyped(typ) {
+                       check.representable(x, typ)
+               }
+               return
+       }
+
+       x.mode = value
+       // x.typ remains unchanged
+}
+
+func isShift(op token.Token) bool {
+       return op == token.SHL || op == token.SHR
+}
+
+func isComparison(op token.Token) bool {
+       // Note: tokens are not ordered well to make this much easier
+       switch op {
+       case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+               return true
+       }
+       return false
+}
+
+func fitsFloat32(x exact.Value) bool {
+       f32, _ := exact.Float32Val(x)
+       f := float64(f32)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat32(x exact.Value) exact.Value {
+       f32, _ := exact.Float32Val(x)
+       f := float64(f32)
+       if !math.IsInf(f, 0) {
+               return exact.MakeFloat64(f)
+       }
+       return nil
+}
+
+func fitsFloat64(x exact.Value) bool {
+       f, _ := exact.Float64Val(x)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat64(x exact.Value) exact.Value {
+       f, _ := exact.Float64Val(x)
+       if !math.IsInf(f, 0) {
+               return exact.MakeFloat64(f)
+       }
+       return nil
+}
+
+// representableConst reports whether x can be represented as
+// value of the given basic type kind and for the configuration
+// provided (only needed for int/uint sizes).
+//
+// If rounded != nil, *rounded is set to the rounded value of x for
+// representable floating-point values; it is left alone otherwise.
+// It is ok to provide the addressof the first argument for rounded.
+func representableConst(x exact.Value, conf *Config, as BasicKind, rounded *exact.Value) bool {
+       switch x.Kind() {
+       case exact.Unknown:
+               return true
+
+       case exact.Bool:
+               return as == Bool || as == UntypedBool
+
+       case exact.Int:
+               if x, ok := exact.Int64Val(x); ok {
+                       switch as {
+                       case Int:
+                               var s = uint(conf.sizeof(Typ[as])) * 8
+                               return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
+                       case Int8:
+                               const s = 8
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int16:
+                               const s = 16
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int32:
+                               const s = 32
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int64:
+                               return true
+                       case Uint, Uintptr:
+                               if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 {
+                                       return 0 <= x && x <= int64(1)<<s-1
+                               }
+                               return 0 <= x
+                       case Uint8:
+                               const s = 8
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint16:
+                               const s = 16
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint32:
+                               const s = 32
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint64:
+                               return 0 <= x
+                       case Float32, Float64, Complex64, Complex128,
+                               UntypedInt, UntypedFloat, UntypedComplex:
+                               return true
+                       }
+               }
+
+               n := exact.BitLen(x)
+               switch as {
+               case Uint, Uintptr:
+                       var s = uint(conf.sizeof(Typ[as])) * 8
+                       return exact.Sign(x) >= 0 && n <= int(s)
+               case Uint64:
+                       return exact.Sign(x) >= 0 && n <= 64
+               case Float32, Complex64:
+                       if rounded == nil {
+                               return fitsFloat32(x)
+                       }
+                       r := roundFloat32(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case Float64, Complex128:
+                       if rounded == nil {
+                               return fitsFloat64(x)
+                       }
+                       r := roundFloat64(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case UntypedInt, UntypedFloat, UntypedComplex:
+                       return true
+               }
+
+       case exact.Float:
+               switch as {
+               case Float32, Complex64:
+                       if rounded == nil {
+                               return fitsFloat32(x)
+                       }
+                       r := roundFloat32(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case Float64, Complex128:
+                       if rounded == nil {
+                               return fitsFloat64(x)
+                       }
+                       r := roundFloat64(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case UntypedFloat, UntypedComplex:
+                       return true
+               }
+
+       case exact.Complex:
+               switch as {
+               case Complex64:
+                       if rounded == nil {
+                               return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x))
+                       }
+                       re := roundFloat32(exact.Real(x))
+                       im := roundFloat32(exact.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+                               return true
+                       }
+               case Complex128:
+                       if rounded == nil {
+                               return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x))
+                       }
+                       re := roundFloat64(exact.Real(x))
+                       im := roundFloat64(exact.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+                               return true
+                       }
+               case UntypedComplex:
+                       return true
+               }
+
+       case exact.String:
+               return as == String || as == UntypedString
+
+       default:
+               unreachable()
+       }
+
+       return false
+}
+
+// representable checks that a constant operand is representable in the given basic type.
+func (check *Checker) representable(x *operand, typ *Basic) {
+       assert(x.mode == constant)
+       if !representableConst(x.val, check.conf, typ.kind, &x.val) {
+               var msg string
+               if isNumeric(x.typ) && isNumeric(typ) {
+                       // numeric conversion : error msg
+                       //
+                       // integer -> integer : overflows
+                       // integer -> float   : overflows (actually not possible)
+                       // float   -> integer : truncated
+                       // float   -> float   : overflows
+                       //
+                       if !isInteger(x.typ) && isInteger(typ) {
+                               msg = "%s truncated to %s"
+                       } else {
+                               msg = "%s overflows %s"
+                       }
+               } else {
+                       msg = "cannot convert %s to %s"
+               }
+               check.errorf(x.pos(), msg, x, typ)
+               x.mode = invalid
+       }
+}
+
+// updateExprType updates the type of x to typ and invokes itself
+// recursively for the operands of x, depending on expression kind.
+// If typ is still an untyped and not the final type, updateExprType
+// only updates the recorded untyped type for x and possibly its
+// operands. Otherwise (i.e., typ is not an untyped type anymore,
+// or it is the final type for x), the type and value are recorded.
+// Also, if x is a constant, it must be representable as a value of typ,
+// and if x is the (formerly untyped) lhs operand of a non-constant
+// shift, it must be an integer value.
+//
+func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
+       old, found := check.untyped[x]
+       if !found {
+               return // nothing to do
+       }
+
+       // update operands of x if necessary
+       switch x := x.(type) {
+       case *ast.BadExpr,
+               *ast.FuncLit,
+               *ast.CompositeLit,
+               *ast.IndexExpr,
+               *ast.SliceExpr,
+               *ast.TypeAssertExpr,
+               *ast.StarExpr,
+               *ast.KeyValueExpr,
+               *ast.ArrayType,
+               *ast.StructType,
+               *ast.FuncType,
+               *ast.InterfaceType,
+               *ast.MapType,
+               *ast.ChanType:
+               // These expression are never untyped - nothing to do.
+               // The respective sub-expressions got their final types
+               // upon assignment or use.
+               if debug {
+                       check.dump("%s: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ)
+                       unreachable()
+               }
+               return
+
+       case *ast.CallExpr:
+               // Resulting in an untyped constant (e.g., built-in complex).
+               // The respective calls take care of calling updateExprType
+               // for the arguments if necessary.
+
+       case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
+               // An identifier denoting a constant, a constant literal,
+               // or a qualified identifier (imported untyped constant).
+               // No operands to take care of.
+
+       case *ast.ParenExpr:
+               check.updateExprType(x.X, typ, final)
+
+       case *ast.UnaryExpr:
+               // If x is a constant, the operands were constants.
+               // They don't need to be updated since they never
+               // get "materialized" into a typed value; and they
+               // will be processed at the end of the type check.
+               if old.val != nil {
+                       break
+               }
+               check.updateExprType(x.X, typ, final)
+
+       case *ast.BinaryExpr:
+               if old.val != nil {
+                       break // see comment for unary expressions
+               }
+               if isComparison(x.Op) {
+                       // The result type is independent of operand types
+                       // and the operand types must have final types.
+               } else if isShift(x.Op) {
+                       // The result type depends only on lhs operand.
+                       // The rhs type was updated when checking the shift.
+                       check.updateExprType(x.X, typ, final)
+               } else {
+                       // The operand types match the result type.
+                       check.updateExprType(x.X, typ, final)
+                       check.updateExprType(x.Y, typ, final)
+               }
+
+       default:
+               unreachable()
+       }
+
+       // If the new type is not final and still untyped, just
+       // update the recorded type.
+       if !final && isUntyped(typ) {
+               old.typ = typ.Underlying().(*Basic)
+               check.untyped[x] = old
+               return
+       }
+
+       // Otherwise we have the final (typed or untyped type).
+       // Remove it from the map of yet untyped expressions.
+       delete(check.untyped, x)
+
+       // If x is the lhs of a shift, its final type must be integer.
+       // We already know from the shift check that it is representable
+       // as an integer if it is a constant.
+       if old.isLhs && !isInteger(typ) {
+               check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
+               return
+       }
+
+       // Everything's fine, record final type and value for x.
+       check.recordTypeAndValue(x, old.mode, typ, old.val)
+}
+
+// updateExprVal updates the value of x to val.
+func (check *Checker) updateExprVal(x ast.Expr, val exact.Value) {
+       if info, ok := check.untyped[x]; ok {
+               info.val = val
+               check.untyped[x] = info
+       }
+}
+
+// convertUntyped attempts to set the type of an untyped value to the target type.
+func (check *Checker) convertUntyped(x *operand, target Type) {
+       if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
+               return
+       }
+
+       // TODO(gri) Sloppy code - clean up. This function is central
+       //           to assignment and expression checking.
+
+       if isUntyped(target) {
+               // both x and target are untyped
+               xkind := x.typ.(*Basic).kind
+               tkind := target.(*Basic).kind
+               if isNumeric(x.typ) && isNumeric(target) {
+                       if xkind < tkind {
+                               x.typ = target
+                               check.updateExprType(x.expr, target, false)
+                       }
+               } else if xkind != tkind {
+                       goto Error
+               }
+               return
+       }
+
+       // typed target
+       switch t := target.Underlying().(type) {
+       case *Basic:
+               if x.mode == constant {
+                       check.representable(x, t)
+                       if x.mode == invalid {
+                               return
+                       }
+                       // expression value may have been rounded - update if needed
+                       // TODO(gri) A floating-point value may silently underflow to
+                       // zero. If it was negative, the sign is lost. See issue 6898.
+                       check.updateExprVal(x.expr, x.val)
+               } else {
+                       // Non-constant untyped values may appear as the
+                       // result of comparisons (untyped bool), intermediate
+                       // (delayed-checked) rhs operands of shifts, and as
+                       // the value nil.
+                       switch x.typ.(*Basic).kind {
+                       case UntypedBool:
+                               if !isBoolean(target) {
+                                       goto Error
+                               }
+                       case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
+                               if !isNumeric(target) {
+                                       goto Error
+                               }
+                       case UntypedString:
+                               // Non-constant untyped string values are not
+                               // permitted by the spec and should not occur.
+                               unreachable()
+                       case UntypedNil:
+                               // Unsafe.Pointer is a basic type that includes nil.
+                               if !hasNil(target) {
+                                       goto Error
+                               }
+                       default:
+                               goto Error
+                       }
+               }
+       case *Interface:
+               if !x.isNil() && !t.Empty() /* empty interfaces are ok */ {
+                       goto Error
+               }
+               // Update operand types to the default type rather then
+               // the target (interface) type: values must have concrete
+               // dynamic types. If the value is nil, keep it untyped
+               // (this is important for tools such as go vet which need
+               // the dynamic type for argument checking of say, print
+               // functions)
+               if x.isNil() {
+                       target = Typ[UntypedNil]
+               } else {
+                       // cannot assign untyped values to non-empty interfaces
+                       if !t.Empty() {
+                               goto Error
+                       }
+                       target = defaultType(x.typ)
+               }
+       case *Pointer, *Signature, *Slice, *Map, *Chan:
+               if !x.isNil() {
+                       goto Error
+               }
+               // keep nil untyped - see comment for interfaces, above
+               target = Typ[UntypedNil]
+       default:
+               goto Error
+       }
+
+       x.typ = target
+       check.updateExprType(x.expr, target, true) // UntypedNils are final
+       return
+
+Error:
+       check.errorf(x.pos(), "cannot convert %s to %s", x, target)
+       x.mode = invalid
+}
+
+func (check *Checker) comparison(x, y *operand, op token.Token) {
+       // spec: "In any comparison, the first operand must be assignable
+       // to the type of the second operand, or vice versa."
+       err := ""
+       if x.assignableTo(check.conf, y.typ) || y.assignableTo(check.conf, x.typ) {
+               defined := false
+               switch op {
+               case token.EQL, token.NEQ:
+                       // spec: "The equality operators == and != apply to operands that are comparable."
+                       defined = Comparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
+               case token.LSS, token.LEQ, token.GTR, token.GEQ:
+                       // spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
+                       defined = isOrdered(x.typ)
+               default:
+                       unreachable()
+               }
+               if !defined {
+                       typ := x.typ
+                       if x.isNil() {
+                               typ = y.typ
+                       }
+                       err = check.sprintf("operator %s not defined for %s", op, typ)
+               }
+       } else {
+               err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
+       }
+
+       if err != "" {
+               check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
+               x.mode = invalid
+               return
+       }
+
+       if x.mode == constant && y.mode == constant {
+               x.val = exact.MakeBool(exact.Compare(x.val, op, y.val))
+               // The operands are never materialized; no need to update
+               // their types.
+       } else {
+               x.mode = value
+               // The operands have now their final types, which at run-
+               // time will be materialized. Update the expression trees.
+               // If the current types are untyped, the materialized type
+               // is the respective default type.
+               check.updateExprType(x.expr, defaultType(x.typ), true)
+               check.updateExprType(y.expr, defaultType(y.typ), true)
+       }
+
+       // spec: "Comparison operators compare two operands and yield
+       //        an untyped boolean value."
+       x.typ = Typ[UntypedBool]
+}
+
+func (check *Checker) shift(x, y *operand, op token.Token) {
+       untypedx := isUntyped(x.typ)
+
+       // The lhs must be of integer type or be representable
+       // as an integer; otherwise the shift has no chance.
+       if !isInteger(x.typ) && (!untypedx || !representableConst(x.val, nil, UntypedInt, nil)) {
+               check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+               x.mode = invalid
+               return
+       }
+
+       // spec: "The right operand in a shift expression must have unsigned
+       // integer type or be an untyped constant that can be converted to
+       // unsigned integer type."
+       switch {
+       case isInteger(y.typ) && isUnsigned(y.typ):
+               // nothing to do
+       case isUntyped(y.typ):
+               check.convertUntyped(y, Typ[UntypedInt])
+               if y.mode == invalid {
+                       x.mode = invalid
+                       return
+               }
+       default:
+               check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
+               x.mode = invalid
+               return
+       }
+
+       if x.mode == constant {
+               if y.mode == constant {
+                       // rhs must be within reasonable bounds
+                       const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
+                       s, ok := exact.Uint64Val(y.val)
+                       if !ok || s > stupidShift {
+                               check.invalidOp(y.pos(), "stupid shift count %s", y)
+                               x.mode = invalid
+                               return
+                       }
+                       // The lhs is representable as an integer but may not be an integer
+                       // (e.g., 2.0, an untyped float) - this can only happen for untyped
+                       // non-integer numeric constants. Correct the type so that the shift
+                       // result is of integer type.
+                       if !isInteger(x.typ) {
+                               x.typ = Typ[UntypedInt]
+                       }
+                       x.val = exact.Shift(x.val, op, uint(s))
+                       return
+               }
+
+               // non-constant shift with constant lhs
+               if untypedx {
+                       // spec: "If the left operand of a non-constant shift
+                       // expression is an untyped constant, the type of the
+                       // constant is what it would be if the shift expression
+                       // were replaced by its left operand alone.".
+                       //
+                       // Delay operand checking until we know the final type:
+                       // The lhs expression must be in the untyped map, mark
+                       // the entry as lhs shift operand.
+                       info, found := check.untyped[x.expr]
+                       assert(found)
+                       info.isLhs = true
+                       check.untyped[x.expr] = info
+                       // keep x's type
+                       x.mode = value
+                       return
+               }
+       }
+
+       // constant rhs must be >= 0
+       if y.mode == constant && exact.Sign(y.val) < 0 {
+               check.invalidOp(y.pos(), "shift count %s must not be negative", y)
+       }
+
+       // non-constant shift - lhs must be an integer
+       if !isInteger(x.typ) {
+               check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+               x.mode = invalid
+               return
+       }
+
+       x.mode = value
+}
+
+var binaryOpPredicates = opPredicates{
+       token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) },
+       token.SUB: isNumeric,
+       token.MUL: isNumeric,
+       token.QUO: isNumeric,
+       token.REM: isInteger,
+
+       token.AND:     isInteger,
+       token.OR:      isInteger,
+       token.XOR:     isInteger,
+       token.AND_NOT: isInteger,
+
+       token.LAND: isBoolean,
+       token.LOR:  isBoolean,
+}
+
+func (check *Checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token) {
+       var y operand
+
+       check.expr(x, lhs)
+       check.expr(&y, rhs)
+
+       if x.mode == invalid {
+               return
+       }
+       if y.mode == invalid {
+               x.mode = invalid
+               x.expr = y.expr
+               return
+       }
+
+       if isShift(op) {
+               check.shift(x, &y, op)
+               return
+       }
+
+       check.convertUntyped(x, y.typ)
+       if x.mode == invalid {
+               return
+       }
+       check.convertUntyped(&y, x.typ)
+       if y.mode == invalid {
+               x.mode = invalid
+               return
+       }
+
+       if isComparison(op) {
+               check.comparison(x, &y, op)
+               return
+       }
+
+       if !Identical(x.typ, y.typ) {
+               // only report an error if we have valid types
+               // (otherwise we had an error reported elsewhere already)
+               if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
+                       check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+               }
+               x.mode = invalid
+               return
+       }
+
+       if !check.op(binaryOpPredicates, x, op) {
+               x.mode = invalid
+               return
+       }
+
+       if (op == token.QUO || op == token.REM) && (x.mode == constant || isInteger(x.typ)) && y.mode == constant && exact.Sign(y.val) == 0 {
+               check.invalidOp(y.pos(), "division by zero")
+               x.mode = invalid
+               return
+       }
+
+       if x.mode == constant && y.mode == constant {
+               typ := x.typ.Underlying().(*Basic)
+               // force integer division of integer operands
+               if op == token.QUO && isInteger(typ) {
+                       op = token.QUO_ASSIGN
+               }
+               x.val = exact.BinaryOp(x.val, op, y.val)
+               // Typed constants must be representable in
+               // their type after each constant operation.
+               if isTyped(typ) {
+                       check.representable(x, typ)
+               }
+               return
+       }
+
+       x.mode = value
+       // x.typ is unchanged
+}
+
+// index checks an index expression for validity.
+// If max >= 0, it is the upper bound for index.
+// If index is valid and the result i >= 0, then i is the constant value of index.
+func (check *Checker) index(index ast.Expr, max int64) (i int64, valid bool) {
+       var x operand
+       check.expr(&x, index)
+       if x.mode == invalid {
+               return
+       }
+
+       // an untyped constant must be representable as Int
+       check.convertUntyped(&x, Typ[Int])
+       if x.mode == invalid {
+               return
+       }
+
+       // the index must be of integer type
+       if !isInteger(x.typ) {
+               check.invalidArg(x.pos(), "index %s must be integer", &x)
+               return
+       }
+
+       // a constant index i must be in bounds
+       if x.mode == constant {
+               if exact.Sign(x.val) < 0 {
+                       check.invalidArg(x.pos(), "index %s must not be negative", &x)
+                       return
+               }
+               i, valid = exact.Int64Val(x.val)
+               if !valid || max >= 0 && i >= max {
+                       check.errorf(x.pos(), "index %s is out of bounds", &x)
+                       return i, false
+               }
+               // 0 <= i [ && i < max ]
+               return i, true
+       }
+
+       return -1, true
+}
+
+// indexElts checks the elements (elts) of an array or slice composite literal
+// against the literal's element type (typ), and the element indices against
+// the literal length if known (length >= 0). It returns the length of the
+// literal (maximum index value + 1).
+//
+func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 {
+       visited := make(map[int64]bool, len(elts))
+       var index, max int64
+       for _, e := range elts {
+               // determine and check index
+               validIndex := false
+               eval := e
+               if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+                       if i, ok := check.index(kv.Key, length); ok {
+                               if i >= 0 {
+                                       index = i
+                                       validIndex = true
+                               } else {
+                                       check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
+                               }
+                       }
+                       eval = kv.Value
+               } else if length >= 0 && index >= length {
+                       check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
+               } else {
+                       validIndex = true
+               }
+
+               // if we have a valid index, check for duplicate entries
+               if validIndex {
+                       if visited[index] {
+                               check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
+                       }
+                       visited[index] = true
+               }
+               index++
+               if index > max {
+                       max = index
+               }
+
+               // check element against composite literal element type
+               var x operand
+               check.exprWithHint(&x, eval, typ)
+               if !check.assignment(&x, typ) && x.mode != invalid {
+                       check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
+               }
+       }
+       return max
+}
+
+// exprKind describes the kind of an expression; the kind
+// determines if an expression is valid in 'statement context'.
+type exprKind int
+
+const (
+       conversion exprKind = iota
+       expression
+       statement
+)
+
+// rawExpr typechecks expression e and initializes x with the expression
+// value or type. If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
+       if trace {
+               check.trace(e.Pos(), "%s", e)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(e.Pos(), "=> %s", x)
+               }()
+       }
+
+       kind := check.exprInternal(x, e, hint)
+
+       // convert x into a user-friendly set of values
+       // TODO(gri) this code can be simplified
+       var typ Type
+       var val exact.Value
+       switch x.mode {
+       case invalid:
+               typ = Typ[Invalid]
+       case novalue:
+               typ = (*Tuple)(nil)
+       case constant:
+               typ = x.typ
+               val = x.val
+       default:
+               typ = x.typ
+       }
+       assert(x.expr != nil && typ != nil)
+
+       if isUntyped(typ) {
+               // delay type and value recording until we know the type
+               // or until the end of type checking
+               check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
+       } else {
+               check.recordTypeAndValue(e, x.mode, typ, val)
+       }
+
+       return kind
+}
+
+// exprInternal contains the core of type checking of expressions.
+// Must only be called by rawExpr.
+//
+func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
+       // make sure x has a valid state in case of bailout
+       // (was issue 5770)
+       x.mode = invalid
+       x.typ = Typ[Invalid]
+
+       switch e := e.(type) {
+       case *ast.BadExpr:
+               goto Error // error was reported before
+
+       case *ast.Ident:
+               check.ident(x, e, nil, nil)
+
+       case *ast.Ellipsis:
+               // ellipses are handled explicitly where they are legal
+               // (array composite literals and parameter lists)
+               check.error(e.Pos(), "invalid use of '...'")
+               goto Error
+
+       case *ast.BasicLit:
+               x.setConst(e.Kind, e.Value)
+               if x.mode == invalid {
+                       check.invalidAST(e.Pos(), "invalid literal %v", e.Value)
+                       goto Error
+               }
+
+       case *ast.FuncLit:
+               if sig, ok := check.typ(e.Type).(*Signature); ok {
+                       // Anonymous functions are considered part of the
+                       // init expression/func declaration which contains
+                       // them: use existing package-level declaration info.
+                       check.funcBody(check.decl, "", sig, e.Body)
+                       x.mode = value
+                       x.typ = sig
+               } else {
+                       check.invalidAST(e.Pos(), "invalid function literal %s", e)
+                       goto Error
+               }
+
+       case *ast.CompositeLit:
+               typ := hint
+               openArray := false
+               if e.Type != nil {
+                       // [...]T array types may only appear with composite literals.
+                       // Check for them here so we don't have to handle ... in general.
+                       typ = nil
+                       if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
+                               if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
+                                       // We have an "open" [...]T array type.
+                                       // Create a new ArrayType with unknown length (-1)
+                                       // and finish setting it up after analyzing the literal.
+                                       typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
+                                       openArray = true
+                               }
+                       }
+                       if typ == nil {
+                               typ = check.typ(e.Type)
+                       }
+               }
+               if typ == nil {
+                       // TODO(gri) provide better error messages depending on context
+                       check.error(e.Pos(), "missing type in composite literal")
+                       goto Error
+               }
+
+               switch typ, _ := deref(typ); utyp := typ.Underlying().(type) {
+               case *Struct:
+                       if len(e.Elts) == 0 {
+                               break
+                       }
+                       fields := utyp.fields
+                       if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
+                               // all elements must have keys
+                               visited := make([]bool, len(fields))
+                               for _, e := range e.Elts {
+                                       kv, _ := e.(*ast.KeyValueExpr)
+                                       if kv == nil {
+                                               check.error(e.Pos(), "mixture of field:value and value elements in struct literal")
+                                               continue
+                                       }
+                                       key, _ := kv.Key.(*ast.Ident)
+                                       if key == nil {
+                                               check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
+                                               continue
+                                       }
+                                       i := fieldIndex(utyp.fields, check.pkg, key.Name)
+                                       if i < 0 {
+                                               check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
+                                               continue
+                                       }
+                                       fld := fields[i]
+                                       check.recordUse(key, fld)
+                                       // 0 <= i < len(fields)
+                                       if visited[i] {
+                                               check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
+                                               continue
+                                       }
+                                       visited[i] = true
+                                       check.expr(x, kv.Value)
+                                       etyp := fld.typ
+                                       if !check.assignment(x, etyp) {
+                                               if x.mode != invalid {
+                                                       check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+                                               }
+                                               continue
+                                       }
+                               }
+                       } else {
+                               // no element must have a key
+                               for i, e := range e.Elts {
+                                       if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+                                               check.error(kv.Pos(), "mixture of field:value and value elements in struct literal")
+                                               continue
+                                       }
+                                       check.expr(x, e)
+                                       if i >= len(fields) {
+                                               check.error(x.pos(), "too many values in struct literal")
+                                               break // cannot continue
+                                       }
+                                       // i < len(fields)
+                                       fld := fields[i]
+                                       if !fld.Exported() && fld.pkg != check.pkg {
+                                               check.errorf(x.pos(), "implicit assignment to unexported field %s in %s literal", fld.name, typ)
+                                               continue
+                                       }
+                                       etyp := fld.typ
+                                       if !check.assignment(x, etyp) {
+                                               if x.mode != invalid {
+                                                       check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+                                               }
+                                               continue
+                                       }
+                               }
+                               if len(e.Elts) < len(fields) {
+                                       check.error(e.Rbrace, "too few values in struct literal")
+                                       // ok to continue
+                               }
+                       }
+
+               case *Array:
+                       n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
+                       // if we have an "open" [...]T array, set the length now that we know it
+                       if openArray {
+                               utyp.len = n
+                       }
+
+               case *Slice:
+                       check.indexedElts(e.Elts, utyp.elem, -1)
+
+               case *Map:
+                       visited := make(map[interface{}][]Type, len(e.Elts))
+                       for _, e := range e.Elts {
+                               kv, _ := e.(*ast.KeyValueExpr)
+                               if kv == nil {
+                                       check.error(e.Pos(), "missing key in map literal")
+                                       continue
+                               }
+                               check.exprWithHint(x, kv.Key, utyp.key)
+                               if !check.assignment(x, utyp.key) {
+                                       if x.mode != invalid {
+                                               check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key)
+                                       }
+                                       continue
+                               }
+                               if x.mode == constant {
+                                       duplicate := false
+                                       // if the key is of interface type, the type is also significant when checking for duplicates
+                                       if _, ok := utyp.key.Underlying().(*Interface); ok {
+                                               for _, vtyp := range visited[x.val] {
+                                                       if Identical(vtyp, x.typ) {
+                                                               duplicate = true
+                                                               break
+                                                       }
+                                               }
+                                               visited[x.val] = append(visited[x.val], x.typ)
+                                       } else {
+                                               _, duplicate = visited[x.val]
+                                               visited[x.val] = nil
+                                       }
+                                       if duplicate {
+                                               check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
+                                               continue
+                                       }
+                               }
+                               check.exprWithHint(x, kv.Value, utyp.elem)
+                               if !check.assignment(x, utyp.elem) {
+                                       if x.mode != invalid {
+                                               check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elem)
+                                       }
+                                       continue
+                               }
+                       }
+
+               default:
+                       // if utyp is invalid, an error was reported before
+                       if utyp != Typ[Invalid] {
+                               check.errorf(e.Pos(), "invalid composite literal type %s", typ)
+                               goto Error
+                       }
+               }
+
+               x.mode = value
+               x.typ = typ
+
+       case *ast.ParenExpr:
+               kind := check.rawExpr(x, e.X, nil)
+               x.expr = e
+               return kind
+
+       case *ast.SelectorExpr:
+               check.selector(x, e)
+
+       case *ast.IndexExpr:
+               check.expr(x, e.X)
+               if x.mode == invalid {
+                       goto Error
+               }
+
+               valid := false
+               length := int64(-1) // valid if >= 0
+               switch typ := x.typ.Underlying().(type) {
+               case *Basic:
+                       if isString(typ) {
+                               valid = true
+                               if x.mode == constant {
+                                       length = int64(len(exact.StringVal(x.val)))
+                               }
+                               // an indexed string always yields a byte value
+                               // (not a constant) even if the string and the
+                               // index are constant
+                               x.mode = value
+                               x.typ = UniverseByte // use 'byte' name
+                       }
+
+               case *Array:
+                       valid = true
+                       length = typ.len
+                       if x.mode != variable {
+                               x.mode = value
+                       }
+                       x.typ = typ.elem
+
+               case *Pointer:
+                       if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+                               valid = true
+                               length = typ.len
+                               x.mode = variable
+                               x.typ = typ.elem
+                       }
+
+               case *Slice:
+                       valid = true
+                       x.mode = variable
+                       x.typ = typ.elem
+
+               case *Map:
+                       var key operand
+                       check.expr(&key, e.Index)
+                       if !check.assignment(&key, typ.key) {
+                               if key.mode != invalid {
+                                       check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key)
+                               }
+                               goto Error
+                       }
+                       x.mode = mapindex
+                       x.typ = typ.elem
+                       x.expr = e
+                       return expression
+               }
+
+               if !valid {
+                       check.invalidOp(x.pos(), "cannot index %s", x)
+                       goto Error
+               }
+
+               if e.Index == nil {
+                       check.invalidAST(e.Pos(), "missing index for %s", x)
+                       goto Error
+               }
+
+               check.index(e.Index, length)
+               // ok to continue
+
+       case *ast.SliceExpr:
+               check.expr(x, e.X)
+               if x.mode == invalid {
+                       goto Error
+               }
+
+               valid := false
+               length := int64(-1) // valid if >= 0
+               switch typ := x.typ.Underlying().(type) {
+               case *Basic:
+                       if isString(typ) {
+                               if slice3(e) {
+                                       check.invalidOp(x.pos(), "3-index slice of string")
+                                       goto Error
+                               }
+                               valid = true
+                               if x.mode == constant {
+                                       length = int64(len(exact.StringVal(x.val)))
+                               }
+                               // spec: "For untyped string operands the result
+                               // is a non-constant value of type string."
+                               if typ.kind == UntypedString {
+                                       x.typ = Typ[String]
+                               }
+                       }
+
+               case *Array:
+                       valid = true
+                       length = typ.len
+                       if x.mode != variable {
+                               check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
+                               goto Error
+                       }
+                       x.typ = &Slice{elem: typ.elem}
+
+               case *Pointer:
+                       if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+                               valid = true
+                               length = typ.len
+                               x.typ = &Slice{elem: typ.elem}
+                       }
+
+               case *Slice:
+                       valid = true
+                       // x.typ doesn't change
+               }
+
+               if !valid {
+                       check.invalidOp(x.pos(), "cannot slice %s", x)
+                       goto Error
+               }
+
+               x.mode = value
+
+               // spec: "Only the first index may be omitted; it defaults to 0."
+               if slice3(e) && (e.High == nil || sliceMax(e) == nil) {
+                       check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice")
+                       goto Error
+               }
+
+               // check indices
+               var ind [3]int64
+               for i, expr := range []ast.Expr{e.Low, e.High, sliceMax(e)} {
+                       x := int64(-1)
+                       switch {
+                       case expr != nil:
+                               // The "capacity" is only known statically for strings, arrays,
+                               // and pointers to arrays, and it is the same as the length for
+                               // those types.
+                               max := int64(-1)
+                               if length >= 0 {
+                                       max = length + 1
+                               }
+                               if t, ok := check.index(expr, max); ok && t >= 0 {
+                                       x = t
+                               }
+                       case i == 0:
+                               // default is 0 for the first index
+                               x = 0
+                       case length >= 0:
+                               // default is length (== capacity) otherwise
+                               x = length
+                       }
+                       ind[i] = x
+               }
+
+               // constant indices must be in range
+               // (check.index already checks that existing indices >= 0)
+       L:
+               for i, x := range ind[:len(ind)-1] {
+                       if x > 0 {
+                               for _, y := range ind[i+1:] {
+                                       if y >= 0 && x > y {
+                                               check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y)
+                                               break L // only report one error, ok to continue
+                                       }
+                               }
+                       }
+               }
+
+       case *ast.TypeAssertExpr:
+               check.expr(x, e.X)
+               if x.mode == invalid {
+                       goto Error
+               }
+               xtyp, _ := x.typ.Underlying().(*Interface)
+               if xtyp == nil {
+                       check.invalidOp(x.pos(), "%s is not an interface", x)
+                       goto Error
+               }
+               // x.(type) expressions are handled explicitly in type switches
+               if e.Type == nil {
+                       check.invalidAST(e.Pos(), "use of .(type) outside type switch")
+                       goto Error
+               }
+               T := check.typ(e.Type)
+               if T == Typ[Invalid] {
+                       goto Error
+               }
+               check.typeAssertion(x.pos(), x, xtyp, T)
+               x.mode = commaok
+               x.typ = T
+
+       case *ast.CallExpr:
+               return check.call(x, e)
+
+       case *ast.StarExpr:
+               check.exprOrType(x, e.X)
+               switch x.mode {
+               case invalid:
+                       goto Error
+               case typexpr:
+                       x.typ = &Pointer{base: x.typ}
+               default:
+                       if typ, ok := x.typ.Underlying().(*Pointer); ok {
+                               x.mode = variable
+                               x.typ = typ.base
+                       } else {
+                               check.invalidOp(x.pos(), "cannot indirect %s", x)
+                               goto Error
+                       }
+               }
+
+       case *ast.UnaryExpr:
+               check.expr(x, e.X)
+               if x.mode == invalid {
+                       goto Error
+               }
+               check.unary(x, e.Op)
+               if x.mode == invalid {
+                       goto Error
+               }
+               if e.Op == token.ARROW {
+                       x.expr = e
+                       return statement // receive operations may appear in statement context
+               }
+
+       case *ast.BinaryExpr:
+               check.binary(x, e.X, e.Y, e.Op)
+               if x.mode == invalid {
+                       goto Error
+               }
+
+       case *ast.KeyValueExpr:
+               // key:value expressions are handled in composite literals
+               check.invalidAST(e.Pos(), "no key:value expected")
+               goto Error
+
+       case *ast.ArrayType, *ast.StructType, *ast.FuncType,
+               *ast.InterfaceType, *ast.MapType, *ast.ChanType:
+               x.mode = typexpr
+               x.typ = check.typ(e)
+               // Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
+               // even though check.typ has already called it. This is fine as both
+               // times the same expression and type are recorded. It is also not a
+               // performance issue because we only reach here for composite literal
+               // types, which are comparatively rare.
+
+       default:
+               panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e))
+       }
+
+       // everything went well
+       x.expr = e
+       return expression
+
+Error:
+       x.mode = invalid
+       x.expr = e
+       return statement // avoid follow-up errors
+}
+
+// typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
+func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type) {
+       method, wrongType := assertableTo(xtyp, T)
+       if method == nil {
+               return
+       }
+
+       var msg string
+       if wrongType {
+               msg = "wrong type for method"
+       } else {
+               msg = "missing method"
+       }
+       check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name)
+}
+
+// expr typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) expr(x *operand, e ast.Expr) {
+       check.rawExpr(x, e, nil)
+       var msg string
+       switch x.mode {
+       default:
+               return
+       case novalue:
+               msg = "used as value"
+       case builtin:
+               msg = "must be called"
+       case typexpr:
+               msg = "is not an expression"
+       }
+       check.errorf(x.pos(), "%s %s", x, msg)
+       x.mode = invalid
+}
+
+// exprWithHint typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
+       assert(hint != nil)
+       check.rawExpr(x, e, hint)
+       var msg string
+       switch x.mode {
+       default:
+               return
+       case novalue:
+               msg = "used as value"
+       case builtin:
+               msg = "must be called"
+       case typexpr:
+               msg = "is not an expression"
+       }
+       check.errorf(x.pos(), "%s %s", x, msg)
+       x.mode = invalid
+}
+
+// exprOrType typechecks expression or type e and initializes x with the expression value or type.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) exprOrType(x *operand, e ast.Expr) {
+       check.rawExpr(x, e, nil)
+       if x.mode == novalue {
+               check.errorf(x.pos(), "%s used as value or type", x)
+               x.mode = invalid
+       }
+}
diff --git a/src/go/types/exprstring.go b/src/go/types/exprstring.go
new file mode 100644 (file)
index 0000000..370bdf3
--- /dev/null
@@ -0,0 +1,220 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements printing of expressions.
+
+package types
+
+import (
+       "bytes"
+       "go/ast"
+)
+
+// ExprString returns the (possibly simplified) string representation for x.
+func ExprString(x ast.Expr) string {
+       var buf bytes.Buffer
+       WriteExpr(&buf, x)
+       return buf.String()
+}
+
+// WriteExpr writes the (possibly simplified) string representation for x to buf.
+func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
+       // The AST preserves source-level parentheses so there is
+       // no need to introduce them here to correct for different
+       // operator precedences. (This assumes that the AST was
+       // generated by a Go parser.)
+
+       switch x := x.(type) {
+       default:
+               buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
+
+       case *ast.Ident:
+               buf.WriteString(x.Name)
+
+       case *ast.Ellipsis:
+               buf.WriteString("...")
+               if x.Elt != nil {
+                       WriteExpr(buf, x.Elt)
+               }
+
+       case *ast.BasicLit:
+               buf.WriteString(x.Value)
+
+       case *ast.FuncLit:
+               buf.WriteByte('(')
+               WriteExpr(buf, x.Type)
+               buf.WriteString(" literal)") // simplified
+
+       case *ast.CompositeLit:
+               buf.WriteByte('(')
+               WriteExpr(buf, x.Type)
+               buf.WriteString(" literal)") // simplified
+
+       case *ast.ParenExpr:
+               buf.WriteByte('(')
+               WriteExpr(buf, x.X)
+               buf.WriteByte(')')
+
+       case *ast.SelectorExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteByte('.')
+               buf.WriteString(x.Sel.Name)
+
+       case *ast.IndexExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteByte('[')
+               WriteExpr(buf, x.Index)
+               buf.WriteByte(']')
+
+       case *ast.SliceExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteByte('[')
+               if x.Low != nil {
+                       WriteExpr(buf, x.Low)
+               }
+               buf.WriteByte(':')
+               if x.High != nil {
+                       WriteExpr(buf, x.High)
+               }
+               if x.Slice3 {
+                       buf.WriteByte(':')
+                       if x.Max != nil {
+                               WriteExpr(buf, x.Max)
+                       }
+               }
+               buf.WriteByte(']')
+
+       case *ast.TypeAssertExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteString(".(")
+               WriteExpr(buf, x.Type)
+               buf.WriteByte(')')
+
+       case *ast.CallExpr:
+               WriteExpr(buf, x.Fun)
+               buf.WriteByte('(')
+               for i, arg := range x.Args {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       WriteExpr(buf, arg)
+               }
+               if x.Ellipsis.IsValid() {
+                       buf.WriteString("...")
+               }
+               buf.WriteByte(')')
+
+       case *ast.StarExpr:
+               buf.WriteByte('*')
+               WriteExpr(buf, x.X)
+
+       case *ast.UnaryExpr:
+               buf.WriteString(x.Op.String())
+               WriteExpr(buf, x.X)
+
+       case *ast.BinaryExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteByte(' ')
+               buf.WriteString(x.Op.String())
+               buf.WriteByte(' ')
+               WriteExpr(buf, x.Y)
+
+       case *ast.ArrayType:
+               buf.WriteByte('[')
+               if x.Len != nil {
+                       WriteExpr(buf, x.Len)
+               }
+               buf.WriteByte(']')
+               WriteExpr(buf, x.Elt)
+
+       case *ast.StructType:
+               buf.WriteString("struct{")
+               writeFieldList(buf, x.Fields, "; ", false)
+               buf.WriteByte('}')
+
+       case *ast.FuncType:
+               buf.WriteString("func")
+               writeSigExpr(buf, x)
+
+       case *ast.InterfaceType:
+               buf.WriteString("interface{")
+               writeFieldList(buf, x.Methods, "; ", true)
+               buf.WriteByte('}')
+
+       case *ast.MapType:
+               buf.WriteString("map[")
+               WriteExpr(buf, x.Key)
+               buf.WriteByte(']')
+               WriteExpr(buf, x.Value)
+
+       case *ast.ChanType:
+               var s string
+               switch x.Dir {
+               case ast.SEND:
+                       s = "chan<- "
+               case ast.RECV:
+                       s = "<-chan "
+               default:
+                       s = "chan "
+               }
+               buf.WriteString(s)
+               WriteExpr(buf, x.Value)
+       }
+}
+
+func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
+       buf.WriteByte('(')
+       writeFieldList(buf, sig.Params, ", ", false)
+       buf.WriteByte(')')
+
+       res := sig.Results
+       n := res.NumFields()
+       if n == 0 {
+               // no result
+               return
+       }
+
+       buf.WriteByte(' ')
+       if n == 1 && len(res.List[0].Names) == 0 {
+               // single unnamed result
+               WriteExpr(buf, res.List[0].Type)
+               return
+       }
+
+       // multiple or named result(s)
+       buf.WriteByte('(')
+       writeFieldList(buf, res, ", ", false)
+       buf.WriteByte(')')
+}
+
+func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
+       for i, f := range fields.List {
+               if i > 0 {
+                       buf.WriteString(sep)
+               }
+
+               // field list names
+               for i, name := range f.Names {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       buf.WriteString(name.Name)
+               }
+
+               // types of interface methods consist of signatures only
+               if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
+                       writeSigExpr(buf, sig)
+                       continue
+               }
+
+               // named fields are separated with a blank from the field type
+               if len(f.Names) > 0 {
+                       buf.WriteByte(' ')
+               }
+
+               WriteExpr(buf, f.Type)
+
+               // ignore tag
+       }
+}
diff --git a/src/go/types/exprstring_test.go b/src/go/types/exprstring_test.go
new file mode 100644 (file)
index 0000000..5110288
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "go/parser"
+       "testing"
+
+       . "go/types"
+)
+
+var testExprs = []testEntry{
+       // basic type literals
+       dup("x"),
+       dup("true"),
+       dup("42"),
+       dup("3.1415"),
+       dup("2.71828i"),
+       dup(`'a'`),
+       dup(`"foo"`),
+       dup("`bar`"),
+
+       // func and composite literals
+       {"func(){}", "(func() literal)"},
+       {"func(x int) complex128 {}", "(func(x int) complex128 literal)"},
+       {"[]int{1, 2, 3}", "([]int literal)"},
+
+       // non-type expressions
+       dup("(x)"),
+       dup("x.f"),
+       dup("a[i]"),
+
+       dup("s[:]"),
+       dup("s[i:]"),
+       dup("s[:j]"),
+       dup("s[i:j]"),
+       dup("s[:j:k]"),
+       dup("s[i:j:k]"),
+
+       dup("x.(T)"),
+
+       dup("x.([10]int)"),
+       dup("x.([...]int)"),
+
+       dup("x.(struct{})"),
+       dup("x.(struct{x int; y, z float32; E})"),
+
+       dup("x.(func())"),
+       dup("x.(func(x int))"),
+       dup("x.(func() int)"),
+       dup("x.(func(x, y int, z float32) (r int))"),
+       dup("x.(func(a, b, c int))"),
+       dup("x.(func(x ...T))"),
+
+       dup("x.(interface{})"),
+       dup("x.(interface{m(); n(x int); E})"),
+       dup("x.(interface{m(); n(x int) T; E; F})"),
+
+       dup("x.(map[K]V)"),
+
+       dup("x.(chan E)"),
+       dup("x.(<-chan E)"),
+       dup("x.(chan<- chan int)"),
+       dup("x.(chan<- <-chan int)"),
+       dup("x.(<-chan chan int)"),
+       dup("x.(chan (<-chan int))"),
+
+       dup("f()"),
+       dup("f(x)"),
+       dup("int(x)"),
+       dup("f(x, x + y)"),
+       dup("f(s...)"),
+       dup("f(a, s...)"),
+
+       dup("*x"),
+       dup("&x"),
+       dup("x + y"),
+       dup("x + y << (2 * s)"),
+}
+
+func TestExprString(t *testing.T) {
+       for _, test := range testExprs {
+               x, err := parser.ParseExpr(test.src)
+               if err != nil {
+                       t.Errorf("%s: %s", test.src, err)
+                       continue
+               }
+               if got := ExprString(x); got != test.str {
+                       t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+               }
+       }
+}
diff --git a/src/go/types/go11.go b/src/go/types/go11.go
new file mode 100644 (file)
index 0000000..cf41cab
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+       return false
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+       return nil
+}
diff --git a/src/go/types/go12.go b/src/go/types/go12.go
new file mode 100644 (file)
index 0000000..2017442
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+       return x.Slice3
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+       return x.Max
+}
diff --git a/src/go/types/hilbert_test.go b/src/go/types/hilbert_test.go
new file mode 100644 (file)
index 0000000..99dcedd
--- /dev/null
@@ -0,0 +1,232 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "io/ioutil"
+       "testing"
+
+       . "go/types"
+)
+
+var (
+       H   = flag.Int("H", 5, "Hilbert matrix size")
+       out = flag.String("out", "", "write generated program to out")
+)
+
+func TestHilbert(t *testing.T) {
+       // generate source
+       src := program(*H, *out)
+       if *out != "" {
+               ioutil.WriteFile(*out, src, 0666)
+               return
+       }
+
+       // parse source
+       fset := token.NewFileSet()
+       f, err := parser.ParseFile(fset, "hilbert.go", src, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // type-check file
+       DefPredeclaredTestFuncs() // define assert built-in
+       _, err = Check(f.Name.Name, fset, []*ast.File{f})
+       if err != nil {
+               t.Fatal(err)
+       }
+}
+
+func program(n int, out string) []byte {
+       var g gen
+
+       g.p(`// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY!
+// (To generate, in go/types directory: go test -run=Hilbert -H=%d -out=%q)
+
+// This program tests arbitrary precision constant arithmetic
+// by generating the constant elements of a Hilbert matrix H,
+// its inverse I, and the product P = H*I. The product should
+// be the identity matrix.
+package main
+
+func main() {
+       if !ok {
+               printProduct()
+               return
+       }
+       println("PASS")
+}
+
+`, n, out)
+       g.hilbert(n)
+       g.inverse(n)
+       g.product(n)
+       g.verify(n)
+       g.printProduct(n)
+       g.binomials(2*n - 1)
+       g.factorials(2*n - 1)
+
+       return g.Bytes()
+}
+
+type gen struct {
+       bytes.Buffer
+}
+
+func (g *gen) p(format string, args ...interface{}) {
+       fmt.Fprintf(&g.Buffer, format, args...)
+}
+
+func (g *gen) hilbert(n int) {
+       g.p(`// Hilbert matrix, n = %d
+const (
+`, n)
+       for i := 0; i < n; i++ {
+               g.p("\t")
+               for j := 0; j < n; j++ {
+                       if j > 0 {
+                               g.p(", ")
+                       }
+                       g.p("h%d_%d", i, j)
+               }
+               if i == 0 {
+                       g.p(" = ")
+                       for j := 0; j < n; j++ {
+                               if j > 0 {
+                                       g.p(", ")
+                               }
+                               g.p("1.0/(iota + %d)", j+1)
+                       }
+               }
+               g.p("\n")
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) inverse(n int) {
+       g.p(`// Inverse Hilbert matrix
+const (
+`)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       s := "+"
+                       if (i+j)&1 != 0 {
+                               s = "-"
+                       }
+                       g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n",
+                               i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i)
+               }
+               g.p("\n")
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) product(n int) {
+       g.p(`// Product matrix
+const (
+`)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       g.p("\tp%d_%d = ", i, j)
+                       for k := 0; k < n; k++ {
+                               if k > 0 {
+                                       g.p(" + ")
+                               }
+                               g.p("h%d_%d*i%d_%d", i, k, k, j)
+                       }
+                       g.p("\n")
+               }
+               g.p("\n")
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) verify(n int) {
+       g.p(`// Verify that product is the identity matrix
+const ok =
+`)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       if j == 0 {
+                               g.p("\t")
+                       } else {
+                               g.p(" && ")
+                       }
+                       v := 0
+                       if i == j {
+                               v = 1
+                       }
+                       g.p("p%d_%d == %d", i, j, v)
+               }
+               g.p(" &&\n")
+       }
+       g.p("\ttrue\n\n")
+
+       // verify ok at type-check time
+       if *out == "" {
+               g.p("const _ = assert(ok)\n\n")
+       }
+}
+
+func (g *gen) printProduct(n int) {
+       g.p("func printProduct() {\n")
+       for i := 0; i < n; i++ {
+               g.p("\tprintln(")
+               for j := 0; j < n; j++ {
+                       if j > 0 {
+                               g.p(", ")
+                       }
+                       g.p("p%d_%d", i, j)
+               }
+               g.p(")\n")
+       }
+       g.p("}\n\n")
+}
+
+func (g *gen) mulRange(a, b int) {
+       if a > b {
+               g.p("1")
+               return
+       }
+       for i := a; i <= b; i++ {
+               if i > a {
+                       g.p("*")
+               }
+               g.p("%d", i)
+       }
+}
+
+func (g *gen) binomials(n int) {
+       g.p(`// Binomials
+const (
+`)
+       for j := 0; j <= n; j++ {
+               if j > 0 {
+                       g.p("\n")
+               }
+               for k := 0; k <= j; k++ {
+                       g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k)
+               }
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) factorials(n int) {
+       g.p(`// Factorials
+const (
+       f0 = 1
+       f1 = 1
+`)
+       for i := 2; i <= n; i++ {
+               g.p("\tf%d = f%d * %d\n", i, i-1, i)
+       }
+       g.p(")\n\n")
+}
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
new file mode 100644 (file)
index 0000000..0fd567b
--- /dev/null
@@ -0,0 +1,222 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+       "container/heap"
+       "fmt"
+)
+
+// initOrder computes the Info.InitOrder for package variables.
+func (check *Checker) initOrder() {
+       // An InitOrder may already have been computed if a package is
+       // built from several calls to (*Checker).Files.  Clear it.
+       check.Info.InitOrder = check.Info.InitOrder[:0]
+
+       // compute the object dependency graph and
+       // initialize a priority queue with the list
+       // of graph nodes
+       pq := nodeQueue(dependencyGraph(check.objMap))
+       heap.Init(&pq)
+
+       const debug = false
+       if debug {
+               fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
+               for _, n := range pq {
+                       for _, o := range n.out {
+                               fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
+                       }
+               }
+               fmt.Println()
+               fmt.Printf("package %s: initialization order\n", check.pkg.Name())
+       }
+
+       // determine initialization order by removing the highest priority node
+       // (the one with the fewest dependencies) and its edges from the graph,
+       // repeatedly, until there are no nodes left.
+       // In a valid Go program, those nodes always have zero dependencies (after
+       // removing all incoming dependencies), otherwise there are initialization
+       // cycles.
+       mark := 0
+       emitted := make(map[*declInfo]bool)
+       for len(pq) > 0 {
+               // get the next node
+               n := heap.Pop(&pq).(*objNode)
+
+               // if n still depends on other nodes, we have a cycle
+               if n.in > 0 {
+                       mark++ // mark nodes using a different value each time
+                       cycle := findPath(n, n, mark)
+                       if i := valIndex(cycle); i >= 0 {
+                               check.reportCycle(cycle, i)
+                       }
+                       // ok to continue, but the variable initialization order
+                       // will be incorrect at this point since it assumes no
+                       // cycle errors
+               }
+
+               // reduce dependency count of all dependent nodes
+               // and update priority queue
+               for _, out := range n.out {
+                       out.in--
+                       heap.Fix(&pq, out.index)
+               }
+
+               // record the init order for variables with initializers only
+               v, _ := n.obj.(*Var)
+               info := check.objMap[v]
+               if v == nil || !info.hasInitializer() {
+                       continue
+               }
+
+               // n:1 variable declarations such as: a, b = f()
+               // introduce a node for each lhs variable (here: a, b);
+               // but they all have the same initializer - emit only
+               // one, for the first variable seen
+               if emitted[info] {
+                       continue // initializer already emitted, if any
+               }
+               emitted[info] = true
+
+               infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
+               if infoLhs == nil {
+                       infoLhs = []*Var{v}
+               }
+               init := &Initializer{infoLhs, info.init}
+               check.Info.InitOrder = append(check.Info.InitOrder, init)
+
+               if debug {
+                       fmt.Printf("\t%s\n", init)
+               }
+       }
+
+       if debug {
+               fmt.Println()
+       }
+}
+
+// findPath returns the (reversed) list of nodes z, ... c, b, a,
+// such that there is a path (list of edges) from a to z.
+// If there is no such path, the result is nil.
+// Nodes marked with the value mark are considered "visited";
+// unvisited nodes are marked during the graph search.
+func findPath(a, z *objNode, mark int) []*objNode {
+       if a.mark == mark {
+               return nil // node already seen
+       }
+       a.mark = mark
+
+       for _, n := range a.out {
+               if n == z {
+                       return []*objNode{z}
+               }
+               if P := findPath(n, z, mark); P != nil {
+                       return append(P, n)
+               }
+       }
+
+       return nil
+}
+
+// valIndex returns the index of the first constant or variable in a,
+// if any; or a value < 0.
+func valIndex(a []*objNode) int {
+       for i, n := range a {
+               switch n.obj.(type) {
+               case *Const, *Var:
+                       return i
+               }
+       }
+       return -1
+}
+
+// reportCycle reports an error for the cycle starting at i.
+func (check *Checker) reportCycle(cycle []*objNode, i int) {
+       obj := cycle[i].obj
+       check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
+       // print cycle
+       for _ = range cycle {
+               check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+               i++
+               if i >= len(cycle) {
+                       i = 0
+               }
+               obj = cycle[i].obj
+       }
+       check.errorf(obj.Pos(), "\t%s", obj.Name())
+}
+
+// An objNode represents a node in the object dependency graph.
+// Each node b in a.out represents an edge a->b indicating that
+// b depends on a.
+// Nodes may be marked for cycle detection. A node n is marked
+// if n.mark corresponds to the current mark value.
+type objNode struct {
+       obj   Object     // object represented by this node
+       in    int        // number of nodes this node depends on
+       out   []*objNode // list of nodes that depend on this node
+       index int        // node index in list of nodes
+       mark  int        // for cycle detection
+}
+
+// dependencyGraph computes the transposed object dependency graph
+// from the given objMap. The transposed graph is returned as a list
+// of nodes; an edge d->n indicates that node n depends on node d.
+func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
+       // M maps each object to its corresponding node
+       M := make(map[Object]*objNode, len(objMap))
+       for obj := range objMap {
+               M[obj] = &objNode{obj: obj}
+       }
+
+       // G is the graph of nodes n
+       G := make([]*objNode, len(M))
+       i := 0
+       for obj, n := range M {
+               deps := objMap[obj].deps
+               n.in = len(deps)
+               for d := range deps {
+                       d := M[d]                // node n depends on node d
+                       d.out = append(d.out, n) // add edge d->n
+               }
+
+               G[i] = n
+               n.index = i
+               i++
+       }
+
+       return G
+}
+
+// nodeQueue implements the container/heap interface;
+// a nodeQueue may be used as a priority queue.
+type nodeQueue []*objNode
+
+func (a nodeQueue) Len() int { return len(a) }
+
+func (a nodeQueue) Swap(i, j int) {
+       x, y := a[i], a[j]
+       a[i], a[j] = y, x
+       x.index, y.index = j, i
+}
+
+func (a nodeQueue) Less(i, j int) bool {
+       x, y := a[i], a[j]
+       // nodes are prioritized by number of incoming dependencies (1st key)
+       // and source order (2nd key)
+       return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
+}
+
+func (a *nodeQueue) Push(x interface{}) {
+       panic("unreachable")
+}
+
+func (a *nodeQueue) Pop() interface{} {
+       n := len(*a)
+       x := (*a)[n-1]
+       x.index = -1 // for safety
+       *a = (*a)[:n-1]
+       return x
+}
diff --git a/src/go/types/internal/gcimporter/exportdata.go b/src/go/types/internal/gcimporter/exportdata.go
new file mode 100644 (file)
index 0000000..657742b
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements FindExportData.
+
+package gcimporter
+
+import (
+       "bufio"
+       "errors"
+       "fmt"
+       "io"
+       "strconv"
+       "strings"
+)
+
+func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
+       // See $GOROOT/include/ar.h.
+       hdr := make([]byte, 16+12+6+6+8+10+2)
+       _, err = io.ReadFull(r, hdr)
+       if err != nil {
+               return
+       }
+       // leave for debugging
+       if false {
+               fmt.Printf("header: %s", hdr)
+       }
+       s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
+       size, err = strconv.Atoi(s)
+       if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
+               err = errors.New("invalid archive header")
+               return
+       }
+       name = strings.TrimSpace(string(hdr[:16]))
+       return
+}
+
+// FindExportData positions the reader r at the beginning of the
+// export data section of an underlying GC-created object/archive
+// file by reading from it. The reader must be positioned at the
+// start of the file before calling this function.
+//
+func FindExportData(r *bufio.Reader) (err error) {
+       // Read first line to make sure this is an object file.
+       line, err := r.ReadSlice('\n')
+       if err != nil {
+               return
+       }
+       if string(line) == "!<arch>\n" {
+               // Archive file. Scan to __.PKGDEF.
+               var name string
+               var size int
+               if name, size, err = readGopackHeader(r); err != nil {
+                       return
+               }
+
+               // Optional leading __.GOSYMDEF or __.SYMDEF.
+               // Read and discard.
+               if name == "__.SYMDEF" || name == "__.GOSYMDEF" {
+                       const block = 4096
+                       tmp := make([]byte, block)
+                       for size > 0 {
+                               n := size
+                               if n > block {
+                                       n = block
+                               }
+                               if _, err = io.ReadFull(r, tmp[:n]); err != nil {
+                                       return
+                               }
+                               size -= n
+                       }
+
+                       if name, size, err = readGopackHeader(r); err != nil {
+                               return
+                       }
+               }
+
+               // First real entry should be __.PKGDEF.
+               if name != "__.PKGDEF" {
+                       err = errors.New("go archive is missing __.PKGDEF")
+                       return
+               }
+
+               // Read first line of __.PKGDEF data, so that line
+               // is once again the first line of the input.
+               if line, err = r.ReadSlice('\n'); err != nil {
+                       return
+               }
+       }
+
+       // Now at __.PKGDEF in archive or still at beginning of file.
+       // Either way, line should begin with "go object ".
+       if !strings.HasPrefix(string(line), "go object ") {
+               err = errors.New("not a go object file")
+               return
+       }
+
+       // Skip over object header to export data.
+       // Begins after first line with $$.
+       for line[0] != '$' {
+               if line, err = r.ReadSlice('\n'); err != nil {
+                       return
+               }
+       }
+
+       return
+}
diff --git a/src/go/types/internal/gcimporter/gcimporter.go b/src/go/types/internal/gcimporter/gcimporter.go
new file mode 100644 (file)
index 0000000..f6ac95f
--- /dev/null
@@ -0,0 +1,961 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gcimporter implements Import for gc-generated object files.
+// Importing this package installs Import as go/types.DefaultImport.
+package gcimporter // import "go/types/internal/gcimporter"
+
+import (
+       "bufio"
+       "errors"
+       "fmt"
+       "go/build"
+       "go/token"
+       "io"
+       "os"
+       "path/filepath"
+       "strconv"
+       "strings"
+       "text/scanner"
+
+       "go/exact"
+       "go/types"
+)
+
+// debugging/development support
+const debug = false
+
+func init() {
+       types.DefaultImport = Import
+}
+
+var pkgExts = [...]string{".a", ".5", ".6", ".8"}
+
+// FindPkg returns the filename and unique package id for an import
+// path based on package information provided by build.Import (using
+// the build.Default build.Context).
+// If no file was found, an empty filename is returned.
+//
+func FindPkg(path, srcDir string) (filename, id string) {
+       if len(path) == 0 {
+               return
+       }
+
+       id = path
+       var noext string
+       switch {
+       default:
+               // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
+               // Don't require the source files to be present.
+               bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
+               if bp.PkgObj == "" {
+                       return
+               }
+               noext = strings.TrimSuffix(bp.PkgObj, ".a")
+
+       case build.IsLocalImport(path):
+               // "./x" -> "/this/directory/x.ext", "/this/directory/x"
+               noext = filepath.Join(srcDir, path)
+               id = noext
+
+       case filepath.IsAbs(path):
+               // for completeness only - go/build.Import
+               // does not support absolute imports
+               // "/x" -> "/x.ext", "/x"
+               noext = path
+       }
+
+       // try extensions
+       for _, ext := range pkgExts {
+               filename = noext + ext
+               if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+                       return
+               }
+       }
+
+       filename = "" // not found
+       return
+}
+
+// ImportData imports a package by reading the gc-generated export data,
+// adds the corresponding package object to the imports map indexed by id,
+// and returns the object.
+//
+// The imports map must contains all packages already imported. The data
+// reader position must be the beginning of the export data section. The
+// filename is only used in error messages.
+//
+// If imports[id] contains the completely imported package, that package
+// can be used directly, and there is no need to call this function (but
+// there is also no harm but for extra time used).
+//
+func ImportData(imports map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) {
+       // support for parser error handling
+       defer func() {
+               switch r := recover().(type) {
+               case nil:
+                       // nothing to do
+               case importError:
+                       err = r
+               default:
+                       panic(r) // internal error
+               }
+       }()
+
+       var p parser
+       p.init(filename, id, data, imports)
+       pkg = p.parseExport()
+
+       return
+}
+
+// Import imports a gc-generated package given its import path, adds the
+// corresponding package object to the imports map, and returns the object.
+// Local import paths are interpreted relative to the current working directory.
+// The imports map must contains all packages already imported.
+//
+func Import(imports map[string]*types.Package, path string) (pkg *types.Package, err error) {
+       if path == "unsafe" {
+               return types.Unsafe, nil
+       }
+
+       srcDir := "."
+       if build.IsLocalImport(path) {
+               srcDir, err = os.Getwd()
+               if err != nil {
+                       return
+               }
+       }
+
+       filename, id := FindPkg(path, srcDir)
+       if filename == "" {
+               err = fmt.Errorf("can't find import: %s", id)
+               return
+       }
+
+       // no need to re-import if the package was imported completely before
+       if pkg = imports[id]; pkg != nil && pkg.Complete() {
+               return
+       }
+
+       // open file
+       f, err := os.Open(filename)
+       if err != nil {
+               return
+       }
+       defer func() {
+               f.Close()
+               if err != nil {
+                       // add file name to error
+                       err = fmt.Errorf("reading export data: %s: %v", filename, err)
+               }
+       }()
+
+       buf := bufio.NewReader(f)
+       if err = FindExportData(buf); err != nil {
+               return
+       }
+
+       pkg, err = ImportData(imports, filename, id, buf)
+
+       return
+}
+
+// ----------------------------------------------------------------------------
+// Parser
+
+// TODO(gri) Imported objects don't have position information.
+//           Ideally use the debug table line info; alternatively
+//           create some fake position (or the position of the
+//           import). That way error messages referring to imported
+//           objects can print meaningful information.
+
+// parser parses the exports inside a gc compiler-produced
+// object/archive file and populates its scope with the results.
+type parser struct {
+       scanner scanner.Scanner
+       tok     rune                      // current token
+       lit     string                    // literal string; only valid for Ident, Int, String tokens
+       id      string                    // package id of imported package
+       imports map[string]*types.Package // package id -> package object
+}
+
+func (p *parser) init(filename, id string, src io.Reader, imports map[string]*types.Package) {
+       p.scanner.Init(src)
+       p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
+       p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
+       p.scanner.Whitespace = 1<<'\t' | 1<<' '
+       p.scanner.Filename = filename // for good error messages
+       p.next()
+       p.id = id
+       p.imports = imports
+       if debug {
+               // check consistency of imports map
+               for _, pkg := range imports {
+                       if pkg.Name() == "" {
+                               fmt.Printf("no package name for %s\n", pkg.Path())
+                       }
+               }
+       }
+}
+
+func (p *parser) next() {
+       p.tok = p.scanner.Scan()
+       switch p.tok {
+       case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·':
+               p.lit = p.scanner.TokenText()
+       default:
+               p.lit = ""
+       }
+       if debug {
+               fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
+       }
+}
+
+func declTypeName(pkg *types.Package, name string) *types.TypeName {
+       scope := pkg.Scope()
+       if obj := scope.Lookup(name); obj != nil {
+               return obj.(*types.TypeName)
+       }
+       obj := types.NewTypeName(token.NoPos, pkg, name, nil)
+       // a named type may be referred to before the underlying type
+       // is known - set it up
+       types.NewNamed(obj, nil, nil)
+       scope.Insert(obj)
+       return obj
+}
+
+// ----------------------------------------------------------------------------
+// Error handling
+
+// Internal errors are boxed as importErrors.
+type importError struct {
+       pos scanner.Position
+       err error
+}
+
+func (e importError) Error() string {
+       return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
+}
+
+func (p *parser) error(err interface{}) {
+       if s, ok := err.(string); ok {
+               err = errors.New(s)
+       }
+       // panic with a runtime.Error if err is not an error
+       panic(importError{p.scanner.Pos(), err.(error)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+       p.error(fmt.Sprintf(format, args...))
+}
+
+func (p *parser) expect(tok rune) string {
+       lit := p.lit
+       if p.tok != tok {
+               p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
+       }
+       p.next()
+       return lit
+}
+
+func (p *parser) expectSpecial(tok string) {
+       sep := 'x' // not white space
+       i := 0
+       for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
+               sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+               p.next()
+               i++
+       }
+       if i < len(tok) {
+               p.errorf("expected %q, got %q", tok, tok[0:i])
+       }
+}
+
+func (p *parser) expectKeyword(keyword string) {
+       lit := p.expect(scanner.Ident)
+       if lit != keyword {
+               p.errorf("expected keyword %s, got %q", keyword, lit)
+       }
+}
+
+// ----------------------------------------------------------------------------
+// Qualified and unqualified names
+
+// PackageId = string_lit .
+//
+func (p *parser) parsePackageId() string {
+       id, err := strconv.Unquote(p.expect(scanner.String))
+       if err != nil {
+               p.error(err)
+       }
+       // id == "" stands for the imported package id
+       // (only known at time of package installation)
+       if id == "" {
+               id = p.id
+       }
+       return id
+}
+
+// PackageName = ident .
+//
+func (p *parser) parsePackageName() string {
+       return p.expect(scanner.Ident)
+}
+
+// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
+func (p *parser) parseDotIdent() string {
+       ident := ""
+       if p.tok != scanner.Int {
+               sep := 'x' // not white space
+               for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
+                       ident += p.lit
+                       sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+                       p.next()
+               }
+       }
+       if ident == "" {
+               p.expect(scanner.Ident) // use expect() for error handling
+       }
+       return ident
+}
+
+// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) .
+//
+func (p *parser) parseQualifiedName() (id, name string) {
+       p.expect('@')
+       id = p.parsePackageId()
+       p.expect('.')
+       // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields.
+       if p.tok == '?' {
+               p.next()
+       } else {
+               name = p.parseDotIdent()
+       }
+       return
+}
+
+// getPkg returns the package for a given id. If the package is
+// not found but we have a package name, create the package and
+// add it to the p.imports map.
+//
+func (p *parser) getPkg(id, name string) *types.Package {
+       // package unsafe is not in the imports map - handle explicitly
+       if id == "unsafe" {
+               return types.Unsafe
+       }
+       pkg := p.imports[id]
+       if pkg == nil && name != "" {
+               pkg = types.NewPackage(id, name)
+               p.imports[id] = pkg
+       }
+       return pkg
+}
+
+// parseExportedName is like parseQualifiedName, but
+// the package id is resolved to an imported *types.Package.
+//
+func (p *parser) parseExportedName() (pkg *types.Package, name string) {
+       id, name := p.parseQualifiedName()
+       pkg = p.getPkg(id, "")
+       if pkg == nil {
+               p.errorf("%s package not found", id)
+       }
+       return
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+// BasicType = identifier .
+//
+func (p *parser) parseBasicType() types.Type {
+       id := p.expect(scanner.Ident)
+       obj := types.Universe.Lookup(id)
+       if obj, ok := obj.(*types.TypeName); ok {
+               return obj.Type()
+       }
+       p.errorf("not a basic type: %s", id)
+       return nil
+}
+
+// ArrayType = "[" int_lit "]" Type .
+//
+func (p *parser) parseArrayType() types.Type {
+       // "[" already consumed and lookahead known not to be "]"
+       lit := p.expect(scanner.Int)
+       p.expect(']')
+       elem := p.parseType()
+       n, err := strconv.ParseInt(lit, 10, 64)
+       if err != nil {
+               p.error(err)
+       }
+       return types.NewArray(elem, n)
+}
+
+// MapType = "map" "[" Type "]" Type .
+//
+func (p *parser) parseMapType() types.Type {
+       p.expectKeyword("map")
+       p.expect('[')
+       key := p.parseType()
+       p.expect(']')
+       elem := p.parseType()
+       return types.NewMap(key, elem)
+}
+
+// Name = identifier | "?" | QualifiedName .
+//
+// If materializePkg is set, the returned package is guaranteed to be set.
+// For fully qualified names, the returned package may be a fake package
+// (without name, scope, and not in the p.imports map), created for the
+// sole purpose of providing a package path. Fake packages are created
+// when the package id is not found in the p.imports map; in that case
+// we cannot create a real package because we don't have a package name.
+// For non-qualified names, the returned package is the imported package.
+//
+func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) {
+       switch p.tok {
+       case scanner.Ident:
+               pkg = p.imports[p.id]
+               name = p.lit
+               p.next()
+       case '?':
+               // anonymous
+               pkg = p.imports[p.id]
+               p.next()
+       case '@':
+               // exported name prefixed with package path
+               var id string
+               id, name = p.parseQualifiedName()
+               if materializePkg {
+                       // we don't have a package name - if the package
+                       // doesn't exist yet, create a fake package instead
+                       pkg = p.getPkg(id, "")
+                       if pkg == nil {
+                               pkg = types.NewPackage(id, "")
+                       }
+               }
+       default:
+               p.error("name expected")
+       }
+       return
+}
+
+func deref(typ types.Type) types.Type {
+       if p, _ := typ.(*types.Pointer); p != nil {
+               return p.Elem()
+       }
+       return typ
+}
+
+// Field = Name Type [ string_lit ] .
+//
+func (p *parser) parseField() (*types.Var, string) {
+       pkg, name := p.parseName(true)
+       typ := p.parseType()
+       anonymous := false
+       if name == "" {
+               // anonymous field - typ must be T or *T and T must be a type name
+               switch typ := deref(typ).(type) {
+               case *types.Basic: // basic types are named types
+                       pkg = nil
+                       name = typ.Name()
+               case *types.Named:
+                       name = typ.Obj().Name()
+               default:
+                       p.errorf("anonymous field expected")
+               }
+               anonymous = true
+       }
+       tag := ""
+       if p.tok == scanner.String {
+               s := p.expect(scanner.String)
+               var err error
+               tag, err = strconv.Unquote(s)
+               if err != nil {
+                       p.errorf("invalid struct tag %s: %s", s, err)
+               }
+       }
+       return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag
+}
+
+// StructType = "struct" "{" [ FieldList ] "}" .
+// FieldList  = Field { ";" Field } .
+//
+func (p *parser) parseStructType() types.Type {
+       var fields []*types.Var
+       var tags []string
+
+       p.expectKeyword("struct")
+       p.expect('{')
+       for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+               if i > 0 {
+                       p.expect(';')
+               }
+               fld, tag := p.parseField()
+               if tag != "" && tags == nil {
+                       tags = make([]string, i)
+               }
+               if tags != nil {
+                       tags = append(tags, tag)
+               }
+               fields = append(fields, fld)
+       }
+       p.expect('}')
+
+       return types.NewStruct(fields, tags)
+}
+
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
+//
+func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
+       _, name := p.parseName(false)
+       // remove gc-specific parameter numbering
+       if i := strings.Index(name, "·"); i >= 0 {
+               name = name[:i]
+       }
+       if p.tok == '.' {
+               p.expectSpecial("...")
+               isVariadic = true
+       }
+       typ := p.parseType()
+       if isVariadic {
+               typ = types.NewSlice(typ)
+       }
+       // ignore argument tag (e.g. "noescape")
+       if p.tok == scanner.String {
+               p.next()
+       }
+       // TODO(gri) should we provide a package?
+       par = types.NewVar(token.NoPos, nil, name, typ)
+       return
+}
+
+// Parameters    = "(" [ ParameterList ] ")" .
+// ParameterList = { Parameter "," } Parameter .
+//
+func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) {
+       p.expect('(')
+       for p.tok != ')' && p.tok != scanner.EOF {
+               if len(list) > 0 {
+                       p.expect(',')
+               }
+               par, variadic := p.parseParameter()
+               list = append(list, par)
+               if variadic {
+                       if isVariadic {
+                               p.error("... not on final argument")
+                       }
+                       isVariadic = true
+               }
+       }
+       p.expect(')')
+
+       return
+}
+
+// Signature = Parameters [ Result ] .
+// Result    = Type | Parameters .
+//
+func (p *parser) parseSignature(recv *types.Var) *types.Signature {
+       params, isVariadic := p.parseParameters()
+
+       // optional result type
+       var results []*types.Var
+       if p.tok == '(' {
+               var variadic bool
+               results, variadic = p.parseParameters()
+               if variadic {
+                       p.error("... not permitted on result type")
+               }
+       }
+
+       return types.NewSignature(nil, recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic)
+}
+
+// InterfaceType = "interface" "{" [ MethodList ] "}" .
+// MethodList    = Method { ";" Method } .
+// Method        = Name Signature .
+//
+// The methods of embedded interfaces are always "inlined"
+// by the compiler and thus embedded interfaces are never
+// visible in the export data.
+//
+func (p *parser) parseInterfaceType() types.Type {
+       var methods []*types.Func
+
+       p.expectKeyword("interface")
+       p.expect('{')
+       for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+               if i > 0 {
+                       p.expect(';')
+               }
+               pkg, name := p.parseName(true)
+               sig := p.parseSignature(nil)
+               methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
+       }
+       p.expect('}')
+
+       // Complete requires the type's embedded interfaces to be fully defined,
+       // but we do not define any
+       return types.NewInterface(methods, nil).Complete()
+}
+
+// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
+//
+func (p *parser) parseChanType() types.Type {
+       dir := types.SendRecv
+       if p.tok == scanner.Ident {
+               p.expectKeyword("chan")
+               if p.tok == '<' {
+                       p.expectSpecial("<-")
+                       dir = types.SendOnly
+               }
+       } else {
+               p.expectSpecial("<-")
+               p.expectKeyword("chan")
+               dir = types.RecvOnly
+       }
+       elem := p.parseType()
+       return types.NewChan(dir, elem)
+}
+
+// Type =
+//     BasicType | TypeName | ArrayType | SliceType | StructType |
+//      PointerType | FuncType | InterfaceType | MapType | ChanType |
+//      "(" Type ")" .
+//
+// BasicType   = ident .
+// TypeName    = ExportedName .
+// SliceType   = "[" "]" Type .
+// PointerType = "*" Type .
+// FuncType    = "func" Signature .
+//
+func (p *parser) parseType() types.Type {
+       switch p.tok {
+       case scanner.Ident:
+               switch p.lit {
+               default:
+                       return p.parseBasicType()
+               case "struct":
+                       return p.parseStructType()
+               case "func":
+                       // FuncType
+                       p.next()
+                       return p.parseSignature(nil)
+               case "interface":
+                       return p.parseInterfaceType()
+               case "map":
+                       return p.parseMapType()
+               case "chan":
+                       return p.parseChanType()
+               }
+       case '@':
+               // TypeName
+               pkg, name := p.parseExportedName()
+               return declTypeName(pkg, name).Type()
+       case '[':
+               p.next() // look ahead
+               if p.tok == ']' {
+                       // SliceType
+                       p.next()
+                       return types.NewSlice(p.parseType())
+               }
+               return p.parseArrayType()
+       case '*':
+               // PointerType
+               p.next()
+               return types.NewPointer(p.parseType())
+       case '<':
+               return p.parseChanType()
+       case '(':
+               // "(" Type ")"
+               p.next()
+               typ := p.parseType()
+               p.expect(')')
+               return typ
+       }
+       p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+       return nil
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// ImportDecl = "import" PackageName PackageId .
+//
+func (p *parser) parseImportDecl() {
+       p.expectKeyword("import")
+       name := p.parsePackageName()
+       p.getPkg(p.parsePackageId(), name)
+}
+
+// int_lit = [ "+" | "-" ] { "0" ... "9" } .
+//
+func (p *parser) parseInt() string {
+       s := ""
+       switch p.tok {
+       case '-':
+               s = "-"
+               p.next()
+       case '+':
+               p.next()
+       }
+       return s + p.expect(scanner.Int)
+}
+
+// number = int_lit [ "p" int_lit ] .
+//
+func (p *parser) parseNumber() (typ *types.Basic, val exact.Value) {
+       // mantissa
+       mant := exact.MakeFromLiteral(p.parseInt(), token.INT)
+       if mant == nil {
+               panic("invalid mantissa")
+       }
+
+       if p.lit == "p" {
+               // exponent (base 2)
+               p.next()
+               exp, err := strconv.ParseInt(p.parseInt(), 10, 0)
+               if err != nil {
+                       p.error(err)
+               }
+               if exp < 0 {
+                       denom := exact.MakeInt64(1)
+                       denom = exact.Shift(denom, token.SHL, uint(-exp))
+                       typ = types.Typ[types.UntypedFloat]
+                       val = exact.BinaryOp(mant, token.QUO, denom)
+                       return
+               }
+               if exp > 0 {
+                       mant = exact.Shift(mant, token.SHL, uint(exp))
+               }
+               typ = types.Typ[types.UntypedFloat]
+               val = mant
+               return
+       }
+
+       typ = types.Typ[types.UntypedInt]
+       val = mant
+       return
+}
+
+// ConstDecl   = "const" ExportedName [ Type ] "=" Literal .
+// Literal     = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit .
+// bool_lit    = "true" | "false" .
+// complex_lit = "(" float_lit "+" float_lit "i" ")" .
+// rune_lit    = "(" int_lit "+" int_lit ")" .
+// string_lit  = `"` { unicode_char } `"` .
+//
+func (p *parser) parseConstDecl() {
+       p.expectKeyword("const")
+       pkg, name := p.parseExportedName()
+
+       var typ0 types.Type
+       if p.tok != '=' {
+               typ0 = p.parseType()
+       }
+
+       p.expect('=')
+       var typ types.Type
+       var val exact.Value
+       switch p.tok {
+       case scanner.Ident:
+               // bool_lit
+               if p.lit != "true" && p.lit != "false" {
+                       p.error("expected true or false")
+               }
+               typ = types.Typ[types.UntypedBool]
+               val = exact.MakeBool(p.lit == "true")
+               p.next()
+
+       case '-', scanner.Int:
+               // int_lit
+               typ, val = p.parseNumber()
+
+       case '(':
+               // complex_lit or rune_lit
+               p.next()
+               if p.tok == scanner.Char {
+                       p.next()
+                       p.expect('+')
+                       typ = types.Typ[types.UntypedRune]
+                       _, val = p.parseNumber()
+                       p.expect(')')
+                       break
+               }
+               _, re := p.parseNumber()
+               p.expect('+')
+               _, im := p.parseNumber()
+               p.expectKeyword("i")
+               p.expect(')')
+               typ = types.Typ[types.UntypedComplex]
+               val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+
+       case scanner.Char:
+               // rune_lit
+               typ = types.Typ[types.UntypedRune]
+               val = exact.MakeFromLiteral(p.lit, token.CHAR)
+               p.next()
+
+       case scanner.String:
+               // string_lit
+               typ = types.Typ[types.UntypedString]
+               val = exact.MakeFromLiteral(p.lit, token.STRING)
+               p.next()
+
+       default:
+               p.errorf("expected literal got %s", scanner.TokenString(p.tok))
+       }
+
+       if typ0 == nil {
+               typ0 = typ
+       }
+
+       pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val))
+}
+
+// TypeDecl = "type" ExportedName Type .
+//
+func (p *parser) parseTypeDecl() {
+       p.expectKeyword("type")
+       pkg, name := p.parseExportedName()
+       obj := declTypeName(pkg, name)
+
+       // The type object may have been imported before and thus already
+       // have a type associated with it. We still need to parse the type
+       // structure, but throw it away if the object already has a type.
+       // This ensures that all imports refer to the same type object for
+       // a given type declaration.
+       typ := p.parseType()
+
+       if name := obj.Type().(*types.Named); name.Underlying() == nil {
+               name.SetUnderlying(typ)
+       }
+}
+
+// VarDecl = "var" ExportedName Type .
+//
+func (p *parser) parseVarDecl() {
+       p.expectKeyword("var")
+       pkg, name := p.parseExportedName()
+       typ := p.parseType()
+       pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
+}
+
+// Func = Signature [ Body ] .
+// Body = "{" ... "}" .
+//
+func (p *parser) parseFunc(recv *types.Var) *types.Signature {
+       sig := p.parseSignature(recv)
+       if p.tok == '{' {
+               p.next()
+               for i := 1; i > 0; p.next() {
+                       switch p.tok {
+                       case '{':
+                               i++
+                       case '}':
+                               i--
+                       }
+               }
+       }
+       return sig
+}
+
+// MethodDecl = "func" Receiver Name Func .
+// Receiver   = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
+//
+func (p *parser) parseMethodDecl() {
+       // "func" already consumed
+       p.expect('(')
+       recv, _ := p.parseParameter() // receiver
+       p.expect(')')
+
+       // determine receiver base type object
+       base := deref(recv.Type()).(*types.Named)
+
+       // parse method name, signature, and possibly inlined body
+       _, name := p.parseName(true)
+       sig := p.parseFunc(recv)
+
+       // methods always belong to the same package as the base type object
+       pkg := base.Obj().Pkg()
+
+       // add method to type unless type was imported before
+       // and method exists already
+       // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small.
+       base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+}
+
+// FuncDecl = "func" ExportedName Func .
+//
+func (p *parser) parseFuncDecl() {
+       // "func" already consumed
+       pkg, name := p.parseExportedName()
+       typ := p.parseFunc(nil)
+       pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ))
+}
+
+// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
+//
+func (p *parser) parseDecl() {
+       if p.tok == scanner.Ident {
+               switch p.lit {
+               case "import":
+                       p.parseImportDecl()
+               case "const":
+                       p.parseConstDecl()
+               case "type":
+                       p.parseTypeDecl()
+               case "var":
+                       p.parseVarDecl()
+               case "func":
+                       p.next() // look ahead
+                       if p.tok == '(' {
+                               p.parseMethodDecl()
+                       } else {
+                               p.parseFuncDecl()
+                       }
+               }
+       }
+       p.expect('\n')
+}
+
+// ----------------------------------------------------------------------------
+// Export
+
+// Export        = "PackageClause { Decl } "$$" .
+// PackageClause = "package" PackageName [ "safe" ] "\n" .
+//
+func (p *parser) parseExport() *types.Package {
+       p.expectKeyword("package")
+       name := p.parsePackageName()
+       if p.tok == scanner.Ident && p.lit == "safe" {
+               // package was compiled with -u option - ignore
+               p.next()
+       }
+       p.expect('\n')
+
+       pkg := p.getPkg(p.id, name)
+
+       for p.tok != '$' && p.tok != scanner.EOF {
+               p.parseDecl()
+       }
+
+       if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
+               // don't call next()/expect() since reading past the
+               // export data may cause scanner errors (e.g. NUL chars)
+               p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
+       }
+
+       if n := p.scanner.ErrorCount; n != 0 {
+               p.errorf("expected no scanner errors, got %d", n)
+       }
+
+       // package was imported completely and without errors
+       pkg.MarkComplete()
+
+       return pkg
+}
diff --git a/src/go/types/internal/gcimporter/gcimporter_test.go b/src/go/types/internal/gcimporter/gcimporter_test.go
new file mode 100644 (file)
index 0000000..7bf81d3
--- /dev/null
@@ -0,0 +1,216 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gcimporter
+
+import (
+       "go/build"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "runtime"
+       "strings"
+       "testing"
+       "time"
+
+       "go/types"
+)
+
+var gcPath string // Go compiler path
+
+func init() {
+       // determine compiler
+       var gc string
+       switch runtime.GOARCH {
+       case "386":
+               gc = "8g"
+       case "amd64":
+               gc = "6g"
+       case "arm":
+               gc = "5g"
+       default:
+               gcPath = "unknown-GOARCH-compiler"
+               return
+       }
+       gcPath = filepath.Join(build.ToolDir, gc)
+}
+
+func compile(t *testing.T, dirname, filename string) string {
+       cmd := exec.Command(gcPath, filename)
+       cmd.Dir = dirname
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Logf("%s", out)
+               t.Fatalf("%s %s failed: %s", gcPath, filename, err)
+       }
+       archCh, _ := build.ArchChar(runtime.GOARCH)
+       // filename should end with ".go"
+       return filepath.Join(dirname, filename[:len(filename)-2]+archCh)
+}
+
+// Use the same global imports map for all tests. The effect is
+// as if all tested packages were imported into a single package.
+var imports = make(map[string]*types.Package)
+
+func testPath(t *testing.T, path string) bool {
+       t0 := time.Now()
+       _, err := Import(imports, path)
+       if err != nil {
+               t.Errorf("testPath(%s): %s", path, err)
+               return false
+       }
+       t.Logf("testPath(%s): %v", path, time.Since(t0))
+       return true
+}
+
+const maxTime = 30 * time.Second
+
+func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
+       dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
+       list, err := ioutil.ReadDir(dirname)
+       if err != nil {
+               t.Fatalf("testDir(%s): %s", dirname, err)
+       }
+       for _, f := range list {
+               if time.Now().After(endTime) {
+                       t.Log("testing time used up")
+                       return
+               }
+               switch {
+               case !f.IsDir():
+                       // try extensions
+                       for _, ext := range pkgExts {
+                               if strings.HasSuffix(f.Name(), ext) {
+                                       name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
+                                       if testPath(t, filepath.Join(dir, name)) {
+                                               nimports++
+                                       }
+                               }
+                       }
+               case f.IsDir():
+                       nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
+               }
+       }
+       return
+}
+
+func TestImport(t *testing.T) {
+       // This package does not handle gccgo export data.
+       if runtime.Compiler == "gccgo" {
+               return
+       }
+
+       // On cross-compile builds, the path will not exist.
+       // Need to use GOHOSTOS, which is not available.
+       if _, err := os.Stat(gcPath); err != nil {
+               t.Skipf("skipping test: %v", err)
+       }
+
+       if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
+               defer os.Remove(outFn)
+       }
+
+       nimports := 0
+       if testPath(t, "./testdata/exports") {
+               nimports++
+       }
+       nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
+       t.Logf("tested %d imports", nimports)
+}
+
+var importedObjectTests = []struct {
+       name string
+       want string
+}{
+       {"unsafe.Pointer", "type Pointer unsafe.Pointer"},
+       {"math.Pi", "const Pi untyped float"},
+       {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
+       {"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
+       {"math.Sin", "func Sin(x float64) float64"},
+       // TODO(gri) add more tests
+}
+
+func TestImportedTypes(t *testing.T) {
+       // This package does not handle gccgo export data.
+       if runtime.Compiler == "gccgo" {
+               return
+       }
+       for _, test := range importedObjectTests {
+               s := strings.Split(test.name, ".")
+               if len(s) != 2 {
+                       t.Fatal("inconsistent test data")
+               }
+               importPath := s[0]
+               objName := s[1]
+
+               pkg, err := Import(imports, importPath)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+
+               obj := pkg.Scope().Lookup(objName)
+               if obj == nil {
+                       t.Errorf("%s: object not found", test.name)
+                       continue
+               }
+
+               got := types.ObjectString(pkg, obj)
+               if got != test.want {
+                       t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+               }
+       }
+}
+
+func TestIssue5815(t *testing.T) {
+       // This package does not handle gccgo export data.
+       if runtime.Compiler == "gccgo" {
+               return
+       }
+
+       pkg, err := Import(make(map[string]*types.Package), "strings")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       scope := pkg.Scope()
+       for _, name := range scope.Names() {
+               obj := scope.Lookup(name)
+               if obj.Pkg() == nil {
+                       t.Errorf("no pkg for %s", obj)
+               }
+               if tname, _ := obj.(*types.TypeName); tname != nil {
+                       named := tname.Type().(*types.Named)
+                       for i := 0; i < named.NumMethods(); i++ {
+                               m := named.Method(i)
+                               if m.Pkg() == nil {
+                                       t.Errorf("no pkg for %s", m)
+                               }
+                       }
+               }
+       }
+}
+
+// Smoke test to ensure that imported methods get the correct package.
+func TestCorrectMethodPackage(t *testing.T) {
+       // This package does not handle gccgo export data.
+       if runtime.Compiler == "gccgo" {
+               return
+       }
+
+       imports := make(map[string]*types.Package)
+       _, err := Import(imports, "net/http")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
+       mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
+       sel := mset.Lookup(nil, "Lock")
+       lock := sel.Obj().(*types.Func)
+       if got, want := lock.Pkg().Path(), "sync"; got != want {
+               t.Errorf("got package path %q; want %q", got, want)
+       }
+}
diff --git a/src/go/types/internal/gcimporter/testdata/exports.go b/src/go/types/internal/gcimporter/testdata/exports.go
new file mode 100644 (file)
index 0000000..8ee28b0
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is used to generate an object file which
+// serves as test file for gcimporter_test.go.
+
+package exports
+
+import (
+       "go/ast"
+)
+
+// Issue 3682: Correctly read dotted identifiers from export data.
+const init1 = 0
+
+func init() {}
+
+const (
+       C0 int = 0
+       C1     = 3.14159265
+       C2     = 2.718281828i
+       C3     = -123.456e-789
+       C4     = +123.456E+789
+       C5     = 1234i
+       C6     = "foo\n"
+       C7     = `bar\n`
+)
+
+type (
+       T1  int
+       T2  [10]int
+       T3  []int
+       T4  *int
+       T5  chan int
+       T6a chan<- int
+       T6b chan (<-chan int)
+       T6c chan<- (chan int)
+       T7  <-chan *ast.File
+       T8  struct{}
+       T9  struct {
+               a    int
+               b, c float32
+               d    []string `go:"tag"`
+       }
+       T10 struct {
+               T8
+               T9
+               _ *T10
+       }
+       T11 map[int]string
+       T12 interface{}
+       T13 interface {
+               m1()
+               m2(int) float32
+       }
+       T14 interface {
+               T12
+               T13
+               m3(x ...struct{}) []T9
+       }
+       T15 func()
+       T16 func(int)
+       T17 func(x int)
+       T18 func() float32
+       T19 func() (x float32)
+       T20 func(...interface{})
+       T21 struct{ next *T21 }
+       T22 struct{ link *T23 }
+       T23 struct{ link *T22 }
+       T24 *T24
+       T25 *T26
+       T26 *T27
+       T27 *T25
+       T28 func(T28) T28
+)
+
+var (
+       V0 int
+       V1 = -991.0
+)
+
+func F1()         {}
+func F2(x int)    {}
+func F3() int     { return 0 }
+func F4() float32 { return 0 }
+func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
+
+func (p *T1) M1()
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
new file mode 100644 (file)
index 0000000..3722dc2
--- /dev/null
@@ -0,0 +1,205 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements tests for various issues.
+
+package types_test
+
+import (
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "sort"
+       "strings"
+       "testing"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+func TestIssue5770(t *testing.T) {
+       src := `package p; type S struct{T}`
+       f, err := parser.ParseFile(fset, "", src, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       _, err = Check(f.Name.Name, fset, []*ast.File{f}) // do not crash
+       want := "undeclared name: T"
+       if err == nil || !strings.Contains(err.Error(), want) {
+               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.Fatal(err)
+       }
+
+       var conf Config
+       types := make(map[ast.Expr]TypeAndValue)
+       _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       for x, tv := range types {
+               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 && !Identical(tv.Type, want) {
+                       t.Errorf("got %s; want %s", tv.Type, want)
+               }
+       }
+}
+
+func TestIssue6413(t *testing.T) {
+       src := `
+package p
+func f() int {
+       defer f()
+       go f()
+       return 0
+}
+`
+       f, err := parser.ParseFile(fset, "", src, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var conf Config
+       types := make(map[ast.Expr]TypeAndValue)
+       _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       want := Typ[Int]
+       n := 0
+       for x, tv := range types {
+               if _, ok := x.(*ast.CallExpr); ok {
+                       if tv.Type != want {
+                               t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want)
+                       }
+                       n++
+               }
+       }
+
+       if n != 2 {
+               t.Errorf("got %d CallExprs; want 2", n)
+       }
+}
+
+func TestIssue7245(t *testing.T) {
+       src := `
+package p
+func (T) m() (res bool) { return }
+type T struct{} // receiver type after method declaration
+`
+       f, err := parser.ParseFile(fset, "", src, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var conf Config
+       defs := make(map[*ast.Ident]Object)
+       _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       m := f.Decls[0].(*ast.FuncDecl)
+       res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
+       res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
+
+       if res1 != res2 {
+               t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
+       }
+}
+
+// This tests that uses of existing vars on the LHS of an assignment
+// are Uses, not Defs; and also that the (illegal) use of a non-var on
+// the LHS of an assignment is a Use nonetheless.
+func TestIssue7827(t *testing.T) {
+       const src = `
+package p
+func _() {
+       const w = 1        // defs w
+        x, y := 2, 3       // defs x, y
+        w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
+        _, _, _ = x, y, z  // uses x, y, z
+}
+`
+       const want = `L3 defs func p._()
+L4 defs const w untyped int
+L5 defs var x int
+L5 defs var y int
+L6 defs var z int
+L6 uses const w untyped int
+L6 uses var x int
+L7 uses var x int
+L7 uses var y int
+L7 uses var z int`
+
+       f, err := parser.ParseFile(fset, "", src, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // don't abort at the first error
+       conf := Config{Error: func(err error) { t.Log(err) }}
+       defs := make(map[*ast.Ident]Object)
+       uses := make(map[*ast.Ident]Object)
+       _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
+       if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
+               t.Errorf("Check: unexpected error: %s", s)
+       }
+
+       var facts []string
+       for id, obj := range defs {
+               if obj != nil {
+                       fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj)
+                       facts = append(facts, fact)
+               }
+       }
+       for id, obj := range uses {
+               fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj)
+               facts = append(facts, fact)
+       }
+       sort.Strings(facts)
+
+       got := strings.Join(facts, "\n")
+       if got != want {
+               t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
+       }
+}
diff --git a/src/go/types/labels.go b/src/go/types/labels.go
new file mode 100644 (file)
index 0000000..d6ffc52
--- /dev/null
@@ -0,0 +1,268 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+)
+
+// labels checks correct label use in body.
+func (check *Checker) labels(body *ast.BlockStmt) {
+       // set of all labels in this body
+       all := NewScope(nil, "label")
+
+       fwdJumps := check.blockBranches(all, nil, nil, body.List)
+
+       // If there are any forward jumps left, no label was found for
+       // the corresponding goto statements. Either those labels were
+       // never defined, or they are inside blocks and not reachable
+       // for the respective gotos.
+       for _, jmp := range fwdJumps {
+               var msg string
+               name := jmp.Label.Name
+               if alt := all.Lookup(name); alt != nil {
+                       msg = "goto %s jumps into block"
+                       alt.(*Label).used = true // avoid another error
+               } else {
+                       msg = "label %s not declared"
+               }
+               check.errorf(jmp.Label.Pos(), msg, name)
+       }
+
+       // spec: "It is illegal to define a label that is never used."
+       for _, obj := range all.elems {
+               if lbl := obj.(*Label); !lbl.used {
+                       check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+               }
+       }
+}
+
+// A block tracks label declarations in a block and its enclosing blocks.
+type block struct {
+       parent *block                      // enclosing block
+       lstmt  *ast.LabeledStmt            // labeled statement to which this block belongs, or nil
+       labels map[string]*ast.LabeledStmt // allocated lazily
+}
+
+// insert records a new label declaration for the current block.
+// The label must not have been declared before in any block.
+func (b *block) insert(s *ast.LabeledStmt) {
+       name := s.Label.Name
+       if debug {
+               assert(b.gotoTarget(name) == nil)
+       }
+       labels := b.labels
+       if labels == nil {
+               labels = make(map[string]*ast.LabeledStmt)
+               b.labels = labels
+       }
+       labels[name] = s
+}
+
+// gotoTarget returns the labeled statement in the current
+// or an enclosing block with the given label name, or nil.
+func (b *block) gotoTarget(name string) *ast.LabeledStmt {
+       for s := b; s != nil; s = s.parent {
+               if t := s.labels[name]; t != nil {
+                       return t
+               }
+       }
+       return nil
+}
+
+// enclosingTarget returns the innermost enclosing labeled
+// statement with the given label name, or nil.
+func (b *block) enclosingTarget(name string) *ast.LabeledStmt {
+       for s := b; s != nil; s = s.parent {
+               if t := s.lstmt; t != nil && t.Label.Name == name {
+                       return t
+               }
+       }
+       return nil
+}
+
+// blockBranches processes a block's statement list and returns the set of outgoing forward jumps.
+// all is the scope of all declared labels, parent the set of labels declared in the immediately
+// enclosing block, and lstmt is the labeled statement this block is associated with (or nil).
+func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.LabeledStmt, list []ast.Stmt) []*ast.BranchStmt {
+       b := &block{parent: parent, lstmt: lstmt}
+
+       var (
+               varDeclPos         token.Pos
+               fwdJumps, badJumps []*ast.BranchStmt
+       )
+
+       // All forward jumps jumping over a variable declaration are possibly
+       // invalid (they may still jump out of the block and be ok).
+       // recordVarDecl records them for the given position.
+       recordVarDecl := func(pos token.Pos) {
+               varDeclPos = pos
+               badJumps = append(badJumps[:0], fwdJumps...) // copy fwdJumps to badJumps
+       }
+
+       jumpsOverVarDecl := func(jmp *ast.BranchStmt) bool {
+               if varDeclPos.IsValid() {
+                       for _, bad := range badJumps {
+                               if jmp == bad {
+                                       return true
+                               }
+                       }
+               }
+               return false
+       }
+
+       blockBranches := func(lstmt *ast.LabeledStmt, list []ast.Stmt) {
+               // Unresolved forward jumps inside the nested block
+               // become forward jumps in the current block.
+               fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, list)...)
+       }
+
+       var stmtBranches func(ast.Stmt)
+       stmtBranches = func(s ast.Stmt) {
+               switch s := s.(type) {
+               case *ast.DeclStmt:
+                       if d, _ := s.Decl.(*ast.GenDecl); d != nil && d.Tok == token.VAR {
+                               recordVarDecl(d.Pos())
+                       }
+
+               case *ast.LabeledStmt:
+                       // declare non-blank label
+                       if name := s.Label.Name; name != "_" {
+                               lbl := NewLabel(s.Label.Pos(), check.pkg, name)
+                               if alt := all.Insert(lbl); alt != nil {
+                                       check.softErrorf(lbl.pos, "label %s already declared", name)
+                                       check.reportAltDecl(alt)
+                                       // ok to continue
+                               } else {
+                                       b.insert(s)
+                                       check.recordDef(s.Label, lbl)
+                               }
+                               // resolve matching forward jumps and remove them from fwdJumps
+                               i := 0
+                               for _, jmp := range fwdJumps {
+                                       if jmp.Label.Name == name {
+                                               // match
+                                               lbl.used = true
+                                               check.recordUse(jmp.Label, lbl)
+                                               if jumpsOverVarDecl(jmp) {
+                                                       check.softErrorf(
+                                                               jmp.Label.Pos(),
+                                                               "goto %s jumps over variable declaration at line %d",
+                                                               name,
+                                                               check.fset.Position(varDeclPos).Line,
+                                                       )
+                                                       // ok to continue
+                                               }
+                                       } else {
+                                               // no match - record new forward jump
+                                               fwdJumps[i] = jmp
+                                               i++
+                                       }
+                               }
+                               fwdJumps = fwdJumps[:i]
+                               lstmt = s
+                       }
+                       stmtBranches(s.Stmt)
+
+               case *ast.BranchStmt:
+                       if s.Label == nil {
+                               return // checked in 1st pass (check.stmt)
+                       }
+
+                       // determine and validate target
+                       name := s.Label.Name
+                       switch s.Tok {
+                       case token.BREAK:
+                               // spec: "If there is a label, it must be that of an enclosing
+                               // "for", "switch", or "select" statement, and that is the one
+                               // whose execution terminates."
+                               valid := false
+                               if t := b.enclosingTarget(name); t != nil {
+                                       switch t.Stmt.(type) {
+                                       case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt:
+                                               valid = true
+                                       }
+                               }
+                               if !valid {
+                                       check.errorf(s.Label.Pos(), "invalid break label %s", name)
+                                       return
+                               }
+
+                       case token.CONTINUE:
+                               // spec: "If there is a label, it must be that of an enclosing
+                               // "for" statement, and that is the one whose execution advances."
+                               valid := false
+                               if t := b.enclosingTarget(name); t != nil {
+                                       switch t.Stmt.(type) {
+                                       case *ast.ForStmt, *ast.RangeStmt:
+                                               valid = true
+                                       }
+                               }
+                               if !valid {
+                                       check.errorf(s.Label.Pos(), "invalid continue label %s", name)
+                                       return
+                               }
+
+                       case token.GOTO:
+                               if b.gotoTarget(name) == nil {
+                                       // label may be declared later - add branch to forward jumps
+                                       fwdJumps = append(fwdJumps, s)
+                                       return
+                               }
+
+                       default:
+                               check.invalidAST(s.Pos(), "branch statement: %s %s", s.Tok, name)
+                               return
+                       }
+
+                       // record label use
+                       obj := all.Lookup(name)
+                       obj.(*Label).used = true
+                       check.recordUse(s.Label, obj)
+
+               case *ast.AssignStmt:
+                       if s.Tok == token.DEFINE {
+                               recordVarDecl(s.Pos())
+                       }
+
+               case *ast.BlockStmt:
+                       blockBranches(lstmt, s.List)
+
+               case *ast.IfStmt:
+                       stmtBranches(s.Body)
+                       if s.Else != nil {
+                               stmtBranches(s.Else)
+                       }
+
+               case *ast.CaseClause:
+                       blockBranches(nil, s.Body)
+
+               case *ast.SwitchStmt:
+                       stmtBranches(s.Body)
+
+               case *ast.TypeSwitchStmt:
+                       stmtBranches(s.Body)
+
+               case *ast.CommClause:
+                       blockBranches(nil, s.Body)
+
+               case *ast.SelectStmt:
+                       stmtBranches(s.Body)
+
+               case *ast.ForStmt:
+                       stmtBranches(s.Body)
+
+               case *ast.RangeStmt:
+                       stmtBranches(s.Body)
+               }
+       }
+
+       for _, s := range list {
+               stmtBranches(s)
+       }
+
+       return fwdJumps
+}
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
new file mode 100644 (file)
index 0000000..3caca55
--- /dev/null
@@ -0,0 +1,341 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements various field and method lookup functions.
+
+package types
+
+// LookupFieldOrMethod looks up a field or method with given package and name
+// in T and returns the corresponding *Var or *Func, an index sequence, and a
+// bool indicating if there were any pointer indirections on the path to the
+// field or method. If addressable is set, T is the type of an addressable
+// variable (only matters for method lookups).
+//
+// The last index entry is the field or method index in the (possibly embedded)
+// type where the entry was found, either:
+//
+//     1) the list of declared methods of a named type; or
+//     2) the list of all methods (method set) of an interface type; or
+//     3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the anonymous struct fields
+// traversed to get to the found entry, starting at depth 0.
+//
+// If no entry is found, a nil object is returned. In this case, the returned
+// index and indirect values have the following meaning:
+//
+//     - If index != nil, the index sequence points to an ambiguous entry
+//     (the same name appeared more than once at the same embedding level).
+//
+//     - If indirect is set, a method with a pointer receiver type was found
+//      but there was no pointer on the path from the actual receiver type to
+//     the method's formal receiver base type, nor was the receiver addressable.
+//
+func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+       // Methods cannot be associated to a named pointer type
+       // (spec: "The type denoted by T is called the receiver base type;
+       // it must not be a pointer or interface type and it must be declared
+       // in the same package as the method.").
+       // Thus, if we have a named pointer type, proceed with the underlying
+       // pointer type but discard the result if it is a method since we would
+       // not have found it for T (see also issue 8590).
+       if t, _ := T.(*Named); t != nil {
+               if p, _ := t.underlying.(*Pointer); p != nil {
+                       obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
+                       if _, ok := obj.(*Func); ok {
+                               return nil, nil, false
+                       }
+                       return
+               }
+       }
+
+       return lookupFieldOrMethod(T, addressable, pkg, name)
+}
+
+// TODO(gri) The named type consolidation and seen maps below must be
+//           indexed by unique keys for a given type. Verify that named
+//           types always have only one representation (even when imported
+//           indirectly via different packages.)
+
+func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+       // WARNING: The code in this function is extremely subtle - do not modify casually!
+       //          This function and NewMethodSet should be kept in sync.
+
+       if name == "_" {
+               return // blank fields/methods are never found
+       }
+
+       typ, isPtr := deref(T)
+       named, _ := typ.(*Named)
+
+       // *typ where typ is an interface has no methods.
+       if isPtr {
+               utyp := typ
+               if named != nil {
+                       utyp = named.underlying
+               }
+               if _, ok := utyp.(*Interface); ok {
+                       return
+               }
+       }
+
+       // Start with typ as single entry at shallowest depth.
+       // If typ is not a named type, insert a nil type instead.
+       current := []embeddedType{{named, nil, isPtr, false}}
+
+       // named types that we have seen already, allocated lazily
+       var seen map[*Named]bool
+
+       // search current depth
+       for len(current) > 0 {
+               var next []embeddedType // embedded types found at current depth
+
+               // look for (pkg, name) in all types at current depth
+               for _, e := range current {
+                       // The very first time only, e.typ may be nil.
+                       // In this case, we don't have a named type and
+                       // we simply continue with the underlying type.
+                       if e.typ != nil {
+                               if seen[e.typ] {
+                                       // We have seen this type before, at a more shallow depth
+                                       // (note that multiples of this type at the current depth
+                                       // were consolidated before). The type at that depth shadows
+                                       // this same type at the current depth, so we can ignore
+                                       // this one.
+                                       continue
+                               }
+                               if seen == nil {
+                                       seen = make(map[*Named]bool)
+                               }
+                               seen[e.typ] = true
+
+                               // look for a matching attached method
+                               if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
+                                       // potential match
+                                       assert(m.typ != nil)
+                                       index = concat(e.index, i)
+                                       if obj != nil || e.multiples {
+                                               return nil, index, false // collision
+                                       }
+                                       obj = m
+                                       indirect = e.indirect
+                                       continue // we can't have a matching field or interface method
+                               }
+
+                               // continue with underlying type
+                               typ = e.typ.underlying
+                       }
+
+                       switch t := typ.(type) {
+                       case *Struct:
+                               // look for a matching field and collect embedded types
+                               for i, f := range t.fields {
+                                       if f.sameId(pkg, name) {
+                                               assert(f.typ != nil)
+                                               index = concat(e.index, i)
+                                               if obj != nil || e.multiples {
+                                                       return nil, index, false // collision
+                                               }
+                                               obj = f
+                                               indirect = e.indirect
+                                               continue // we can't have a matching interface method
+                                       }
+                                       // Collect embedded struct fields for searching the next
+                                       // lower depth, but only if we have not seen a match yet
+                                       // (if we have a match it is either the desired field or
+                                       // we have a name collision on the same depth; in either
+                                       // case we don't need to look further).
+                                       // Embedded fields are always of the form T or *T where
+                                       // T is a named type. If e.typ appeared multiple times at
+                                       // this depth, f.typ appears multiple times at the next
+                                       // depth.
+                                       if obj == nil && f.anonymous {
+                                               // Ignore embedded basic types - only user-defined
+                                               // named types can have methods or struct fields.
+                                               typ, isPtr := deref(f.typ)
+                                               if t, _ := typ.(*Named); t != nil {
+                                                       next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+                                               }
+                                       }
+                               }
+
+                       case *Interface:
+                               // look for a matching method
+                               // TODO(gri) t.allMethods is sorted - use binary search
+                               if i, m := lookupMethod(t.allMethods, pkg, name); m != nil {
+                                       assert(m.typ != nil)
+                                       index = concat(e.index, i)
+                                       if obj != nil || e.multiples {
+                                               return nil, index, false // collision
+                                       }
+                                       obj = m
+                                       indirect = e.indirect
+                               }
+                       }
+               }
+
+               if obj != nil {
+                       // found a potential match
+                       // spec: "A method call x.m() is valid if the method set of (the type of) x
+                       //        contains m and the argument list can be assigned to the parameter
+                       //        list of m. If x is addressable and &x's method set contains m, x.m()
+                       //        is shorthand for (&x).m()".
+                       if f, _ := obj.(*Func); f != nil && ptrRecv(f) && !indirect && !addressable {
+                               return nil, nil, true // pointer/addressable receiver required
+                       }
+                       return
+               }
+
+               current = consolidateMultiples(next)
+       }
+
+       return nil, nil, false // not found
+}
+
+// embeddedType represents an embedded named type
+type embeddedType struct {
+       typ       *Named // nil means use the outer typ variable instead
+       index     []int  // embedded field indices, starting with index at depth 0
+       indirect  bool   // if set, there was a pointer indirection on the path to this field
+       multiples bool   // if set, typ appears multiple times at this depth
+}
+
+// consolidateMultiples collects multiple list entries with the same type
+// into a single entry marked as containing multiples. The result is the
+// consolidated list.
+func consolidateMultiples(list []embeddedType) []embeddedType {
+       if len(list) <= 1 {
+               return list // at most one entry - nothing to do
+       }
+
+       n := 0                       // number of entries w/ unique type
+       prev := make(map[*Named]int) // index at which type was previously seen
+       for _, e := range list {
+               if i, found := prev[e.typ]; found {
+                       list[i].multiples = true
+                       // ignore this entry
+               } else {
+                       prev[e.typ] = n
+                       list[n] = e
+                       n++
+               }
+       }
+       return list[:n]
+}
+
+// MissingMethod returns (nil, false) if V implements T, otherwise it
+// returns a missing method required by T and whether it is missing or
+// just has the wrong type.
+//
+// For non-interface types V, or if static is set, V implements T if all
+// methods of T are present in V. Otherwise (V is an interface and static
+// is not set), MissingMethod only checks that methods of T which are also
+// present in V have matching types (e.g., for a type assertion x.(T) where
+// x is of interface type V).
+//
+func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
+       // fast path for common case
+       if T.Empty() {
+               return
+       }
+
+       // TODO(gri) Consider using method sets here. Might be more efficient.
+
+       if ityp, _ := V.Underlying().(*Interface); ityp != nil {
+               // TODO(gri) allMethods is sorted - can do this more efficiently
+               for _, m := range T.allMethods {
+                       _, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
+                       switch {
+                       case obj == nil:
+                               if static {
+                                       return m, false
+                               }
+                       case !Identical(obj.Type(), m.typ):
+                               return m, true
+                       }
+               }
+               return
+       }
+
+       // A concrete type implements T if it implements all methods of T.
+       for _, m := range T.allMethods {
+               obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
+
+               f, _ := obj.(*Func)
+               if f == nil {
+                       return m, false
+               }
+
+               if !Identical(f.typ, m.typ) {
+                       return m, true
+               }
+       }
+
+       return
+}
+
+// assertableTo reports whether a value of type V can be asserted to have type T.
+// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
+// method required by V and whether it is missing or just has the wrong type.
+func assertableTo(V *Interface, T Type) (method *Func, wrongType bool) {
+       // no static check is required if T is an interface
+       // spec: "If T is an interface type, x.(T) asserts that the
+       //        dynamic type of x implements the interface T."
+       if _, ok := T.Underlying().(*Interface); ok && !strict {
+               return
+       }
+       return MissingMethod(T, V, false)
+}
+
+// deref dereferences typ if it is a *Pointer and returns its base and true.
+// Otherwise it returns (typ, false).
+func deref(typ Type) (Type, bool) {
+       if p, _ := typ.(*Pointer); p != nil {
+               return p.base, true
+       }
+       return typ, false
+}
+
+// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
+// (named or unnamed) struct and returns its base. Otherwise it returns typ.
+func derefStructPtr(typ Type) Type {
+       if p, _ := typ.Underlying().(*Pointer); p != nil {
+               if _, ok := p.base.Underlying().(*Struct); ok {
+                       return p.base
+               }
+       }
+       return typ
+}
+
+// concat returns the result of concatenating list and i.
+// The result does not share its underlying array with list.
+func concat(list []int, i int) []int {
+       var t []int
+       t = append(t, list...)
+       return append(t, i)
+}
+
+// fieldIndex returns the index for the field with matching package and name, or a value < 0.
+func fieldIndex(fields []*Var, pkg *Package, name string) int {
+       if name != "_" {
+               for i, f := range fields {
+                       if f.sameId(pkg, name) {
+                               return i
+                       }
+               }
+       }
+       return -1
+}
+
+// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
+func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
+       if name != "_" {
+               for i, m := range methods {
+                       if m.sameId(pkg, name) {
+                               return i, m
+                       }
+               }
+       }
+       return -1, nil
+}
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
new file mode 100644 (file)
index 0000000..8aff6f9
--- /dev/null
@@ -0,0 +1,271 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements method sets.
+
+package types
+
+import (
+       "bytes"
+       "fmt"
+       "sort"
+)
+
+// A MethodSet is an ordered set of concrete or abstract (interface) methods;
+// a method is a MethodVal selection, and they are ordered by ascending m.Obj().Id().
+// The zero value for a MethodSet is a ready-to-use empty method set.
+type MethodSet struct {
+       list []*Selection
+}
+
+func (s *MethodSet) String() string {
+       if s.Len() == 0 {
+               return "MethodSet {}"
+       }
+
+       var buf bytes.Buffer
+       fmt.Fprintln(&buf, "MethodSet {")
+       for _, f := range s.list {
+               fmt.Fprintf(&buf, "\t%s\n", f)
+       }
+       fmt.Fprintln(&buf, "}")
+       return buf.String()
+}
+
+// Len returns the number of methods in s.
+func (s *MethodSet) Len() int { return len(s.list) }
+
+// At returns the i'th method in s for 0 <= i < s.Len().
+func (s *MethodSet) At(i int) *Selection { return s.list[i] }
+
+// Lookup returns the method with matching package and name, or nil if not found.
+func (s *MethodSet) Lookup(pkg *Package, name string) *Selection {
+       if s.Len() == 0 {
+               return nil
+       }
+
+       key := Id(pkg, name)
+       i := sort.Search(len(s.list), func(i int) bool {
+               m := s.list[i]
+               return m.obj.Id() >= key
+       })
+       if i < len(s.list) {
+               m := s.list[i]
+               if m.obj.Id() == key {
+                       return m
+               }
+       }
+       return nil
+}
+
+// Shared empty method set.
+var emptyMethodSet MethodSet
+
+// NewMethodSet returns the method set for the given type T.  It
+// always returns a non-nil method set, even if it is empty.
+//
+// A MethodSetCache handles repeat queries more efficiently.
+//
+func NewMethodSet(T Type) *MethodSet {
+       // WARNING: The code in this function is extremely subtle - do not modify casually!
+       //          This function and lookupFieldOrMethod should be kept in sync.
+
+       // method set up to the current depth, allocated lazily
+       var base methodSet
+
+       typ, isPtr := deref(T)
+       named, _ := typ.(*Named)
+
+       // *typ where typ is an interface has no methods.
+       if isPtr {
+               utyp := typ
+               if named != nil {
+                       utyp = named.underlying
+               }
+               if _, ok := utyp.(*Interface); ok {
+                       return &emptyMethodSet
+               }
+       }
+
+       // Start with typ as single entry at shallowest depth.
+       // If typ is not a named type, insert a nil type instead.
+       current := []embeddedType{{named, nil, isPtr, false}}
+
+       // named types that we have seen already, allocated lazily
+       var seen map[*Named]bool
+
+       // collect methods at current depth
+       for len(current) > 0 {
+               var next []embeddedType // embedded types found at current depth
+
+               // field and method sets at current depth, allocated lazily
+               var fset fieldSet
+               var mset methodSet
+
+               for _, e := range current {
+                       // The very first time only, e.typ may be nil.
+                       // In this case, we don't have a named type and
+                       // we simply continue with the underlying type.
+                       if e.typ != nil {
+                               if seen[e.typ] {
+                                       // We have seen this type before, at a more shallow depth
+                                       // (note that multiples of this type at the current depth
+                                       // were consolidated before). The type at that depth shadows
+                                       // this same type at the current depth, so we can ignore
+                                       // this one.
+                                       continue
+                               }
+                               if seen == nil {
+                                       seen = make(map[*Named]bool)
+                               }
+                               seen[e.typ] = true
+
+                               mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+
+                               // continue with underlying type
+                               typ = e.typ.underlying
+                       }
+
+                       switch t := typ.(type) {
+                       case *Struct:
+                               for i, f := range t.fields {
+                                       fset = fset.add(f, e.multiples)
+
+                                       // Embedded fields are always of the form T or *T where
+                                       // T is a named type. If typ appeared multiple times at
+                                       // this depth, f.Type appears multiple times at the next
+                                       // depth.
+                                       if f.anonymous {
+                                               // Ignore embedded basic types - only user-defined
+                                               // named types can have methods or struct fields.
+                                               typ, isPtr := deref(f.typ)
+                                               if t, _ := typ.(*Named); t != nil {
+                                                       next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+                                               }
+                                       }
+                               }
+
+                       case *Interface:
+                               mset = mset.add(t.allMethods, e.index, true, e.multiples)
+                       }
+               }
+
+               // Add methods and collisions at this depth to base if no entries with matching
+               // names exist already.
+               for k, m := range mset {
+                       if _, found := base[k]; !found {
+                               // Fields collide with methods of the same name at this depth.
+                               if _, found := fset[k]; found {
+                                       m = nil // collision
+                               }
+                               if base == nil {
+                                       base = make(methodSet)
+                               }
+                               base[k] = m
+                       }
+               }
+
+               // Multiple fields with matching names collide at this depth and shadow all
+               // entries further down; add them as collisions to base if no entries with
+               // matching names exist already.
+               for k, f := range fset {
+                       if f == nil {
+                               if _, found := base[k]; !found {
+                                       if base == nil {
+                                               base = make(methodSet)
+                                       }
+                                       base[k] = nil // collision
+                               }
+                       }
+               }
+
+               current = consolidateMultiples(next)
+       }
+
+       if len(base) == 0 {
+               return &emptyMethodSet
+       }
+
+       // collect methods
+       var list []*Selection
+       for _, m := range base {
+               if m != nil {
+                       m.recv = T
+                       list = append(list, m)
+               }
+       }
+       sort.Sort(byUniqueName(list))
+       return &MethodSet{list}
+}
+
+// A fieldSet is a set of fields and name collisions.
+// A collision indicates that multiple fields with the
+// same unique id appeared.
+type fieldSet map[string]*Var // a nil entry indicates a name collision
+
+// Add adds field f to the field set s.
+// If multiples is set, f appears multiple times
+// and is treated as a collision.
+func (s fieldSet) add(f *Var, multiples bool) fieldSet {
+       if s == nil {
+               s = make(fieldSet)
+       }
+       key := f.Id()
+       // if f is not in the set, add it
+       if !multiples {
+               if _, found := s[key]; !found {
+                       s[key] = f
+                       return s
+               }
+       }
+       s[key] = nil // collision
+       return s
+}
+
+// A methodSet is a set of methods and name collisions.
+// A collision indicates that multiple methods with the
+// same unique id appeared.
+type methodSet map[string]*Selection // a nil entry indicates a name collision
+
+// Add adds all functions in list to the method set s.
+// If multiples is set, every function in list appears multiple times
+// and is treated as a collision.
+func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
+       if len(list) == 0 {
+               return s
+       }
+       if s == nil {
+               s = make(methodSet)
+       }
+       for i, f := range list {
+               key := f.Id()
+               // if f is not in the set, add it
+               if !multiples {
+                       // TODO(gri) A found method may not be added because it's not in the method set
+                       // (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method
+                       // set and may not collide with the first one, thus leading to a false positive.
+                       // Is that possible? Investigate.
+                       if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
+                               s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
+                               continue
+                       }
+               }
+               s[key] = nil // collision
+       }
+       return s
+}
+
+// ptrRecv reports whether the receiver is of the form *T.
+// The receiver must exist.
+func ptrRecv(f *Func) bool {
+       _, isPtr := deref(f.typ.(*Signature).recv.typ)
+       return isPtr
+}
+
+// byUniqueName function lists can be sorted by their unique names.
+type byUniqueName []*Selection
+
+func (a byUniqueName) Len() int           { return len(a) }
+func (a byUniqueName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/src/go/types/methodsetcache.go b/src/go/types/methodsetcache.go
new file mode 100644 (file)
index 0000000..5a482e9
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a cache of method sets.
+
+package types
+
+import "sync"
+
+// A MethodSetCache records the method set of each type T for which
+// MethodSet(T) is called so that repeat queries are fast.
+// The zero value is a ready-to-use cache instance.
+type MethodSetCache struct {
+       mu     sync.Mutex
+       named  map[*Named]struct{ value, pointer *MethodSet } // method sets for named N and *N
+       others map[Type]*MethodSet                            // all other types
+}
+
+// MethodSet returns the method set of type T.  It is thread-safe.
+//
+// If cache is nil, this function is equivalent to NewMethodSet(T).
+// Utility functions can thus expose an optional *MethodSetCache
+// parameter to clients that care about performance.
+//
+func (cache *MethodSetCache) MethodSet(T Type) *MethodSet {
+       if cache == nil {
+               return NewMethodSet(T)
+       }
+       cache.mu.Lock()
+       defer cache.mu.Unlock()
+
+       switch T := T.(type) {
+       case *Named:
+               return cache.lookupNamed(T).value
+
+       case *Pointer:
+               if N, ok := T.Elem().(*Named); ok {
+                       return cache.lookupNamed(N).pointer
+               }
+       }
+
+       // all other types
+       // (The map uses pointer equivalence, not type identity.)
+       mset := cache.others[T]
+       if mset == nil {
+               mset = NewMethodSet(T)
+               if cache.others == nil {
+                       cache.others = make(map[Type]*MethodSet)
+               }
+               cache.others[T] = mset
+       }
+       return mset
+}
+
+func (cache *MethodSetCache) lookupNamed(named *Named) struct{ value, pointer *MethodSet } {
+       if cache.named == nil {
+               cache.named = make(map[*Named]struct{ value, pointer *MethodSet })
+       }
+       // Avoid recomputing mset(*T) for each distinct Pointer
+       // instance whose underlying type is a named type.
+       msets, ok := cache.named[named]
+       if !ok {
+               msets.value = NewMethodSet(named)
+               msets.pointer = NewMethodSet(NewPointer(named))
+               cache.named[named] = msets
+       }
+       return msets
+}
diff --git a/src/go/types/object.go b/src/go/types/object.go
new file mode 100644 (file)
index 0000000..38ddaa4
--- /dev/null
@@ -0,0 +1,340 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/token"
+
+       "go/exact"
+)
+
+// TODO(gri) Document factory, accessor methods, and fields. General clean-up.
+
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
+// All objects implement the Object interface.
+//
+type Object interface {
+       Parent() *Scope // scope in which this object is declared
+       Pos() token.Pos // position of object identifier in declaration
+       Pkg() *Package  // nil for objects in the Universe scope and labels
+       Name() string   // package local object name
+       Type() Type     // object type
+       Exported() bool // reports whether the name starts with a capital letter
+       Id() string     // object id (see Id below)
+
+       // String returns a human-readable string of the object.
+       String() string
+
+       // order reflects a package-level object's source order: if object
+       // a is before object b in the source, then a.order() < b.order().
+       // order returns a value > 0 for package-level objects; it returns
+       // 0 for all other objects (including objects in file scopes).
+       order() uint32
+
+       // setOrder sets the order number of the object. It must be > 0.
+       setOrder(uint32)
+
+       // setParent sets the parent scope of the object.
+       setParent(*Scope)
+
+       // sameId reports whether obj.Id() and Id(pkg, name) are the same.
+       sameId(pkg *Package, name string) bool
+}
+
+// Id returns name if it is exported, otherwise it
+// returns the name qualified with the package path.
+func Id(pkg *Package, name string) string {
+       if ast.IsExported(name) {
+               return name
+       }
+       // unexported names need the package path for differentiation
+       // (if there's no package, make sure we don't start with '.'
+       // as that may change the order of methods between a setup
+       // inside a package and outside a package - which breaks some
+       // tests)
+       path := "_"
+       // TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
+       // if pkg == nil {
+       //      panic("nil package in lookup of unexported name")
+       // }
+       if pkg != nil {
+               path = pkg.path
+               if path == "" {
+                       path = "_"
+               }
+       }
+       return path + "." + name
+}
+
+// An object implements the common parts of an Object.
+type object struct {
+       parent *Scope
+       pos    token.Pos
+       pkg    *Package
+       name   string
+       typ    Type
+       order_ uint32
+}
+
+func (obj *object) Parent() *Scope { return obj.parent }
+func (obj *object) Pos() token.Pos { return obj.pos }
+func (obj *object) Pkg() *Package  { return obj.pkg }
+func (obj *object) Name() string   { return obj.name }
+func (obj *object) Type() Type     { return obj.typ }
+func (obj *object) Exported() bool { return ast.IsExported(obj.name) }
+func (obj *object) Id() string     { return Id(obj.pkg, obj.name) }
+func (obj *object) String() string { panic("abstract") }
+func (obj *object) order() uint32  { return obj.order_ }
+
+func (obj *object) setOrder(order uint32)   { assert(order > 0); obj.order_ = order }
+func (obj *object) setParent(parent *Scope) { obj.parent = parent }
+
+func (obj *object) sameId(pkg *Package, name string) bool {
+       // spec:
+       // "Two identifiers are different if they are spelled differently,
+       // or if they appear in different packages and are not exported.
+       // Otherwise, they are the same."
+       if name != obj.name {
+               return false
+       }
+       // obj.Name == name
+       if obj.Exported() {
+               return true
+       }
+       // not exported, so packages must be the same (pkg == nil for
+       // fields in Universe scope; this can only happen for types
+       // introduced via Eval)
+       if pkg == nil || obj.pkg == nil {
+               return pkg == obj.pkg
+       }
+       // pkg != nil && obj.pkg != nil
+       return pkg.path == obj.pkg.path
+}
+
+// A PkgName represents an imported Go package.
+type PkgName struct {
+       object
+       imported *Package
+       used     bool // set if the package was used
+}
+
+func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName {
+       return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0}, imported, false}
+}
+
+// Imported returns the package that was imported.
+// It is distinct from Pkg(), which is the package containing the import statement.
+func (obj *PkgName) Imported() *Package { return obj.imported }
+
+// A Const represents a declared constant.
+type Const struct {
+       object
+       val     exact.Value
+       visited bool // for initialization cycle detection
+}
+
+func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val exact.Value) *Const {
+       return &Const{object{nil, pos, pkg, name, typ, 0}, val, false}
+}
+
+func (obj *Const) Val() exact.Value { return obj.val }
+
+// A TypeName represents a declared type.
+type TypeName struct {
+       object
+}
+
+func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
+       return &TypeName{object{nil, pos, pkg, name, typ, 0}}
+}
+
+// A Variable represents a declared variable (including function parameters and results, and struct fields).
+type Var struct {
+       object
+       anonymous bool // if set, the variable is an anonymous struct field, and name is the type name
+       visited   bool // for initialization cycle detection
+       isField   bool // var is struct field
+       used      bool // set if the variable was used
+}
+
+func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+       return &Var{object: object{nil, pos, pkg, name, typ, 0}}
+}
+
+func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+       return &Var{object: object{nil, pos, pkg, name, typ, 0}, used: true} // parameters are always 'used'
+}
+
+func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Var {
+       return &Var{object: object{nil, pos, pkg, name, typ, 0}, anonymous: anonymous, isField: true}
+}
+
+func (obj *Var) Anonymous() bool { return obj.anonymous }
+
+func (obj *Var) IsField() bool { return obj.isField }
+
+// A Func represents a declared function, concrete method, or abstract
+// (interface) method.  Its Type() is always a *Signature.
+// An abstract method may belong to many interfaces due to embedding.
+type Func struct {
+       object
+}
+
+func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
+       // don't store a nil signature
+       var typ Type
+       if sig != nil {
+               typ = sig
+       }
+       return &Func{object{nil, pos, pkg, name, typ, 0}}
+}
+
+// FullName returns the package- or receiver-type-qualified name of
+// function or method obj.
+func (obj *Func) FullName() string {
+       var buf bytes.Buffer
+       writeFuncName(&buf, nil, obj)
+       return buf.String()
+}
+
+func (obj *Func) Scope() *Scope {
+       return obj.typ.(*Signature).scope
+}
+
+// A Label represents a declared label.
+type Label struct {
+       object
+       used bool // set if the label was used
+}
+
+func NewLabel(pos token.Pos, pkg *Package, name string) *Label {
+       return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false}
+}
+
+// A Builtin represents a built-in function.
+// Builtins don't have a valid type.
+type Builtin struct {
+       object
+       id builtinId
+}
+
+func newBuiltin(id builtinId) *Builtin {
+       return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id}
+}
+
+// Nil represents the predeclared value nil.
+type Nil struct {
+       object
+}
+
+func writeObject(buf *bytes.Buffer, this *Package, obj Object) {
+       typ := obj.Type()
+       switch obj := obj.(type) {
+       case *PkgName:
+               fmt.Fprintf(buf, "package %s", obj.Name())
+               if path := obj.imported.path; path != "" && path != obj.name {
+                       fmt.Fprintf(buf, " (%q)", path)
+               }
+               return
+
+       case *Const:
+               buf.WriteString("const")
+
+       case *TypeName:
+               buf.WriteString("type")
+               typ = typ.Underlying()
+
+       case *Var:
+               if obj.isField {
+                       buf.WriteString("field")
+               } else {
+                       buf.WriteString("var")
+               }
+
+       case *Func:
+               buf.WriteString("func ")
+               writeFuncName(buf, this, obj)
+               if typ != nil {
+                       WriteSignature(buf, this, typ.(*Signature))
+               }
+               return
+
+       case *Label:
+               buf.WriteString("label")
+               typ = nil
+
+       case *Builtin:
+               buf.WriteString("builtin")
+               typ = nil
+
+       case *Nil:
+               buf.WriteString("nil")
+               return
+
+       default:
+               panic(fmt.Sprintf("writeObject(%T)", obj))
+       }
+
+       buf.WriteByte(' ')
+
+       // For package-level objects, package-qualify the name,
+       // except for intra-package references (this != nil).
+       if pkg := obj.Pkg(); pkg != nil && this != pkg && pkg.scope.Lookup(obj.Name()) == obj {
+               buf.WriteString(pkg.path)
+               buf.WriteByte('.')
+       }
+       buf.WriteString(obj.Name())
+       if typ != nil {
+               buf.WriteByte(' ')
+               WriteType(buf, this, typ)
+       }
+}
+
+// ObjectString returns the string form of obj.
+// Object and type names are printed package-qualified
+// only if they do not belong to this package.
+//
+func ObjectString(this *Package, obj Object) string {
+       var buf bytes.Buffer
+       writeObject(&buf, this, obj)
+       return buf.String()
+}
+
+func (obj *PkgName) String() string  { return ObjectString(nil, obj) }
+func (obj *Const) String() string    { return ObjectString(nil, obj) }
+func (obj *TypeName) String() string { return ObjectString(nil, obj) }
+func (obj *Var) String() string      { return ObjectString(nil, obj) }
+func (obj *Func) String() string     { return ObjectString(nil, obj) }
+func (obj *Label) String() string    { return ObjectString(nil, obj) }
+func (obj *Builtin) String() string  { return ObjectString(nil, obj) }
+func (obj *Nil) String() string      { return ObjectString(nil, obj) }
+
+func writeFuncName(buf *bytes.Buffer, this *Package, f *Func) {
+       if f.typ != nil {
+               sig := f.typ.(*Signature)
+               if recv := sig.Recv(); recv != nil {
+                       buf.WriteByte('(')
+                       if _, ok := recv.Type().(*Interface); ok {
+                               // gcimporter creates abstract methods of
+                               // named interfaces using the interface type
+                               // (not the named type) as the receiver.
+                               // Don't print it in full.
+                               buf.WriteString("interface")
+                       } else {
+                               WriteType(buf, this, recv.Type())
+                       }
+                       buf.WriteByte(')')
+                       buf.WriteByte('.')
+               } else if f.pkg != nil && f.pkg != this {
+                       buf.WriteString(f.pkg.path)
+                       buf.WriteByte('.')
+               }
+       }
+       buf.WriteString(f.name)
+}
diff --git a/src/go/types/objset.go b/src/go/types/objset.go
new file mode 100644 (file)
index 0000000..55eb74a
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements objsets.
+//
+// An objset is similar to a Scope but objset elements
+// are identified by their unique id, instead of their
+// object name.
+
+package types
+
+// An objset is a set of objects identified by their unique id.
+// The zero value for objset is a ready-to-use empty objset.
+type objset map[string]Object // initialized lazily
+
+// insert attempts to insert an object obj into objset s.
+// If s already contains an alternative object alt with
+// the same name, insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj and returns nil.
+func (s *objset) insert(obj Object) Object {
+       id := obj.Id()
+       if alt := (*s)[id]; alt != nil {
+               return alt
+       }
+       if *s == nil {
+               *s = make(map[string]Object)
+       }
+       (*s)[id] = obj
+       return nil
+}
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
new file mode 100644 (file)
index 0000000..1fb8017
--- /dev/null
@@ -0,0 +1,287 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file defines operands and associated operations.
+
+package types
+
+import (
+       "bytes"
+       "go/ast"
+       "go/token"
+
+       "go/exact"
+)
+
+// An operandMode specifies the (addressing) mode of an operand.
+type operandMode byte
+
+const (
+       invalid  operandMode = iota // operand is invalid
+       novalue                     // operand represents no value (result of a function call w/o result)
+       builtin                     // operand is a built-in function
+       typexpr                     // operand is a type
+       constant                    // operand is a constant; the operand's typ is a Basic type
+       variable                    // operand is an addressable variable
+       mapindex                    // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
+       value                       // operand is a computed value
+       commaok                     // like value, but operand may be used in a comma,ok expression
+)
+
+var operandModeString = [...]string{
+       invalid:  "invalid operand",
+       novalue:  "no value",
+       builtin:  "built-in",
+       typexpr:  "type",
+       constant: "constant",
+       variable: "variable",
+       mapindex: "map index expression",
+       value:    "value",
+       commaok:  "comma, ok expression",
+}
+
+// An operand represents an intermediate value during type checking.
+// Operands have an (addressing) mode, the expression evaluating to
+// the operand, the operand's type, a value for constants, and an id
+// for built-in functions.
+// The zero value of operand is a ready to use invalid operand.
+//
+type operand struct {
+       mode operandMode
+       expr ast.Expr
+       typ  Type
+       val  exact.Value
+       id   builtinId
+}
+
+// pos returns the position of the expression corresponding to x.
+// If x is invalid the position is token.NoPos.
+//
+func (x *operand) pos() token.Pos {
+       // x.expr may not be set if x is invalid
+       if x.expr == nil {
+               return token.NoPos
+       }
+       return x.expr.Pos()
+}
+
+// Operand string formats
+// (not all "untyped" cases can appear due to the type system,
+// but they fall out naturally here)
+//
+// mode       format
+//
+// invalid    <expr> (               <mode>                    )
+// novalue    <expr> (               <mode>                    )
+// builtin    <expr> (               <mode>                    )
+// typexpr    <expr> (               <mode>                    )
+//
+// constant   <expr> (<untyped kind> <mode>                    )
+// constant   <expr> (               <mode>       of type <typ>)
+// constant   <expr> (<untyped kind> <mode> <val>              )
+// constant   <expr> (               <mode> <val> of type <typ>)
+//
+// variable   <expr> (<untyped kind> <mode>                    )
+// variable   <expr> (               <mode>       of type <typ>)
+//
+// mapindex   <expr> (<untyped kind> <mode>                    )
+// mapindex   <expr> (               <mode>       of type <typ>)
+//
+// value      <expr> (<untyped kind> <mode>                    )
+// value      <expr> (               <mode>       of type <typ>)
+//
+// commaok    <expr> (<untyped kind> <mode>                    )
+// commaok    <expr> (               <mode>       of type <typ>)
+//
+func operandString(this *Package, x *operand) string {
+       var buf bytes.Buffer
+
+       var expr string
+       if x.expr != nil {
+               expr = ExprString(x.expr)
+       } else {
+               switch x.mode {
+               case builtin:
+                       expr = predeclaredFuncs[x.id].name
+               case typexpr:
+                       expr = TypeString(this, x.typ)
+               case constant:
+                       expr = x.val.String()
+               }
+       }
+
+       // <expr> (
+       if expr != "" {
+               buf.WriteString(expr)
+               buf.WriteString(" (")
+       }
+
+       // <untyped kind>
+       hasType := false
+       switch x.mode {
+       case invalid, novalue, builtin, typexpr:
+               // no type
+       default:
+               // has type
+               if isUntyped(x.typ) {
+                       buf.WriteString(x.typ.(*Basic).name)
+                       buf.WriteByte(' ')
+                       break
+               }
+               hasType = true
+       }
+
+       // <mode>
+       buf.WriteString(operandModeString[x.mode])
+
+       // <val>
+       if x.mode == constant {
+               if s := x.val.String(); s != expr {
+                       buf.WriteByte(' ')
+                       buf.WriteString(s)
+               }
+       }
+
+       // <typ>
+       if hasType {
+               if x.typ != Typ[Invalid] {
+                       buf.WriteString(" of type ")
+                       WriteType(&buf, this, x.typ)
+               } else {
+                       buf.WriteString(" with invalid type")
+               }
+       }
+
+       // )
+       if expr != "" {
+               buf.WriteByte(')')
+       }
+
+       return buf.String()
+}
+
+func (x *operand) String() string {
+       return operandString(nil, x)
+}
+
+// setConst sets x to the untyped constant for literal lit.
+func (x *operand) setConst(tok token.Token, lit string) {
+       val := exact.MakeFromLiteral(lit, tok)
+       if val == nil {
+               // TODO(gri) Should we make it an unknown constant instead?
+               x.mode = invalid
+               return
+       }
+
+       var kind BasicKind
+       switch tok {
+       case token.INT:
+               kind = UntypedInt
+       case token.FLOAT:
+               kind = UntypedFloat
+       case token.IMAG:
+               kind = UntypedComplex
+       case token.CHAR:
+               kind = UntypedRune
+       case token.STRING:
+               kind = UntypedString
+       }
+
+       x.mode = constant
+       x.typ = Typ[kind]
+       x.val = val
+}
+
+// isNil reports whether x is the nil value.
+func (x *operand) isNil() bool {
+       return x.mode == value && x.typ == Typ[UntypedNil]
+}
+
+// TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
+//           checker.representable, and checker.assignment are
+//           overlapping in functionality. Need to simplify and clean up.
+
+// assignableTo reports whether x is assignable to a variable of type T.
+func (x *operand) assignableTo(conf *Config, T Type) bool {
+       if x.mode == invalid || T == Typ[Invalid] {
+               return true // avoid spurious errors
+       }
+
+       V := x.typ
+
+       // x's type is identical to T
+       if Identical(V, T) {
+               return true
+       }
+
+       Vu := V.Underlying()
+       Tu := T.Underlying()
+
+       // T is an interface type and x implements T
+       // (Do this check first as it might succeed early.)
+       if Ti, ok := Tu.(*Interface); ok {
+               if Implements(x.typ, Ti) {
+                       return true
+               }
+       }
+
+       // x's type V and T have identical underlying types
+       // and at least one of V or T is not a named type
+       if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+               return true
+       }
+
+       // x is a bidirectional channel value, T is a channel
+       // type, x's type V and T have identical element types,
+       // and at least one of V or T is not a named type
+       if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
+               if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
+                       return !isNamed(V) || !isNamed(T)
+               }
+       }
+
+       // x is the predeclared identifier nil and T is a pointer,
+       // function, slice, map, channel, or interface type
+       if x.isNil() {
+               switch t := Tu.(type) {
+               case *Basic:
+                       if t.kind == UnsafePointer {
+                               return true
+                       }
+               case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface:
+                       return true
+               }
+               return false
+       }
+
+       // x is an untyped constant representable by a value of type T
+       // TODO(gri) This is borrowing from checker.convertUntyped and
+       //           checker.representable. Need to clean up.
+       if isUntyped(Vu) {
+               switch t := Tu.(type) {
+               case *Basic:
+                       if x.mode == constant {
+                               return representableConst(x.val, conf, t.kind, nil)
+                       }
+                       // The result of a comparison is an untyped boolean,
+                       // but may not be a constant.
+                       if Vb, _ := Vu.(*Basic); Vb != nil {
+                               return Vb.kind == UntypedBool && isBoolean(Tu)
+                       }
+               case *Interface:
+                       return x.isNil() || t.Empty()
+               case *Pointer, *Signature, *Slice, *Map, *Chan:
+                       return x.isNil()
+               }
+       }
+
+       return false
+}
+
+// isInteger reports whether x is a (typed or untyped) integer value.
+func (x *operand) isInteger() bool {
+       return x.mode == invalid ||
+               isInteger(x.typ) ||
+               x.mode == constant && representableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt
+}
diff --git a/src/go/types/ordering.go b/src/go/types/ordering.go
new file mode 100644 (file)
index 0000000..6bb98f2
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements resolveOrder.
+
+package types
+
+import (
+       "go/ast"
+       "sort"
+)
+
+// resolveOrder computes the order in which package-level objects
+// must be type-checked.
+//
+// Interface types appear first in the list, sorted topologically
+// by dependencies on embedded interfaces that are also declared
+// in this package, followed by all other objects sorted in source
+// order.
+//
+// TODO(gri) Consider sorting all types by dependencies here, and
+// in the process check _and_ report type cycles. This may simplify
+// the full type-checking phase.
+//
+func (check *Checker) resolveOrder() []Object {
+       var ifaces, others []Object
+
+       // collect interface types with their dependencies, and all other objects
+       for obj := range check.objMap {
+               if ityp := check.interfaceFor(obj); ityp != nil {
+                       ifaces = append(ifaces, obj)
+                       // determine dependencies on embedded interfaces
+                       for _, f := range ityp.Methods.List {
+                               if len(f.Names) == 0 {
+                                       // Embedded interface: The type must be a (possibly
+                                       // qualified) identifier denoting another interface.
+                                       // Imported interfaces are already fully resolved,
+                                       // so we can ignore qualified identifiers.
+                                       if ident, _ := f.Type.(*ast.Ident); ident != nil {
+                                               embedded := check.pkg.scope.Lookup(ident.Name)
+                                               if check.interfaceFor(embedded) != nil {
+                                                       check.objMap[obj].addDep(embedded)
+                                               }
+                                       }
+                               }
+                       }
+               } else {
+                       others = append(others, obj)
+               }
+       }
+
+       // final object order
+       var order []Object
+
+       // sort interface types topologically by dependencies,
+       // and in source order if there are no dependencies
+       sort.Sort(inSourceOrder(ifaces))
+       if debug {
+               for _, obj := range ifaces {
+                       assert(check.objMap[obj].mark == 0)
+               }
+       }
+       for _, obj := range ifaces {
+               check.appendInPostOrder(&order, obj)
+       }
+
+       // sort everything else in source order
+       sort.Sort(inSourceOrder(others))
+
+       return append(order, others...)
+}
+
+// interfaceFor returns the AST interface denoted by obj, or nil.
+func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType {
+       tname, _ := obj.(*TypeName)
+       if tname == nil {
+               return nil // not a type
+       }
+       d := check.objMap[obj]
+       if d == nil {
+               check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+               unreachable()
+       }
+       if d.typ == nil {
+               return nil // invalid AST - ignore (will be handled later)
+       }
+       ityp, _ := d.typ.(*ast.InterfaceType)
+       return ityp
+}
+
+func (check *Checker) appendInPostOrder(order *[]Object, obj Object) {
+       d := check.objMap[obj]
+       if d.mark != 0 {
+               // We've already seen this object; either because it's
+               // already added to order, or because we have a cycle.
+               // In both cases we stop. Cycle errors are reported
+               // when type-checking types.
+               return
+       }
+       d.mark = 1
+
+       for _, obj := range orderedSetObjects(d.deps) {
+               check.appendInPostOrder(order, obj)
+       }
+
+       *order = append(*order, obj)
+}
+
+func orderedSetObjects(set map[Object]bool) []Object {
+       list := make([]Object, len(set))
+       i := 0
+       for obj := range set {
+               // we don't care about the map element value
+               list[i] = obj
+               i++
+       }
+       sort.Sort(inSourceOrder(list))
+       return list
+}
+
+// inSourceOrder implements the sort.Sort interface.
+type inSourceOrder []Object
+
+func (a inSourceOrder) Len() int           { return len(a) }
+func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() }
+func (a inSourceOrder) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/src/go/types/package.go b/src/go/types/package.go
new file mode 100644 (file)
index 0000000..366ca39
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import "fmt"
+
+// A Package describes a Go package.
+type Package struct {
+       path     string
+       name     string
+       scope    *Scope
+       complete bool
+       imports  []*Package
+       fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
+}
+
+// NewPackage returns a new Package for the given package path and name;
+// the name must not be the blank identifier.
+// The package is not complete and contains no explicit imports.
+func NewPackage(path, name string) *Package {
+       if name == "_" {
+               panic("invalid package name _")
+       }
+       scope := NewScope(Universe, fmt.Sprintf("package %q", path))
+       return &Package{path: path, name: name, scope: scope}
+}
+
+// Path returns the package path.
+func (pkg *Package) Path() string { return pkg.path }
+
+// Name returns the package name.
+func (pkg *Package) Name() string { return pkg.name }
+
+// Scope returns the (complete or incomplete) package scope
+// holding the objects declared at package level (TypeNames,
+// Consts, Vars, and Funcs).
+func (pkg *Package) Scope() *Scope { return pkg.scope }
+
+// A package is complete if its scope contains (at least) all
+// exported objects; otherwise it is incomplete.
+func (pkg *Package) Complete() bool { return pkg.complete }
+
+// MarkComplete marks a package as complete.
+func (pkg *Package) MarkComplete() { pkg.complete = true }
+
+// Imports returns the list of packages explicitly imported by
+// pkg; the list is in source order. Package unsafe is excluded.
+func (pkg *Package) Imports() []*Package { return pkg.imports }
+
+// SetImports sets the list of explicitly imported packages to list.
+// It is the caller's responsibility to make sure list elements are unique.
+func (pkg *Package) SetImports(list []*Package) { pkg.imports = list }
+
+func (pkg *Package) String() string {
+       return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path)
+}
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
new file mode 100644 (file)
index 0000000..b5c39d9
--- /dev/null
@@ -0,0 +1,309 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements commonly used type predicates.
+
+package types
+
+import "sort"
+
+func isNamed(typ Type) bool {
+       if _, ok := typ.(*Basic); ok {
+               return ok
+       }
+       _, ok := typ.(*Named)
+       return ok
+}
+
+func isBoolean(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsBoolean != 0
+}
+
+func isInteger(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsInteger != 0
+}
+
+func isUnsigned(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsUnsigned != 0
+}
+
+func isFloat(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsFloat != 0
+}
+
+func isComplex(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsComplex != 0
+}
+
+func isNumeric(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsNumeric != 0
+}
+
+func isString(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsString != 0
+}
+
+func isTyped(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return !ok || t.info&IsUntyped == 0
+}
+
+func isUntyped(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsUntyped != 0
+}
+
+func isOrdered(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsOrdered != 0
+}
+
+func isConstType(typ Type) bool {
+       t, ok := typ.Underlying().(*Basic)
+       return ok && t.info&IsConstType != 0
+}
+
+// IsInterface reports whether typ is an interface type.
+func IsInterface(typ Type) bool {
+       _, ok := typ.Underlying().(*Interface)
+       return ok
+}
+
+// Comparable reports whether values of type T are comparable.
+func Comparable(T Type) bool {
+       switch t := T.Underlying().(type) {
+       case *Basic:
+               // assume invalid types to be comparable
+               // to avoid follow-up errors
+               return t.kind != UntypedNil
+       case *Pointer, *Interface, *Chan:
+               return true
+       case *Struct:
+               for _, f := range t.fields {
+                       if !Comparable(f.typ) {
+                               return false
+                       }
+               }
+               return true
+       case *Array:
+               return Comparable(t.elem)
+       }
+       return false
+}
+
+// hasNil reports whether a type includes the nil value.
+func hasNil(typ Type) bool {
+       switch t := typ.Underlying().(type) {
+       case *Basic:
+               return t.kind == UnsafePointer
+       case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
+               return true
+       }
+       return false
+}
+
+// Identical reports whether x and y are identical.
+func Identical(x, y Type) bool {
+       return identical(x, y, nil)
+}
+
+// An ifacePair is a node in a stack of interface type pairs compared for identity.
+type ifacePair struct {
+       x, y *Interface
+       prev *ifacePair
+}
+
+func (p *ifacePair) identical(q *ifacePair) bool {
+       return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
+}
+
+func identical(x, y Type, p *ifacePair) bool {
+       if x == y {
+               return true
+       }
+
+       switch x := x.(type) {
+       case *Basic:
+               // Basic types are singletons except for the rune and byte
+               // aliases, thus we cannot solely rely on the x == y check
+               // above.
+               if y, ok := y.(*Basic); ok {
+                       return x.kind == y.kind
+               }
+
+       case *Array:
+               // Two array types are identical if they have identical element types
+               // and the same array length.
+               if y, ok := y.(*Array); ok {
+                       return x.len == y.len && identical(x.elem, y.elem, p)
+               }
+
+       case *Slice:
+               // Two slice types are identical if they have identical element types.
+               if y, ok := y.(*Slice); ok {
+                       return identical(x.elem, y.elem, p)
+               }
+
+       case *Struct:
+               // Two struct types are identical if they have the same sequence of fields,
+               // and if corresponding fields have the same names, and identical types,
+               // and identical tags. Two anonymous fields are considered to have the same
+               // name. Lower-case field names from different packages are always different.
+               if y, ok := y.(*Struct); ok {
+                       if x.NumFields() == y.NumFields() {
+                               for i, f := range x.fields {
+                                       g := y.fields[i]
+                                       if f.anonymous != g.anonymous ||
+                                               x.Tag(i) != y.Tag(i) ||
+                                               !f.sameId(g.pkg, g.name) ||
+                                               !identical(f.typ, g.typ, p) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Pointer:
+               // Two pointer types are identical if they have identical base types.
+               if y, ok := y.(*Pointer); ok {
+                       return identical(x.base, y.base, p)
+               }
+
+       case *Tuple:
+               // Two tuples types are identical if they have the same number of elements
+               // and corresponding elements have identical types.
+               if y, ok := y.(*Tuple); ok {
+                       if x.Len() == y.Len() {
+                               if x != nil {
+                                       for i, v := range x.vars {
+                                               w := y.vars[i]
+                                               if !identical(v.typ, w.typ, p) {
+                                                       return false
+                                               }
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Signature:
+               // Two function types are identical if they have the same number of parameters
+               // and result values, corresponding parameter and result types are identical,
+               // and either both functions are variadic or neither is. Parameter and result
+               // names are not required to match.
+               if y, ok := y.(*Signature); ok {
+                       return x.variadic == y.variadic &&
+                               identical(x.params, y.params, p) &&
+                               identical(x.results, y.results, p)
+               }
+
+       case *Interface:
+               // Two interface types are identical if they have the same set of methods with
+               // the same names and identical function types. Lower-case method names from
+               // different packages are always different. The order of the methods is irrelevant.
+               if y, ok := y.(*Interface); ok {
+                       a := x.allMethods
+                       b := y.allMethods
+                       if len(a) == len(b) {
+                               // Interface types are the only types where cycles can occur
+                               // that are not "terminated" via named types; and such cycles
+                               // can only be created via method parameter types that are
+                               // anonymous interfaces (directly or indirectly) embedding
+                               // the current interface. Example:
+                               //
+                               //    type T interface {
+                               //        m() interface{T}
+                               //    }
+                               //
+                               // If two such (differently named) interfaces are compared,
+                               // endless recursion occurs if the cycle is not detected.
+                               //
+                               // If x and y were compared before, they must be equal
+                               // (if they were not, the recursion would have stopped);
+                               // search the ifacePair stack for the same pair.
+                               //
+                               // This is a quadratic algorithm, but in practice these stacks
+                               // are extremely short (bounded by the nesting depth of interface
+                               // type declarations that recur via parameter types, an extremely
+                               // rare occurrence). An alternative implementation might use a
+                               // "visited" map, but that is probably less efficient overall.
+                               q := &ifacePair{x, y, p}
+                               for p != nil {
+                                       if p.identical(q) {
+                                               return true // same pair was compared before
+                                       }
+                                       p = p.prev
+                               }
+                               if debug {
+                                       assert(sort.IsSorted(byUniqueMethodName(a)))
+                                       assert(sort.IsSorted(byUniqueMethodName(b)))
+                               }
+                               for i, f := range a {
+                                       g := b[i]
+                                       if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Map:
+               // Two map types are identical if they have identical key and value types.
+               if y, ok := y.(*Map); ok {
+                       return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
+               }
+
+       case *Chan:
+               // Two channel types are identical if they have identical value types
+               // and the same direction.
+               if y, ok := y.(*Chan); ok {
+                       return x.dir == y.dir && identical(x.elem, y.elem, p)
+               }
+
+       case *Named:
+               // Two named types are identical if their type names originate
+               // in the same type declaration.
+               if y, ok := y.(*Named); ok {
+                       return x.obj == y.obj
+               }
+
+       default:
+               unreachable()
+       }
+
+       return false
+}
+
+// defaultType returns the default "typed" type for an "untyped" type;
+// 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 {
+               switch t.kind {
+               case UntypedBool:
+                       return Typ[Bool]
+               case UntypedInt:
+                       return Typ[Int]
+               case UntypedRune:
+                       return UniverseRune // use 'rune' name
+               case UntypedFloat:
+                       return Typ[Float64]
+               case UntypedComplex:
+                       return Typ[Complex128]
+               case UntypedString:
+                       return Typ[String]
+               }
+       }
+       return typ
+}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
new file mode 100644 (file)
index 0000000..ee8fff0
--- /dev/null
@@ -0,0 +1,446 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import (
+       "errors"
+       "fmt"
+       "go/ast"
+       "go/token"
+       pathLib "path"
+       "strconv"
+       "strings"
+       "unicode"
+
+       "go/exact"
+)
+
+// A declInfo describes a package-level const, type, var, or func declaration.
+type declInfo struct {
+       file  *Scope        // scope of file containing this declaration
+       lhs   []*Var        // lhs of n:1 variable declarations, or nil
+       typ   ast.Expr      // type, or nil
+       init  ast.Expr      // init expression, or nil
+       fdecl *ast.FuncDecl // func declaration, or nil
+
+       deps map[Object]bool // type and init dependencies; lazily allocated
+       mark int             // for dependency analysis
+}
+
+// hasInitializer reports whether the declared object has an initialization
+// expression or function body.
+func (d *declInfo) hasInitializer() bool {
+       return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
+}
+
+// addDep adds obj as a dependency to d.
+func (d *declInfo) addDep(obj Object) {
+       m := d.deps
+       if m == nil {
+               m = make(map[Object]bool)
+               d.deps = m
+       }
+       m[obj] = true
+}
+
+// arityMatch checks that the lhs and rhs of a const or var decl
+// have the appropriate number of names and init exprs. For const
+// decls, init is the value spec providing the init exprs; for
+// var decls, init is nil (the init exprs are in s in this case).
+func (check *Checker) arityMatch(s, init *ast.ValueSpec) {
+       l := len(s.Names)
+       r := len(s.Values)
+       if init != nil {
+               r = len(init.Values)
+       }
+
+       switch {
+       case init == nil && r == 0:
+               // var decl w/o init expr
+               if s.Type == nil {
+                       check.errorf(s.Pos(), "missing type or init expr")
+               }
+       case l < r:
+               if l < len(s.Values) {
+                       // init exprs from s
+                       n := s.Values[l]
+                       check.errorf(n.Pos(), "extra init expr %s", n)
+                       // TODO(gri) avoid declared but not used error here
+               } else {
+                       // init exprs "inherited"
+                       check.errorf(s.Pos(), "extra init expr at %s", init.Pos())
+                       // TODO(gri) avoid declared but not used error here
+               }
+       case l > r && (init != nil || r != 1):
+               n := s.Names[r]
+               check.errorf(n.Pos(), "missing init expr for %s", n)
+       }
+}
+
+func validatedImportPath(path string) (string, error) {
+       s, err := strconv.Unquote(path)
+       if err != nil {
+               return "", err
+       }
+       if s == "" {
+               return "", fmt.Errorf("empty string")
+       }
+       const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+       for _, r := range s {
+               if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+                       return s, fmt.Errorf("invalid character %#U", r)
+               }
+       }
+       return s, nil
+}
+
+// declarePkgObj declares obj in the package scope, records its ident -> obj mapping,
+// and updates check.objMap. The object must not be a function or method.
+func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
+       assert(ident.Name == obj.Name())
+
+       // spec: "A package-scope or file-scope identifier with name init
+       // may only be declared to be a function with this (func()) signature."
+       if ident.Name == "init" {
+               check.errorf(ident.Pos(), "cannot declare init - must be func")
+               return
+       }
+
+       check.declare(check.pkg.scope, ident, obj)
+       check.objMap[obj] = d
+       obj.setOrder(uint32(len(check.objMap)))
+}
+
+// filename returns a filename suitable for debugging output.
+func (check *Checker) filename(fileNo int) string {
+       file := check.files[fileNo]
+       if pos := file.Pos(); pos.IsValid() {
+               return check.fset.File(pos).Name()
+       }
+       return fmt.Sprintf("file[%d]", fileNo)
+}
+
+// collectObjects collects all file and package objects and inserts them
+// into their respective scopes. It also performs imports and associates
+// methods with receiver base type names.
+func (check *Checker) collectObjects() {
+       pkg := check.pkg
+
+       importer := check.conf.Import
+       if importer == nil {
+               if DefaultImport != nil {
+                       importer = DefaultImport
+               } else {
+                       // Panic if we encounter an import.
+                       importer = func(map[string]*Package, string) (*Package, error) {
+                               panic(`no Config.Import or DefaultImport (missing import _ "go/types/internal/gcimporter"?)`)
+                       }
+               }
+       }
+
+       // pkgImports is the set of packages already imported by any package file seen
+       // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
+       // it (pkg.imports may not be empty if we are checking test files incrementally).
+       var pkgImports = make(map[*Package]bool)
+       for _, imp := range pkg.imports {
+               pkgImports[imp] = true
+       }
+
+       for fileNo, file := range check.files {
+               // The package identifier denotes the current package,
+               // but there is no corresponding package object.
+               check.recordDef(file.Name, nil)
+
+               fileScope := NewScope(check.pkg.scope, check.filename(fileNo))
+               check.recordScope(file, fileScope)
+
+               for _, decl := range file.Decls {
+                       switch d := decl.(type) {
+                       case *ast.BadDecl:
+                               // ignore
+
+                       case *ast.GenDecl:
+                               var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+                               for iota, spec := range d.Specs {
+                                       switch s := spec.(type) {
+                                       case *ast.ImportSpec:
+                                               // import package
+                                               var imp *Package
+                                               path, err := validatedImportPath(s.Path.Value)
+                                               if err != nil {
+                                                       check.errorf(s.Path.Pos(), "invalid import path (%s)", err)
+                                                       continue
+                                               }
+                                               if path == "C" && check.conf.FakeImportC {
+                                                       // TODO(gri) shouldn't create a new one each time
+                                                       imp = NewPackage("C", "C")
+                                                       imp.fake = true
+                                               } else {
+                                                       var err error
+                                                       imp, err = importer(check.conf.Packages, path)
+                                                       if imp == nil && err == nil {
+                                                               err = errors.New("Config.Import returned nil but no error")
+                                                       }
+                                                       if err != nil {
+                                                               check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
+                                                               continue
+                                                       }
+                                               }
+
+                                               // add package to list of explicit imports
+                                               // (this functionality is provided as a convenience
+                                               // for clients; it is not needed for type-checking)
+                                               if !pkgImports[imp] {
+                                                       pkgImports[imp] = true
+                                                       if imp != Unsafe {
+                                                               pkg.imports = append(pkg.imports, imp)
+                                                       }
+                                               }
+
+                                               // local name overrides imported package name
+                                               name := imp.name
+                                               if s.Name != nil {
+                                                       name = s.Name.Name
+                                                       if name == "init" {
+                                                               check.errorf(s.Name.Pos(), "cannot declare init - must be func")
+                                                               continue
+                                                       }
+                                               }
+
+                                               obj := NewPkgName(s.Pos(), pkg, name, imp)
+                                               if s.Name != nil {
+                                                       // in a dot-import, the dot represents the package
+                                                       check.recordDef(s.Name, obj)
+                                               } else {
+                                                       check.recordImplicit(s, obj)
+                                               }
+
+                                               // add import to file scope
+                                               if name == "." {
+                                                       // merge imported scope with file scope
+                                                       for _, obj := range imp.scope.elems {
+                                                               // A package scope may contain non-exported objects,
+                                                               // do not import them!
+                                                               if obj.Exported() {
+                                                                       // TODO(gri) When we import a package, we create
+                                                                       // a new local package object. We should do the
+                                                                       // same for each dot-imported object. That way
+                                                                       // they can have correct position information.
+                                                                       // (We must not modify their existing position
+                                                                       // information because the same package - found
+                                                                       // via Config.Packages - may be dot-imported in
+                                                                       // another package!)
+                                                                       check.declare(fileScope, nil, obj)
+                                                                       check.recordImplicit(s, obj)
+                                                               }
+                                                       }
+                                                       // add position to set of dot-import positions for this file
+                                                       // (this is only needed for "imported but not used" errors)
+                                                       check.addUnusedDotImport(fileScope, imp, s.Pos())
+                                               } else {
+                                                       // declare imported package object in file scope
+                                                       check.declare(fileScope, nil, obj)
+                                               }
+
+                                       case *ast.ValueSpec:
+                                               switch d.Tok {
+                                               case token.CONST:
+                                                       // determine which initialization expressions to use
+                                                       switch {
+                                                       case s.Type != nil || len(s.Values) > 0:
+                                                               last = s
+                                                       case last == nil:
+                                                               last = new(ast.ValueSpec) // make sure last exists
+                                                       }
+
+                                                       // declare all constants
+                                                       for i, name := range s.Names {
+                                                               obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
+
+                                                               var init ast.Expr
+                                                               if i < len(last.Values) {
+                                                                       init = last.Values[i]
+                                                               }
+
+                                                               d := &declInfo{file: fileScope, typ: last.Type, init: init}
+                                                               check.declarePkgObj(name, obj, d)
+                                                       }
+
+                                                       check.arityMatch(s, last)
+
+                                               case token.VAR:
+                                                       lhs := make([]*Var, len(s.Names))
+                                                       // If there's exactly one rhs initializer, use
+                                                       // the same declInfo d1 for all lhs variables
+                                                       // so that each lhs variable depends on the same
+                                                       // rhs initializer (n:1 var declaration).
+                                                       var d1 *declInfo
+                                                       if len(s.Values) == 1 {
+                                                               // The lhs elements are only set up after the for loop below,
+                                                               // but that's ok because declareVar only collects the declInfo
+                                                               // for a later phase.
+                                                               d1 = &declInfo{file: fileScope, lhs: lhs, typ: s.Type, init: s.Values[0]}
+                                                       }
+
+                                                       // declare all variables
+                                                       for i, name := range s.Names {
+                                                               obj := NewVar(name.Pos(), pkg, name.Name, nil)
+                                                               lhs[i] = obj
+
+                                                               d := d1
+                                                               if d == nil {
+                                                                       // individual assignments
+                                                                       var init ast.Expr
+                                                                       if i < len(s.Values) {
+                                                                               init = s.Values[i]
+                                                                       }
+                                                                       d = &declInfo{file: fileScope, typ: s.Type, init: init}
+                                                               }
+
+                                                               check.declarePkgObj(name, obj, d)
+                                                       }
+
+                                                       check.arityMatch(s, nil)
+
+                                               default:
+                                                       check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+                                               }
+
+                                       case *ast.TypeSpec:
+                                               obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+                                               check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
+
+                                       default:
+                                               check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
+                                       }
+                               }
+
+                       case *ast.FuncDecl:
+                               name := d.Name.Name
+                               obj := NewFunc(d.Name.Pos(), pkg, name, nil)
+                               if d.Recv == nil {
+                                       // regular function
+                                       if name == "init" {
+                                               // don't declare init functions in the package scope - they are invisible
+                                               obj.parent = pkg.scope
+                                               check.recordDef(d.Name, obj)
+                                               // init functions must have a body
+                                               if d.Body == nil {
+                                                       check.softErrorf(obj.pos, "missing function body")
+                                               }
+                                       } else {
+                                               check.declare(pkg.scope, d.Name, obj)
+                                       }
+                               } else {
+                                       // method
+                                       check.recordDef(d.Name, obj)
+                                       // Associate method with receiver base type name, if possible.
+                                       // Ignore methods that have an invalid receiver, or a blank _
+                                       // receiver name. They will be type-checked later, with regular
+                                       // functions.
+                                       if list := d.Recv.List; len(list) > 0 {
+                                               typ := list[0].Type
+                                               if ptr, _ := typ.(*ast.StarExpr); ptr != nil {
+                                                       typ = ptr.X
+                                               }
+                                               if base, _ := typ.(*ast.Ident); base != nil && base.Name != "_" {
+                                                       check.assocMethod(base.Name, obj)
+                                               }
+                                       }
+                               }
+                               info := &declInfo{file: fileScope, fdecl: d}
+                               check.objMap[obj] = info
+                               obj.setOrder(uint32(len(check.objMap)))
+
+                       default:
+                               check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+                       }
+               }
+       }
+
+       // verify that objects in package and file scopes have different names
+       for _, scope := range check.pkg.scope.children /* file scopes */ {
+               for _, obj := range scope.elems {
+                       if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
+                               if pkg, ok := obj.(*PkgName); ok {
+                                       check.errorf(alt.Pos(), "%s already declared through import of %s", alt.Name(), pkg.Imported())
+                                       check.reportAltDecl(pkg)
+                               } else {
+                                       check.errorf(alt.Pos(), "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
+                                       // TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything
+                                       check.reportAltDecl(obj)
+                               }
+                       }
+               }
+       }
+}
+
+// packageObjects typechecks all package objects in objList, but not function bodies.
+func (check *Checker) packageObjects(objList []Object) {
+       // add new methods to already type-checked types (from a prior Checker.Files call)
+       for _, obj := range objList {
+               if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
+                       check.addMethodDecls(obj)
+               }
+       }
+
+       // pre-allocate space for type declaration paths so that the underlying array is reused
+       typePath := make([]*TypeName, 0, 8)
+
+       for _, obj := range objList {
+               check.objDecl(obj, nil, typePath)
+       }
+
+       // At this point we may have a non-empty check.methods map; this means that not all
+       // entries were deleted at the end of typeDecl because the respective receiver base
+       // types were not found. In that case, an error was reported when declaring those
+       // methods. We can now safely discard this map.
+       check.methods = nil
+}
+
+// functionBodies typechecks all function bodies.
+func (check *Checker) functionBodies() {
+       for _, f := range check.funcs {
+               check.funcBody(f.decl, f.name, f.sig, f.body)
+       }
+}
+
+// unusedImports checks for unused imports.
+func (check *Checker) unusedImports() {
+       // if function bodies are not checked, packages' uses are likely missing - don't check
+       if check.conf.IgnoreFuncBodies {
+               return
+       }
+
+       // spec: "It is illegal (...) to directly import a package without referring to
+       // any of its exported identifiers. To import a package solely for its side-effects
+       // (initialization), use the blank identifier as explicit package name."
+
+       // check use of regular imported packages
+       for _, scope := range check.pkg.scope.children /* file scopes */ {
+               for _, obj := range scope.elems {
+                       if obj, ok := obj.(*PkgName); ok {
+                               // Unused "blank imports" are automatically ignored
+                               // since _ identifiers are not entered into scopes.
+                               if !obj.used {
+                                       path := obj.imported.path
+                                       base := pathLib.Base(path)
+                                       if obj.name == base {
+                                               check.softErrorf(obj.pos, "%q imported but not used", path)
+                                       } else {
+                                               check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name)
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // check use of dot-imported packages
+       for _, unusedDotImports := range check.unusedDotImports {
+               for pkg, pos := range unusedDotImports {
+                       check.softErrorf(pos, "%q imported but not used", pkg.path)
+               }
+       }
+}
diff --git a/src/go/types/resolver_test.go b/src/go/types/resolver_test.go
new file mode 100644 (file)
index 0000000..505e3d8
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "sort"
+       "testing"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+var sources = []string{
+       `
+       package p
+       import "fmt"
+       import "math"
+       const pi = math.Pi
+       func sin(x float64) float64 {
+               return math.Sin(x)
+       }
+       var Println = fmt.Println
+       `,
+       `
+       package p
+       import "fmt"
+       type errorStringer struct { fmt.Stringer; error }
+       func f() string {
+               _ = "foo"
+               return fmt.Sprintf("%d", g())
+       }
+       func g() (x int) { return }
+       `,
+       `
+       package p
+       import . "go/parser"
+       import "sync"
+       func h() Mode { return ImportsOnly }
+       var _, x int = 1, 2
+       func init() {}
+       type T struct{ *sync.Mutex; a, b, c int}
+       type I interface{ m() }
+       var _ = T{a: 1, b: 2, c: 3}
+       func (_ T) m() {}
+       func (T) _() {}
+       var i I
+       var _ = i.m
+       func _(s []int) { for i, x := range s { _, _ = i, x } }
+       func _(x interface{}) {
+               switch x := x.(type) {
+               case int:
+                       _ = x
+               }
+               switch {} // implicit 'true' tag
+       }
+       `,
+       `
+       package p
+       type S struct{}
+       func (T) _() {}
+       func (T) _() {}
+       `,
+       `
+       package p
+       func _() {
+       L0:
+       L1:
+               goto L0
+               for {
+                       goto L1
+               }
+               if true {
+                       goto L2
+               }
+       L2:
+       }
+       `,
+}
+
+var pkgnames = []string{
+       "fmt",
+       "math",
+}
+
+func TestResolveIdents(t *testing.T) {
+       // parse package files
+       fset := token.NewFileSet()
+       var files []*ast.File
+       for i, src := range sources {
+               f, err := parser.ParseFile(fset, fmt.Sprintf("sources[%d]", i), src, parser.DeclarationErrors)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               files = append(files, f)
+       }
+
+       // resolve and type-check package AST
+       var conf Config
+       uses := make(map[*ast.Ident]Object)
+       defs := make(map[*ast.Ident]Object)
+       _, err := conf.Check("testResolveIdents", fset, files, &Info{Defs: defs, Uses: uses})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // check that all packages were imported
+       for _, name := range pkgnames {
+               if conf.Packages[name] == nil {
+                       t.Errorf("package %s not imported", name)
+               }
+       }
+
+       // check that qualified identifiers are resolved
+       for _, f := range files {
+               ast.Inspect(f, func(n ast.Node) bool {
+                       if s, ok := n.(*ast.SelectorExpr); ok {
+                               if x, ok := s.X.(*ast.Ident); ok {
+                                       obj := uses[x]
+                                       if obj == nil {
+                                               t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name)
+                                               return false
+                                       }
+                                       if _, ok := obj.(*PkgName); ok && uses[s.Sel] == nil {
+                                               t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name)
+                                               return false
+                                       }
+                                       return false
+                               }
+                               return false
+                       }
+                       return true
+               })
+       }
+
+       for id, obj := range uses {
+               if obj == nil {
+                       t.Errorf("%s: Uses[%s] == nil", fset.Position(id.Pos()), id.Name)
+               }
+       }
+
+       // check that each identifier in the source is found in uses or defs or both
+       var both []string
+       for _, f := range files {
+               ast.Inspect(f, func(n ast.Node) bool {
+                       if x, ok := n.(*ast.Ident); ok {
+                               var objects int
+                               if _, found := uses[x]; found {
+                                       objects |= 1
+                                       delete(uses, x)
+                               }
+                               if _, found := defs[x]; found {
+                                       objects |= 2
+                                       delete(defs, x)
+                               }
+                               if objects == 0 {
+                                       t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name)
+                               } else if objects == 3 {
+                                       both = append(both, x.Name)
+                               }
+                               return false
+                       }
+                       return true
+               })
+       }
+
+       // check the expected set of idents that are simultaneously uses and defs
+       sort.Strings(both)
+       if got, want := fmt.Sprint(both), "[Mutex Stringer error]"; got != want {
+               t.Errorf("simultaneous uses/defs = %s, want %s", got, want)
+       }
+
+       // any left-over identifiers didn't exist in the source
+       for x := range uses {
+               t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+       }
+       for x := range defs {
+               t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+       }
+
+       // TODO(gri) add tests to check ImplicitObj callbacks
+}
diff --git a/src/go/types/return.go b/src/go/types/return.go
new file mode 100644 (file)
index 0000000..df5a482
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements isTerminating.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+)
+
+// isTerminating reports if s is a terminating statement.
+// If s is labeled, label is the label name; otherwise s
+// is "".
+func (check *Checker) isTerminating(s ast.Stmt, label string) bool {
+       switch s := s.(type) {
+       default:
+               unreachable()
+
+       case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt,
+               *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt,
+               *ast.RangeStmt:
+               // no chance
+
+       case *ast.LabeledStmt:
+               return check.isTerminating(s.Stmt, s.Label.Name)
+
+       case *ast.ExprStmt:
+               // the predeclared (possibly parenthesized) panic() function is terminating
+               if call, _ := unparen(s.X).(*ast.CallExpr); call != nil {
+                       if id, _ := call.Fun.(*ast.Ident); id != nil {
+                               if _, obj := check.scope.LookupParent(id.Name); obj != nil {
+                                       if b, _ := obj.(*Builtin); b != nil && b.id == _Panic {
+                                               return true
+                                       }
+                               }
+                       }
+               }
+
+       case *ast.ReturnStmt:
+               return true
+
+       case *ast.BranchStmt:
+               if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH {
+                       return true
+               }
+
+       case *ast.BlockStmt:
+               return check.isTerminatingList(s.List, "")
+
+       case *ast.IfStmt:
+               if s.Else != nil &&
+                       check.isTerminating(s.Body, "") &&
+                       check.isTerminating(s.Else, "") {
+                       return true
+               }
+
+       case *ast.SwitchStmt:
+               return check.isTerminatingSwitch(s.Body, label)
+
+       case *ast.TypeSwitchStmt:
+               return check.isTerminatingSwitch(s.Body, label)
+
+       case *ast.SelectStmt:
+               for _, s := range s.Body.List {
+                       cc := s.(*ast.CommClause)
+                       if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+                               return false
+                       }
+
+               }
+               return true
+
+       case *ast.ForStmt:
+               if s.Cond == nil && !hasBreak(s.Body, label, true) {
+                       return true
+               }
+       }
+
+       return false
+}
+
+func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool {
+       n := len(list)
+       return n > 0 && check.isTerminating(list[n-1], label)
+}
+
+func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool {
+       hasDefault := false
+       for _, s := range body.List {
+               cc := s.(*ast.CaseClause)
+               if cc.List == nil {
+                       hasDefault = true
+               }
+               if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+                       return false
+               }
+       }
+       return hasDefault
+}
+
+// TODO(gri) For nested breakable statements, the current implementation of hasBreak
+//          will traverse the same subtree repeatedly, once for each label. Replace
+//           with a single-pass label/break matching phase.
+
+// hasBreak reports if s is or contains a break statement
+// referring to the label-ed statement or implicit-ly the
+// closest outer breakable statement.
+func hasBreak(s ast.Stmt, label string, implicit bool) bool {
+       switch s := s.(type) {
+       default:
+               unreachable()
+
+       case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt,
+               *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt,
+               *ast.DeferStmt, *ast.ReturnStmt:
+               // no chance
+
+       case *ast.LabeledStmt:
+               return hasBreak(s.Stmt, label, implicit)
+
+       case *ast.BranchStmt:
+               if s.Tok == token.BREAK {
+                       if s.Label == nil {
+                               return implicit
+                       }
+                       if s.Label.Name == label {
+                               return true
+                       }
+               }
+
+       case *ast.BlockStmt:
+               return hasBreakList(s.List, label, implicit)
+
+       case *ast.IfStmt:
+               if hasBreak(s.Body, label, implicit) ||
+                       s.Else != nil && hasBreak(s.Else, label, implicit) {
+                       return true
+               }
+
+       case *ast.CaseClause:
+               return hasBreakList(s.Body, label, implicit)
+
+       case *ast.SwitchStmt:
+               if label != "" && hasBreak(s.Body, label, false) {
+                       return true
+               }
+
+       case *ast.TypeSwitchStmt:
+               if label != "" && hasBreak(s.Body, label, false) {
+                       return true
+               }
+
+       case *ast.CommClause:
+               return hasBreakList(s.Body, label, implicit)
+
+       case *ast.SelectStmt:
+               if label != "" && hasBreak(s.Body, label, false) {
+                       return true
+               }
+
+       case *ast.ForStmt:
+               if label != "" && hasBreak(s.Body, label, false) {
+                       return true
+               }
+
+       case *ast.RangeStmt:
+               if label != "" && hasBreak(s.Body, label, false) {
+                       return true
+               }
+       }
+
+       return false
+}
+
+func hasBreakList(list []ast.Stmt, label string, implicit bool) bool {
+       for _, s := range list {
+               if hasBreak(s, label, implicit) {
+                       return true
+               }
+       }
+       return false
+}
diff --git a/src/go/types/scope.go b/src/go/types/scope.go
new file mode 100644 (file)
index 0000000..8ab0f64
--- /dev/null
@@ -0,0 +1,145 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements Scopes.
+
+package types
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "sort"
+       "strings"
+)
+
+// TODO(gri) Provide scopes with a name or other mechanism so that
+//           objects can use that information for better printing.
+
+// A Scope maintains a set of objects and links to its containing
+// (parent) and contained (children) scopes. Objects may be inserted
+// and looked up by name. The zero value for Scope is a ready-to-use
+// empty scope.
+type Scope struct {
+       parent   *Scope
+       children []*Scope
+       comment  string            // for debugging only
+       elems    map[string]Object // lazily allocated
+}
+
+// NewScope returns a new, empty scope contained in the given parent
+// scope, if any.  The comment is for debugging only.
+func NewScope(parent *Scope, comment string) *Scope {
+       s := &Scope{parent: parent, comment: comment}
+       // don't add children to Universe scope!
+       if parent != nil && parent != Universe {
+               parent.children = append(parent.children, s)
+       }
+       return s
+}
+
+// Parent returns the scope's containing (parent) scope.
+func (s *Scope) Parent() *Scope { return s.parent }
+
+// Len() returns the number of scope elements.
+func (s *Scope) Len() int { return len(s.elems) }
+
+// Names returns the scope's element names in sorted order.
+func (s *Scope) Names() []string {
+       names := make([]string, len(s.elems))
+       i := 0
+       for name := range s.elems {
+               names[i] = name
+               i++
+       }
+       sort.Strings(names)
+       return names
+}
+
+// NumChildren() returns the number of scopes nested in s.
+func (s *Scope) NumChildren() int { return len(s.children) }
+
+// Child returns the i'th child scope for 0 <= i < NumChildren().
+func (s *Scope) Child(i int) *Scope { return s.children[i] }
+
+// Lookup returns the object in scope s with the given name if such an
+// object exists; otherwise the result is nil.
+func (s *Scope) Lookup(name string) Object {
+       return s.elems[name]
+}
+
+// LookupParent follows the parent chain of scopes starting with s until
+// it finds a scope where Lookup(name) returns a non-nil object, and then
+// returns that scope and object. If no such scope exists, the result is (nil, nil).
+//
+// Note that obj.Parent() may be different from the returned scope if the
+// object was inserted into the scope and already had a parent at that
+// time (see Insert, below). This can only happen for dot-imported objects
+// whose scope is the scope of the package that exported them.
+func (s *Scope) LookupParent(name string) (*Scope, Object) {
+       for ; s != nil; s = s.parent {
+               if obj := s.elems[name]; obj != nil {
+                       return s, obj
+               }
+       }
+       return nil, nil
+}
+
+// Insert attempts to insert an object obj into scope s.
+// If s already contains an alternative object alt with
+// the same name, Insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj, sets the object's parent scope
+// if not already set, and returns nil.
+func (s *Scope) Insert(obj Object) Object {
+       name := obj.Name()
+       if alt := s.elems[name]; alt != nil {
+               return alt
+       }
+       if s.elems == nil {
+               s.elems = make(map[string]Object)
+       }
+       s.elems[name] = obj
+       if obj.Parent() == nil {
+               obj.setParent(s)
+       }
+       return nil
+}
+
+// WriteTo writes a string representation of the scope to w,
+// with the scope elements sorted by name.
+// The level of indentation is controlled by n >= 0, with
+// n == 0 for no indentation.
+// If recurse is set, it also writes nested (children) scopes.
+func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
+       const ind = ".  "
+       indn := strings.Repeat(ind, n)
+
+       fmt.Fprintf(w, "%s%s scope %p {", indn, s.comment, s)
+       if len(s.elems) == 0 {
+               fmt.Fprintf(w, "}\n")
+               return
+       }
+
+       fmt.Fprintln(w)
+       indn1 := indn + ind
+       for _, name := range s.Names() {
+               fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
+       }
+
+       if recurse {
+               for _, s := range s.children {
+                       fmt.Fprintln(w)
+                       s.WriteTo(w, n+1, recurse)
+               }
+       }
+
+       fmt.Fprintf(w, "%s}", indn)
+}
+
+// String returns a string representation of the scope, for debugging.
+func (s *Scope) String() string {
+       var buf bytes.Buffer
+       s.WriteTo(&buf, 0, false)
+       return buf.String()
+}
diff --git a/src/go/types/selection.go b/src/go/types/selection.go
new file mode 100644 (file)
index 0000000..1c70165
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements Selections.
+
+package types
+
+import (
+       "bytes"
+       "fmt"
+)
+
+// SelectionKind describes the kind of a selector expression x.f
+// (excluding qualified identifiers).
+type SelectionKind int
+
+const (
+       FieldVal   SelectionKind = iota // x.f is a struct field selector
+       MethodVal                       // x.f is a method selector
+       MethodExpr                      // x.f is a method expression
+)
+
+// A Selection describes a selector expression x.f.
+// For the declarations:
+//
+//     type T struct{ x int; E }
+//     type E struct{}
+//     func (e E) m() {}
+//     var p *T
+//
+// the following relations exist:
+//
+//     Selector    Kind          Recv    Obj    Type               Index     Indirect
+//
+//     p.x         FieldVal      T       x      int                {0}       true
+//     p.m         MethodVal     *T      m      func (e *T) m()    {1, 0}    true
+//     T.m         MethodExpr    T       m      func m(_ T)        {1, 0}    false
+//
+type Selection struct {
+       kind     SelectionKind
+       recv     Type   // type of x
+       obj      Object // object denoted by x.f
+       index    []int  // path from x to x.f
+       indirect bool   // set if there was any pointer indirection on the path
+}
+
+// Kind returns the selection kind.
+func (s *Selection) Kind() SelectionKind { return s.kind }
+
+// Recv returns the type of x in x.f.
+func (s *Selection) Recv() Type { return s.recv }
+
+// Obj returns the object denoted by x.f; a *Var for
+// a field selection, and a *Func in all other cases.
+func (s *Selection) Obj() Object { return s.obj }
+
+// Type returns the type of x.f, which may be different from the type of f.
+// See Selection for more information.
+func (s *Selection) Type() Type {
+       switch s.kind {
+       case MethodVal:
+               // The type of x.f is a method with its receiver type set
+               // to the type of x.
+               sig := *s.obj.(*Func).typ.(*Signature)
+               recv := *sig.recv
+               recv.typ = s.recv
+               sig.recv = &recv
+               return &sig
+
+       case MethodExpr:
+               // The type of x.f is a function (without receiver)
+               // and an additional first argument with the same type as x.
+               // TODO(gri) Similar code is already in call.go - factor!
+               // TODO(gri) Compute this eagerly to avoid allocations.
+               sig := *s.obj.(*Func).typ.(*Signature)
+               arg0 := *sig.recv
+               sig.recv = nil
+               arg0.typ = s.recv
+               var params []*Var
+               if sig.params != nil {
+                       params = sig.params.vars
+               }
+               sig.params = NewTuple(append([]*Var{&arg0}, params...)...)
+               return &sig
+       }
+
+       // In all other cases, the type of x.f is the type of x.
+       return s.obj.Type()
+}
+
+// Index describes the path from x to f in x.f.
+// The last index entry is the field or method index of the type declaring f;
+// either:
+//
+//     1) the list of declared methods of a named type; or
+//     2) the list of methods of an interface type; or
+//     3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the embedded fields implicitly
+// traversed to get from (the type of) x to f, starting at embedding depth 0.
+func (s *Selection) Index() []int { return s.index }
+
+// Indirect reports whether any pointer indirection was required to get from
+// x to f in x.f.
+func (s *Selection) Indirect() bool { return s.indirect }
+
+func (s *Selection) String() string { return SelectionString(nil, s) }
+
+// SelectionString returns the string form of s.
+// Type names are printed package-qualified
+// only if they do not belong to this package.
+//
+// Examples:
+//     "field (T) f int"
+//     "method (T) f(X) Y"
+//     "method expr (T) f(X) Y"
+//
+func SelectionString(this *Package, s *Selection) string {
+       var k string
+       switch s.kind {
+       case FieldVal:
+               k = "field "
+       case MethodVal:
+               k = "method "
+       case MethodExpr:
+               k = "method expr "
+       default:
+               unreachable()
+       }
+       var buf bytes.Buffer
+       buf.WriteString(k)
+       buf.WriteByte('(')
+       WriteType(&buf, this, s.Recv())
+       fmt.Fprintf(&buf, ") %s", s.obj.Name())
+       if T := s.Type(); s.kind == FieldVal {
+               buf.WriteByte(' ')
+               WriteType(&buf, this, T)
+       } else {
+               WriteSignature(&buf, this, T.(*Signature))
+       }
+       return buf.String()
+}
diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go
new file mode 100644 (file)
index 0000000..dc397b5
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "path/filepath"
+       "testing"
+       "time"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+var benchmark = flag.Bool("b", false, "run benchmarks")
+
+func TestSelf(t *testing.T) {
+       fset := token.NewFileSet()
+       files, err := pkgFiles(fset, ".")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       _, err = Check("go/types", fset, files)
+       if err != nil {
+               // Importing go.tools/go/exact doensn't work in the
+               // build dashboard environment. Don't report an error
+               // for now so that the build remains green.
+               // TODO(gri) fix this
+               t.Log(err) // replace w/ t.Fatal eventually
+               return
+       }
+}
+
+func TestBenchmark(t *testing.T) {
+       if !*benchmark {
+               return
+       }
+
+       // We're not using testing's benchmarking mechanism directly
+       // because we want custom output.
+
+       for _, p := range []string{"types", "exact", "gcimporter"} {
+               path := filepath.Join("..", p)
+               runbench(t, path, false)
+               runbench(t, path, true)
+               fmt.Println()
+       }
+}
+
+func runbench(t *testing.T, path string, ignoreFuncBodies bool) {
+       fset := token.NewFileSet()
+       files, err := pkgFiles(fset, path)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       b := testing.Benchmark(func(b *testing.B) {
+               for i := 0; i < b.N; i++ {
+                       conf := Config{IgnoreFuncBodies: ignoreFuncBodies}
+                       conf.Check(path, fset, files, nil)
+               }
+       })
+
+       // determine line count
+       lines := 0
+       fset.Iterate(func(f *token.File) bool {
+               lines += f.LineCount()
+               return true
+       })
+
+       d := time.Duration(b.NsPerOp())
+       fmt.Printf(
+               "%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n",
+               filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies,
+       )
+}
+
+func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) {
+       filenames, err := pkgFilenames(path) // from stdlib_test.go
+       if err != nil {
+               return nil, err
+       }
+
+       var files []*ast.File
+       for _, filename := range filenames {
+               file, err := parser.ParseFile(fset, filename, nil, 0)
+               if err != nil {
+                       return nil, err
+               }
+               files = append(files, file)
+       }
+
+       return files, nil
+}
diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go
new file mode 100644 (file)
index 0000000..56fb310
--- /dev/null
@@ -0,0 +1,211 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements Sizes.
+
+package types
+
+// Sizes defines the sizing functions for package unsafe.
+type Sizes interface {
+       // Alignof returns the alignment of a variable of type T.
+       // Alignof must implement the alignment guarantees required by the spec.
+       Alignof(T Type) int64
+
+       // Offsetsof returns the offsets of the given struct fields, in bytes.
+       // Offsetsof must implement the offset guarantees required by the spec.
+       Offsetsof(fields []*Var) []int64
+
+       // Sizeof returns the size of a variable of type T.
+       // Sizeof must implement the size guarantees required by the spec.
+       Sizeof(T Type) int64
+}
+
+// StdSizes is a convenience type for creating commonly used Sizes.
+// It makes the following simplifying assumptions:
+//
+//     - The size of explicitly sized basic types (int16, etc.) is the
+//       specified size.
+//     - The size of strings and interfaces is 2*WordSize.
+//     - The size of slices is 3*WordSize.
+//     - The size of an array of n elements corresponds to the size of
+//       a struct of n consecutive fields of the array's element type.
+//      - The size of a struct is the offset of the last field plus that
+//       field's size. As with all element types, if the struct is used
+//       in an array its size must first be aligned to a multiple of the
+//       struct's alignment.
+//     - All other types have size WordSize.
+//     - Arrays and structs are aligned per spec definition; all other
+//       types are naturally aligned with a maximum alignment MaxAlign.
+//
+// *StdSizes implements Sizes.
+//
+type StdSizes struct {
+       WordSize int64 // word size in bytes - must be >= 4 (32bits)
+       MaxAlign int64 // maximum alignment in bytes - must be >= 1
+}
+
+func (s *StdSizes) Alignof(T Type) int64 {
+       // For arrays and structs, alignment is defined in terms
+       // of alignment of the elements and fields, respectively.
+       switch t := T.Underlying().(type) {
+       case *Array:
+               // spec: "For a variable x of array type: unsafe.Alignof(x)
+               // is the same as unsafe.Alignof(x[0]), but at least 1."
+               return s.Alignof(t.elem)
+       case *Struct:
+               // spec: "For a variable x of struct type: unsafe.Alignof(x)
+               // is the largest of the values unsafe.Alignof(x.f) for each
+               // field f of x, but at least 1."
+               max := int64(1)
+               for _, f := range t.fields {
+                       if a := s.Alignof(f.typ); a > max {
+                               max = a
+                       }
+               }
+               return max
+       }
+       a := s.Sizeof(T) // may be 0
+       // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
+       if a < 1 {
+               return 1
+       }
+       if a > s.MaxAlign {
+               return s.MaxAlign
+       }
+       return a
+}
+
+func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
+       offsets := make([]int64, len(fields))
+       var o int64
+       for i, f := range fields {
+               a := s.Alignof(f.typ)
+               o = align(o, a)
+               offsets[i] = o
+               o += s.Sizeof(f.typ)
+       }
+       return offsets
+}
+
+var basicSizes = [...]byte{
+       Bool:       1,
+       Int8:       1,
+       Int16:      2,
+       Int32:      4,
+       Int64:      8,
+       Uint8:      1,
+       Uint16:     2,
+       Uint32:     4,
+       Uint64:     8,
+       Float32:    4,
+       Float64:    8,
+       Complex64:  8,
+       Complex128: 16,
+}
+
+func (s *StdSizes) Sizeof(T Type) int64 {
+       switch t := T.Underlying().(type) {
+       case *Basic:
+               assert(isTyped(T))
+               k := t.kind
+               if int(k) < len(basicSizes) {
+                       if s := basicSizes[k]; s > 0 {
+                               return int64(s)
+                       }
+               }
+               if k == String {
+                       return s.WordSize * 2
+               }
+       case *Array:
+               n := t.len
+               if n == 0 {
+                       return 0
+               }
+               a := s.Alignof(t.elem)
+               z := s.Sizeof(t.elem)
+               return align(z, a)*(n-1) + z
+       case *Slice:
+               return s.WordSize * 3
+       case *Struct:
+               n := t.NumFields()
+               if n == 0 {
+                       return 0
+               }
+               offsets := t.offsets
+               if t.offsets == nil {
+                       // compute offsets on demand
+                       offsets = s.Offsetsof(t.fields)
+                       t.offsets = offsets
+               }
+               return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+       case *Interface:
+               return s.WordSize * 2
+       }
+       return s.WordSize // catch-all
+}
+
+// stdSizes is used if Config.Sizes == nil.
+var stdSizes = StdSizes{8, 8}
+
+func (conf *Config) alignof(T Type) int64 {
+       if s := conf.Sizes; s != nil {
+               if a := s.Alignof(T); a >= 1 {
+                       return a
+               }
+               panic("Config.Sizes.Alignof returned an alignment < 1")
+       }
+       return stdSizes.Alignof(T)
+}
+
+func (conf *Config) offsetsof(T *Struct) []int64 {
+       offsets := T.offsets
+       if offsets == nil && T.NumFields() > 0 {
+               // compute offsets on demand
+               if s := conf.Sizes; s != nil {
+                       offsets = s.Offsetsof(T.fields)
+                       // sanity checks
+                       if len(offsets) != T.NumFields() {
+                               panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+                       }
+                       for _, o := range offsets {
+                               if o < 0 {
+                                       panic("Config.Sizes.Offsetsof returned an offset < 0")
+                               }
+                       }
+               } else {
+                       offsets = stdSizes.Offsetsof(T.fields)
+               }
+               T.offsets = offsets
+       }
+       return offsets
+}
+
+// offsetof returns the offset of the field specified via
+// the index sequence relative to typ. All embedded fields
+// must be structs (rather than pointer to structs).
+func (conf *Config) offsetof(typ Type, index []int) int64 {
+       var o int64
+       for _, i := range index {
+               s := typ.Underlying().(*Struct)
+               o += conf.offsetsof(s)[i]
+               typ = s.fields[i].typ
+       }
+       return o
+}
+
+func (conf *Config) sizeof(T Type) int64 {
+       if s := conf.Sizes; s != nil {
+               if z := s.Sizeof(T); z >= 0 {
+                       return z
+               }
+               panic("Config.Sizes.Sizeof returned a size < 0")
+       }
+       return stdSizes.Sizeof(T)
+}
+
+// align returns the smallest y >= x such that y % a == 0.
+func align(x, a int64) int64 {
+       y := x + a - 1
+       return y - y%a
+}
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
new file mode 100644 (file)
index 0000000..a5d088f
--- /dev/null
@@ -0,0 +1,254 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file tests types.Check by using it to
+// typecheck the standard library and tests.
+
+package types_test
+
+import (
+       "fmt"
+       "go/ast"
+       "go/build"
+       "go/parser"
+       "go/scanner"
+       "go/token"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "runtime"
+       "strings"
+       "testing"
+       "time"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+var (
+       pkgCount int // number of packages processed
+       start    = time.Now()
+)
+
+func TestStdlib(t *testing.T) {
+       walkDirs(t, filepath.Join(runtime.GOROOT(), "src"))
+       if testing.Verbose() {
+               fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
+       }
+}
+
+// firstComment returns the contents of the first comment in
+// the given file, assuming there's one within the first KB.
+func firstComment(filename string) string {
+       f, err := os.Open(filename)
+       if err != nil {
+               return ""
+       }
+       defer f.Close()
+
+       var src [1 << 10]byte // read at most 1KB
+       n, _ := f.Read(src[:])
+
+       var s scanner.Scanner
+       s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments)
+       for {
+               _, tok, lit := s.Scan()
+               switch tok {
+               case token.COMMENT:
+                       // remove trailing */ of multi-line comment
+                       if lit[1] == '*' {
+                               lit = lit[:len(lit)-2]
+                       }
+                       return strings.TrimSpace(lit[2:])
+               case token.EOF:
+                       return ""
+               }
+       }
+}
+
+func testTestDir(t *testing.T, path string, ignore ...string) {
+       files, err := ioutil.ReadDir(path)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       excluded := make(map[string]bool)
+       for _, filename := range ignore {
+               excluded[filename] = true
+       }
+
+       fset := token.NewFileSet()
+       for _, f := range files {
+               // filter directory contents
+               if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
+                       continue
+               }
+
+               // get per-file instructions
+               expectErrors := false
+               filename := filepath.Join(path, f.Name())
+               if cmd := firstComment(filename); cmd != "" {
+                       switch cmd {
+                       case "skip", "compiledir":
+                               continue // ignore this file
+                       case "errorcheck":
+                               expectErrors = true
+                       }
+               }
+
+               // parse and type-check file
+               file, err := parser.ParseFile(fset, filename, nil, 0)
+               if err == nil {
+                       _, err = Check(filename, fset, []*ast.File{file})
+               }
+
+               if expectErrors {
+                       if err == nil {
+                               t.Errorf("expected errors but found none in %s", filename)
+                       }
+               } else {
+                       if err != nil {
+                               t.Error(err)
+                       }
+               }
+       }
+}
+
+func TestStdTest(t *testing.T) {
+       testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
+               "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
+               "sigchld.go",     // don't work on Windows; testTestDir should consult build tags
+               "float_lit2.go",  // TODO(gri) enable for releases 1.4 and higher
+       )
+}
+
+func TestStdFixed(t *testing.T) {
+       testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
+               "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
+               "bug459.go",    // possibly incorrect test - see issue 6703 (pending spec clarification)
+               "issue3924.go", // possibly incorrect test - see issue 6671 (pending spec clarification)
+               "issue6889.go", // gc-specific test
+       )
+}
+
+func TestStdKen(t *testing.T) {
+       testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
+}
+
+// Package paths of excluded packages.
+var excluded = map[string]bool{
+       "builtin": true,
+}
+
+// typecheck typechecks the given package files.
+func typecheck(t *testing.T, path string, filenames []string) {
+       fset := token.NewFileSet()
+
+       // parse package files
+       var files []*ast.File
+       for _, filename := range filenames {
+               file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+               if err != nil {
+                       // the parser error may be a list of individual errors; report them all
+                       if list, ok := err.(scanner.ErrorList); ok {
+                               for _, err := range list {
+                                       t.Error(err)
+                               }
+                               return
+                       }
+                       t.Error(err)
+                       return
+               }
+
+               if testing.Verbose() {
+                       if len(files) == 0 {
+                               fmt.Println("package", file.Name.Name)
+                       }
+                       fmt.Println("\t", filename)
+               }
+
+               files = append(files, file)
+       }
+
+       // typecheck package files
+       var conf Config
+       conf.Error = func(err error) { t.Error(err) }
+       info := Info{Uses: make(map[*ast.Ident]Object)}
+       conf.Check(path, fset, files, &info)
+       pkgCount++
+
+       // Perform checks of API invariants.
+
+       // All Objects have a package, except predeclared ones.
+       errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
+       for id, obj := range info.Uses {
+               predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
+               if predeclared == (obj.Pkg() != nil) {
+                       posn := fset.Position(id.Pos())
+                       if predeclared {
+                               t.Errorf("%s: predeclared object with package: %s", posn, obj)
+                       } else {
+                               t.Errorf("%s: user-defined object without package: %s", posn, obj)
+                       }
+               }
+       }
+}
+
+// pkgFilenames returns the list of package filenames for the given directory.
+func pkgFilenames(dir string) ([]string, error) {
+       ctxt := build.Default
+       ctxt.CgoEnabled = false
+       pkg, err := ctxt.ImportDir(dir, 0)
+       if err != nil {
+               if _, nogo := err.(*build.NoGoError); nogo {
+                       return nil, nil // no *.go files, not an error
+               }
+               return nil, err
+       }
+       if excluded[pkg.ImportPath] {
+               return nil, nil
+       }
+       var filenames []string
+       for _, name := range pkg.GoFiles {
+               filenames = append(filenames, filepath.Join(pkg.Dir, name))
+       }
+       for _, name := range pkg.TestGoFiles {
+               filenames = append(filenames, filepath.Join(pkg.Dir, name))
+       }
+       return filenames, nil
+}
+
+// Note: Could use filepath.Walk instead of walkDirs but that wouldn't
+//       necessarily be shorter or clearer after adding the code to
+//       terminate early for -short tests.
+
+func walkDirs(t *testing.T, dir string) {
+       // limit run time for short tests
+       if testing.Short() && time.Since(start) >= 750*time.Millisecond {
+               return
+       }
+
+       fis, err := ioutil.ReadDir(dir)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       // typecheck package in directory
+       files, err := pkgFilenames(dir)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       if files != nil {
+               typecheck(t, dir, files)
+       }
+
+       // traverse subdirectories, but don't walk into testdata
+       for _, fi := range fis {
+               if fi.IsDir() && fi.Name() != "testdata" {
+                       walkDirs(t, filepath.Join(dir, fi.Name()))
+               }
+       }
+}
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
new file mode 100644 (file)
index 0000000..2b399e7
--- /dev/null
@@ -0,0 +1,732 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements typechecking of statements.
+
+package types
+
+import (
+       "fmt"
+       "go/ast"
+       "go/token"
+
+       "go/exact"
+)
+
+func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) {
+       if trace {
+               if name == "" {
+                       name = "<function literal>"
+               }
+               fmt.Printf("--- %s: %s {\n", name, sig)
+               defer fmt.Println("--- <end>")
+       }
+
+       // save/restore current context and setup function context
+       // (and use 0 indentation at function start)
+       defer func(ctxt context, indent int) {
+               check.context = ctxt
+               check.indent = indent
+       }(check.context, check.indent)
+       check.context = context{
+               decl:  decl,
+               scope: sig.scope,
+               sig:   sig,
+       }
+       check.indent = 0
+
+       check.stmtList(0, body.List)
+
+       if check.hasLabel {
+               check.labels(body)
+       }
+
+       if sig.results.Len() > 0 && !check.isTerminating(body, "") {
+               check.error(body.Rbrace, "missing return")
+       }
+
+       // spec: "Implementation restriction: A compiler may make it illegal to
+       // declare a variable inside a function body if the variable is never used."
+       // (One could check each scope after use, but that distributes this check
+       // over several places because CloseScope is not always called explicitly.)
+       check.usage(sig.scope)
+}
+
+func (check *Checker) usage(scope *Scope) {
+       for _, obj := range scope.elems {
+               if v, _ := obj.(*Var); v != nil && !v.used {
+                       check.softErrorf(v.pos, "%s declared but not used", v.name)
+               }
+       }
+       for _, scope := range scope.children {
+               check.usage(scope)
+       }
+}
+
+// stmtContext is a bitset describing which
+// control-flow statements are permissible.
+type stmtContext uint
+
+const (
+       breakOk stmtContext = 1 << iota
+       continueOk
+       fallthroughOk
+)
+
+func (check *Checker) simpleStmt(s ast.Stmt) {
+       if s != nil {
+               check.stmt(0, s)
+       }
+}
+
+func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
+       ok := ctxt&fallthroughOk != 0
+       inner := ctxt &^ fallthroughOk
+       for i, s := range list {
+               inner := inner
+               if ok && i+1 == len(list) {
+                       inner |= fallthroughOk
+               }
+               check.stmt(inner, s)
+       }
+}
+
+func (check *Checker) multipleDefaults(list []ast.Stmt) {
+       var first ast.Stmt
+       for _, s := range list {
+               var d ast.Stmt
+               switch c := s.(type) {
+               case *ast.CaseClause:
+                       if len(c.List) == 0 {
+                               d = s
+                       }
+               case *ast.CommClause:
+                       if c.Comm == nil {
+                               d = s
+                       }
+               default:
+                       check.invalidAST(s.Pos(), "case/communication clause expected")
+               }
+               if d != nil {
+                       if first != nil {
+                               check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
+                       } else {
+                               first = d
+                       }
+               }
+       }
+}
+
+func (check *Checker) openScope(s ast.Stmt, comment string) {
+       scope := NewScope(check.scope, comment)
+       check.recordScope(s, scope)
+       check.scope = scope
+}
+
+func (check *Checker) closeScope() {
+       check.scope = check.scope.Parent()
+}
+
+func assignOp(op token.Token) token.Token {
+       // token_test.go verifies the token ordering this function relies on
+       if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
+               return op + (token.ADD - token.ADD_ASSIGN)
+       }
+       return token.ILLEGAL
+}
+
+func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
+       var x operand
+       var msg string
+       switch check.rawExpr(&x, call, nil) {
+       case conversion:
+               msg = "requires function call, not conversion"
+       case expression:
+               msg = "discards result of"
+       case statement:
+               return
+       default:
+               unreachable()
+       }
+       check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
+}
+
+func (check *Checker) caseValues(x operand /* copy argument (not *operand!) */, values []ast.Expr) {
+       // No duplicate checking for now. See issue 4524.
+       for _, e := range values {
+               var y operand
+               check.expr(&y, e)
+               if y.mode == invalid {
+                       return
+               }
+               // TODO(gri) The convertUntyped call pair below appears in other places. Factor!
+               // Order matters: By comparing y against x, error positions are at the case values.
+               check.convertUntyped(&y, x.typ)
+               if y.mode == invalid {
+                       return
+               }
+               check.convertUntyped(&x, y.typ)
+               if x.mode == invalid {
+                       return
+               }
+               check.comparison(&y, &x, token.EQL)
+       }
+}
+
+func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) {
+L:
+       for _, e := range types {
+               T = check.typOrNil(e)
+               if T == Typ[Invalid] {
+                       continue
+               }
+               // complain about duplicate types
+               // TODO(gri) use a type hash to avoid quadratic algorithm
+               for t, pos := range seen {
+                       if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
+                               // talk about "case" rather than "type" because of nil case
+                               check.error(e.Pos(), "duplicate case in type switch")
+                               check.errorf(pos, "\tprevious case %s", T) // secondary error, \t indented
+                               continue L
+                       }
+               }
+               seen[T] = e.Pos()
+               if T != nil {
+                       check.typeAssertion(e.Pos(), x, xtyp, T)
+               }
+       }
+       return
+}
+
+// stmt typechecks statement s.
+func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
+       // statements cannot use iota in general
+       // (constant declarations set it explicitly)
+       assert(check.iota == nil)
+
+       // statements must end with the same top scope as they started with
+       if debug {
+               defer func(scope *Scope) {
+                       // don't check if code is panicking
+                       if p := recover(); p != nil {
+                               panic(p)
+                       }
+                       assert(scope == check.scope)
+               }(check.scope)
+       }
+
+       inner := ctxt &^ fallthroughOk
+       switch s := s.(type) {
+       case *ast.BadStmt, *ast.EmptyStmt:
+               // ignore
+
+       case *ast.DeclStmt:
+               check.declStmt(s.Decl)
+
+       case *ast.LabeledStmt:
+               check.hasLabel = true
+               check.stmt(ctxt, s.Stmt)
+
+       case *ast.ExprStmt:
+               // spec: "With the exception of specific built-in functions,
+               // function and method calls and receive operations can appear
+               // in statement context. Such statements may be parenthesized."
+               var x operand
+               kind := check.rawExpr(&x, s.X, nil)
+               var msg string
+               switch x.mode {
+               default:
+                       if kind == statement {
+                               return
+                       }
+                       msg = "is not used"
+               case builtin:
+                       msg = "must be called"
+               case typexpr:
+                       msg = "is not an expression"
+               }
+               check.errorf(x.pos(), "%s %s", &x, msg)
+
+       case *ast.SendStmt:
+               var ch, x operand
+               check.expr(&ch, s.Chan)
+               check.expr(&x, s.Value)
+               if ch.mode == invalid || x.mode == invalid {
+                       return
+               }
+               if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir == RecvOnly || !check.assignment(&x, tch.elem) {
+                       if x.mode != invalid {
+                               check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch)
+                       }
+               }
+
+       case *ast.IncDecStmt:
+               var op token.Token
+               switch s.Tok {
+               case token.INC:
+                       op = token.ADD
+               case token.DEC:
+                       op = token.SUB
+               default:
+                       check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
+                       return
+               }
+               var x operand
+               Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
+               check.binary(&x, s.X, Y, op)
+               if x.mode == invalid {
+                       return
+               }
+               check.assignVar(s.X, &x)
+
+       case *ast.AssignStmt:
+               switch s.Tok {
+               case token.ASSIGN, token.DEFINE:
+                       if len(s.Lhs) == 0 {
+                               check.invalidAST(s.Pos(), "missing lhs in assignment")
+                               return
+                       }
+                       if s.Tok == token.DEFINE {
+                               check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
+                       } else {
+                               // regular assignment
+                               check.assignVars(s.Lhs, s.Rhs)
+                       }
+
+               default:
+                       // assignment operations
+                       if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
+                               check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
+                               return
+                       }
+                       op := assignOp(s.Tok)
+                       if op == token.ILLEGAL {
+                               check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
+                               return
+                       }
+                       var x operand
+                       check.binary(&x, s.Lhs[0], s.Rhs[0], op)
+                       if x.mode == invalid {
+                               return
+                       }
+                       check.assignVar(s.Lhs[0], &x)
+               }
+
+       case *ast.GoStmt:
+               check.suspendedCall("go", s.Call)
+
+       case *ast.DeferStmt:
+               check.suspendedCall("defer", s.Call)
+
+       case *ast.ReturnStmt:
+               res := check.sig.results
+               if res.Len() > 0 {
+                       // function returns results
+                       // (if one, say the first, result parameter is named, all of them are named)
+                       if len(s.Results) == 0 && res.vars[0].name != "" {
+                               // spec: "Implementation restriction: A compiler may disallow an empty expression
+                               // list in a "return" statement if a different entity (constant, type, or variable)
+                               // with the same name as a result parameter is in scope at the place of the return."
+                               for _, obj := range res.vars {
+                                       if _, alt := check.scope.LookupParent(obj.name); alt != nil && alt != obj {
+                                               check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
+                                               check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
+                                               // ok to continue
+                                       }
+                               }
+                       } else {
+                               // return has results or result parameters are unnamed
+                               check.initVars(res.vars, s.Results, s.Return)
+                       }
+               } else if len(s.Results) > 0 {
+                       check.error(s.Results[0].Pos(), "no result values expected")
+                       check.use(s.Results...)
+               }
+
+       case *ast.BranchStmt:
+               if s.Label != nil {
+                       check.hasLabel = true
+                       return // checked in 2nd pass (check.labels)
+               }
+               switch s.Tok {
+               case token.BREAK:
+                       if ctxt&breakOk == 0 {
+                               check.error(s.Pos(), "break not in for, switch, or select statement")
+                       }
+               case token.CONTINUE:
+                       if ctxt&continueOk == 0 {
+                               check.error(s.Pos(), "continue not in for statement")
+                       }
+               case token.FALLTHROUGH:
+                       if ctxt&fallthroughOk == 0 {
+                               check.error(s.Pos(), "fallthrough statement out of place")
+                       }
+               default:
+                       check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
+               }
+
+       case *ast.BlockStmt:
+               check.openScope(s, "block")
+               defer check.closeScope()
+
+               check.stmtList(inner, s.List)
+
+       case *ast.IfStmt:
+               check.openScope(s, "if")
+               defer check.closeScope()
+
+               check.simpleStmt(s.Init)
+               var x operand
+               check.expr(&x, s.Cond)
+               if x.mode != invalid && !isBoolean(x.typ) {
+                       check.error(s.Cond.Pos(), "non-boolean condition in if statement")
+               }
+               check.stmt(inner, s.Body)
+               if s.Else != nil {
+                       check.stmt(inner, s.Else)
+               }
+
+       case *ast.SwitchStmt:
+               inner |= breakOk
+               check.openScope(s, "switch")
+               defer check.closeScope()
+
+               check.simpleStmt(s.Init)
+               var x operand
+               if s.Tag != nil {
+                       check.expr(&x, s.Tag)
+               } else {
+                       // spec: "A missing switch expression is
+                       // equivalent to the boolean value true."
+                       x.mode = constant
+                       x.typ = Typ[Bool]
+                       x.val = exact.MakeBool(true)
+                       x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
+               }
+
+               check.multipleDefaults(s.Body.List)
+
+               for i, c := range s.Body.List {
+                       clause, _ := c.(*ast.CaseClause)
+                       if clause == nil {
+                               check.invalidAST(c.Pos(), "incorrect expression switch case")
+                               continue
+                       }
+                       if x.mode != invalid {
+                               check.caseValues(x, clause.List)
+                       }
+                       check.openScope(clause, "case")
+                       inner := inner
+                       if i+1 < len(s.Body.List) {
+                               inner |= fallthroughOk
+                       }
+                       check.stmtList(inner, clause.Body)
+                       check.closeScope()
+               }
+
+       case *ast.TypeSwitchStmt:
+               inner |= breakOk
+               check.openScope(s, "type switch")
+               defer check.closeScope()
+
+               check.simpleStmt(s.Init)
+
+               // A type switch guard must be of the form:
+               //
+               //     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
+               //
+               // The parser is checking syntactic correctness;
+               // remaining syntactic errors are considered AST errors here.
+               // TODO(gri) better factoring of error handling (invalid ASTs)
+               //
+               var lhs *ast.Ident // lhs identifier or nil
+               var rhs ast.Expr
+               switch guard := s.Assign.(type) {
+               case *ast.ExprStmt:
+                       rhs = guard.X
+               case *ast.AssignStmt:
+                       if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
+                               check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+                               return
+                       }
+
+                       lhs, _ = guard.Lhs[0].(*ast.Ident)
+                       if lhs == nil {
+                               check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+                               return
+                       }
+
+                       if lhs.Name == "_" {
+                               // _ := x.(type) is an invalid short variable declaration
+                               check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
+                               lhs = nil // avoid declared but not used error below
+                       } else {
+                               check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
+                       }
+
+                       rhs = guard.Rhs[0]
+
+               default:
+                       check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+                       return
+               }
+
+               // rhs must be of the form: expr.(type) and expr must be an interface
+               expr, _ := rhs.(*ast.TypeAssertExpr)
+               if expr == nil || expr.Type != nil {
+                       check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+                       return
+               }
+               var x operand
+               check.expr(&x, expr.X)
+               if x.mode == invalid {
+                       return
+               }
+               xtyp, _ := x.typ.Underlying().(*Interface)
+               if xtyp == nil {
+                       check.errorf(x.pos(), "%s is not an interface", &x)
+                       return
+               }
+
+               check.multipleDefaults(s.Body.List)
+
+               var lhsVars []*Var               // list of implicitly declared lhs variables
+               seen := make(map[Type]token.Pos) // map of seen types to positions
+               for _, s := range s.Body.List {
+                       clause, _ := s.(*ast.CaseClause)
+                       if clause == nil {
+                               check.invalidAST(s.Pos(), "incorrect type switch case")
+                               continue
+                       }
+                       // Check each type in this type switch case.
+                       T := check.caseTypes(&x, xtyp, clause.List, seen)
+                       check.openScope(clause, "case")
+                       // If lhs exists, declare a corresponding variable in the case-local scope.
+                       if lhs != nil {
+                               // spec: "The TypeSwitchGuard may include a short variable declaration.
+                               // When that form is used, the variable is declared at the beginning of
+                               // the implicit block in each clause. In clauses with a case listing
+                               // exactly one type, the variable has that type; otherwise, the variable
+                               // has the type of the expression in the TypeSwitchGuard."
+                               if len(clause.List) != 1 || T == nil {
+                                       T = x.typ
+                               }
+                               obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
+                               check.declare(check.scope, nil, obj)
+                               check.recordImplicit(clause, obj)
+                               // For the "declared but not used" error, all lhs variables act as
+                               // one; i.e., if any one of them is 'used', all of them are 'used'.
+                               // Collect them for later analysis.
+                               lhsVars = append(lhsVars, obj)
+                       }
+                       check.stmtList(inner, clause.Body)
+                       check.closeScope()
+               }
+
+               // If lhs exists, we must have at least one lhs variable that was used.
+               if lhs != nil {
+                       var used bool
+                       for _, v := range lhsVars {
+                               if v.used {
+                                       used = true
+                               }
+                               v.used = true // avoid usage error when checking entire function
+                       }
+                       if !used {
+                               check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
+                       }
+               }
+
+       case *ast.SelectStmt:
+               inner |= breakOk
+
+               check.multipleDefaults(s.Body.List)
+
+               for _, s := range s.Body.List {
+                       clause, _ := s.(*ast.CommClause)
+                       if clause == nil {
+                               continue // error reported before
+                       }
+
+                       // clause.Comm must be a SendStmt, RecvStmt, or default case
+                       valid := false
+                       var rhs ast.Expr // rhs of RecvStmt, or nil
+                       switch s := clause.Comm.(type) {
+                       case nil, *ast.SendStmt:
+                               valid = true
+                       case *ast.AssignStmt:
+                               if len(s.Rhs) == 1 {
+                                       rhs = s.Rhs[0]
+                               }
+                       case *ast.ExprStmt:
+                               rhs = s.X
+                       }
+
+                       // if present, rhs must be a receive operation
+                       if rhs != nil {
+                               if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
+                                       valid = true
+                               }
+                       }
+
+                       if !valid {
+                               check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
+                               continue
+                       }
+
+                       check.openScope(s, "case")
+                       if clause.Comm != nil {
+                               check.stmt(inner, clause.Comm)
+                       }
+                       check.stmtList(inner, clause.Body)
+                       check.closeScope()
+               }
+
+       case *ast.ForStmt:
+               inner |= breakOk | continueOk
+               check.openScope(s, "for")
+               defer check.closeScope()
+
+               check.simpleStmt(s.Init)
+               if s.Cond != nil {
+                       var x operand
+                       check.expr(&x, s.Cond)
+                       if x.mode != invalid && !isBoolean(x.typ) {
+                               check.error(s.Cond.Pos(), "non-boolean condition in for statement")
+                       }
+               }
+               check.simpleStmt(s.Post)
+               // spec: "The init statement may be a short variable
+               // declaration, but the post statement must not."
+               if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
+                       check.softErrorf(s.Pos(), "cannot declare in post statement")
+                       check.use(s.Lhs...) // avoid follow-up errors
+               }
+               check.stmt(inner, s.Body)
+
+       case *ast.RangeStmt:
+               inner |= breakOk | continueOk
+               check.openScope(s, "for")
+               defer check.closeScope()
+
+               // check expression to iterate over
+               var x operand
+               check.expr(&x, s.X)
+
+               // determine key/value types
+               var key, val Type
+               if x.mode != invalid {
+                       switch typ := x.typ.Underlying().(type) {
+                       case *Basic:
+                               if isString(typ) {
+                                       key = Typ[Int]
+                                       val = UniverseRune // use 'rune' name
+                               }
+                       case *Array:
+                               key = Typ[Int]
+                               val = typ.elem
+                       case *Slice:
+                               key = Typ[Int]
+                               val = typ.elem
+                       case *Pointer:
+                               if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+                                       key = Typ[Int]
+                                       val = typ.elem
+                               }
+                       case *Map:
+                               key = typ.key
+                               val = typ.elem
+                       case *Chan:
+                               key = typ.elem
+                               val = Typ[Invalid]
+                               if typ.dir == SendOnly {
+                                       check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
+                                       // ok to continue
+                               }
+                               if s.Value != nil {
+                                       check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
+                                       // ok to continue
+                               }
+                       }
+               }
+
+               if key == nil {
+                       check.errorf(x.pos(), "cannot range over %s", &x)
+                       // ok to continue
+               }
+
+               // check assignment to/declaration of iteration variables
+               // (irregular assignment, cannot easily map to existing assignment checks)
+
+               // lhs expressions and initialization value (rhs) types
+               lhs := [2]ast.Expr{s.Key, s.Value}
+               rhs := [2]Type{key, val} // key, val may be nil
+
+               if s.Tok == token.DEFINE {
+                       // short variable declaration; variable scope starts after the range clause
+                       // (the for loop opens a new scope, so variables on the lhs never redeclare
+                       // previously declared variables)
+                       var vars []*Var
+                       for i, lhs := range lhs {
+                               if lhs == nil {
+                                       continue
+                               }
+
+                               // determine lhs variable
+                               var obj *Var
+                               if ident, _ := lhs.(*ast.Ident); ident != nil {
+                                       // declare new variable
+                                       name := ident.Name
+                                       obj = NewVar(ident.Pos(), check.pkg, name, nil)
+                                       check.recordDef(ident, obj)
+                                       // _ variables don't count as new variables
+                                       if name != "_" {
+                                               vars = append(vars, obj)
+                                       }
+                               } else {
+                                       check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+                                       obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+                               }
+
+                               // initialize lhs variable
+                               if typ := rhs[i]; typ != nil {
+                                       x.mode = value
+                                       x.expr = lhs // we don't have a better rhs expression to use here
+                                       x.typ = typ
+                                       check.initVar(obj, &x, false)
+                               } else {
+                                       obj.typ = Typ[Invalid]
+                                       obj.used = true // don't complain about unused variable
+                               }
+                       }
+
+                       // declare variables
+                       if len(vars) > 0 {
+                               for _, obj := range vars {
+                                       check.declare(check.scope, nil /* recordDef already called */, obj)
+                               }
+                       } else {
+                               check.error(s.TokPos, "no new variables on left side of :=")
+                       }
+               } else {
+                       // ordinary assignment
+                       for i, lhs := range lhs {
+                               if lhs == nil {
+                                       continue
+                               }
+                               if typ := rhs[i]; typ != nil {
+                                       x.mode = value
+                                       x.expr = lhs // we don't have a better rhs expression to use here
+                                       x.typ = typ
+                                       check.assignVar(lhs, &x)
+                               }
+                       }
+               }
+
+               check.stmt(inner, s.Body)
+
+       default:
+               check.error(s.Pos(), "invalid statement")
+       }
+}
diff --git a/src/go/types/testdata/blank.src b/src/go/types/testdata/blank.src
new file mode 100644 (file)
index 0000000..6a2507f
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package _ /* ERROR invalid package name */
diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src
new file mode 100644 (file)
index 0000000..9eb551d
--- /dev/null
@@ -0,0 +1,881 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// builtin calls
+
+package builtins
+
+import "unsafe"
+
+func f0() {}
+
+func append1() {
+       var b byte
+       var x int
+       var s []byte
+       _ = append() // ERROR not enough arguments
+       _ = append("foo" /* ERROR not a slice */ )
+       _ = append(nil /* ERROR not a slice */ , s)
+       _ = append(x /* ERROR not a slice */ , s)
+       _ = append(s)
+       append /* ERROR not used */ (s)
+
+       _ = append(s, b)
+       _ = append(s, x /* ERROR cannot pass argument x */ )
+       _ = append(s, s /* ERROR cannot pass argument s */ )
+       _ = append(s... /* ERROR can only use ... with matching parameter */ )
+       _ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
+       _ = append(s, 1, 2, 3)
+       _ = append(s, 1, 2, 3, x /* ERROR cannot pass argument x */ , 5, 6, 6)
+       _ = append(s, 1, 2, s... /* ERROR can only use ... with matching parameter */ )
+       _ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
+
+       type S []byte
+       type T string
+       var t T
+       _ = append(s, "foo" /* ERROR cannot convert */ )
+       _ = append(s, "foo"...)
+       _ = append(S(s), "foo" /* ERROR cannot convert */ )
+       _ = append(S(s), "foo"...)
+       _ = append(s, t /* ERROR cannot pass argument t */ )
+       _ = append(s, t...)
+       _ = append(s, T("foo")...)
+       _ = append(S(s), t /* ERROR cannot pass argument t */ )
+       _ = append(S(s), t...)
+       _ = append(S(s), T("foo")...)
+       _ = append([]string{}, t /* ERROR cannot pass argument t */ , "foo")
+       _ = append([]T{}, t, "foo")
+}
+
+// from the spec
+func append2() {
+       s0 := []int{0, 0}
+       s1 := append(s0, 2)                // append a single element     s1 == []int{0, 0, 2}
+       s2 := append(s1, 3, 5, 7)          // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
+       s3 := append(s2, s0...)            // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
+       s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
+
+       var t []interface{}
+       t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}
+
+       var b []byte
+       b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }
+
+       _ = s4
+}
+
+func append3() {
+       f1 := func() (s []int) { return }
+       f2 := func() (s []int, x int) { return }
+       f3 := func() (s []int, x, y int) { return }
+       f5 := func() (s []interface{}, x int, y float32, z string, b bool) { return }
+       ff := func() (int, float32) { return 0, 0 }
+       _ = append(f0 /* ERROR used as value */ ())
+       _ = append(f1())
+       _ = append(f2())
+       _ = append(f3())
+       _ = append(f5())
+       _ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message
+}
+
+func cap1() {
+       var a [10]bool
+       var p *[20]int
+       var c chan string
+       _ = cap() // ERROR not enough arguments
+       _ = cap(1, 2) // ERROR too many arguments
+       _ = cap(42 /* ERROR invalid */)
+       const _3 = cap(a)
+       assert(_3 == 10)
+       const _4 = cap(p)
+       assert(_4 == 20)
+       _ = cap(c)
+       cap /* ERROR not used */ (c)
+
+       // issue 4744
+       type T struct{ a [10]int }
+       const _ = cap(((*T)(nil)).a)
+
+       var s [][]byte
+       _ = cap(s)
+       _ = cap(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func cap2() {
+       f1a := func() (a [10]int) { return }
+       f1s := func() (s []int) { return }
+       f2 := func() (s []int, x int) { return }
+       _ = cap(f0 /* ERROR used as value */ ())
+       _ = cap(f1a())
+       _ = cap(f1s())
+       _ = cap(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func cap3() {
+       var f = func() int { return 0 }
+       var x = f()
+       const (
+               _ = cap([4]int{})
+               _ = cap([4]int{x})
+               _ = cap /* ERROR not constant */ ([4]int{f()})
+               _ = cap /* ERROR not constant */ ([4]int{cap([]int{})})
+               _ = cap([4]int{cap([4]int{})})
+       )
+       var y float64
+       var z complex128
+       const (
+               _ = cap([4]float64{})
+               _ = cap([4]float64{y})
+               _ = cap([4]float64{real(2i)})
+               _ = cap /* ERROR not constant */ ([4]float64{real(z)})
+       )
+       var ch chan [10]int
+       const (
+               _ = cap /* ERROR not constant */ (<-ch)
+               _ = cap /* ERROR not constant */ ([4]int{(<-ch)[0]})
+       )
+}
+
+func close1() {
+       var c chan int
+       var r <-chan int
+       close() // ERROR not enough arguments
+       close(1, 2) // ERROR too many arguments
+       close(42 /* ERROR not a channel */)
+       close(r /* ERROR receive-only channel */)
+       close(c)
+       _ = close /* ERROR used as value */ (c)
+
+       var s []chan int
+       close(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func close2() {
+       f1 := func() (ch chan int) { return }
+       f2 := func() (ch chan int, x int) { return }
+       close(f0 /* ERROR used as value */ ())
+       close(f1())
+       close(f2()) // ERROR too many arguments
+}
+
+func complex1() {
+       var i32 int32
+       var f32 float32
+       var f64 float64
+       var c64 complex64
+       var c128 complex128
+       _ = complex() // ERROR not enough arguments
+       _ = complex(1) // ERROR not enough arguments
+       _ = complex(true /* ERROR invalid argument */ , 0)
+       _ = complex(i32 /* ERROR invalid argument */ , 0)
+       _ = complex("foo" /* ERROR invalid argument */ , 0)
+       _ = complex(c64 /* ERROR invalid argument */ , 0)
+       _ = complex(0, true /* ERROR invalid argument */ )
+       _ = complex(0, i32 /* ERROR invalid argument */ )
+       _ = complex(0, "foo" /* ERROR invalid argument */ )
+       _ = complex(0, c64 /* ERROR invalid argument */ )
+       _ = complex(f32, f32)
+       _ = complex(f32, 1)
+       _ = complex(f32, 1.0)
+       _ = complex(f32, 'a')
+       _ = complex(f64, f64)
+       _ = complex(f64, 1)
+       _ = complex(f64, 1.0)
+       _ = complex(f64, 'a')
+       _ = complex(f32 /* ERROR mismatched types */ , f64)
+       _ = complex(f64 /* ERROR mismatched types */ , f32)
+       _ = complex(1, 1)
+       _ = complex(1, 1.1)
+       _ = complex(1, 'a')
+       complex /* ERROR not used */ (1, 2)
+
+       var _ complex64 = complex(f32, f32)
+       var _ complex64 = complex /* ERROR cannot initialize */ (f64, f64)
+
+       var _ complex128 = complex /* ERROR cannot initialize */ (f32, f32)
+       var _ complex128 = complex(f64, f64)
+
+       // untyped constants
+       const _ int = complex(1, 0)
+       const _ float32 = complex(1, 0)
+       const _ complex64 = complex(1, 0)
+       const _ complex128 = complex(1, 0)
+
+       const _ int = complex /* ERROR int */ (1.1, 0)
+       const _ float32 = complex /* ERROR float32 */ (1, 2)
+
+       // untyped values
+       var s uint
+       _ = complex(1 /* ERROR integer */ <<s, 0)
+       const _ = complex /* ERROR not constant */ (1 /* ERROR integer */ <<s, 0)
+       var _ int = complex /* ERROR cannot initialize */ (1 /* ERROR integer */ <<s, 0)
+
+       // floating-point argument types must be identical
+       type F32 float32
+       type F64 float64
+       var x32 F32
+       var x64 F64
+       c64 = complex(x32, x32)
+       _ = complex(x32 /* ERROR mismatched types */ , f32)
+       _ = complex(f32 /* ERROR mismatched types */ , x32)
+       c128 = complex(x64, x64)
+       _ = c128
+       _ = complex(x64 /* ERROR mismatched types */ , f64)
+       _ = complex(f64 /* ERROR mismatched types */ , x64)
+
+       var t []float32
+       _ = complex(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func complex2() {
+       f1 := func() (x float32) { return }
+       f2 := func() (x, y float32) { return }
+       f3 := func() (x, y, z float32) { return }
+       _ = complex(f0 /* ERROR used as value */ ())
+       _ = complex(f1()) // ERROR not enough arguments
+       _ = complex(f2())
+       _ = complex(f3()) // ERROR too many arguments
+}
+
+func copy1() {
+       copy() // ERROR not enough arguments
+       copy("foo") // ERROR not enough arguments
+       copy([ /* ERROR copy expects slice arguments */ ...]int{}, []int{})
+       copy([ /* ERROR copy expects slice arguments */ ]int{}, [...]int{})
+       copy([ /* ERROR different element types */ ]int8{}, "foo")
+
+       // spec examples
+       var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
+       var s = make([]int, 6)
+       var b = make([]byte, 5)
+       n1 := copy(s, a[0:])            // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
+       n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+       n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
+       _, _, _ = n1, n2, n3
+
+       var t [][]int
+       copy(t, t)
+       copy(t /* ERROR copy expects slice arguments */ , nil)
+       copy(nil /* ERROR copy expects slice arguments */ , t)
+       copy(nil /* ERROR copy expects slice arguments */ , nil)
+       copy(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func copy2() {
+       f1 := func() (a []int) { return }
+       f2 := func() (a, b []int) { return }
+       f3 := func() (a, b, c []int) { return }
+       copy(f0 /* ERROR used as value */ ())
+       copy(f1()) // ERROR not enough arguments
+       copy(f2())
+       copy(f3()) // ERROR too many arguments
+}
+
+func delete1() {
+       var m map[string]int
+       var s string
+       delete() // ERROR not enough arguments
+       delete(1) // ERROR not enough arguments
+       delete(1, 2, 3) // ERROR too many arguments
+       delete(m, 0 /* ERROR not assignable */)
+       delete(m, s)
+       _ = delete /* ERROR used as value */ (m, s)
+
+       var t []map[string]string
+       delete(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func delete2() {
+       f1 := func() (m map[string]int) { return }
+       f2 := func() (m map[string]int, k string) { return }
+       f3 := func() (m map[string]int, k string, x float32) { return }
+       delete(f0 /* ERROR used as value */ ())
+       delete(f1()) // ERROR not enough arguments
+       delete(f2())
+       delete(f3()) // ERROR too many arguments
+}
+
+func imag1() {
+       var f32 float32
+       var f64 float64
+       var c64 complex64
+       var c128 complex128
+       _ = imag() // ERROR not enough arguments
+       _ = imag(1, 2) // ERROR too many arguments
+       _ = imag(10 /* ERROR must be a complex number */)
+       _ = imag(2.7182818 /* ERROR must be a complex number */)
+       _ = imag("foo" /* ERROR must be a complex number */)
+       const _5 = imag(1 + 2i)
+       assert(_5 == 2)
+       f32 = _5
+       f64 = _5
+       const _6 = imag(0i)
+       assert(_6 == 0)
+       f32 = imag(c64)
+       f64 = imag(c128)
+       f32 = imag /* ERROR cannot assign */ (c128)
+       f64 = imag /* ERROR cannot assign */ (c64)
+       imag /* ERROR not used */ (c64)
+       _, _ = f32, f64
+
+       // complex type may not be predeclared
+       type C64 complex64
+       type C128 complex128
+       var x64 C64
+       var x128 C128
+       f32 = imag(x64)
+       f64 = imag(x128)
+
+       var s []complex64
+       _ = imag(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func imag2() {
+       f1 := func() (x complex128) { return }
+       f2 := func() (x, y complex128) { return }
+       _ = imag(f0 /* ERROR used as value */ ())
+       _ = imag(f1())
+       _ = imag(f2()) // ERROR too many arguments
+}
+
+func len1() {
+       const c = "foobar"
+       var a [10]bool
+       var p *[20]int
+       var m map[string]complex128
+       _ = len() // ERROR not enough arguments
+       _ = len(1, 2) // ERROR too many arguments
+       _ = len(42 /* ERROR invalid */)
+       const _3 = len(c)
+       assert(_3 == 6)
+       const _4 = len(a)
+       assert(_4 == 10)
+       const _5 = len(p)
+       assert(_5 == 20)
+       _ = len(m)
+       len /* ERROR not used */ (c)
+
+       // esoteric case
+       var t string
+       var hash map[interface{}][]*[10]int
+       const n = len /* ERROR not constant */ (hash[recover()][len(t)])
+       assert(n == 10) // ok because n has unknown value and no error is reported
+       var ch <-chan int
+       const nn = len /* ERROR not constant */ (hash[<-ch][len(t)])
+
+       // issue 4744
+       type T struct{ a [10]int }
+       const _ = len(((*T)(nil)).a)
+
+       var s [][]byte
+       _ = len(s)
+       _ = len(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func len2() {
+       f1 := func() (x []int) { return }
+       f2 := func() (x, y []int) { return }
+       _ = len(f0 /* ERROR used as value */ ())
+       _ = len(f1())
+       _ = len(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func len3() {
+       var f = func() int { return 0 }
+       var x = f()
+       const (
+               _ = len([4]int{})
+               _ = len([4]int{x})
+               _ = len /* ERROR not constant */ ([4]int{f()})
+               _ = len /* ERROR not constant */ ([4]int{len([]int{})})
+               _ = len([4]int{len([4]int{})})
+       )
+       var y float64
+       var z complex128
+       const (
+               _ = len([4]float64{})
+               _ = len([4]float64{y})
+               _ = len([4]float64{real(2i)})
+               _ = len /* ERROR not constant */ ([4]float64{real(z)})
+       )
+       var ch chan [10]int
+       const (
+               _ = len /* ERROR not constant */ (<-ch)
+               _ = len /* ERROR not constant */ ([4]int{(<-ch)[0]})
+       )
+}
+
+func make1() {
+       var n int
+       var m float32
+       var s uint
+
+       _ = make() // ERROR not enough arguments
+       _ = make(1 /* ERROR not a type */)
+       _ = make(int /* ERROR cannot make */)
+
+       // slices
+       _ = make/* ERROR arguments */ ([]int)
+       _ = make/* ERROR arguments */ ([]int, 2, 3, 4)
+       _ = make([]int, int /* ERROR not an expression */)
+       _ = make([]int, 10, float32 /* ERROR not an expression */)
+       _ = make([]int, "foo" /* ERROR cannot convert */)
+       _ = make([]int, 10, 2.3 /* ERROR truncated */)
+       _ = make([]int, 5, 10.0)
+       _ = make([]int, 0i)
+       _ = make([]int, 1.0)
+       _ = make([]int, 1.0<<s)
+       _ = make([]int, 1.1 /* ERROR int */ <<s)
+       _ = make([]int, - /* ERROR must not be negative */ 1, 10)
+       _ = make([]int, 0, - /* ERROR must not be negative */ 1)
+       _ = make([]int, - /* ERROR must not be negative */ 1, - /* ERROR must not be negative */ 1)
+       _ = make([]int, 1 /* ERROR overflows */ <<100, 1 /* ERROR overflows */ <<100)
+       _ = make([]int, 10 /* ERROR length and capacity swapped */ , 9)
+       _ = make([]int, 1 /* ERROR overflows */ <<100, 12345)
+       _ = make([]int, m /* ERROR must be integer */ )
+        _ = &make /* ERROR cannot take address */ ([]int, 0)
+
+       // maps
+       _ = make /* ERROR arguments */ (map[int]string, 10, 20)
+       _ = make(map[int]float32, int /* ERROR not an expression */)
+       _ = make(map[int]float32, "foo" /* ERROR cannot convert */)
+       _ = make(map[int]float32, 10)
+       _ = make(map[int]float32, n)
+       _ = make(map[int]float32, int64(n))
+       _ = make(map[string]bool, 10.0)
+       _ = make(map[string]bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (map[string]bool)
+
+       // channels
+       _ = make /* ERROR arguments */ (chan int, 10, 20)
+       _ = make(chan int, int /* ERROR not an expression */)
+       _ = make(chan<- int, "foo" /* ERROR cannot convert */)
+       _ = make(chan int, - /* ERROR must not be negative */ 10)
+       _ = make(<-chan float64, 10)
+       _ = make(chan chan int, n)
+       _ = make(chan string, int64(n))
+       _ = make(chan bool, 10.0)
+       _ = make(chan bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (chan bool)
+
+       make /* ERROR not used */ ([]int, 10)
+
+       var t []int
+       _ = make([]int, t[0], t[1])
+       _ = make([]int, t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func make2() {
+       f1 /* ERROR not used */ := func() (x []int) { return }
+       _ = make(f0 /* ERROR not a type */ ())
+       _ = make(f1 /* ERROR not a type */ ())
+}
+
+func new1() {
+       _ = new() // ERROR not enough arguments
+       _ = new(1, 2) // ERROR too many arguments
+       _ = new("foo" /* ERROR not a type */)
+       p := new(float64)
+       _ = new(struct{ x, y int })
+       q := new(*float64)
+       _ = *p == **q
+       new /* ERROR not used */ (int)
+        _ = &new /* ERROR cannot take address */ (int)
+
+       _ = new(int... /* ERROR invalid use of \.\.\. */ )
+}
+
+func new2() {
+       f1 /* ERROR not used */ := func() (x []int) { return }
+       _ = new(f0 /* ERROR not a type */ ())
+       _ = new(f1 /* ERROR not a type */ ())
+}
+
+func panic1() {
+       panic() // ERROR not enough arguments
+       panic(1, 2) // ERROR too many arguments
+       panic(0)
+       panic("foo")
+       panic(false)
+       panic(1<<10)
+       panic(1 /* ERROR overflows */ <<1000)
+       _ = panic /* ERROR used as value */ (0)
+
+       var s []byte
+       panic(s)
+       panic(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func panic2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       panic(f0 /* ERROR used as value */ ())
+       panic(f1())
+       panic(f2()) // ERROR too many arguments
+}
+
+func print1() {
+       print()
+       print(1)
+       print(1, 2)
+       print("foo")
+       print(2.718281828)
+       print(false)
+       print(1<<10)
+       print(1 /* ERROR overflows */ <<1000)
+       println(nil /* ERROR untyped nil */ )
+
+       var s []int
+       print(s... /* ERROR invalid use of \.\.\. */ )
+       _ = print /* ERROR used as value */ ()
+}
+
+func print2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       f3 := func() (x int, y float32, z string) { return }
+       print(f0 /* ERROR used as value */ ())
+       print(f1())
+       print(f2())
+       print(f3())
+}
+
+func println1() {
+       println()
+       println(1)
+       println(1, 2)
+       println("foo")
+       println(2.718281828)
+       println(false)
+       println(1<<10)
+       println(1 /* ERROR overflows */ <<1000)
+       println(nil /* ERROR untyped nil */ )
+
+       var s []int
+       println(s... /* ERROR invalid use of \.\.\. */ )
+       _ = println /* ERROR used as value */ ()
+}
+
+func println2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       f3 := func() (x int, y float32, z string) { return }
+       println(f0 /* ERROR used as value */ ())
+       println(f1())
+       println(f2())
+       println(f3())
+}
+
+func real1() {
+       var f32 float32
+       var f64 float64
+       var c64 complex64
+       var c128 complex128
+       _ = real() // ERROR not enough arguments
+       _ = real(1, 2) // ERROR too many arguments
+       _ = real(10 /* ERROR must be a complex number */)
+       _ = real(2.7182818 /* ERROR must be a complex number */)
+       _ = real("foo" /* ERROR must be a complex number */)
+       const _5 = real(1 + 2i)
+       assert(_5 == 1)
+       f32 = _5
+       f64 = _5
+       const _6 = real(0i)
+       assert(_6 == 0)
+       f32 = real(c64)
+       f64 = real(c128)
+       f32 = real /* ERROR cannot assign */ (c128)
+       f64 = real /* ERROR cannot assign */ (c64)
+       real /* ERROR not used */ (c64)
+
+       // complex type may not be predeclared
+       type C64 complex64
+       type C128 complex128
+       var x64 C64
+       var x128 C128
+       f32 = imag(x64)
+       f64 = imag(x128)
+
+       var s []complex64
+       _ = real(s... /* ERROR invalid use of \.\.\. */ )
+       _, _ = f32, f64
+}
+
+func real2() {
+       f1 := func() (x complex128) { return }
+       f2 := func() (x, y complex128) { return }
+       _ = real(f0 /* ERROR used as value */ ())
+       _ = real(f1())
+       _ = real(f2()) // ERROR too many arguments
+}
+
+func recover1() {
+       _ = recover()
+       _ = recover(10) // ERROR too many arguments
+       recover()
+
+       var s []int
+       recover(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func recover2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       _ = recover(f0 /* ERROR used as value */ ())
+       _ = recover(f1()) // ERROR too many arguments
+       _ = recover(f2()) // ERROR too many arguments
+}
+
+// assuming types.DefaultPtrSize == 8
+type S0 struct{      // offset
+       a bool       //  0
+       b rune       //  4
+       c *int       //  8
+       d bool       // 16
+       e complex128 // 24
+}                    // 40
+
+type S1 struct{   // offset
+       x float32 //  0
+       y string  //  8
+       z *S1     // 24
+       S0        // 32
+}                 // 72
+
+type S2 struct{ // offset
+       *S1     //  0
+}               //  8
+
+type S3 struct { // offset
+       a int64  //  0
+       b int32  //  8
+}                // 12
+
+type S4 struct { // offset
+       S3       //  0
+       int32    // 12
+}                // 16
+
+type S5 struct {   // offset
+       a [3]int32 //  0
+       b int32    // 12
+}                  // 16
+
+func (S2) m() {}
+
+func Alignof1() {
+       var x int
+       _ = unsafe.Alignof() // ERROR not enough arguments
+       _ = unsafe.Alignof(1, 2) // ERROR too many arguments
+       _ = unsafe.Alignof(int /* ERROR not an expression */)
+       _ = unsafe.Alignof(42)
+       _ = unsafe.Alignof(new(struct{}))
+       _ = unsafe.Alignof(1<<10)
+       _ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
+       _ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
+       unsafe /* ERROR not used */ .Alignof(x)
+
+       var y S0
+       assert(unsafe.Alignof(y.a) == 1)
+       assert(unsafe.Alignof(y.b) == 4)
+       assert(unsafe.Alignof(y.c) == 8)
+       assert(unsafe.Alignof(y.d) == 1)
+       assert(unsafe.Alignof(y.e) == 8)
+
+       var s []byte
+       _ = unsafe.Alignof(s)
+       _ = unsafe.Alignof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Alignof2() {
+       f1 := func() (x int32) { return }
+       f2 := func() (x, y int32) { return }
+       _ = unsafe.Alignof(f0 /* ERROR used as value */ ())
+       assert(unsafe.Alignof(f1()) == 4)
+       _ = unsafe.Alignof(f2()) // ERROR too many arguments
+}
+
+func Offsetof1() {
+       var x struct{ f int }
+       _ = unsafe.Offsetof() // ERROR not enough arguments
+       _ = unsafe.Offsetof(1, 2) // ERROR too many arguments
+       _ = unsafe.Offsetof(int /* ERROR not a selector expression */ )
+       _ = unsafe.Offsetof(x /* ERROR not a selector expression */ )
+       _ = unsafe.Offsetof(nil /* ERROR not a selector expression */ )
+       _ = unsafe.Offsetof(x.f)
+       _ = unsafe.Offsetof((x.f))
+       _ = unsafe.Offsetof((((((((x))).f)))))
+       unsafe /* ERROR not used */ .Offsetof(x.f)
+
+       var y0 S0
+       assert(unsafe.Offsetof(y0.a) == 0)
+       assert(unsafe.Offsetof(y0.b) == 4)
+       assert(unsafe.Offsetof(y0.c) == 8)
+       assert(unsafe.Offsetof(y0.d) == 16)
+       assert(unsafe.Offsetof(y0.e) == 24)
+
+       var y1 S1
+       assert(unsafe.Offsetof(y1.x) == 0)
+       assert(unsafe.Offsetof(y1.y) == 8)
+       assert(unsafe.Offsetof(y1.z) == 24)
+       assert(unsafe.Offsetof(y1.S0) == 32)
+
+       assert(unsafe.Offsetof(y1.S0.a) == 0) // relative to S0
+       assert(unsafe.Offsetof(y1.a) == 32)   // relative to S1
+       assert(unsafe.Offsetof(y1.b) == 36)   // relative to S1
+       assert(unsafe.Offsetof(y1.c) == 40)   // relative to S1
+       assert(unsafe.Offsetof(y1.d) == 48)   // relative to S1
+       assert(unsafe.Offsetof(y1.e) == 56)   // relative to S1
+
+       var y1p *S1
+       assert(unsafe.Offsetof(y1p.S0) == 32)
+
+       type P *S1
+       var p P = y1p
+       assert(unsafe.Offsetof(p.S0) == 32)
+
+       var y2 S2
+       assert(unsafe.Offsetof(y2.S1) == 0)
+       _ = unsafe.Offsetof(y2 /* ERROR embedded via a pointer */ .x)
+       _ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
+
+       var s []byte
+       _ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Offsetof2() {
+       f1 := func() (x int32) { return }
+       f2 := func() (x, y int32) { return }
+       _ = unsafe.Offsetof(f0 /* ERROR not a selector expression */ ())
+       _ = unsafe.Offsetof(f1 /* ERROR not a selector expression */ ())
+       _ = unsafe.Offsetof(f2 /* ERROR not a selector expression */ ())
+}
+
+func Sizeof1() {
+       var x int
+       _ = unsafe.Sizeof() // ERROR not enough arguments
+       _ = unsafe.Sizeof(1, 2) // ERROR too many arguments
+       _ = unsafe.Sizeof(int /* ERROR not an expression */)
+       _ = unsafe.Sizeof(42)
+       _ = unsafe.Sizeof(new(complex128))
+       _ = unsafe.Sizeof(1<<10)
+       _ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
+       _ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
+       unsafe /* ERROR not used */ .Sizeof(x)
+
+       // basic types have size guarantees
+       assert(unsafe.Sizeof(byte(0)) == 1)
+       assert(unsafe.Sizeof(uint8(0)) == 1)
+       assert(unsafe.Sizeof(int8(0)) == 1)
+       assert(unsafe.Sizeof(uint16(0)) == 2)
+       assert(unsafe.Sizeof(int16(0)) == 2)
+       assert(unsafe.Sizeof(uint32(0)) == 4)
+       assert(unsafe.Sizeof(int32(0)) == 4)
+       assert(unsafe.Sizeof(float32(0)) == 4)
+       assert(unsafe.Sizeof(uint64(0)) == 8)
+       assert(unsafe.Sizeof(int64(0)) == 8)
+       assert(unsafe.Sizeof(float64(0)) == 8)
+       assert(unsafe.Sizeof(complex64(0)) == 8)
+       assert(unsafe.Sizeof(complex128(0)) == 16)
+
+       var y0 S0
+       assert(unsafe.Sizeof(y0.a) == 1)
+       assert(unsafe.Sizeof(y0.b) == 4)
+       assert(unsafe.Sizeof(y0.c) == 8)
+       assert(unsafe.Sizeof(y0.d) == 1)
+       assert(unsafe.Sizeof(y0.e) == 16)
+       assert(unsafe.Sizeof(y0) == 40)
+
+       var y1 S1
+       assert(unsafe.Sizeof(y1) == 72)
+
+       var y2 S2
+       assert(unsafe.Sizeof(y2) == 8)
+
+       var y3 S3
+       assert(unsafe.Sizeof(y3) == 12)
+
+       var y4 S4
+       assert(unsafe.Sizeof(y4) == 16)
+
+       var y5 S5
+       assert(unsafe.Sizeof(y5) == 16)
+
+       var a3 [10]S3
+       assert(unsafe.Sizeof(a3) == 156)
+
+       // test case for issue 5670
+       type T struct {
+               a int32
+               _ int32
+               c int32
+       }
+       assert(unsafe.Sizeof(T{}) == 12)
+
+       var s []byte
+       _ = unsafe.Sizeof(s)
+       _ = unsafe.Sizeof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Sizeof2() {
+       f1 := func() (x int64) { return }
+       f2 := func() (x, y int64) { return }
+       _ = unsafe.Sizeof(f0 /* ERROR used as value */ ())
+       assert(unsafe.Sizeof(f1()) == 8)
+       _ = unsafe.Sizeof(f2()) // ERROR too many arguments
+}
+
+// self-testing only
+func assert1() {
+       var x int
+       assert() /* ERROR not enough arguments */
+       assert(1, 2) /* ERROR too many arguments */
+       assert("foo" /* ERROR boolean constant */ )
+       assert(x /* ERROR boolean constant */)
+       assert(true)
+       assert /* ERROR failed */ (false)
+       _ = assert(true)
+
+       var s []byte
+       assert(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func assert2() {
+       f1 := func() (x bool) { return }
+       f2 := func() (x bool) { return }
+       assert(f0 /* ERROR used as value */ ())
+       assert(f1 /* ERROR boolean constant */ ())
+       assert(f2 /* ERROR boolean constant */ ())
+}
+
+// self-testing only
+func trace1() {
+       // Uncomment the code below to test trace - will produce console output
+       // _ = trace /* ERROR no value */ ()
+       // _ = trace(1)
+       // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
+
+       var s []byte
+       trace(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func trace2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x int, y string) { return }
+       f3 := func() (x int, y string, z []int) { return }
+       _ = f1
+       _ = f2
+       _ = f3
+       // Uncomment the code below to test trace - will produce console output
+       // trace(f0())
+       // trace(f1())
+       // trace(f2())
+       // trace(f3())
+       // trace(f0(), 1)
+       // trace(f1(), 1, 2)
+       // trace(f2(), 1, 2, 3)
+       // trace(f3(), 1, 2, 3, 4)
+}
diff --git a/src/go/types/testdata/const0.src b/src/go/types/testdata/const0.src
new file mode 100644 (file)
index 0000000..c4419ab
--- /dev/null
@@ -0,0 +1,282 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// constant declarations
+
+package const0
+
+// constants declarations must be initialized by constants
+var x = 0
+const c0 = x /* ERROR "not constant" */
+
+// typed constants must have constant types
+const _ interface /* ERROR invalid constant type */ {} = 0
+
+func _ () {
+       const _ interface /* ERROR invalid constant type */ {} = 0
+       for i := 0; i < 10; i++ {} // don't crash with non-nil iota here
+}
+
+// untyped constants
+const (
+       // boolean values
+       ub0 = false
+       ub1 = true
+       ub2 = 2 < 1
+       ub3 = ui1 == uf1
+       ub4 = true /* ERROR "cannot convert" */ == 0
+
+       // integer values
+       ui0 = 0
+       ui1 = 1
+       ui2 = 42
+       ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286
+       ui4 = -10
+
+       ui5 = ui0 + ui1
+       ui6 = ui1 - ui1
+       ui7 = ui2 * ui1
+       ui8 = ui3 / ui3
+       ui9 = ui3 % ui3
+
+       ui10 = 1 / 0 /* ERROR "division by zero" */
+       ui11 = ui1 / 0 /* ERROR "division by zero" */
+       ui12 = ui3 / ui0 /* ERROR "division by zero" */
+       ui13 = 1 % 0 /* ERROR "division by zero" */
+       ui14 = ui1 % 0 /* ERROR "division by zero" */
+       ui15 = ui3 % ui0 /* ERROR "division by zero" */
+
+       ui16 = ui2 & ui3
+       ui17 = ui2 | ui3
+       ui18 = ui2 ^ ui3
+       ui19 = 1 /* ERROR "invalid operation" */ % 1.0
+
+       // floating point values
+       uf0 = 0.
+       uf1 = 1.
+       uf2 = 4.2e1
+       uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+       uf4 = 1e-1
+
+       uf5 = uf0 + uf1
+       uf6 = uf1 - uf1
+       uf7 = uf2 * uf1
+       uf8 = uf3 / uf3
+       uf9 = uf3 /* ERROR "not defined" */ % uf3
+
+       uf10 = 1 / 0 /* ERROR "division by zero" */
+       uf11 = uf1 / 0 /* ERROR "division by zero" */
+       uf12 = uf3 / uf0 /* ERROR "division by zero" */
+
+       uf16 = uf2 /* ERROR "not defined" */ & uf3
+       uf17 = uf2 /* ERROR "not defined" */ | uf3
+       uf18 = uf2 /* ERROR "not defined" */ ^ uf3
+
+       // complex values
+       uc0 = 0.i
+       uc1 = 1.i
+       uc2 = 4.2e1i
+       uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+       uc4 = 1e-1i
+
+       uc5 = uc0 + uc1
+       uc6 = uc1 - uc1
+       uc7 = uc2 * uc1
+       uc8 = uc3 / uc3
+       uc9 = uc3 /* ERROR "not defined" */ % uc3
+
+       uc10 = 1 / 0 /* ERROR "division by zero" */
+       uc11 = uc1 / 0 /* ERROR "division by zero" */
+       uc12 = uc3 / uc0 /* ERROR "division by zero" */
+
+       uc16 = uc2 /* ERROR "not defined" */ & uc3
+       uc17 = uc2 /* ERROR "not defined" */ | uc3
+       uc18 = uc2 /* ERROR "not defined" */ ^ uc3
+)
+
+type (
+       mybool bool
+       myint int
+       myfloat float64
+       mycomplex complex128
+)
+
+// typed constants
+const (
+       // boolean values
+       tb0 bool = false
+       tb1 bool = true
+       tb2 mybool = 2 < 1
+       tb3 mybool = ti1 /* ERROR "mismatched types" */ == tf1
+
+       // integer values
+       ti0 int8 = ui0
+       ti1 int32 = ui1
+       ti2 int64 = ui2
+       ti3 myint = ui3 /* ERROR "overflows" */
+       ti4 myint = ui4
+
+       ti5 = ti0 /* ERROR "mismatched types" */ + ti1
+       ti6 = ti1 - ti1
+       ti7 = ti2 /* ERROR "mismatched types" */ * ti1
+       ti8 = ti3 / ti3
+       ti9 = ti3 % ti3
+
+       ti10 = 1 / 0 /* ERROR "division by zero" */
+       ti11 = ti1 / 0 /* ERROR "division by zero" */
+       ti12 = ti3 /* ERROR "mismatched types" */ / ti0
+       ti13 = 1 % 0 /* ERROR "division by zero" */
+       ti14 = ti1 % 0 /* ERROR "division by zero" */
+       ti15 = ti3 /* ERROR "mismatched types" */ % ti0
+
+       ti16 = ti2 /* ERROR "mismatched types" */ & ti3
+       ti17 = ti2 /* ERROR "mismatched types" */ | ti4
+       ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown
+
+       // floating point values
+       tf0 float32 = 0.
+       tf1 float32 = 1.
+       tf2 float64 = 4.2e1
+       tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+       tf4 myfloat = 1e-1
+
+       tf5 = tf0 + tf1
+       tf6 = tf1 - tf1
+       tf7 = tf2 /* ERROR "mismatched types" */ * tf1
+       tf8 = tf3 / tf3
+       tf9 = tf3 /* ERROR "not defined" */ % tf3
+
+       tf10 = 1 / 0 /* ERROR "division by zero" */
+       tf11 = tf1 / 0 /* ERROR "division by zero" */
+       tf12 = tf3 /* ERROR "mismatched types" */ / tf0
+
+       tf16 = tf2 /* ERROR "mismatched types" */ & tf3
+       tf17 = tf2 /* ERROR "mismatched types" */ | tf3
+       tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3
+
+       // complex values
+       tc0 = 0.i
+       tc1 = 1.i
+       tc2 = 4.2e1i
+       tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+       tc4 = 1e-1i
+
+       tc5 = tc0 + tc1
+       tc6 = tc1 - tc1
+       tc7 = tc2 * tc1
+       tc8 = tc3 / tc3
+       tc9 = tc3 /* ERROR "not defined" */ % tc3
+
+       tc10 = 1 / 0 /* ERROR "division by zero" */
+       tc11 = tc1 / 0 /* ERROR "division by zero" */
+       tc12 = tc3 / tc0 /* ERROR "division by zero" */
+
+       tc16 = tc2 /* ERROR "not defined" */ & tc3
+       tc17 = tc2 /* ERROR "not defined" */ | tc3
+       tc18 = tc2 /* ERROR "not defined" */ ^ tc3
+)
+
+// initialization cycles
+const (
+       a /* ERROR "initialization cycle" */ = a
+       b /* ERROR "initialization cycle" */ , c /* ERROR "initialization cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error
+       f float64 = d
+)
+
+// multiple initialization
+const (
+       a1, a2, a3 = 7, 3.1415926, "foo"
+       b1, b2, b3 = b3, b1, 42
+       c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+       d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+       _p0 = assert(a1 == 7)
+       _p1 = assert(a2 == 3.1415926)
+       _p2 = assert(a3 == "foo")
+       _p3 = assert(b1 == 42)
+       _p4 = assert(b2 == 42)
+       _p5 = assert(b3 == 42)
+)
+
+func _() {
+       const (
+               a1, a2, a3 = 7, 3.1415926, "foo"
+               b1, b2, b3 = b3, b1, 42
+               c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+               d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+               _p0 = assert(a1 == 7)
+               _p1 = assert(a2 == 3.1415926)
+               _p2 = assert(a3 == "foo")
+               _p3 = assert(b1 == 42)
+               _p4 = assert(b2 == 42)
+               _p5 = assert(b3 == 42)
+       )
+}
+
+// iota
+const (
+       iota0 = iota
+       iota1 = iota
+       iota2 = iota*2
+       _a0 = assert(iota0 == 0)
+       _a1 = assert(iota1 == 1)
+       _a2 = assert(iota2 == 4)
+       iota6 = iota*3
+
+       iota7
+       iota8
+       _a3 = assert(iota7 == 21)
+       _a4 = assert(iota8 == 24)
+)
+
+const (
+       _b0 = iota
+       _b1 = assert(iota + iota2 == 5)
+       _b2 = len([iota]int{}) // iota may appear in a type!
+       _b3 = assert(_b2 == 2)
+       _b4 = len(A{})
+)
+
+type A [iota /* ERROR "cannot use iota" */ ]int
+
+// constant expressions with operands accross different
+// constant declarations must use the right iota values
+const (
+       _c0 = iota
+       _c1
+       _c2
+       _x = _c2 + _d1 + _e0 // 3
+)
+
+const (
+       _d0 = iota
+       _d1
+)
+
+const (
+       _e0 = iota
+)
+
+var _ = assert(_x == 3)
+
+// special cases
+const (
+       _n0 = nil /* ERROR "not constant" */
+       _n1 = [ /* ERROR "not constant" */ ]int{}
+)
+
+// iotas must not be usable in expressions outside constant declarations
+type _ [iota /* ERROR "iota outside constant decl" */ ]byte
+var _ = iota /* ERROR "iota outside constant decl" */
+func _() {
+       _ = iota /* ERROR "iota outside constant decl" */
+       const _ = iota
+       _ = iota /* ERROR "iota outside constant decl" */
+}
+
+func _() {
+       iota := 123
+       const x = iota /* ERROR "is not constant" */
+       var y = iota
+       _ = y
+}
diff --git a/src/go/types/testdata/const1.src b/src/go/types/testdata/const1.src
new file mode 100644 (file)
index 0000000..88e9fad
--- /dev/null
@@ -0,0 +1,314 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// constant conversions
+
+package const1
+
+const(
+       mi = ^int(0)
+       mu = ^uint(0)
+       mp = ^uintptr(0)
+
+       logSizeofInt     = uint(mi>>8&1 + mi>>16&1 + mi>>32&1)
+       logSizeofUint    = uint(mu>>8&1 + mu>>16&1 + mu>>32&1)
+       logSizeofUintptr = uint(mp>>8&1 + mp>>16&1 + mp>>32&1)
+)
+
+const (
+       minInt8 = -1<<(8<<iota - 1)
+       minInt16
+       minInt32
+       minInt64
+       minInt = -1<<(8<<logSizeofInt - 1)
+)
+
+const (
+       maxInt8 = 1<<(8<<iota - 1) - 1
+       maxInt16
+       maxInt32
+       maxInt64
+       maxInt = 1<<(8<<logSizeofInt - 1) - 1
+)
+
+const (
+       maxUint8 = 1<<(8<<iota) - 1
+       maxUint16
+       maxUint32
+       maxUint64
+       maxUint    = 1<<(8<<logSizeofUint) - 1
+       maxUintptr = 1<<(8<<logSizeofUintptr) - 1
+)
+
+const (
+       smallestFloat32 = 1.0 / (1<<(127 - 1 + 23))
+       smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
+)
+
+const (
+       _ = assert(smallestFloat32 > 0)
+       _ = assert(smallestFloat64 > 0)
+)
+
+const (
+       maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23)
+       maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
+)
+
+const (
+       _ int8 = minInt8 /* ERROR "overflows" */ - 1
+       _ int8 = minInt8
+       _ int8 = maxInt8
+       _ int8 = maxInt8 /* ERROR "overflows" */ + 1
+       _ int8 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int8(minInt8 /* ERROR "cannot convert" */ - 1)
+       _ = int8(minInt8)
+       _ = int8(maxInt8)
+       _ = int8(maxInt8 /* ERROR "cannot convert" */ + 1)
+       _ = int8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int16 = minInt16 /* ERROR "overflows" */ - 1
+       _ int16 = minInt16
+       _ int16 = maxInt16
+       _ int16 = maxInt16 /* ERROR "overflows" */ + 1
+       _ int16 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int16(minInt16 /* ERROR "cannot convert" */ - 1)
+       _ = int16(minInt16)
+       _ = int16(maxInt16)
+       _ = int16(maxInt16 /* ERROR "cannot convert" */ + 1)
+       _ = int16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int32 = minInt32 /* ERROR "overflows" */ - 1
+       _ int32 = minInt32
+       _ int32 = maxInt32
+       _ int32 = maxInt32 /* ERROR "overflows" */ + 1
+       _ int32 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int32(minInt32 /* ERROR "cannot convert" */ - 1)
+       _ = int32(minInt32)
+       _ = int32(maxInt32)
+       _ = int32(maxInt32 /* ERROR "cannot convert" */ + 1)
+       _ = int32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int64 = minInt64 /* ERROR "overflows" */ - 1
+       _ int64 = minInt64
+       _ int64 = maxInt64
+       _ int64 = maxInt64 /* ERROR "overflows" */ + 1
+       _ int64 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int64(minInt64 /* ERROR "cannot convert" */ - 1)
+       _ = int64(minInt64)
+       _ = int64(maxInt64)
+       _ = int64(maxInt64 /* ERROR "cannot convert" */ + 1)
+       _ = int64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int = minInt /* ERROR "overflows" */ - 1
+       _ int = minInt
+       _ int = maxInt
+       _ int = maxInt /* ERROR "overflows" */ + 1
+       _ int = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int(minInt /* ERROR "cannot convert" */ - 1)
+       _ = int(minInt)
+       _ = int(maxInt)
+       _ = int(maxInt /* ERROR "cannot convert" */ + 1)
+       _ = int(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint8 = 0 /* ERROR "overflows" */ - 1
+       _ uint8 = 0
+       _ uint8 = maxUint8
+       _ uint8 = maxUint8 /* ERROR "overflows" */ + 1
+       _ uint8 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint8(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint8(0)
+       _ = uint8(maxUint8)
+       _ = uint8(maxUint8 /* ERROR "cannot convert" */ + 1)
+       _ = uint8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint16 = 0 /* ERROR "overflows" */ - 1
+       _ uint16 = 0
+       _ uint16 = maxUint16
+       _ uint16 = maxUint16 /* ERROR "overflows" */ + 1
+       _ uint16 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint16(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint16(0)
+       _ = uint16(maxUint16)
+       _ = uint16(maxUint16 /* ERROR "cannot convert" */ + 1)
+       _ = uint16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint32 = 0 /* ERROR "overflows" */ - 1
+       _ uint32 = 0
+       _ uint32 = maxUint32
+       _ uint32 = maxUint32 /* ERROR "overflows" */ + 1
+       _ uint32 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint32(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint32(0)
+       _ = uint32(maxUint32)
+       _ = uint32(maxUint32 /* ERROR "cannot convert" */ + 1)
+       _ = uint32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint64 = 0 /* ERROR "overflows" */ - 1
+       _ uint64 = 0
+       _ uint64 = maxUint64
+       _ uint64 = maxUint64 /* ERROR "overflows" */ + 1
+       _ uint64 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint64(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint64(0)
+       _ = uint64(maxUint64)
+       _ = uint64(maxUint64 /* ERROR "cannot convert" */ + 1)
+       _ = uint64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint = 0 /* ERROR "overflows" */ - 1
+       _ uint = 0
+       _ uint = maxUint
+       _ uint = maxUint /* ERROR "overflows" */ + 1
+       _ uint = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint(0)
+       _ = uint(maxUint)
+       _ = uint(maxUint /* ERROR "cannot convert" */ + 1)
+       _ = uint(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uintptr = 0 /* ERROR "overflows" */ - 1
+       _ uintptr = 0
+       _ uintptr = maxUintptr
+       _ uintptr = maxUintptr /* ERROR "overflows" */ + 1
+       _ uintptr = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uintptr(0 /* ERROR "cannot convert" */ - 1)
+       _ = uintptr(0)
+       _ = uintptr(maxUintptr)
+       _ = uintptr(maxUintptr /* ERROR "cannot convert" */ + 1)
+       _ = uintptr(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ float32 = minInt64
+       _ float64 = minInt64
+       _ complex64 = minInt64
+       _ complex128 = minInt64
+
+       _ = float32(minInt64)
+       _ = float64(minInt64)
+       _ = complex64(minInt64)
+       _ = complex128(minInt64)
+)
+
+const (
+       _ float32 = maxUint64
+       _ float64 = maxUint64
+       _ complex64 = maxUint64
+       _ complex128 = maxUint64
+
+       _ = float32(maxUint64)
+       _ = float64(maxUint64)
+       _ = complex64(maxUint64)
+       _ = complex128(maxUint64)
+)
+
+// TODO(gri) find smaller deltas below
+
+const delta32 = maxFloat32/(1 << 23)
+
+const (
+       _ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+       _ float32 = -maxFloat32
+       _ float32 = maxFloat32
+       _ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+       _ = float32(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+       _ = float32(-maxFloat32)
+       _ = float32(maxFloat32)
+       _ = float32(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+
+       _ = assert(float32(smallestFloat32) == smallestFloat32)
+       _ = assert(float32(smallestFloat32/2) == 0)
+       _ = assert(float32(smallestFloat64) == 0)
+       _ = assert(float32(smallestFloat64/2) == 0)
+)
+
+const delta64 = maxFloat64/(1 << 52)
+
+const (
+       _ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+       _ float64 = -maxFloat64
+       _ float64 = maxFloat64
+       _ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+       _ = float64(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+       _ = float64(-maxFloat64)
+       _ = float64(maxFloat64)
+       _ = float64(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+
+       _ = assert(float64(smallestFloat32) == smallestFloat32)
+       _ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
+       _ = assert(float64(smallestFloat64) == smallestFloat64)
+       _ = assert(float64(smallestFloat64/2) == 0)
+)
+
+const (
+       _ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+       _ complex64 = -maxFloat32
+       _ complex64 = maxFloat32
+       _ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+       _ = complex64(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+       _ = complex64(-maxFloat32)
+       _ = complex64(maxFloat32)
+       _ = complex64(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+)
+
+const (
+       _ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+       _ complex128 = -maxFloat64
+       _ complex128 = maxFloat64
+       _ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+       _ = complex128(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+       _ = complex128(-maxFloat64)
+       _ = complex128(maxFloat64)
+       _ = complex128(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+)
+
+// Initialization of typed constant and conversion are the same:
+const (
+       f32 = 1 + smallestFloat32
+       x32 float32 = f32
+       y32 = float32(f32)
+       _ = assert(x32 - y32 == 0)
+)
+
+const (
+       f64 = 1 + smallestFloat64
+       x64 float64 = f64
+       y64 = float64(f64)
+       _ = assert(x64 - y64 == 0)
+)
diff --git a/src/go/types/testdata/constdecl.src b/src/go/types/testdata/constdecl.src
new file mode 100644 (file)
index 0000000..6de9b13
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package constdecl
+
+import "math"
+
+var v int
+
+// Const decls must be initialized by constants.
+const _ = v /* ERROR "not constant" */
+const _ = math /* ERROR "not constant" */ .Sin(0)
+const _ = int /* ERROR "not an expression" */
+
+func _() {
+       const _ = v /* ERROR "not constant" */
+       const _ = math /* ERROR "not constant" */ .Sin(0)
+       const _ = int /* ERROR "not an expression" */
+}
+
+// Identifier and expression arity must match.
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+const (
+       _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+       _ = 1, 2 /* ERROR "extra init expr 2" */
+
+       _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+       _ int = 1, 2 /* ERROR "extra init expr 2" */
+)
+
+const (
+       _ = 1
+       _
+       _, _ /* ERROR "missing init expr for _" */
+       _
+)
+
+const (
+       _, _ = 1, 2
+       _, _
+       _ /* ERROR "extra init expr at" */
+       _, _
+       _, _, _ /* ERROR "missing init expr for _" */
+       _, _
+)
+
+func _() {
+       const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+       const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+       const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+       const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+       const (
+               _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+               _ = 1, 2 /* ERROR "extra init expr 2" */
+
+               _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+               _ int = 1, 2 /* ERROR "extra init expr 2" */
+       )
+
+       const (
+               _ = 1
+               _
+               _, _ /* ERROR "missing init expr for _" */
+               _
+       )
+
+       const (
+               _, _ = 1, 2
+               _, _
+               _ /* ERROR "extra init expr at" */
+               _, _
+               _, _, _ /* ERROR "missing init expr for _" */
+               _, _
+       )
+}
+
+// Test case for constant with invalid initialization.
+// Caused panic because the constant value was not set up (gri - 7/8/2014).
+func _() {
+       const (
+           x string = missing /* ERROR "undeclared name" */
+           y = x + ""
+       )
+}
+
+// TODO(gri) move extra tests from testdata/const0.src into here
diff --git a/src/go/types/testdata/conversions.src b/src/go/types/testdata/conversions.src
new file mode 100644 (file)
index 0000000..4251424
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// conversions
+
+package conversions
+
+import "unsafe"
+
+// argument count
+var (
+       _ = int() /* ERROR "missing argument" */
+       _ = int(1, 2 /* ERROR "too many arguments" */ )
+)
+
+// numeric constant conversions are in const1.src.
+
+func string_conversions() {
+       const A = string(65)
+       assert(A == "A")
+       const E = string(-1)
+       assert(E == "\uFFFD")
+       assert(E == string(1234567890))
+
+       type myint int
+       assert(A == string(myint(65)))
+
+       type mystring string
+       const _ mystring = mystring("foo")
+
+       const _ = string(true /* ERROR "cannot convert" */ )
+       const _ = string(1.2 /* ERROR "cannot convert" */ )
+       const _ = string(nil /* ERROR "cannot convert" */ )
+}
+
+func interface_conversions() {
+       type E interface{}
+
+       type I1 interface{
+               m1()
+       }
+
+       type I2 interface{
+               m1()
+               m2(x int)
+       }
+
+       type I3 interface{
+               m1()
+               m2() int
+       }
+
+       var e E
+       var i1 I1
+       var i2 I2
+       var i3 I3
+
+       _ = E(0)
+       _ = E(nil)
+       _ = E(e)
+       _ = E(i1)
+       _ = E(i2)
+
+       _ = I1(0 /* ERROR "cannot convert" */ )
+       _ = I1(nil)
+       _ = I1(i1)
+       _ = I1(e /* ERROR "cannot convert" */ )
+       _ = I1(i2)
+
+       _ = I2(nil)
+       _ = I2(i1 /* ERROR "cannot convert" */ )
+       _ = I2(i2)
+       _ = I2(i3 /* ERROR "cannot convert" */ )
+
+       _ = I3(nil)
+       _ = I3(i1 /* ERROR "cannot convert" */ )
+       _ = I3(i2 /* ERROR "cannot convert" */ )
+       _ = I3(i3)
+
+       // TODO(gri) add more tests, improve error message
+}
+
+func issue6326() {
+       type T unsafe.Pointer
+       var x T
+       _ = uintptr(x) // see issue 6326
+}
diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src
new file mode 100644 (file)
index 0000000..621d83c
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cycles
+
+type (
+       T0 int
+       T1 /* ERROR cycle */ T1
+       T2 *T2
+
+       T3 /* ERROR cycle */ T4
+       T4 T5
+       T5 T3
+
+       T6 T7
+       T7 *T8
+       T8 T6
+
+       // arrays
+       A0 /* ERROR cycle */ [10]A0
+       A1 [10]*A1
+
+       A2 /* ERROR cycle */ [10]A3
+       A3 [10]A4
+       A4 A2
+
+       A5 [10]A6
+       A6 *A5
+
+       // slices
+       L0 []L0
+
+       // structs
+       S0 /* ERROR cycle */ struct{ _ S0 }
+       S1 /* ERROR cycle */ struct{ S1 }
+       S2 struct{ _ *S2 }
+       S3 struct{ *S3 }
+
+       S4 /* ERROR cycle */ struct{ S5 }
+       S5 struct{ S6 }
+       S6 S4
+
+       // pointers
+       P0 *P0
+
+       // functions
+       F0 func(F0)
+       F1 func() F1
+       F2 func(F2) F2
+
+       // interfaces
+       I0 /* ERROR cycle */ interface{ I0 }
+
+       I1 interface{ I2 }
+       I2 interface{ I3 }
+       I3 /* ERROR cycle */ interface{ I1 }
+
+       I4 interface{ f(I4) }
+
+       // testcase for issue 5090
+       I5 interface{ f(I6) }
+       I6 interface{ I5 }
+
+       // maps
+       M0 map[M0 /* ERROR invalid map key */ ]M0
+
+       // channels
+       C0 chan C0
+)
+
+func _() {
+       type (
+               t1 /* ERROR cycle */ t1
+               t2 *t2
+
+               t3 t4 /* ERROR undeclared */
+               t4 t5 /* ERROR undeclared */
+               t5 t3
+
+               // arrays
+               a0 /* ERROR cycle */ [10]a0
+               a1 [10]*a1
+
+               // slices
+               l0 []l0
+
+               // structs
+               s0 /* ERROR cycle */ struct{ _ s0 }
+               s1 /* ERROR cycle */ struct{ s1 }
+               s2 struct{ _ *s2 }
+               s3 struct{ *s3 }
+
+               // pointers
+               p0 *p0
+
+               // functions
+               f0 func(f0)
+               f1 func() f1
+               f2 func(f2) f2
+
+               // interfaces
+               i0 /* ERROR cycle */ interface{ i0 }
+
+               // maps
+               m0 map[m0 /* ERROR invalid map key */ ]m0
+
+               // channels
+               c0 chan c0
+       )
+}
+
+// test cases for issue 6667
+
+type A [10]map[A /* ERROR invalid map key */ ]bool
+
+type S struct {
+       m map[S /* ERROR invalid map key */ ]bool
+}
+
+// test cases for issue 7236
+// (cycle detection must not be dependent on starting point of resolution)
+
+type (
+       P1 *T9
+       T9 /* ERROR cycle */ T9
+
+       T10 /* ERROR cycle */ T10
+       P2 *T10
+)
+
+func (T11) m() {}
+
+type T11 /* ERROR cycle */ struct{ T11 }
+
+type T12 /* ERROR cycle */ struct{ T12 }
+
+func (*T12) m() {}
+
+type (
+       P3 *T13
+       T13 /* ERROR cycle */ T13
+)
\ No newline at end of file
diff --git a/src/go/types/testdata/cycles1.src b/src/go/types/testdata/cycles1.src
new file mode 100644 (file)
index 0000000..ae2b38e
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type (
+       A interface {
+               a() interface {
+                       ABC1
+               }
+       }
+       B interface {
+               b() interface {
+                       ABC2
+               }
+       }
+       C interface {
+               c() interface {
+                       ABC3
+               }
+       }
+
+       AB interface {
+               A
+               B
+       }
+       BC interface {
+               B
+               C
+       }
+
+       ABC1 interface {
+               A
+               B
+               C
+       }
+       ABC2 interface {
+               AB
+               C
+       }
+       ABC3 interface {
+               A
+               BC
+       }
+)
+
+var (
+       x1 ABC1
+       x2 ABC2
+       x3 ABC3
+)
+
+func _() {
+       // all types have the same method set
+       x1 = x2
+       x2 = x1
+
+       x1 = x3
+       x3 = x1
+
+       x2 = x3
+       x3 = x2
+
+       // all methods return the same type again
+       x1 = x1.a()
+       x1 = x1.b()
+       x1 = x1.c()
+
+       x2 = x2.a()
+       x2 = x2.b()
+       x2 = x2.c()
+
+       x3 = x3.a()
+       x3 = x3.b()
+       x3 = x3.c()
+}
diff --git a/src/go/types/testdata/cycles2.src b/src/go/types/testdata/cycles2.src
new file mode 100644 (file)
index 0000000..345ab56
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import "unsafe"
+
+// Test case for issue 5090
+
+type t interface {
+       f(u)
+}
+
+type u interface {
+       t
+}
+
+func _() {
+       var t t
+       var u u
+
+       t.f(t)
+       t.f(u)
+       
+       u.f(t)
+       u.f(u)
+}
+
+
+// Test case for issue 6589.
+
+type A interface {
+       a() interface {
+               AB
+       }
+}
+
+type B interface {
+       a() interface {
+               AB
+       }
+}
+
+type AB interface {
+       a() interface {
+               A
+               B /* ERROR a redeclared */
+       }
+       b() interface {
+               A
+               B /* ERROR a redeclared */
+       }
+}
+
+var x AB
+var y interface {
+       A
+       B /* ERROR a redeclared */
+}
+var _ = x /* ERROR cannot compare */ == y
+
+
+// Test case for issue 6638.
+
+type T interface {
+       m() [T /* ERROR no value */ (nil).m()[0]]int
+}
+
+// Variations of this test case.
+
+type T1 interface {
+       m() [x1 /* ERROR no value */ .m()[0]]int
+}
+
+var x1 T1
+
+type T2 interface {
+       m() [len(x2 /* ERROR no value */ .m())]int
+}
+
+var x2 T2
+
+type T3 interface {
+       m() [unsafe.Sizeof(x3.m)]int
+}
+
+var x3 T3
+
+// The test case below should also report an error for
+// the cast inside the T4 interface (like it does for the
+// variable initialization). The reason why it does not is
+// that inside T4, the method x4.m depends on T4 which is not
+// fully set up yet. The x4.m method happens to have an empty
+// signature which is why the cast is permitted.
+// TODO(gri) Consider marking methods as incomplete and provide
+// a better error message in that case.
+
+type T4 interface {
+       m() [unsafe.Sizeof(cast4(x4.m))]int
+}
+
+var x4 T4
+var _ = cast4(x4 /* ERROR cannot convert */.m)
+
+type cast4 func()
+
+// This test is symmetric to the T4 case: Here the cast is
+// "correct", but it doesn't work inside the T5 interface.
+
+type T5 interface {
+       m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int
+}
+
+var x5 T5
+var _ = cast5(x5.m)
+
+type cast5 func() [0]int
diff --git a/src/go/types/testdata/cycles3.src b/src/go/types/testdata/cycles3.src
new file mode 100644 (file)
index 0000000..3da4fb5
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import "unsafe"
+
+var (
+       _ A = A(nil).a().b().c().d().e().f()
+       _ A = A(nil).b().c().d().e().f()
+       _ A = A(nil).c().d().e().f()
+       _ A = A(nil).d().e().f()
+       _ A = A(nil).e().f()
+       _ A = A(nil).f()
+       _ A = A(nil)
+)
+
+type (
+       A interface {
+               a() B
+               B
+       }
+
+       B interface {
+               b() C
+               C
+       }
+
+       C interface {
+               c() D
+               D
+       }
+
+       D interface {
+               d() E
+               E
+       }
+
+       E interface {
+               e() F
+               F
+       }
+
+       F interface {
+               f() A
+       }
+)
+
+type (
+       U interface {
+               V
+       }
+
+       V interface {
+               v() [unsafe.Sizeof(u)]int
+       }
+)
+
+var u U
diff --git a/src/go/types/testdata/cycles4.src b/src/go/types/testdata/cycles4.src
new file mode 100644 (file)
index 0000000..445babc
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// Check that all methods of T are collected before
+// determining the result type of m (which embeds
+// all methods of T).
+
+type T interface {
+       m() interface {T}
+       E
+}
+
+var _ = T.m(nil).m().e()
+
+type E interface {
+       e() int
+}
+
+// Check that unresolved forward chains are followed
+// (see also comment in resolver.go, checker.typeDecl).
+
+var _ = C.m(nil).m().e()
+
+type A B
+
+type B interface {
+       m() interface{C}
+       E
+}
+
+type C A
+
+// Check that interface type comparison for identity
+// does not recur endlessly.
+
+type T1 interface {
+       m() interface{T1}
+}
+
+type T2 interface {
+       m() interface{T2}
+}
+
+func _(x T1, y T2) {
+       // Checking for assignability of interfaces must check
+       // if all methods of x are present in y, and that they
+       // have identical signatures. The signatures recur via
+       // the result type, which is an interface that embeds
+       // a single method m that refers to the very interface
+       // that contains it. This requires cycle detection in
+       // identity checks for interface types.
+       x = y
+}
+
+type T3 interface {
+       m() interface{T4}
+}
+
+type T4 interface {
+       m() interface{T3}
+}
+
+func _(x T1, y T3) {
+       x = y
+}
+
+// Check that interfaces are type-checked in order of
+// (embedded interface) dependencies (was issue 7158).
+
+var x1 T5 = T7(nil)
+
+type T5 interface {
+       T6
+}
+
+type T6 interface {
+       m() T7
+}
+type T7 interface {
+       T5
+}
+
+// Actual test case from issue 7158.
+
+func wrapNode() Node {
+       return wrapElement()
+}
+
+func wrapElement() Element {
+       return nil
+}
+
+type EventTarget interface {
+       AddEventListener(Event)
+}
+
+type Node interface {
+       EventTarget
+}
+
+type Element interface {
+       Node
+}
+
+type Event interface {
+       Target() Element
+}
diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src
new file mode 100644 (file)
index 0000000..f1df3ea
--- /dev/null
@@ -0,0 +1,206 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// type declarations
+
+package decls0
+
+import "unsafe"
+
+const pi = 3.1415
+
+type (
+       N undeclared /* ERROR "undeclared" */
+       B bool
+       I int32
+       A [10]P
+       T struct {
+               x, y P
+       }
+       P *T
+       R (*R)
+       F func(A) I
+       Y interface {
+               f(A) I
+       }
+       S [](((P)))
+       M map[I]F
+       C chan<- I
+
+       // blank types must be typechecked
+       _ pi /* ERROR "not a type" */
+       _ struct{}
+       _ struct{ pi /* ERROR "not a type" */ }
+)
+
+
+// declarations of init
+const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2
+type init /* ERROR "cannot declare init" */ struct{}
+var _, init /* ERROR "cannot declare init" */ int
+
+func init() {}
+func init /* ERROR "missing function body" */ ()
+
+func _() { const init = 0 }
+func _() { type init int }
+func _() { var init int; _ = init }
+
+// invalid array types
+type (
+       iA0 [... /* ERROR "invalid use of '...'" */ ]byte
+       iA1 [1 /* ERROR "invalid array length" */ <<100]int
+       iA2 [- /* ERROR "invalid array length" */ 1]complex128
+       iA3 ["foo" /* ERROR "must be integer" */ ]string
+)
+
+
+type (
+       p1 pi /* ERROR "no field or method foo" */ .foo
+       p2 unsafe.Pointer
+)
+
+
+type (
+       Pi pi /* ERROR "not a type" */
+
+       a /* ERROR "illegal cycle" */ a
+       a /* ERROR "redeclared" */ int
+
+       // where the cycle error appears depends on the
+       // order in which declarations are processed
+       // (which depends on the order in which a map
+       // is iterated through)
+       b /* ERROR "illegal cycle" */ c
+       c d
+       d e
+       e b
+
+       t *t
+
+       U V
+       V *W
+       W U
+
+       P1 *S2
+       P2 P1
+
+       S0 struct {
+       }
+       S1 struct {
+               a, b, c int
+               u, v, a /* ERROR "redeclared" */ float32
+       }
+       S2 struct {
+               S0 // anonymous field
+               S0 /* ERROR "redeclared" */ int
+       }
+       S3 struct {
+               x S2
+       }
+       S4/* ERROR "illegal cycle" */ struct {
+               S4
+       }
+       S5 /* ERROR "illegal cycle" */ struct {
+               S6
+       }
+       S6 struct {
+               field S7
+       }
+       S7 struct {
+               S5
+       }
+
+       L1 []L1
+       L2 []int
+
+       A1 [10.0]int
+       A2 /* ERROR "illegal cycle" */ [10]A2
+       A3 /* ERROR "illegal cycle" */ [10]struct {
+               x A4
+       }
+       A4 [10]A3
+
+       F1 func()
+       F2 func(x, y, z float32)
+       F3 func(x, y, x /* ERROR "redeclared" */ float32)
+       F4 func() (x, y, x /* ERROR "redeclared" */ float32)
+       F5 func(x int) (x /* ERROR "redeclared" */ float32)
+       F6 func(x ...int)
+
+       I1 interface{}
+       I2 interface {
+               m1()
+       }
+       I3 interface {
+               m1()
+               m1 /* ERROR "redeclared" */ ()
+       }
+       I4 interface {
+               m1(x, y, x /* ERROR "redeclared" */ float32)
+               m2() (x, y, x /* ERROR "redeclared" */ float32)
+               m3(x int) (x /* ERROR "redeclared" */ float32)
+       }
+       I5 interface {
+               m1(I5)
+       }
+       I6 interface {
+               S0 /* ERROR "not an interface" */
+       }
+       I7 interface {
+               I1
+               I1
+       }
+       I8 /* ERROR "illegal cycle" */ interface {
+               I8
+       }
+       I9 interface {
+               I10
+       }
+       I10 interface {
+               I11
+       }
+       I11 /* ERROR "illegal cycle" */ interface {
+               I9
+       }
+
+       C1 chan int
+       C2 <-chan int
+       C3 chan<- C3
+       C4 chan C5
+       C5 chan C6
+       C6 chan C4
+
+       M1 map[Last]string
+       M2 map[string]M2
+
+       Last int
+)
+
+// cycles in function/method declarations
+// (test cases for issue 5217 and variants)
+func f1(x f1 /* ERROR "not a type" */ ) {}
+func f2(x *f2 /* ERROR "not a type" */ ) {}
+func f3() (x f3 /* ERROR "not a type" */ ) { return }
+func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+
+func (S0) m1(x S0 /* ERROR "field or method" */ .m1) {}
+func (S0) m2(x *S0 /* ERROR "field or method" */ .m2) {}
+func (S0) m3() (x S0 /* ERROR "field or method" */ .m3) { return }
+func (S0) m4() (x *S0 /* ERROR "field or method" */ .m4) { return }
+
+// interfaces may not have any blank methods
+type BlankI interface {
+       _ /* ERROR "invalid method name" */ ()
+       _ /* ERROR "invalid method name" */ (float32) int
+       m()
+}
+
+// non-interface types may have multiple blank methods
+type BlankT struct{}
+
+func (BlankT) _() {}
+func (BlankT) _(int) {}
+func (BlankT) _() int { return 0 }
+func (BlankT) _(int) int { return 0}
diff --git a/src/go/types/testdata/decls1.src b/src/go/types/testdata/decls1.src
new file mode 100644 (file)
index 0000000..7855e46
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// variable declarations
+
+package decls1
+
+import (
+       "math"
+)
+
+// Global variables without initialization
+var (
+       a, b bool
+       c byte
+       d uint8
+       r rune
+       i int
+       j, k, l int
+       x, y float32
+       xx, yy float64
+       u, v complex64
+       uu, vv complex128
+       s, t string
+       array []byte
+       iface interface{}
+       
+       blank _ /* ERROR "cannot use _" */
+)
+
+// Global variables with initialization
+var (
+       s1 = i + j
+       s2 = i /* ERROR "mismatched types" */ + x
+       s3 = c + d
+       s4 = s + t
+       s5 = s /* ERROR "invalid operation" */ / t
+       s6 = array[t1]
+       s7 = array[x /* ERROR "integer" */]
+       s8 = &a
+       s10 = &42 /* ERROR "cannot take address" */
+       s11 = &v
+       s12 = -(u + *t11) / *&v
+       s13 = a /* ERROR "shifted operand" */ << d
+       s14 = i << j /* ERROR "must be unsigned" */ 
+       s18 = math.Pi * 10.0
+       s19 = s1 /* ERROR "cannot call" */ ()
+       s20 = f0 /* ERROR "no value" */ ()
+       s21 = f6(1, s1, i)
+       s22 = f6(1, s1, uu /* ERROR "cannot pass argument" */ )
+       
+       t1 int = i + j
+       t2 int = i /* ERROR "mismatched types" */ + x
+       t3 int = c /* ERROR "cannot initialize" */ + d
+       t4 string = s + t
+       t5 string = s /* ERROR "invalid operation" */ / t
+       t6 byte = array[t1]
+       t7 byte = array[x /* ERROR "must be integer" */]
+       t8 *int = & /* ERROR "cannot initialize" */ a
+       t10 *int = &42 /* ERROR "cannot take address" */
+       t11 *complex64 = &v
+       t12 complex64 = -(u + *t11) / *&v
+       t13 int = a /* ERROR "shifted operand" */ << d
+       t14 int = i << j /* ERROR "must be unsigned" */ 
+       t15 math /* ERROR "not in selector" */
+       t16 math /* ERROR "not declared" */ .xxx
+       t17 math /* ERROR "not a type" */ .Pi
+       t18 float64 = math.Pi * 10.0
+       t19 int = t1 /* ERROR "cannot call" */ ()
+       t20 int = f0 /* ERROR "no value" */ ()
+       t21 int = a /* ERROR "cannot initialize" */
+)
+
+// Various more complex expressions
+var (
+       u1 = x /* ERROR "not an interface" */ .(int)
+       u2 = iface.([]int)
+       u3 = iface.(a /* ERROR "not a type" */ )
+       u4, ok = iface.(int)
+       u5, ok2, ok3 = iface /* ERROR "assignment count mismatch" */ .(int)
+)
+
+// Constant expression initializations
+var (
+       v1 = 1 /* ERROR "cannot convert" */ + "foo"
+       v2 = c + 255
+       v3 = c + 256 /* ERROR "overflows" */
+       v4 = r + 2147483647
+       v5 = r + 2147483648 /* ERROR "overflows" */
+       v6 = 42
+       v7 = v6 + 9223372036854775807
+       v8 = v6 + 9223372036854775808 /* ERROR "overflows" */
+       v9 = i + 1 << 10
+       v10 byte = 1024 /* ERROR "overflows" */
+       v11 = xx/yy*yy - xx
+       v12 = true && false
+       v13 = nil /* ERROR "use of untyped nil" */
+)
+
+// Multiple assignment expressions
+var (
+       m1a, m1b = 1, 2
+       m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+       m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+)
+
+func _() {
+       var (
+               m1a, m1b = 1, 2
+               m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+               m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+       )
+
+       _, _ = m1a, m1b
+       _, _, _ = m2a, m2b, m2c
+       _, _ = m3a, m3b
+}
+
+// Declaration of parameters and results
+func f0() {}
+func f1(a /* ERROR "not a type" */) {}
+func f2(a, b, c d /* ERROR "not a type" */) {}
+
+func f3() int { return 0 }
+func f4() a /* ERROR "not a type" */ { return 0 }
+func f5() (a, b, c d /* ERROR "not a type" */) { return }
+
+func f6(a, b, c int) complex128 { return 0 }
+
+// Declaration of receivers
+type T struct{}
+
+func (T) m0() {}
+func (*T) m1() {}
+func (x T) m2() {}
+func (x *T) m3() {}
+
+// Initialization functions
+func init() {}
+func /* ERROR "no arguments and no return values" */ init(int) {}
+func /* ERROR "no arguments and no return values" */ init() int { return 0 }
+func /* ERROR "no arguments and no return values" */ init(int) int { return 0 }
+func (T) init(int) int { return 0 }
diff --git a/src/go/types/testdata/decls2a.src b/src/go/types/testdata/decls2a.src
new file mode 100644 (file)
index 0000000..bdbecd9
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// method declarations
+
+package decls2
+
+import "time"
+import "unsafe"
+
+// T1 declared before its methods.
+type T1 struct{
+       f int
+}
+
+func (T1) m() {}
+func (T1) m /* ERROR "already declared" */ () {}
+func (x *T1) f /* ERROR "field and method" */ () {}
+
+// Conflict between embedded field and method name,
+// with the embedded field being a basic type.
+type T1b struct {
+       int
+}
+
+func (T1b) int /* ERROR "field and method" */ () {}
+
+type T1c struct {
+       time.Time
+}
+
+func (T1c) Time /* ERROR "field and method" */ () int { return 0 }
+
+// Disabled for now: LookupFieldOrMethod will find Pointer even though
+// it's double-declared (it would cost extra in the common case to verify
+// this). But the MethodSet computation will not find it due to the name
+// collision caused by the double-declaration, leading to an internal
+// inconsistency while we are verifying one computation against the other.
+// var _ = T1c{}.Pointer
+
+// T2's method declared before the type.
+func (*T2) f /* ERROR "field and method" */ () {}
+
+type T2 struct {
+       f int
+}
+
+// Methods declared without a declared type.
+func (undeclared /* ERROR "undeclared" */) m() {}
+func (x *undeclared /* ERROR "undeclared" */) m() {}
+
+func (pi /* ERROR "not a type" */) m1() {}
+func (x pi /* ERROR "not a type" */) m2() {}
+func (x *pi /* ERROR "not a type" */ ) m3() {}
+
+// Blank types.
+type _ struct { m int }
+type _ struct { m int }
+
+func (_ /* ERROR "cannot use _" */) m() {}
+func m(_ /* ERROR "cannot use _" */) {}
+
+// Methods with receiver base type declared in another file.
+func (T3) m1() {}
+func (*T3) m2() {}
+func (x T3) m3() {}
+func (x *T3) f /* ERROR "field and method" */ () {}
+
+// Methods of non-struct type.
+type T4 func()
+
+func (self T4) m() func() { return self }
+
+// Methods associated with an interface.
+type T5 interface {
+       m() int
+}
+
+func (T5 /* ERROR "invalid receiver" */ ) m1() {}
+func (T5 /* ERROR "invalid receiver" */ ) m2() {}
+
+// Methods associated with a named pointer type.
+type ptr *int
+func (ptr /* ERROR "invalid receiver" */ ) _() {}
+func (* /* ERROR "invalid receiver" */ ptr) _() {}
+
+// Methods with zero or multiple receivers.
+func ( /* ERROR "missing receiver" */ ) _() {}
+func (T3, * /* ERROR "exactly one receiver" */ T3) _() {}
+func (T3, T3, T3 /* ERROR "exactly one receiver" */ ) _() {}
+func (a, b /* ERROR "exactly one receiver" */ T3) _() {}
+func (a, b, c /* ERROR "exactly one receiver" */ T3) _() {}
+
+// Methods associated with non-local or unnamed types.
+func (int /* ERROR "invalid receiver" */ ) m() {}
+func ([ /* ERROR "invalid receiver" */ ]int) m() {}
+func (time /* ERROR "invalid receiver" */ .Time) m() {}
+func (* /* ERROR "invalid receiver" */ time.Time) m() {}
+func (x /* ERROR "invalid receiver" */ interface{}) m() {}
+
+// Unsafe.Pointer is treated like a pointer when used as receiver type.
+type UP unsafe.Pointer
+func (UP /* ERROR "invalid" */ ) m1() {}
+func (* /* ERROR "invalid" */ UP) m2() {}
+
+// Double declarations across package files
+const c_double = 0
+type t_double int
+var v_double int
+func f_double() {}
diff --git a/src/go/types/testdata/decls2b.src b/src/go/types/testdata/decls2b.src
new file mode 100644 (file)
index 0000000..e7bc394
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// method declarations
+
+package decls2
+
+import "io"
+
+const pi = 3.1415
+
+func (T1) m /* ERROR "already declared" */ () {}
+func (T2) m(io.Writer) {}
+
+type T3 struct {
+       f *T3
+}
+
+type T6 struct {
+       x int
+}
+
+func (t *T6) m1() int {
+       return t.x
+}
+
+func f() {
+       var t *T6
+       t.m1()
+}
+
+// Double declarations across package files
+const c_double /* ERROR "redeclared" */ = 0
+type t_double  /* ERROR "redeclared" */ int
+var v_double /* ERROR "redeclared" */ int
+func f_double /* ERROR "redeclared" */ () {}
+
+// Blank methods need to be type-checked.
+// Verify by checking that errors are reported.
+func (T /* ERROR "undeclared" */ ) _() {}
+func (T1) _(undeclared /* ERROR "undeclared" */ ) {}
+func (T1) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Methods with undeclared receiver type can still be checked.
+// Verify by checking that errors are reported.
+func (Foo /* ERROR "undeclared" */ ) m() {}
+func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ }
+
+func (Foo /* ERROR "undeclared" */ ) _() {}
+func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Receiver declarations are regular parameter lists;
+// receiver types may use parentheses, and the list
+// may have a trailing comma.
+type T7 struct {}
+
+func (T7) m1() {}
+func ((T7)) m2() {}
+func ((*T7)) m3() {}
+func (x *(T7),) m4() {}
+func (x (*(T7)),) m5() {}
+func (x ((*((T7)))),) m6() {}
diff --git a/src/go/types/testdata/decls3.src b/src/go/types/testdata/decls3.src
new file mode 100644 (file)
index 0000000..80d2bc8
--- /dev/null
@@ -0,0 +1,309 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// embedded types
+
+package decls3
+
+import "unsafe"
+import "fmt"
+
+// fields with the same name at the same level cancel each other out
+
+func _() {
+       type (
+               T1 struct { X int }
+               T2 struct { X int }
+               T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
+       )
+
+       var t T3
+       _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+       type (
+               T1 struct { X int }
+               T2 struct { T1 }
+               T3 struct { T1 }
+               T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
+       )
+
+       var t T4
+       _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func issue4355() {
+       type (
+           T1 struct {X int}
+           T2 struct {T1}
+           T3 struct {T2}
+           T4 struct {T2}
+           T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
+       )       
+
+       var t T5
+       _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+       type State int
+       type A struct{ State }
+       type B struct{ fmt.State }
+       type T struct{ A; B }
+
+       var t T
+       _ = t /* ERROR "ambiguous selector" */ .State
+}
+
+// Embedded fields can be predeclared types.
+
+func _() {
+       type T0 struct{
+               int
+               float32
+               f int
+       }
+       var x T0
+       _ = x.int
+       _ = x.float32
+       _ = x.f
+
+       type T1 struct{
+               T0
+       }
+       var y T1
+       _ = y.int
+       _ = y.float32
+       _ = y.f
+}
+
+// Restrictions on embedded field types.
+
+func _() {
+       type I1 interface{}
+       type I2 interface{}
+       type P1 *int
+       type P2 *int
+       type UP unsafe.Pointer
+
+       type T1 struct {
+               I1
+               * /* ERROR "cannot be a pointer to an interface" */ I2
+               * /* ERROR "cannot be a pointer to an interface" */ error
+               P1 /* ERROR "cannot be a pointer" */
+               * /* ERROR "cannot be a pointer" */ P2
+       }
+
+       // unsafe.Pointers are treated like regular pointers when embedded
+       type T2 struct {
+               unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
+               */* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer
+               UP /* ERROR "cannot be unsafe.Pointer" */
+               * /* ERROR "cannot be unsafe.Pointer" */ UP
+       }
+}
+
+// Named types that are pointers.
+
+type S struct{ x int }
+func (*S) m() {}
+type P *S
+
+func _() {
+       var s *S
+       _ = s.x
+       _ = s.m
+
+       var p P
+       _ = p.x
+       _ = p /* ERROR "no field or method" */ .m
+       _ = P /* ERROR "no field or method" */ .m
+}
+
+// Borrowed from the FieldByName test cases in reflect/all_test.go.
+
+type D1 struct {
+       d int
+}
+type D2 struct {
+       d int
+}
+
+type S0 struct {
+       A, B, C int
+       D1
+       D2
+}
+
+type S1 struct {
+       B int
+       S0
+}
+
+type S2 struct {
+       A int
+       *S1
+}
+
+type S1x struct {
+       S1
+}
+
+type S1y struct {
+       S1
+}
+
+type S3 struct {
+       S1x
+       S2
+       D, E int
+       *S1y
+}
+
+type S4 struct {
+       *S4
+       A int
+}
+
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+       S6
+       S7
+       S8
+}
+
+type S6 struct {
+       X int
+}
+
+type S7 S6
+
+type S8 struct {
+       S9
+}
+
+type S9 struct {
+       X int
+       Y int
+}
+
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+       S11
+       S12
+       S13
+}
+
+type S11 struct {
+       S6
+}
+
+type S12 struct {
+       S6
+}
+
+type S13 struct {
+       S8
+}
+
+func _() {
+       _ = struct /* ERROR "no field or method" */ {}{}.Foo
+       _ = S0{}.A
+       _ = S0 /* ERROR "no field or method" */ {}.D
+       _ = S1{}.A
+       _ = S1{}.B
+       _ = S1{}.S0
+       _ = S1{}.C
+       _ = S2{}.A
+       _ = S2{}.S1
+       _ = S2{}.B
+       _ = S2{}.C
+       _ = S2 /* ERROR "no field or method" */ {}.D
+       _ = S3 /* ERROR "ambiguous selector" */ {}.S1
+       _ = S3{}.A
+       _ = S3 /* ERROR "ambiguous selector" */ {}.B
+       _ = S3{}.D
+       _ = S3{}.E
+       _ = S4{}.A
+       _ = S4 /* ERROR "no field or method" */ {}.B
+       _ = S5 /* ERROR "ambiguous selector" */ {}.X
+       _ = S5{}.Y
+       _ = S10 /* ERROR "ambiguous selector" */ {}.X
+       _ = S10{}.Y
+}
+
+// Borrowed from the FieldByName benchmark in reflect/all_test.go.
+
+type R0 struct {
+       *R1
+       *R2
+       *R3
+       *R4
+}
+
+type R1 struct {
+       *R5
+       *R6
+       *R7
+       *R8
+}
+
+type R2 R1
+type R3 R1
+type R4 R1
+
+type R5 struct {
+       *R9
+       *R10
+       *R11
+       *R12
+}
+
+type R6 R5
+type R7 R5
+type R8 R5
+
+type R9 struct {
+       *R13
+       *R14
+       *R15
+       *R16
+}
+
+type R10 R9
+type R11 R9
+type R12 R9
+
+type R13 struct {
+       *R17
+       *R18
+       *R19
+       *R20
+}
+
+type R14 R13
+type R15 R13
+type R16 R13
+
+type R17 struct {
+       *R21
+       *R22
+       *R23
+       *R24
+}
+
+type R18 R17
+type R19 R17
+type R20 R17
+
+type R21 struct {
+       X int
+}
+
+type R22 R21
+type R23 R21
+type R24 R21
+
+var _ = R0 /* ERROR "ambiguous selector" */ {}.X
\ No newline at end of file
diff --git a/src/go/types/testdata/errors.src b/src/go/types/testdata/errors.src
new file mode 100644 (file)
index 0000000..45bd45a
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package errors
+
+// Testing precise operand formatting in error messages
+// (matching messages are regular expressions, hence the \'s).
+func f(x int, m map[string]int) {
+       // no values
+       _ = f /* ERROR "f\(0, m\) \(no value\) used as value" */ (0, m)
+
+       // built-ins
+       _ = println /* ERROR "println \(built-in\) must be called" */
+
+       // types
+       _ = complex128 /* ERROR "complex128 \(type\) is not an expression" */
+
+       // constants
+       const c1 = 991
+       const c2 float32 = 0.5
+       0 /* ERROR "0 \(untyped int constant\) is not used" */
+       c1 /* ERROR "c1 \(untyped int constant 991\) is not used" */
+       c2 /* ERROR "c2 \(constant 1/2 of type float32\) is not used" */
+       c1 /* ERROR "c1 \+ c2 \(constant 1983/2 of type float32\) is not used" */ + c2
+
+       // variables
+       x /* ERROR "x \(variable of type int\) is not used" */
+
+       // values
+       x /* ERROR "x != x \(untyped bool value\) is not used" */ != x
+       x /* ERROR "x \+ x \(value of type int\) is not used" */ + x
+
+       // value, ok's
+       const s = "foo"
+       m /* ERROR "m\[s\] \(map index expression of type int\) is not used" */ [s]
+}
+
+// Valid ERROR comments can have a variety of forms.
+func _() {
+       0 /* ERROR "0 .* is not used" */
+       0 /* ERROR 0 .* is not used */
+       0 // ERROR "0 .* is not used"
+       0 // ERROR 0 .* is not used
+}
+
+// Don't report spurious errors as a consequence of earlier errors.
+// Add more tests as needed.
+func _() {
+       if err := foo /* ERROR undeclared */ (); err != nil /* no error here */ {}
+}
+
+// Use unqualified names for package-local objects.
+type T struct{}
+var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T
diff --git a/src/go/types/testdata/expr0.src b/src/go/types/testdata/expr0.src
new file mode 100644 (file)
index 0000000..5afb5d7
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// unary expressions
+
+package expr0 
+
+type mybool bool
+
+var (
+       // bool
+       b0 = true
+       b1 bool = b0
+       b2 = !true
+       b3 = !b1
+       b4 bool = !true
+       b5 bool = !b4
+       b6 = +b0 /* ERROR "not defined" */
+       b7 = -b0 /* ERROR "not defined" */
+       b8 = ^b0 /* ERROR "not defined" */
+       b9 = *b0 /* ERROR "cannot indirect" */
+       b10 = &true /* ERROR "cannot take address" */
+       b11 = &b0
+       b12 = <-b0 /* ERROR "cannot receive" */
+       b13 = & & /* ERROR "cannot take address" */ b0
+
+       // int
+       i0 = 1
+       i1 int = i0
+       i2 = +1
+       i3 = +i0
+       i4 int = +1
+       i5 int = +i4
+       i6 = -1
+       i7 = -i0
+       i8 int = -1
+       i9 int = -i4
+       i10 = !i0 /* ERROR "not defined" */
+       i11 = ^1
+       i12 = ^i0
+       i13 int = ^1
+       i14 int = ^i4
+       i15 = *i0 /* ERROR "cannot indirect" */
+       i16 = &i0
+       i17 = *i16
+       i18 = <-i16 /* ERROR "cannot receive" */
+
+       // uint
+       u0 = uint(1)
+       u1 uint = u0
+       u2 = +1
+       u3 = +u0
+       u4 uint = +1
+       u5 uint = +u4
+       u6 = -1
+       u7 = -u0
+       u8 uint = - /* ERROR "overflows" */ 1
+       u9 uint = -u4
+       u10 = !u0 /* ERROR "not defined" */
+       u11 = ^1
+       u12 = ^i0
+       u13 uint = ^ /* ERROR "overflows" */ 1
+       u14 uint = ^u4
+       u15 = *u0 /* ERROR "cannot indirect" */
+       u16 = &u0
+       u17 = *u16
+       u18 = <-u16 /* ERROR "cannot receive" */
+       u19 = ^uint(0)
+
+       // float64
+       f0 = float64(1)
+       f1 float64 = f0
+       f2 = +1
+       f3 = +f0
+       f4 float64 = +1
+       f5 float64 = +f4
+       f6 = -1
+       f7 = -f0
+       f8 float64 = -1
+       f9 float64 = -f4
+       f10 = !f0 /* ERROR "not defined" */
+       f11 = ^1
+       f12 = ^i0
+       f13 float64 = ^1
+       f14 float64 = ^f4 /* ERROR "not defined" */
+       f15 = *f0 /* ERROR "cannot indirect" */
+       f16 = &f0
+       f17 = *u16
+       f18 = <-u16 /* ERROR "cannot receive" */
+
+       // complex128
+       c0 = complex128(1)
+       c1 complex128 = c0
+       c2 = +1
+       c3 = +c0
+       c4 complex128 = +1
+       c5 complex128 = +c4
+       c6 = -1
+       c7 = -c0
+       c8 complex128 = -1
+       c9 complex128 = -c4
+       c10 = !c0 /* ERROR "not defined" */
+       c11 = ^1
+       c12 = ^i0
+       c13 complex128 = ^1
+       c14 complex128 = ^c4 /* ERROR "not defined" */
+       c15 = *c0 /* ERROR "cannot indirect" */
+       c16 = &c0
+       c17 = *u16
+       c18 = <-u16 /* ERROR "cannot receive" */
+
+       // string
+       s0 = "foo"
+       s1 = +"foo" /* ERROR "not defined" */
+       s2 = -s0 /* ERROR "not defined" */
+       s3 = !s0 /* ERROR "not defined" */
+       s4 = ^s0 /* ERROR "not defined" */
+       s5 = *s4
+       s6 = &s4
+       s7 = *s6
+       s8 = <-s7
+
+       // channel
+       ch chan int
+       rc <-chan float64
+       sc chan <- string
+       ch0 = +ch /* ERROR "not defined" */
+       ch1 = -ch /* ERROR "not defined" */
+       ch2 = !ch /* ERROR "not defined" */
+       ch3 = ^ch /* ERROR "not defined" */
+       ch4 = *ch /* ERROR "cannot indirect" */
+       ch5 = &ch
+       ch6 = *ch5
+       ch7 = <-ch
+       ch8 = <-rc
+       ch9 = <-sc /* ERROR "cannot receive" */
+       ch10, ok = <-ch
+       // ok is of type bool
+       ch11, myok = <-ch
+       _ mybool = myok /* ERROR "cannot initialize" */
+)
+
+// address of composite literals
+type T struct{x, y int}
+
+func f() T { return T{} }
+
+var (
+       _ = &T{1, 2}
+       _ = &[...]int{}
+       _ = &[]int{}
+       _ = &[]int{}
+       _ = &map[string]T{}
+       _ = &(T{1, 2})
+       _ = &((((T{1, 2}))))
+       _ = &f /* ERROR "cannot take address" */ ()
+)
+
+// recursive pointer types
+type P *P
+
+var (
+       p1 P = new(P)
+       p2 P = *p1
+       p3 P = &p2
+)
+
diff --git a/src/go/types/testdata/expr1.src b/src/go/types/testdata/expr1.src
new file mode 100644 (file)
index 0000000..8ef0aed
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// binary expressions
+
+package expr1
diff --git a/src/go/types/testdata/expr2.src b/src/go/types/testdata/expr2.src
new file mode 100644 (file)
index 0000000..31dc5f0
--- /dev/null
@@ -0,0 +1,247 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// comparisons
+
+package expr2
+
+func _bool() {
+       const t = true == true
+       const f = true == false
+       _ = t /* ERROR "cannot compare" */ < f
+       _ = 0 /* ERROR "cannot convert" */ == t
+       var b bool
+       var x, y float32
+       b = x < y
+       _ = b
+       _ = struct{b bool}{x < y}
+}
+
+// corner cases
+var (
+       v0 = nil /* ERROR "cannot compare" */ == nil
+)
+
+func arrays() {
+       // basics
+       var a, b [10]int
+       _ = a == b
+       _ = a != b
+       _ = a /* ERROR < not defined */ < b
+       _ = a == nil /* ERROR cannot convert */
+
+       type C [10]int
+       var c C
+       _ = a == c
+
+       type D [10]int
+       var d D
+       _ = c /* ERROR mismatched types */ == d
+
+       var e [10]func() int
+       _ = e /* ERROR == not defined */ == e
+}
+
+func structs() {
+       // basics
+       var s, t struct {
+               x int
+               a [10]float32
+               _ bool
+       }
+       _ = s == t
+       _ = s != t
+       _ = s /* ERROR < not defined */ < t
+       _ = s == nil /* ERROR cannot convert */
+
+       type S struct {
+               x int
+               a [10]float32
+               _ bool
+       }
+       type T struct {
+               x int
+               a [10]float32
+               _ bool
+       }
+       var ss S
+       var tt T
+       _ = s == ss
+       _ = ss /* ERROR mismatched types */ == tt
+
+       var u struct {
+               x int
+               a [10]map[string]int
+       }
+       _ = u /* ERROR cannot compare */ == u
+}
+
+func pointers() {
+       // nil
+       _ = nil /* ERROR == not defined */ == nil
+       _ = nil /* ERROR != not defined */ != nil
+       _ = nil /* ERROR < not defined */ < nil
+       _ = nil /* ERROR <= not defined */ <= nil
+       _ = nil /* ERROR > not defined */ > nil
+       _ = nil /* ERROR >= not defined */ >= nil
+
+       // basics
+       var p, q *int
+       _ = p == q
+       _ = p != q
+
+       _ = p == nil
+       _ = p != nil
+       _ = nil == q
+       _ = nil != q
+
+       _ = p /* ERROR < not defined */ < q
+       _ = p /* ERROR <= not defined */ <= q
+       _ = p /* ERROR > not defined */ > q
+       _ = p /* ERROR >= not defined */ >= q
+
+       // various element types
+       type (
+               S1 struct{}
+               S2 struct{}
+               P1 *S1
+               P2 *S2
+       )
+       var (
+               ps1 *S1
+               ps2 *S2
+               p1 P1
+               p2 P2
+       )
+       _ = ps1 == ps1
+       _ = ps1 /* ERROR mismatched types */ == ps2
+       _ = ps2 /* ERROR mismatched types */ == ps1
+
+       _ = p1 == p1
+       _ = p1 /* ERROR mismatched types */ == p2
+
+       _ = p1 == ps1
+}
+
+func channels() {
+       // basics
+       var c, d chan int
+       _ = c == d
+       _ = c != d
+       _ = c == nil
+       _ = c /* ERROR < not defined */ < d
+
+       // various element types (named types)
+       type (
+               C1 chan int
+               C1r <-chan int
+               C1s chan<- int
+               C2 chan float32
+       )
+       var (
+               c1 C1
+               c1r C1r
+               c1s C1s
+               c1a chan int
+               c2 C2
+       )
+       _ = c1 == c1
+       _ = c1 /* ERROR mismatched types */ == c1r
+       _ = c1 /* ERROR mismatched types */ == c1s
+       _ = c1r /* ERROR mismatched types */ == c1s
+       _ = c1 == c1a
+       _ = c1a == c1
+       _ = c1 /* ERROR mismatched types */ == c2
+       _ = c1a /* ERROR mismatched types */ == c2
+
+       // various element types (unnamed types)
+       var (
+               d1 chan int
+               d1r <-chan int
+               d1s chan<- int
+               d1a chan<- int
+               d2 chan float32
+       )
+       _ = d1 == d1
+       _ = d1 == d1r
+       _ = d1 == d1s
+       _ = d1r /* ERROR mismatched types */ == d1s
+       _ = d1 == d1a
+       _ = d1a == d1
+       _ = d1 /* ERROR mismatched types */ == d2
+       _ = d1a /* ERROR mismatched types */ == d2
+}
+
+// for interfaces test
+type S1 struct{}
+type S11 struct{}
+type S2 struct{}
+func (*S1) m() int
+func (*S11) m() int
+func (*S11) n()
+func (*S2) m() float32
+
+func interfaces() {
+       // basics
+       var i, j interface{ m() int }
+       _ = i == j
+       _ = i != j
+       _ = i == nil
+       _ = i /* ERROR < not defined */ < j
+
+       // various interfaces
+       var ii interface { m() int; n() }
+       var k interface { m() float32 }
+       _ = i == ii
+       _ = i /* ERROR mismatched types */ == k
+
+       // interfaces vs values
+       var s1 S1
+       var s11 S11
+       var s2 S2
+
+       _ = i == 0 /* ERROR cannot convert */
+       _ = i /* ERROR mismatched types */ == s1
+       _ = i == &s1
+       _ = i == &s11
+
+       _ = i /* ERROR mismatched types */ == s2
+       _ = i /* ERROR mismatched types */ == &s2
+}
+
+func slices() {
+       // basics
+       var s []int
+       _ = s == nil
+       _ = s != nil
+       _ = s /* ERROR < not defined */ < nil
+
+       // slices are not otherwise comparable
+       _ = s /* ERROR == not defined */ == s
+       _ = s /* ERROR < not defined */ < s
+}
+
+func maps() {
+       // basics
+       var m map[string]int
+       _ = m == nil
+       _ = m != nil
+       _ = m /* ERROR < not defined */ < nil
+
+       // maps are not otherwise comparable
+       _ = m /* ERROR == not defined */ == m
+       _ = m /* ERROR < not defined */ < m
+}
+
+func funcs() {
+       // basics
+       var f func(int) float32
+       _ = f == nil
+       _ = f != nil
+       _ = f /* ERROR < not defined */ < nil
+
+       // funcs are not otherwise comparable
+       _ = f /* ERROR == not defined */ == f
+       _ = f /* ERROR < not defined */ < f
+}
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
new file mode 100644 (file)
index 0000000..5772095
--- /dev/null
@@ -0,0 +1,534 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package expr3
+
+import "time"
+
+func indexes() {
+       _ = 1 /* ERROR "cannot index" */ [0]
+       _ = indexes /* ERROR "cannot index" */ [0]
+       _ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
+
+       var a [10]int
+       _ = a[true /* ERROR "cannot convert" */ ]
+       _ = a["foo" /* ERROR "cannot convert" */ ]
+       _ = a[1.1 /* ERROR "truncated" */ ]
+       _ = a[1.0]
+       _ = a[- /* ERROR "negative" */ 1]
+       _ = a[- /* ERROR "negative" */ 1 :]
+       _ = a[: - /* ERROR "negative" */ 1]
+       _ = a[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+       _ = a[0: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+       _ = a[0: /* ERROR "2nd index required" */ :10]
+       _ = a[:10:10]
+
+       var a0 int
+       a0 = a[0]
+       _ = a0
+       var a1 int32
+       a1 = a /* ERROR "cannot assign" */ [1]
+       _ = a1
+
+       _ = a[9]
+       _ = a[10 /* ERROR "index .* out of bounds" */ ]
+       _ = a[1 /* ERROR "overflows" */ <<100]
+       _ = a[10:]
+       _ = a[:10]
+       _ = a[10:10]
+       _ = a[11 /* ERROR "index .* out of bounds" */ :]
+       _ = a[: 11 /* ERROR "index .* out of bounds" */ ]
+       _ = a[: 1 /* ERROR "overflows" */ <<100]
+       _ = a[:10:10]
+       _ = a[:11 /* ERROR "index .* out of bounds" */ :10]
+       _ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
+       _ = a[10:0:10] /* ERROR "invalid slice indices" */
+       _ = a[0:10:0] /* ERROR "invalid slice indices" */
+       _ = a[10:0:0] /* ERROR "invalid slice indices" */
+       _ = &a /* ERROR "cannot take address" */ [:10]
+
+       pa := &a
+       _ = pa[9]
+       _ = pa[10 /* ERROR "index .* out of bounds" */ ]
+       _ = pa[1 /* ERROR "overflows" */ <<100]
+       _ = pa[10:]
+       _ = pa[:10]
+       _ = pa[10:10]
+       _ = pa[11 /* ERROR "index .* out of bounds" */ :]
+       _ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
+       _ = pa[: 1 /* ERROR "overflows" */ <<100]
+       _ = pa[:10:10]
+       _ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
+       _ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
+       _ = pa[10:0:10] /* ERROR "invalid slice indices" */
+       _ = pa[0:10:0] /* ERROR "invalid slice indices" */
+       _ = pa[10:0:0] /* ERROR "invalid slice indices" */
+       _ = &pa /* ERROR "cannot take address" */ [:10]
+
+       var b [0]int
+       _ = b[0 /* ERROR "index .* out of bounds" */ ]
+       _ = b[:]
+       _ = b[0:]
+       _ = b[:0]
+       _ = b[0:0]
+       _ = b[0:0:0]
+       _ = b[1 /* ERROR "index .* out of bounds" */ :0:0]
+
+       var s []int
+       _ = s[- /* ERROR "negative" */ 1]
+       _ = s[- /* ERROR "negative" */ 1 :]
+       _ = s[: - /* ERROR "negative" */ 1]
+       _ = s[0]
+       _ = s[1:2]
+       _ = s[2:1] /* ERROR "invalid slice indices" */
+       _ = s[2:]
+       _ = s[: 1 /* ERROR "overflows" */ <<100]
+       _ = s[1 /* ERROR "overflows" */ <<100 :]
+       _ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
+       _ = s[: /* ERROR "2nd index required" */ :  /* ERROR "3rd index required" */ ]
+       _ = s[:10:10]
+       _ = s[10:0:10] /* ERROR "invalid slice indices" */
+       _ = s[0:10:0] /* ERROR "invalid slice indices" */
+       _ = s[10:0:0] /* ERROR "invalid slice indices" */
+       _ = &s /* ERROR "cannot take address" */ [:10]
+
+       var m map[string]int
+       _ = m[0 /* ERROR "cannot convert" */ ]
+       _ = m /* ERROR "cannot slice" */ ["foo" : "bar"]
+       _ = m["foo"]
+       // ok is of type bool
+       type mybool bool
+       var ok mybool
+       _, ok = m["bar"]
+       _ = ok
+
+       var t string
+       _ = t[- /* ERROR "negative" */ 1]
+       _ = t[- /* ERROR "negative" */ 1 :]
+       _ = t[: - /* ERROR "negative" */ 1]
+       _ = t /* ERROR "3-index slice of string" */ [1:2:3]
+       _ = "foo" /* ERROR "3-index slice of string" */ [1:2:3]
+       var t0 byte
+       t0 = t[0]
+       _ = t0
+       var t1 rune
+       t1 = t /* ERROR "cannot assign" */ [2]
+       _ = t1
+       _ = ("foo" + "bar")[5]
+       _ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
+
+       const c = "foo"
+       _ = c[- /* ERROR "negative" */ 1]
+       _ = c[- /* ERROR "negative" */ 1 :]
+       _ = c[: - /* ERROR "negative" */ 1]
+       var c0 byte
+       c0 = c[0]
+       _ = c0
+       var c2 float32
+       c2 = c /* ERROR "cannot assign" */ [2]
+       _ = c[3 /* ERROR "index .* out of bounds" */ ]
+       _ = ""[0 /* ERROR "index .* out of bounds" */ ]
+       _ = c2
+
+       _ = s[1<<30] // no compile-time error here
+
+       // issue 4913
+       type mystring string
+       var ss string
+       var ms mystring
+       var i, j int
+       ss = "foo"[1:2]
+       ss = "foo"[i:j]
+       ms = "foo" /* ERROR "cannot assign" */ [1:2]
+       ms = "foo" /* ERROR "cannot assign" */ [i:j]
+       _, _ = ss, ms
+}
+
+type T struct {
+       x int
+       y func()
+}
+
+func (*T) m() {}
+
+func method_expressions() {
+       _ = T /* ERROR "no field or method" */ .a
+       _ = T /* ERROR "has no method" */ .x
+       _ = T /* ERROR "not in method set" */ .m
+       _ = (*T).m
+
+       var f func(*T) = T /* ERROR "not in method set" */ .m
+       var g func(*T) = (*T).m
+       _, _ = f, g
+
+       _ = T /* ERROR "has no method" */ .y
+       _ = ( /* ERROR "has no method" */ *T).y
+}
+
+func struct_literals() {
+       type T0 struct {
+               a, b, c int
+       }
+
+       type T1 struct {
+               T0
+               a, b int
+               u float64
+               s string
+       }
+
+       // keyed elements
+       _ = T1{}
+       _ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
+       _ = T1{aa /* ERROR "unknown field" */ : 0}
+       _ = T1{1 /* ERROR "invalid field name" */ : 0}
+       _ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
+       _ = T1{a: "foo" /* ERROR "cannot convert" */ }
+       _ = T1{c /* ERROR "unknown field" */ : 0}
+       _ = T1{T0: { /* ERROR "missing type" */ }} // struct literal element type may not be elided
+       _ = T1{T0: T0{}}
+       _ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
+
+       // unkeyed elements
+       _ = T0{1, 2, 3}
+       _ = T0{1, b /* ERROR "mixture" */ : 2, 3}
+       _ = T0{1, 2} /* ERROR "too few values" */
+       _ = T0{1, 2, 3, 4  /* ERROR "too many values" */ }
+       _ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4  /* ERROR "truncated" */}
+
+       // invalid type
+       type P *struct{
+               x int
+       }
+       _ = P /* ERROR "invalid composite literal type" */ {}
+
+       // unexported fields
+       _ = time.Time{}
+       _ = time.Time{sec /* ERROR "unknown field" */ : 0}
+       _ = time.Time{
+               0 /* ERROR implicit assignment to unexported field sec in time.Time literal */,
+               0 /* ERROR implicit assignment */ ,
+               nil /* ERROR implicit assignment */ ,
+       }
+}
+
+func array_literals() {
+       type A0 [0]int
+       _ = A0{}
+       _ = A0{0 /* ERROR "index .* out of bounds" */}
+       _ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
+
+       type A1 [10]int
+       _ = A1{}
+       _ = A1{0, 1, 2}
+       _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+       _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+       _ = A1{- /* ERROR "negative" */ 1: 0}
+       _ = A1{8: 8, 9}
+       _ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+       _ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+       _ = A1{5: 5, 6, 7, 3: 3, 4}
+       _ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+       _ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
+       _ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+       _ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+       _ = A1{2.0}
+       _ = A1{2.1 /* ERROR "truncated" */ }
+       _ = A1{"foo" /* ERROR "cannot convert" */ }
+
+       // indices must be integer constants
+       i := 1
+       const f = 2.1
+       const s = "foo"
+       _ = A1{i /* ERROR "index i must be integer constant" */ : 0}
+       _ = A1{f /* ERROR "truncated" */ : 0}
+       _ = A1{s /* ERROR "cannot convert" */ : 0}
+
+       a0 := [...]int{}
+       assert(len(a0) == 0)
+
+       a1 := [...]int{0, 1, 2}
+       assert(len(a1) == 3)
+       var a13 [3]int
+       var a14 [4]int
+       a13 = a1
+       a14 = a1 /* ERROR "cannot assign" */
+       _, _ = a13, a14
+
+       a2 := [...]int{- /* ERROR "negative" */ 1: 0}
+       _ = a2
+
+       a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+       assert(len(a3) == 5) // somewhat arbitrary
+
+       a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
+       assert(len(a4) == 1024)
+
+       // composite literal element types may be elided
+       type T []int
+       _ = [10]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+       a6 := [...]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+       assert(len(a6) == 8)
+
+       // recursively so
+       _ = [10][10]T{{}, [10]T{{}}, {{1, 2, 3}}}
+
+       // from the spec
+       type Point struct { x, y float32 }
+       _ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+       _ = [...]Point{{1.5, -3.5}, {0, 0}}
+       _ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
+       _ = [][]int{{1, 2, 3}, {4, 5}}
+       _ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+       _ = [...]*Point{{1.5, -3.5}, {0, 0}}
+}
+
+func slice_literals() {
+       type S0 []int
+       _ = S0{}
+       _ = S0{0, 1, 2}
+       _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+       _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+       _ = S0{- /* ERROR "negative" */ 1: 0}
+       _ = S0{8: 8, 9}
+       _ = S0{8: 8, 9, 10}
+       _ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+       _ = S0{5: 5, 6, 7, 3: 3, 4}
+       _ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+       _ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
+       _ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+       _ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+       _ = S0{2.0}
+       _ = S0{2.1 /* ERROR "truncated" */ }
+       _ = S0{"foo" /* ERROR "cannot convert" */ }
+
+       // indices must be resolved correctly
+       const index1 = 1
+       _ = S0{index1: 1}
+       _ = S0{index2: 2}
+       _ = S0{index3 /* ERROR "undeclared name" */ : 3}
+
+       // indices must be integer constants
+       i := 1
+       const f = 2.1
+       const s = "foo"
+       _ = S0{i /* ERROR "index i must be integer constant" */ : 0}
+       _ = S0{f /* ERROR "truncated" */ : 0}
+       _ = S0{s /* ERROR "cannot convert" */ : 0}
+
+       // composite literal element types may be elided
+       type T []int
+       _ = []T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+       _ = [][]int{{1, 2, 3}, {4, 5}}
+
+       // recursively so
+       _ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
+}
+
+const index2 int = 2
+
+type N int
+func (N) f() {}
+
+func map_literals() {
+       type M0 map[string]int
+       type M1 map[bool]int
+       type M2 map[*int]int
+
+       _ = M0{}
+       _ = M0{1 /* ERROR "missing key" */ }
+       _ = M0{1 /* ERROR "cannot convert" */ : 2}
+       _ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
+       _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
+
+       _ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1}
+       _ = map[interface{}]int{int(2): 1, int16(2): 1}
+       _ = map[interface{}]int{int16(2): 1, int16 /* ERROR "duplicate key" */ (2): 1}
+
+       type S string
+
+       _ = map[interface{}]int{"a": 1, "a" /* ERROR "duplicate key" */ : 1}
+       _ = map[interface{}]int{"a": 1, S("a"): 1}
+       _ = map[interface{}]int{S("a"): 1, S /* ERROR "duplicate key" */ ("a"): 1}
+
+       type I interface {
+               f()
+       }
+
+       _ = map[I]int{N(0): 1, N(2): 1}
+       _ = map[I]int{N(2): 1, N /* ERROR "duplicate key" */ (2): 1}
+
+       // map keys must be resolved correctly
+       key1 := "foo"
+       _ = M0{key1: 1}
+       _ = M0{key2: 2}
+       _ = M0{key3 /* ERROR "undeclared name" */ : 2}
+
+       var value int
+       _ = M1{true: 1, false: 0}
+       _ = M2{nil: 0, &value: 1}
+
+       // composite literal element types may be elided
+       type T [2]int
+       _ = map[int]T{0: T{3, 4}, 1: {5, 6}}
+
+       // recursively so
+       _ = map[int][]T{0: {}, 1: {{}, T{1, 2}}}
+
+       // composite literal key types may be elided
+       _ = map[T]int{T{3, 4}: 0, {5, 6}: 1}
+
+       // recursively so
+       _ = map[[2]T]int{{}: 0, {{}}: 1, [2]T{{}}: 2, {T{1, 2}}: 3}
+
+       // composite literal element and key types may be elided
+       _ = map[T]T{{}: {}, {1, 2}: T{3, 4}, T{4, 5}: {}}
+       _ = map[T]M0{{} : {}, T{1, 2}: M0{"foo": 0}, {1, 3}: {"foo": 1}}
+
+       // recursively so
+       _ = map[[2]T][]T{{}: {}, {{}}: {{}, T{1, 2}}, [2]T{{}}: nil, {T{1, 2}}: {{}, {}}}
+
+       // from the spec
+       type Point struct { x, y float32 }
+       _ = map[string]Point{"orig": {0, 0}}
+       _ = map[*Point]string{{0, 0}: "orig"}
+}
+
+var key2 string = "bar"
+
+type I interface {
+       m()
+}
+
+type I2 interface {
+       m(int)
+}
+
+type T1 struct{}
+type T2 struct{}
+
+func (T2) m(int) {}
+
+type mybool bool
+
+func type_asserts() {
+       var x int
+       _ = x /* ERROR "not an interface" */ .(int)
+
+       var e interface{}
+       var ok bool
+       x, ok = e.(int)
+       _ = ok
+
+       // ok value is of type bool
+       var myok mybool
+       _, myok = e.(int)
+       _ = myok
+
+       var t I
+       _ = t /* ERROR "use of .* outside type switch" */ .(type)
+       _ = t /* ERROR "missing method m" */ .(T)
+       _ = t.(*T)
+       _ = t /* ERROR "missing method m" */ .(T1)
+       _ = t /* ERROR "wrong type for method m" */ .(T2)
+       _ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561)
+
+       // e doesn't statically have an m, but may have one dynamically.
+       _ = e.(I2)
+}
+
+func f0() {}
+func f1(x int) {}
+func f2(u float32, s string) {}
+func fs(s []byte) {}
+func fv(x ...int) {}
+func fi(x ... interface{}) {}
+func (T) fm(x ...int)
+
+func g0() {}
+func g1() int { return 0}
+func g2() (u float32, s string) { return }
+func gs() []byte { return nil }
+
+func _calls() {
+       var x int
+       var y float32
+       var s []int
+
+       f0()
+       _ = f0 /* ERROR "used as value" */ ()
+       f0(g0 /* ERROR "too many arguments" */ )
+
+       f1(0)
+       f1(x)
+       f1(10.0)
+       f1() /* ERROR "too few arguments" */
+       f1(x, y /* ERROR "too many arguments" */ )
+       f1(s /* ERROR "cannot pass" */ )
+       f1(x ... /* ERROR "cannot use ..." */ )
+       f1(g0 /* ERROR "used as value" */ ())
+       f1(g1())
+       // f1(g2()) // TODO(gri) missing position in error message
+
+       f2() /* ERROR "too few arguments" */
+       f2(3.14) /* ERROR "too few arguments" */
+       f2(3.14, "foo")
+       f2(x /* ERROR "cannot pass" */ , "foo")
+       f2(g0 /* ERROR "used as value" */ ())
+       f2(g1 /* ERROR "cannot pass" */ ()) /* ERROR "too few arguments" */
+       f2(g2())
+
+       fs() /* ERROR "too few arguments" */
+       fs(g0 /* ERROR "used as value" */ ())
+       fs(g1 /* ERROR "cannot pass" */ ())
+       fs(g2 /* ERROR "cannot pass" */ /* ERROR "too many arguments" */ ())
+       fs(gs())
+
+       fv()
+       fv(1, 2.0, x)
+       fv(s /* ERROR "cannot pass" */ )
+       fv(s...)
+       fv(x /* ERROR "cannot use" */ ...)
+       fv(1, s... /* ERROR "can only use ... with matching parameter" */ )
+       fv(gs /* ERROR "cannot pass" */ ())
+       fv(gs /* ERROR "cannot pass" */ ()...)
+
+       var t T
+       t.fm()
+       t.fm(1, 2.0, x)
+       t.fm(s /* ERROR "cannot pass" */ )
+       t.fm(g1())
+       t.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+       t.fm(gs /* ERROR "cannot pass" */ ())
+       t.fm(gs /* ERROR "cannot pass" */ ()...)
+
+       T.fm(t, )
+       T.fm(t, 1, 2.0, x)
+       T.fm(t, s /* ERROR "cannot pass" */ )
+       T.fm(t, g1())
+       T.fm(t, 1, s... /* ERROR "can only use ... with matching parameter" */ )
+       T.fm(t, gs /* ERROR "cannot pass" */ ())
+       T.fm(t, gs /* ERROR "cannot pass" */ ()...)
+
+       var i interface{ fm(x ...int) } = t
+       i.fm()
+       i.fm(1, 2.0, x)
+       i.fm(s /* ERROR "cannot pass" */ )
+       i.fm(g1())
+       i.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+       i.fm(gs /* ERROR "cannot pass" */ ())
+       i.fm(gs /* ERROR "cannot pass" */ ()...)
+
+       fi()
+       fi(1, 2.0, x, 3.14, "foo")
+       fi(g2())
+       fi(0, g2)
+       fi(0, g2 /* ERROR "2-valued expression" */ ())
+}
+
+func issue6344() {
+       type T []interface{}
+       var x T
+       fi(x...) // ... applies also to named slices
+}
diff --git a/src/go/types/testdata/gotos.src b/src/go/types/testdata/gotos.src
new file mode 100644 (file)
index 0000000..0c7ee44
--- /dev/null
@@ -0,0 +1,560 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is a modified copy of $GOROOT/test/goto.go.
+
+package gotos
+
+var (
+       i, n int
+       x    []int
+       c    chan int
+       m    map[int]int
+       s    string
+)
+
+// goto after declaration okay
+func _() {
+       x := 1
+       goto L
+L:
+       _ = x
+}
+
+// goto before declaration okay
+func _() {
+       goto L
+L:
+       x := 1
+       _ = x
+}
+
+// goto across declaration not okay
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration at line 36" */
+       x := 1
+       _ = x
+L:
+}
+
+// goto across declaration in inner scope okay
+func _() {
+       goto L
+       {
+               x := 1
+               _ = x
+       }
+L:
+}
+
+// goto across declaration after inner scope not okay
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration at line 58" */
+       {
+               x := 1
+               _ = x
+       }
+       x := 1
+       _ = x
+L:
+}
+
+// goto across declaration in reverse okay
+func _() {
+L:
+       x := 1
+       _ = x
+       goto L
+}
+
+func _() {
+L: L1:
+       x := 1
+       _ = x
+       goto L
+       goto L1
+}
+
+// error shows first offending variable
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration at line 84" */
+       x := 1
+       _ = x
+       y := 1
+       _ = y
+L:
+}
+
+// goto not okay even if code path is dead
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration" */
+       x := 1
+       _ = x
+       y := 1
+       _ = y
+       return
+L:
+}
+
+// goto into outer block okay
+func _() {
+       {
+               goto L
+       }
+L:
+}
+
+func _() {
+       {
+               goto L
+               goto L1
+       }
+L: L1:
+}
+
+// goto backward into outer block okay
+func _() {
+L:
+       {
+               goto L
+       }
+}
+
+func _() {
+L: L1:
+       {
+               goto L
+               goto L1
+       }
+}
+
+// goto into inner block not okay
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       {
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       goto L1 /* ERROR "goto L1 jumps into block" */
+       {
+       L: L1:
+       }
+}
+
+// goto backward into inner block still not okay
+func _() {
+       {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       {
+       L: L1:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+       goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+// error shows first (outermost) offending block
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       {
+               {
+                       {
+                       L:
+                       }
+               }
+       }
+}
+
+// error prefers block diagnostic over declaration diagnostic
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       x := 1
+       _ = x
+       {
+       L:
+       }
+}
+
+// many kinds of blocks, all invalid to jump into or among,
+// but valid to jump out of
+
+// if
+
+func _() {
+L:
+       if true {
+               goto L
+       }
+}
+
+func _() {
+L:
+       if true {
+               goto L
+       } else {
+       }
+}
+
+func _() {
+L:
+       if false {
+       } else {
+               goto L
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       if true {
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       if true {
+       L:
+       } else {
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       if true {
+       } else {
+       L:
+       }
+}
+
+func _() {
+       if false {
+       L:
+       } else {
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else {
+       L:
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else if false {
+       L:
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else if false {
+       L:
+       } else {
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else if false {
+       } else {
+       L:
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else {
+               L:
+       }
+}
+
+func _() {
+       if true {
+               L:
+       } else {
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
+
+// for
+
+func _() {
+       for {
+               goto L
+       }
+L:
+}
+
+func _() {
+       for {
+               goto L
+       L:
+       }
+}
+
+func _() {
+       for {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for {
+               goto L
+       L1:
+       }
+L:
+       goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+func _() {
+       for i < n {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = 0; i < n; i++ {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range x {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range c {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range m {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range s {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+// switch
+
+func _() {
+L:
+       switch i {
+       case 0:
+               goto L
+       }
+}
+
+func _() {
+L:
+       switch i {
+       case 0:
+
+       default:
+               goto L
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+
+       default:
+       L:
+               goto L
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+
+       default:
+               goto L
+       L:
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+               goto L
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       switch i {
+       case 0:
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       switch i {
+       case 0:
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       switch i {
+       case 0:
+       default:
+       L:
+       }
+}
+
+func _() {
+       switch i {
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       case 0:
+       L:
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+       L:
+               ;
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
+
+// select
+// different from switch.  the statement has no implicit block around it.
+
+func _() {
+L:
+       select {
+       case <-c:
+               goto L
+       }
+}
+
+func _() {
+L:
+       select {
+       case c <- 1:
+
+       default:
+               goto L
+       }
+}
+
+func _() {
+       select {
+       case <-c:
+
+       default:
+       L:
+               goto L
+       }
+}
+
+func _() {
+       select {
+       case c <- 1:
+
+       default:
+               goto L
+       L:
+       }
+}
+
+func _() {
+       select {
+       case <-c:
+               goto L
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       select {
+       case c <- 1:
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       select {
+       case c <- 1:
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       select {
+       case <-c:
+       default:
+       L:
+       }
+}
+
+func _() {
+       select {
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       case <-c:
+       L:
+       }
+}
+
+func _() {
+       select {
+       case <-c:
+       L:
+               ;
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
diff --git a/src/go/types/testdata/importdecl0a.src b/src/go/types/testdata/importdecl0a.src
new file mode 100644 (file)
index 0000000..463dcd0
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package importdecl0
+
+import ()
+
+import (
+       // we can have multiple blank imports (was bug)
+       _ "math"
+       _ "net/rpc"
+       init /* ERROR "cannot declare init" */ "fmt"
+       // reflect defines a type "flag" which shows up in the gc export data
+       "reflect"
+       . /* ERROR "imported but not used" */ "reflect"
+)
+
+import "math" /* ERROR "imported but not used" */
+import m /* ERROR "imported but not used as m" */ "math"
+import _ "math"
+
+import (
+       "math/big" /* ERROR "imported but not used" */
+       b /* ERROR "imported but not used" */ "math/big"
+       _ "math/big"
+)
+
+import "fmt"
+import f1 "fmt"
+import f2 "fmt"
+
+// reflect.flag must not be visible in this package
+type flag int
+type _ reflect /* ERROR "not exported" */ .flag
+
+// imported package name may conflict with local objects
+type reflect /* ERROR "reflect already declared" */ int
+
+// dot-imported exported objects may conflict with local objects
+type Value /* ERROR "Value already declared through dot-import of package reflect" */ struct{}
+
+var _ = fmt.Println // use "fmt"
+
+func _() {
+       f1.Println() // use "fmt"
+}
+
+func _() {
+       _ = func() {
+               f2.Println() // use "fmt"
+       }
+}
diff --git a/src/go/types/testdata/importdecl0b.src b/src/go/types/testdata/importdecl0b.src
new file mode 100644 (file)
index 0000000..6844e70
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package importdecl0
+
+import "math"
+import m "math"
+
+import . "testing" // declares T in file scope
+import . /* ERROR "imported but not used" */ "unsafe"
+import . "fmt"     // declares Println in file scope
+
+import (
+       // TODO(gri) At the moment, 2 errors are reported because both go/parser
+       // and the type checker report it. Eventually, this test should not be
+       // done by the parser anymore.
+       "" /* ERROR invalid import path */ /* ERROR invalid import path */
+       "a!b" /* ERROR invalid import path */ /* ERROR invalid import path */
+       "abc\xffdef" /* ERROR invalid import path */ /* ERROR invalid import path */
+)
+
+// using "math" in this file doesn't affect its use in other files
+const Pi0 = math.Pi
+const Pi1 = m.Pi
+
+type _ T // use "testing"
+
+func _() func() interface{} {
+       return func() interface{} {
+               return Println // use "fmt"
+       }
+}
diff --git a/src/go/types/testdata/importdecl1a.src b/src/go/types/testdata/importdecl1a.src
new file mode 100644 (file)
index 0000000..8301820
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 8969.
+
+package importdecl1
+
+import . "unsafe"
+
+var _ Pointer // use dot-imported package unsafe
diff --git a/src/go/types/testdata/importdecl1b.src b/src/go/types/testdata/importdecl1b.src
new file mode 100644 (file)
index 0000000..f24bb9a
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package importdecl1
+
+import . /* ERROR "imported but not used" */ "unsafe"
diff --git a/src/go/types/testdata/init0.src b/src/go/types/testdata/init0.src
new file mode 100644 (file)
index 0000000..ef0349c
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// initialization cycles
+
+package init0
+
+// initialization cycles (we don't know the types)
+const (
+       s0 /* ERROR initialization cycle */ = s0
+
+       x0 /* ERROR initialization cycle */ = y0
+       y0 = x0
+
+       a0 = b0
+       b0 /* ERROR initialization cycle */ = c0
+       c0 = d0
+       d0 = b0
+)
+
+var (
+       s1 /* ERROR initialization cycle */ = s1
+
+       x1 /* ERROR initialization cycle */ = y1
+       y1 = x1
+
+       a1 = b1
+       b1 /* ERROR initialization cycle */ = c1
+       c1 = d1
+       d1 = b1
+)
+
+// initialization cycles (we know the types)
+const (
+       s2 /* ERROR initialization cycle */ int = s2
+
+       x2 /* ERROR initialization cycle */ int = y2
+       y2 = x2
+
+       a2 = b2
+       b2 /* ERROR initialization cycle */ int = c2
+       c2 = d2
+       d2 = b2
+)
+
+var (
+       s3 /* ERROR initialization cycle */ int = s3
+
+       x3 /* ERROR initialization cycle */ int = y3
+       y3 = x3
+
+       a3 = b3
+       b3 /* ERROR initialization cycle */ int = c3
+       c3 = d3
+       d3 = b3
+)
+
+// cycles via struct fields
+
+type S1 struct {
+       f int
+}
+const cx3 S1 /* ERROR invalid constant type */ = S1{cx3.f}
+var vx3 /* ERROR initialization cycle */ S1 = S1{vx3.f}
+
+// cycles via functions
+
+var x4 = x5
+var x5 /* ERROR initialization cycle */ = f1()
+func f1() int { return x5*10 }
+
+var x6, x7 /* ERROR initialization cycle */ = f2()
+var x8 = x7
+func f2() (int, int) { return f3() + f3(), 0 }
+func f3() int { return x8 }
+
+// cycles via closures
+
+var x9 /* ERROR initialization cycle */ = func() int { return x9 }()
+
+var x10 /* ERROR initialization cycle */ = f4()
+
+func f4() int {
+       _ = func() {
+               _ = x10
+       }
+       return 0
+}
+
+// cycles via method expressions
+
+type T1 struct{}
+
+func (T1) m() bool { _ = x11; return false }
+
+var x11 /* ERROR initialization cycle */ = T1.m(T1{})
+
+// cycles via method values
+
+type T2 struct{}
+
+func (T2) m() bool { _ = x12; return false }
+
+var t1 T2
+var x12 /* ERROR initialization cycle */ = t1.m
diff --git a/src/go/types/testdata/init1.src b/src/go/types/testdata/init1.src
new file mode 100644 (file)
index 0000000..39ca314
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// initialization cycles
+
+package init1
+
+// issue 6683 (marked as WorkingAsIntended)
+
+type T0 struct{}
+
+func (T0) m() int { return y0 }
+
+var x0 = T0{}
+
+var y0 /* ERROR initialization cycle */ = x0.m()
+
+type T1 struct{}
+
+func (T1) m() int { return y1 }
+
+var x1 interface {
+       m() int
+} = T1{}
+
+var y1 = x1.m() // no cycle reported, x1 is of interface type
+
+// issue 6703 (modified)
+
+var x2 /* ERROR initialization cycle */ = T2.m
+
+var y2 = x2
+
+type T2 struct{}
+
+func (T2) m() int {
+       _ = y2
+       return 0
+}
+
+var x3 /* ERROR initialization cycle */ = T3.m(T3{}) // <<<< added (T3{})
+
+var y3 = x3
+
+type T3 struct{}
+
+func (T3) m() int {
+       _ = y3
+       return 0
+}
+
+var x4 /* ERROR initialization cycle */ = T4{}.m // <<<< added {}
+
+var y4 = x4
+
+type T4 struct{}
+
+func (T4) m() int {
+       _ = y4
+       return 0
+}
+
+var x5 /* ERROR initialization cycle */ = T5{}.m() // <<<< added ()
+
+var y5 = x5
+
+type T5 struct{}
+
+func (T5) m() int {
+       _ = y5
+       return 0
+}
+
+// issue 4847
+// simplified test case
+
+var x6 = f6
+var y6 /* ERROR initialization cycle */ = f6
+func f6() { _ = y6 }
+
+// full test case
+
+type (
+      E int
+      S int
+)
+
+type matcher func(s *S) E
+
+func matchList(s *S) E { return matcher(matchAnyFn)(s) }
+
+var foo = matcher(matchList)
+
+var matchAny /* ERROR initialization cycle */ = matcher(matchList)
+
+func matchAnyFn(s *S) (err E) { return matchAny(s) }
\ No newline at end of file
diff --git a/src/go/types/testdata/init2.src b/src/go/types/testdata/init2.src
new file mode 100644 (file)
index 0000000..614db6c
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// initialization cycles
+
+package init2
+
+// cycles through functions
+
+func f1() int { _ = x1; return 0 }
+var x1 /* ERROR initialization cycle */ = f1
+
+func f2() int { _ = x2; return 0 }
+var x2 /* ERROR initialization cycle */ = f2()
+
+// cycles through method expressions
+
+type T3 int
+func (T3) m() int { _ = x3; return 0 }
+var x3 /* ERROR initialization cycle */ = T3.m
+
+type T4 int
+func (T4) m() int { _ = x4; return 0 }
+var x4 /* ERROR initialization cycle */ = T4.m(0)
+
+type T3p int
+func (*T3p) m() int { _ = x3p; return 0 }
+var x3p /* ERROR initialization cycle */ = (*T3p).m
+
+type T4p int
+func (*T4p) m() int { _ = x4p; return 0 }
+var x4p /* ERROR initialization cycle */ = (*T4p).m(nil)
+
+// cycles through method expressions of embedded methods
+
+type T5 struct { E5 }
+type E5 int
+func (E5) m() int { _ = x5; return 0 }
+var x5 /* ERROR initialization cycle */ = T5.m
+
+type T6 struct { E6 }
+type E6 int
+func (E6) m() int { _ = x6; return 0 }
+var x6 /* ERROR initialization cycle */ = T6.m(T6{0})
+
+type T5p struct { E5p }
+type E5p int
+func (*E5p) m() int { _ = x5p; return 0 }
+var x5p /* ERROR initialization cycle */ = (*T5p).m
+
+type T6p struct { E6p }
+type E6p int
+func (*E6p) m() int { _ = x6p; return 0 }
+var x6p /* ERROR initialization cycle */ = (*T6p).m(nil)
+
+// cycles through method values
+
+type T7 int
+func (T7) m() int { _ = x7; return 0 }
+var x7 /* ERROR initialization cycle */ = T7(0).m
+
+type T8 int
+func (T8) m() int { _ = x8; return 0 }
+var x8 /* ERROR initialization cycle */ = T8(0).m()
+
+type T7p int
+func (*T7p) m() int { _ = x7p; return 0 }
+var x7p /* ERROR initialization cycle */ = new(T7p).m
+
+type T8p int
+func (*T8p) m() int { _ = x8p; return 0 }
+var x8p /* ERROR initialization cycle */ = new(T8p).m()
+
+type T7v int
+func (T7v) m() int { _ = x7v; return 0 }
+var x7var T7v
+var x7v /* ERROR initialization cycle */ = x7var.m
+
+type T8v int
+func (T8v) m() int { _ = x8v; return 0 }
+var x8var T8v
+var x8v /* ERROR initialization cycle */ = x8var.m()
+
+type T7pv int
+func (*T7pv) m() int { _ = x7pv; return 0 }
+var x7pvar *T7pv
+var x7pv /* ERROR initialization cycle */ = x7pvar.m
+
+type T8pv int
+func (*T8pv) m() int { _ = x8pv; return 0 }
+var x8pvar *T8pv
+var x8pv /* ERROR initialization cycle */ = x8pvar.m()
+
+// cycles through method values of embedded methods
+
+type T9 struct { E9 }
+type E9 int
+func (E9) m() int { _ = x9; return 0 }
+var x9 /* ERROR initialization cycle */ = T9{0}.m
+
+type T10 struct { E10 }
+type E10 int
+func (E10) m() int { _ = x10; return 0 }
+var x10 /* ERROR initialization cycle */ = T10{0}.m()
+
+type T9p struct { E9p }
+type E9p int
+func (*E9p) m() int { _ = x9p; return 0 }
+var x9p /* ERROR initialization cycle */ = new(T9p).m
+
+type T10p struct { E10p }
+type E10p int
+func (*E10p) m() int { _ = x10p; return 0 }
+var x10p /* ERROR initialization cycle */ = new(T10p).m()
+
+type T9v struct { E9v }
+type E9v int
+func (E9v) m() int { _ = x9v; return 0 }
+var x9var T9v
+var x9v /* ERROR initialization cycle */ = x9var.m
+
+type T10v struct { E10v }
+type E10v int
+func (E10v) m() int { _ = x10v; return 0 }
+var x10var T10v
+var x10v /* ERROR initialization cycle */ = x10var.m()
+
+type T9pv struct { E9pv }
+type E9pv int
+func (*E9pv) m() int { _ = x9pv; return 0 }
+var x9pvar *T9pv
+var x9pv /* ERROR initialization cycle */ = x9pvar.m
+
+type T10pv struct { E10pv }
+type E10pv int
+func (*E10pv) m() int { _ = x10pv; return 0 }
+var x10pvar *T10pv
+var x10pv /* ERROR initialization cycle */ = x10pvar.m()
diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
new file mode 100644 (file)
index 0000000..d08e0fd
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issues
+
+import "fmt"
+
+func issue7035() {
+       type T struct{ X int }
+       _ = func() {
+               fmt.Println() // must refer to imported fmt rather than the fmt below
+       }
+       fmt := new(T)
+       _ = fmt.X
+}
+
+func issue8066() {
+       const (
+               // TODO(gri) Enable test below for releases 1.4 and higher
+               // _ = float32(340282356779733661637539395458142568447)
+               _ = float32(340282356779733661637539395458142568448 /* ERROR cannot convert */ )
+       )
+}
+
+// Check that a missing identifier doesn't lead to a spurious error cascade.
+func issue8799a() {
+       x, ok := missing /* ERROR undeclared */ ()
+       _ = !ok
+       _ = x
+}
+
+func issue8799b(x int, ok bool) {
+       x, ok = missing /* ERROR undeclared */ ()
+       _ = !ok
+       _ = x
+}
+
+func issue9182() {
+       type Point C /* ERROR undeclared */ .Point
+       // no error for composite literal based on unknown type
+       _ = Point{x: 1, y: 2}
+}
+
+func f0() (a []int)         { return }
+func f1() (a []int, b int)  { return }
+func f2() (a, b []int)      { return }
+
+func append_([]int, ...int) {}
+
+func issue9473(a []int, b ...int) {
+       // variadic builtin function
+       _ = append(f0())
+       _ = append(f0(), f0()...)
+       _ = append(f1())
+       _ = append(f2 /* ERROR cannot pass argument */ ())
+       _ = append(f2()... /* ERROR cannot use ... */ )
+       _ = append(f0(), f1 /* ERROR 2-valued expression */ ())
+       _ = append(f0(), f2 /* ERROR 2-valued expression */ ())
+       _ = append(f0(), f1()... /* ERROR cannot use ... */ )
+       _ = append(f0(), f2()... /* ERROR cannot use ... */ )
+
+       // variadic user-defined function
+       append_(f0())
+       append_(f0(), f0()...)
+       append_(f1())
+       append_(f2 /* ERROR cannot pass argument */ ())
+       append_(f2()... /* ERROR cannot use ... */ )
+       append_(f0(), f1 /* ERROR 2-valued expression */ ())
+       append_(f0(), f2 /* ERROR 2-valued expression */ ())
+       append_(f0(), f1()... /* ERROR cannot use */ )
+       append_(f0(), f2()... /* ERROR cannot use */ )
+}
diff --git a/src/go/types/testdata/labels.src b/src/go/types/testdata/labels.src
new file mode 100644 (file)
index 0000000..102ffc7
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is a modified concatenation of the files
+// $GOROOT/test/label.go and $GOROOT/test/label1.go.
+
+package labels
+
+var x int
+
+func f0() {
+L1 /* ERROR "label L1 declared but not used" */ :
+       for {
+       }
+L2 /* ERROR "label L2 declared but not used" */ :
+       select {
+       }
+L3 /* ERROR "label L3 declared but not used" */ :
+       switch {
+       }
+L4 /* ERROR "label L4 declared but not used" */ :
+       if true {
+       }
+L5 /* ERROR "label L5 declared but not used" */ :
+       f0()
+L6:
+       f0()
+L6 /* ERROR "label L6 already declared" */ :
+       f0()
+       if x == 20 {
+               goto L6
+       }
+
+L7:
+       for {
+               break L7
+               break L8 /* ERROR "invalid break label L8" */
+       }
+
+// A label must be directly associated with a switch, select, or
+// for statement; it cannot be the label of a labeled statement.
+
+L7a /* ERROR "declared but not used" */ : L7b:
+       for {
+               break L7a /* ERROR "invalid break label L7a" */
+               continue L7a /* ERROR "invalid continue label L7a" */
+               continue L7b
+       }
+
+L8:
+       for {
+               if x == 21 {
+                       continue L8
+                       continue L7 /* ERROR "invalid continue label L7" */
+               }
+       }
+
+L9:
+       switch {
+       case true:
+               break L9
+       defalt /* ERROR "label defalt declared but not used" */ :
+       }
+
+L10:
+       select {
+       default:
+               break L10
+               break L9 /* ERROR "invalid break label L9" */
+       }
+
+       goto L10a
+L10a: L10b:
+       select {
+       default:
+               break L10a /* ERROR "invalid break label L10a" */
+               break L10b
+               continue L10b /* ERROR "invalid continue label L10b" */
+       }
+}
+
+func f1() {
+L1:
+       for {
+               if x == 0 {
+                       break L1
+               }
+               if x == 1 {
+                       continue L1
+               }
+               goto L1
+       }
+
+L2:
+       select {
+       default:
+               if x == 0 {
+                       break L2
+               }
+               if x == 1 {
+                       continue L2 /* ERROR "invalid continue label L2" */
+               }
+               goto L2
+       }
+
+L3:
+       switch {
+       case x > 10:
+               if x == 11 {
+                       break L3
+               }
+               if x == 12 {
+                       continue L3 /* ERROR "invalid continue label L3" */
+               }
+               goto L3
+       }
+
+L4:
+       if true {
+               if x == 13 {
+                       break L4 /* ERROR "invalid break label L4" */
+               }
+               if x == 14 {
+                       continue L4 /* ERROR "invalid continue label L4" */
+               }
+               if x == 15 {
+                       goto L4
+               }
+       }
+
+L5:
+       f1()
+       if x == 16 {
+               break L5 /* ERROR "invalid break label L5" */
+       }
+       if x == 17 {
+               continue L5 /* ERROR "invalid continue label L5" */
+       }
+       if x == 18 {
+               goto L5
+       }
+
+       for {
+               if x == 19 {
+                       break L1 /* ERROR "invalid break label L1" */
+               }
+               if x == 20 {
+                       continue L1 /* ERROR "invalid continue label L1" */
+               }
+               if x == 21 {
+                       goto L1
+               }
+       }
+}
+
+// Additional tests not in the original files.
+
+func f2() {
+L1 /* ERROR "label L1 declared but not used" */ :
+       if x == 0 {
+               for {
+                       continue L1 /* ERROR "invalid continue label L1" */
+               }
+       }
+}
+
+func f3() {
+L1:
+L2:
+L3:
+       for {
+               break L1 /* ERROR "invalid break label L1" */
+               break L2 /* ERROR "invalid break label L2" */
+               break L3
+               continue L1 /* ERROR "invalid continue label L1" */
+               continue L2 /* ERROR "invalid continue label L2" */
+               continue L3
+               goto L1
+               goto L2
+               goto L3
+       }
+}
+
+// Blank labels are never declared.
+
+func f4() {
+_:
+_: // multiple blank labels are ok
+       goto _ /* ERROR "label _ not declared" */
+}
+
+func f5() {
+_:
+       for {
+               break _ /* ERROR "invalid break label _" */
+               continue _ /* ERROR "invalid continue label _" */
+       }
+}
+
+func f6() {
+_:
+       switch {
+       default:
+               break _ /* ERROR "invalid break label _" */
+       }
+}
diff --git a/src/go/types/testdata/methodsets.src b/src/go/types/testdata/methodsets.src
new file mode 100644 (file)
index 0000000..8921146
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package methodsets
+
+type T0 struct {}
+
+func (T0) v0() {}
+func (*T0) p0() {}
+
+type T1 struct {} // like T0 with different method names
+
+func (T1) v1() {}
+func (*T1) p1() {}
+
+type T2 interface {
+       v2()
+       p2()
+}
+
+type T3 struct {
+       T0
+       *T1
+       T2
+}
+
+// Method expressions
+func _() {
+       var (
+               _ func(T0) = T0.v0
+               _ = T0 /* ERROR "not in method set" */ .p0
+
+               _ func (*T0) = (*T0).v0
+               _ func (*T0) = (*T0).p0
+
+               // T1 is like T0
+
+               _ func(T2) = T2.v2
+               _ func(T2) = T2.p2
+
+               _ func(T3) = T3.v0
+               _ func(T3) = T3 /* ERROR "not in method set" */ .p0
+               _ func(T3) = T3.v1
+               _ func(T3) = T3.p1
+               _ func(T3) = T3.v2
+               _ func(T3) = T3.p2
+
+               _ func(*T3) = (*T3).v0
+               _ func(*T3) = (*T3).p0
+               _ func(*T3) = (*T3).v1
+               _ func(*T3) = (*T3).p1
+               _ func(*T3) = (*T3).v2
+               _ func(*T3) = (*T3).p2
+       )
+}
+
+// Method values with addressable receivers
+func _() {
+       var (
+               v0 T0
+               _ func() = v0.v0
+               _ func() = v0.p0
+       )
+
+       var (
+               p0 *T0
+               _ func() = p0.v0
+               _ func() = p0.p0
+       )
+
+       // T1 is like T0
+
+       var (
+               v2 T2
+               _ func() = v2.v2
+               _ func() = v2.p2
+       )
+
+       var (
+               v4 T3
+               _ func() = v4.v0
+               _ func() = v4.p0
+               _ func() = v4.v1
+               _ func() = v4.p1
+               _ func() = v4.v2
+               _ func() = v4.p2
+       )
+
+       var (
+               p4 *T3
+               _ func() = p4.v0
+               _ func() = p4.p0
+               _ func() = p4.v1
+               _ func() = p4.p1
+               _ func() = p4.v2
+               _ func() = p4.p2
+       )
+}
+
+// Method calls with addressable receivers
+func _() {
+       var v0 T0
+       v0.v0()
+       v0.p0()
+
+       var p0 *T0
+       p0.v0()
+       p0.p0()
+
+       // T1 is like T0
+
+       var v2 T2
+       v2.v2()
+       v2.p2()
+
+       var v4 T3
+       v4.v0()
+       v4.p0()
+       v4.v1()
+       v4.p1()
+       v4.v2()
+       v4.p2()
+
+       var p4 *T3
+       p4.v0()
+       p4.p0()
+       p4.v1()
+       p4.p1()
+       p4.v2()
+       p4.p2()
+}
+
+// Method values with value receivers
+func _() {
+       var (
+               _ func() = T0{}.v0
+               _ func() = T0 /* ERROR "not in method set" */ {}.p0
+
+               _ func() = (&T0{}).v0
+               _ func() = (&T0{}).p0
+
+               // T1 is like T0
+
+               // no values for T2
+
+               _ func() = T3{}.v0
+               _ func() = T3 /* ERROR "not in method set" */ {}.p0
+               _ func() = T3{}.v1
+               _ func() = T3{}.p1
+               _ func() = T3{}.v2
+               _ func() = T3{}.p2
+
+               _ func() = (&T3{}).v0
+               _ func() = (&T3{}).p0
+               _ func() = (&T3{}).v1
+               _ func() = (&T3{}).p1
+               _ func() = (&T3{}).v2
+               _ func() = (&T3{}).p2
+       )
+}
+
+// Method calls with value receivers
+func _() {
+       T0{}.v0()
+       T0 /* ERROR "not in method set" */ {}.p0()
+
+       (&T0{}).v0()
+       (&T0{}).p0()
+
+       // T1 is like T0
+
+       // no values for T2
+
+       T3{}.v0()
+       T3 /* ERROR "not in method set" */ {}.p0()
+       T3{}.v1()
+       T3{}.p1()
+       T3{}.v2()
+       T3{}.p2()
+
+       (&T3{}).v0()
+       (&T3{}).p0()
+       (&T3{}).v1()
+       (&T3{}).p1()
+       (&T3{}).v2()
+       (&T3{}).p2()
+}
+
+// *T has no methods if T is an interface type
+func issue5918() {
+       var (
+               err error
+               _ = err.Error()
+               _ func() string = err.Error
+               _ func(error) string = error.Error
+
+               perr = &err
+               _ = perr /* ERROR "no field or method" */ .Error()
+               _ func() string = perr /* ERROR "no field or method" */ .Error
+               _ func(*error) string = ( /* ERROR "no field or method" */ *error).Error
+       )
+
+       type T *interface{ m() int }
+       var (
+               x T
+               _ = (*x).m()
+               _ = (*x).m
+
+               _ = x /* ERROR "no field or method" */ .m()
+               _ = x /* ERROR "no field or method" */ .m
+               _ = T /* ERROR "no field or method" */ .m
+       )
+}
diff --git a/src/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src
new file mode 100644 (file)
index 0000000..7f8ed06
--- /dev/null
@@ -0,0 +1,321 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package shifts
+
+func shifts0() {
+       // basic constant shifts
+       const (
+               s = 10
+               _ = 0<<0
+               _ = 1<<s
+               _ = 1<<- /* ERROR "stupid shift" */ 1
+               _ = 1<<1075 /* ERROR "stupid shift" */
+               _ = 2.0<<1
+
+               _ int = 2<<s
+               _ float32 = 2<<s
+               _ complex64 = 2<<s
+
+               _ int = 2.0<<s
+               _ float32 = 2.0<<s
+               _ complex64 = 2.0<<s
+
+               _ int = 'a'<<s
+               _ float32 = 'a'<<s
+               _ complex64 = 'a'<<s
+       )
+}
+
+func shifts1() {
+       // basic non-constant shifts
+       var (
+               i int
+               u uint
+
+               _ = 1<<0
+               _ = 1<<i /* ERROR "must be unsigned" */
+               _ = 1<<u
+               _ = 1<<"foo" /* ERROR "cannot convert" */
+               _ = i<<0
+               _ = i<<- /* ERROR "must not be negative" */ 1
+               _ = 1 /* ERROR "overflows" */ <<100
+
+               _ uint = 1 << 0
+               _ uint = 1 << u
+               _ float32 = 1 /* ERROR "must be integer" */ << u
+       )
+}
+
+func shifts2() {
+       // from the spec
+       var (
+               s uint = 33
+               i = 1<<s           // 1 has type int
+               j int32 = 1<<s     // 1 has type int32; j == 0
+               k = uint64(1<<s)   // 1 has type uint64; k == 1<<33
+               m int = 1.0<<s     // 1.0 has type int
+               n = 1.0<<s != i    // 1.0 has type int; n == false if ints are 32bits in size
+               o = 1<<s == 2<<s   // 1 and 2 have type int; o == true if ints are 32bits in size
+               p = 1<<s == 1<<33  // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
+               u = 1.0 /* ERROR "must be integer" */ <<s         // illegal: 1.0 has type float64, cannot shift
+               u1 = 1.0 /* ERROR "must be integer" */ <<s != 0   // illegal: 1.0 has type float64, cannot shift
+               u2 = 1 /* ERROR "must be integer" */ <<s != 1.0   // illegal: 1 has type float64, cannot shift
+               v float32 = 1 /* ERROR "must be integer" */ <<s   // illegal: 1 has type float32, cannot shift
+               w int64 = 1.0<<33  // 1.0<<33 is a constant shift expression
+       )
+       _, _, _, _, _, _, _, _, _, _, _, _ = i, j, k, m, n, o, p, u, u1, u2, v, w
+}
+
+func shifts3(a int16, b float32) {
+       // random tests
+       var (
+               s uint = 11
+               u = 1 /* ERROR "must be integer" */ <<s + 1.0
+               v complex128 = 1 /* ERROR "must be integer" */ << s + 1.0 /* ERROR "must be integer" */ << s + 1
+       )
+       x := 1.0 /* ERROR "must be integer" */ <<s + 1
+       shifts3(1.0 << s, 1 /* ERROR "must be integer" */ >> s)
+       _, _, _ = u, v, x
+}
+
+func shifts4() {
+       // shifts in comparisons w/ untyped operands
+       var s uint
+
+       _ = 1<<s == 1
+       _ = 1 /* ERROR "integer" */ <<s == 1.
+       _ = 1. /* ERROR "integer" */ <<s == 1
+       _ = 1. /* ERROR "integer" */ <<s == 1.
+
+       _ = 1<<s + 1 == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1 == 1.
+       _ = 1 /* ERROR "integer" */ <<s + 1. == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1. == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1 == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1 == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1. == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1. == 1.
+
+       _ = 1<<s == 1<<s
+       _ = 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+
+       _ = 1<<s + 1<<s == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+
+       _ = 1<<s + 1<<s == 1<<s + 1<<s
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+}
+
+func shifts5() {
+       // shifts in comparisons w/ typed operands
+       var s uint
+       var x int
+
+       _ = 1<<s == x
+       _ = 1.<<s == x
+       _ = 1.1 /* ERROR "int" */ <<s == x
+
+       _ = 1<<s + x == 1
+       _ = 1<<s + x == 1.
+       _ = 1<<s + x == 1.1 /* ERROR "int" */
+       _ = 1.<<s + x == 1
+       _ = 1.<<s + x == 1.
+       _ = 1.<<s + x == 1.1 /* ERROR "int" */
+       _ = 1.1 /* ERROR "int" */ <<s + x == 1
+       _ = 1.1 /* ERROR "int" */ <<s + x == 1.
+       _ = 1.1 /* ERROR "int" */ <<s + x == 1.1
+
+       _ = 1<<s == x<<s
+       _ = 1.<<s == x<<s
+       _ = 1.1  /* ERROR "int" */ <<s == x<<s
+}
+
+func shifts6() {
+       // shifts as operands in non-arithmetic operations and as arguments
+       var a [10]int
+       var s uint
+
+       _ = a[1<<s]
+       _ = a[1.0]
+       _ = a[1.0<<s]
+
+       _ = make([]int, 1.0)
+       _ = make([]int, 1.0<<s)
+       _ = make([]int, 1.1 /* ERROR "must be integer" */ <<s)
+
+       _ = float32(1)
+       _ = float32(1 /* ERROR "must be integer" */ <<s)
+       _ = float32(1.0)
+       _ = float32(1.0 /* ERROR "must be integer" */ <<s)
+       _ = float32(1.1 /* ERROR "must be integer" */ <<s)
+
+       var b []int
+       _ = append(b, 1<<s)
+       _ = append(b, 1.0<<s)
+       _ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+       _ = append(b, 1<<s)
+       _ = append(b, 1.0<<s) // should fail - see TODO in append code
+       _ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+       _ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
+       _ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
+       _ = complex(0, 1.0 /* ERROR "must be integer" */ <<s)
+       _ = complex(0, 1.1 /* ERROR "must be integer" */ <<s)
+
+       // TODO(gri) The delete below is not type-checked correctly yet.
+       // var m1 map[int]string
+       // delete(m1, 1<<s)
+}
+
+func shifts7() {
+       // shifts of shifts
+       var s uint
+       var x int
+       _ = x
+
+       _ = 1<<(1<<s)
+       _ = 1<<(1.<<s)
+       _ = 1. /* ERROR "integer" */ <<(1<<s)
+       _ = 1. /* ERROR "integer" */ <<(1.<<s)
+
+       x = 1<<(1<<s)
+       x = 1<<(1.<<s)
+       x = 1.<<(1<<s)
+       x = 1.<<(1.<<s)
+
+       _ = (1<<s)<<(1<<s)
+       _ = (1<<s)<<(1.<<s)
+       _ = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+       _ = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+
+       x = (1<<s)<<(1<<s)
+       x = (1<<s)<<(1.<<s)
+       x = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+       x = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+}
+
+func shifts8() {
+       // shift examples from shift discussion: better error messages
+       var s uint
+       _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1
+       _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1.0
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s == 1.0
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.0 == 1
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.1 == 1
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1 == 1.0
+
+       // additional cases
+       _ = complex(1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s, 1)
+       _ = complex(1.0, 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s)
+
+       _ = int(1.<<s)
+       _ = int(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+       _ = float32(1 /* ERROR "shifted operand .* must be integer" */ <<s)
+       _ = float32(1. /* ERROR "shifted operand .* must be integer" */ <<s)
+       _ = float32(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+       // TODO(gri) the error messages for these two are incorrect - disabled for now
+       // _ = complex64(1<<s)
+       // _ = complex64(1.<<s)
+       _ = complex64(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+}
+
+func shifts9() {
+       // various originally failing snippets of code from the std library
+       // from src/compress/lzw/reader.go:90
+       {
+               var d struct {
+                       bits     uint32
+                       width    uint
+               }
+               _ = uint16(d.bits & (1<<d.width - 1))
+       }
+
+       // from src/debug/dwarf/buf.go:116
+       {
+               var ux uint64
+               var bits uint
+               x := int64(ux)
+               if x&(1<<(bits-1)) != 0 {}
+       }
+
+       // from src/encoding/asn1/asn1.go:160
+       {
+               var bytes []byte
+               if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
+       }
+
+       // from src/math/big/rat.go:140
+       {
+               var exp int
+               var mantissa uint64
+               shift := uint64(-1022 - (exp - 1)) // [1..53)
+               _ = mantissa & (1<<shift - 1)
+       }
+
+       // from src/net/interface.go:51
+       {
+               type Flags uint
+               var f Flags
+               var i int
+               if f&(1<<uint(i)) != 0 {}
+       }
+
+       // from src/runtime/softfloat64.go:234
+       {
+               var gm uint64
+               var shift uint
+               _ = gm & (1<<shift - 1)
+       }
+
+       // from src/strconv/atof.go:326
+       {
+               var mant uint64
+               var mantbits uint
+               if mant == 2<<mantbits {}
+       }
+
+       // from src/route_bsd.go:82
+       {
+               var Addrs int32
+               const rtaRtMask = 1
+               var i uint
+               if Addrs&rtaRtMask&(1<<i) == 0 {}
+       }
+
+       // from src/text/scanner/scanner.go:540
+       {
+               var s struct { Whitespace uint64 }
+               var ch rune
+               for s.Whitespace&(1<<uint(ch)) != 0 {}
+       }
+}
+
+func issue5895() {
+       var x = 'a' << 1 // type of x must be rune
+       var _ rune = x
+}
diff --git a/src/go/types/testdata/stmt0.src b/src/go/types/testdata/stmt0.src
new file mode 100644 (file)
index 0000000..fd1ddba
--- /dev/null
@@ -0,0 +1,833 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// statements
+
+package stmt0
+
+func assignments0() (int, int) {
+       var a, b, c int
+       var ch chan int
+       f0 := func() {}
+       f1 := func() int { return 1 }
+       f2 := func() (int, int) { return 1, 2 }
+       f3 := func() (int, int, int) { return 1, 2, 3 }
+
+       a, b, c = 1, 2, 3
+       a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2
+       a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2, 3, 4
+       _, _, _ = a, b, c
+
+       a = f0 /* ERROR "used as value" */ ()
+       a = f1()
+       a = f2 /* ERROR "assignment count mismatch" */ ()
+       a, b = f2()
+       a, b, c = f2 /* ERROR "assignment count mismatch" */ ()
+       a, b, c = f3()
+       a, b = f3 /* ERROR "assignment count mismatch" */ ()
+
+       a, b, c = <- /* ERROR "assignment count mismatch" */ ch
+
+       return /* ERROR "wrong number of return values" */
+       return /* ERROR "wrong number of return values" */ 1
+       return 1, 2
+       return /* ERROR "wrong number of return values" */ 1, 2, 3
+}
+
+func assignments1() {
+       b, i, f, c, s := false, 1, 1.0, 1i, "foo"
+       b = i /* ERROR "cannot assign" */
+       i = f /* ERROR "cannot assign" */
+       f = c /* ERROR "cannot assign" */
+       c = s /* ERROR "cannot assign" */
+       s = b /* ERROR "cannot assign" */
+
+       v0, v1, v2 := 1 /* ERROR "mismatch" */ , 2, 3, 4
+       _, _, _ = v0, v1, v2
+
+       b = true
+
+       i += 1
+       i += "foo" /* ERROR "cannot convert.*int" */
+
+       f -= 1
+       f /= 0
+       f = float32(0)/0 /* ERROR "division by zero" */
+       f -= "foo" /* ERROR "cannot convert.*float64" */
+
+       c *= 1
+       c /= 0
+
+       s += "bar"
+       s += 1 /* ERROR "cannot convert.*string" */
+
+       var u64 uint64
+       u64 += 1<<u64
+
+       undeclared /* ERROR "undeclared" */ = 991
+
+       // test cases for issue 5800
+       var (
+               _ int = nil /* ERROR "untyped nil value" */
+               _ [10]int = nil /* ERROR "untyped nil value" */
+               _ []byte = nil
+               _ struct{} = nil /* ERROR "untyped nil value" */
+               _ func() = nil
+               _ map[int]string = nil
+               _ chan int = nil
+       )
+
+       // test cases for issue 5500
+       _ = func() (int, bool) {
+               var m map[int]int
+               return /* ERROR "wrong number of return values" */ m[0]
+       }
+
+       g := func(int, bool){}
+       var m map[int]int
+       g(m[0]) /* ERROR "too few arguments" */
+
+       // assignments to _
+       _ = nil /* ERROR "use of untyped nil" */
+       _ = 1 /* ERROR overflow */ <<1000
+       (_) = 0
+}
+
+func assignments2() {
+       type mybool bool
+       var m map[string][]bool
+       var s []bool
+       var b bool
+       var d mybool
+       _ = s
+       _ = b
+       _ = d
+
+       // assignments to map index expressions are ok
+       s, b = m["foo"]
+       _, d = m["bar"]
+       m["foo"] = nil
+       m["foo"] = nil /* ERROR assignment count mismatch */ , false
+       _ = append(m["foo"])
+       _ = append(m["foo"], true)
+
+       var c chan int
+       _, b = <-c
+       _, d = <-c
+       <- /* ERROR cannot assign */ c = 0
+       <-c = 0 /* ERROR assignment count mismatch */ , false
+
+       var x interface{}
+       _, b = x.(int)
+       x /* ERROR cannot assign */ .(int) = 0
+       x.(int) = 0 /* ERROR assignment count mismatch */ , false
+
+       assignments2 /* ERROR used as value */ () = nil
+       int /* ERROR not an expression */ = 0
+}
+
+func issue6487() {
+       type S struct{x int}
+       _ = &S /* ERROR "cannot take address" */ {}.x
+       _ = &( /* ERROR "cannot take address" */ S{}.x)
+       _ = (&S{}).x
+       S /* ERROR "cannot assign" */ {}.x = 0
+       (&S{}).x = 0
+
+       type M map[string]S
+       var m M
+       m /* ERROR "cannot assign" */ ["foo"].x = 0
+       _ = &( /* ERROR "cannot take address" */ m["foo"].x)
+       _ = &m /* ERROR "cannot take address" */ ["foo"].x
+}
+
+func issue6766a() {
+       a, a /* ERROR redeclared */ := 1, 2
+       _ = a
+       a, b, b /* ERROR redeclared */ := 1, 2, 3
+       _ = b
+       c, c /* ERROR redeclared */, b := 1, 2, 3
+       _ = c
+       a, b := /* ERROR no new variables */ 1, 2
+}
+
+func shortVarDecls1() {
+       const c = 0
+       type d int
+       a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */  := 1, "zwei", 3.0, 4
+       var _ int = a // a is of type int
+       var _ string = b // b is of type string
+}
+
+func incdecs() {
+       const c = 3.14
+       c /* ERROR "cannot assign" */ ++
+       s := "foo"
+       s /* ERROR "cannot convert" */ --
+       3.14 /* ERROR "cannot assign" */ ++
+       var (
+               x int
+               y float32
+               z complex128
+       )
+       x++
+       y--
+       z++
+}
+
+func sends() {
+       var ch chan int
+       var rch <-chan int
+       var x int
+       x /* ERROR "cannot send" */ <- x
+       rch /* ERROR "cannot send" */ <- x
+       ch <- "foo" /* ERROR "cannot convert" */
+       ch <- x
+}
+
+func selects() {
+       select {}
+       var (
+               ch chan int
+               sc chan <- bool
+       )
+       select {
+       case <-ch:
+       case (<-ch):
+       case t := <-ch:
+               _ = t
+       case t := (<-ch):
+               _ = t
+       case t, ok := <-ch:
+               _, _ = t, ok
+       case t, ok := (<-ch):
+               _, _ = t, ok
+       case <-sc /* ERROR "cannot receive from send-only channel" */ :
+       }
+       select {
+       default:
+       default /* ERROR "multiple defaults" */ :
+       }
+       select {
+       case a, b := <-ch:
+               _, b = a, b
+       case x /* ERROR send or receive */ :
+       case a /* ERROR send or receive */ := ch:
+       }
+
+       // test for issue 9570: ch2 in second case falsely resolved to
+       // ch2 declared in body of first case
+       ch1 := make(chan int)
+       ch2 := make(chan int)
+       select {
+       case <-ch1:
+               var ch2 /* ERROR ch2 declared but not used */ chan bool
+       case i := <-ch2:
+               print(i + 1)
+       }
+}
+
+func gos() {
+       go 1 /* ERROR HERE "function must be invoked" */
+       go int /* ERROR "go requires function call, not conversion" */ (0)
+       go gos()
+       var c chan int
+       go close(c)
+       go len /* ERROR "go discards result" */ (c)
+}
+
+func defers() {
+       defer 1 /* ERROR HERE "function must be invoked" */
+       defer int /* ERROR "defer requires function call, not conversion" */ (0)
+       defer defers()
+       var c chan int
+       defer close(c)
+       defer len /* ERROR "defer discards result" */ (c)
+}
+
+func breaks() {
+       var x, y int
+
+       break /* ERROR "break" */
+       {
+               break /* ERROR "break" */
+       }
+       if x < y {
+               break /* ERROR "break" */
+       }
+
+       switch x {
+       case 0:
+               break
+       case 1:
+               if x == y {
+                       break
+               }
+       default:
+               break
+               break
+       }
+
+       var z interface{}
+       switch z.(type) {
+       case int:
+               break
+       }
+
+       for {
+               break
+       }
+
+       var a []int
+       for _ = range a {
+               break
+       }
+
+       for {
+               if x == y {
+                       break
+               }
+       }
+
+       var ch chan int
+       select {
+       case <-ch:
+               break
+       }
+
+       select {
+       case <-ch:
+               if x == y {
+                       break
+               }
+       default:
+               break
+       }
+}
+
+func continues() {
+       var x, y int
+
+       continue /* ERROR "continue" */
+       {
+               continue /* ERROR "continue" */
+       }
+
+       if x < y {
+               continue /* ERROR "continue" */
+       }
+
+       switch x {
+       case 0:
+               continue /* ERROR "continue" */
+       }
+
+       var z interface{}
+       switch z.(type) {
+       case int:
+               continue /* ERROR "continue" */
+       }
+
+       var ch chan int
+       select {
+       case <-ch:
+               continue /* ERROR "continue" */
+       }
+
+       for i := 0; i < 10; i++ {
+               continue
+               if x < y {
+                       continue
+                       break
+               }
+               switch x {
+               case y:
+                       continue
+               default:
+                       break
+               }
+               select {
+               case <-ch:
+                       continue
+               }
+       }
+
+       var a []int
+       for _ = range a {
+               continue
+               if x < y {
+                       continue
+                       break
+               }
+               switch x {
+               case y:
+                       continue
+               default:
+                       break
+               }
+               select {
+               case <-ch:
+                       continue
+               }
+       }
+}
+
+func returns0() {
+       return
+       return 0 /* ERROR no result values expected */
+}
+
+func returns1(x float64) (int, *float64) {
+       return 0, &x
+       return /* ERROR wrong number of return values */
+       return "foo" /* ERROR "cannot convert" */, x /* ERROR "cannot return" */
+       return /* ERROR wrong number of return values */ 0, &x, 1
+}
+
+func returns2() (a, b int) {
+       return
+       return 1, "foo" /* ERROR cannot convert */
+       return /* ERROR wrong number of return values */ 1, 2, 3
+       {
+               type a int
+               return 1, 2
+               return /* ERROR a not in scope at return */
+       }
+}
+
+func returns3() (_ int) {
+       return
+       {
+               var _ int // blank (_) identifiers never shadow since they are in no scope
+               return
+       }
+}
+
+func switches0() {
+       var x int
+
+       switch x {
+       }
+
+       switch x {
+       default:
+       default /* ERROR "multiple defaults" */ :
+       }
+
+       switch {
+       case 1  /* ERROR "cannot convert" */ :
+       }
+
+       true := "false"
+       _ = true
+       // A tagless switch is equivalent to the bool 
+        // constant true, not the identifier 'true'.
+       switch {
+       case "false" /* ERROR "cannot convert" */:
+       }
+
+       switch int32(x) {
+       case 1, 2:
+       case x /* ERROR "cannot compare" */ :
+       }
+
+       switch x {
+       case 1 /* ERROR "overflows" */ << 100:
+       }
+
+       switch x {
+       case 1:
+       case 1 /* DISABLED "duplicate case" */ :
+       case 2, 3, 4:
+       case 1 /* DISABLED "duplicate case" */ :
+       }
+
+       switch uint64(x) {
+       case 1 /* DISABLED duplicate case */ <<64-1:
+       case 1 /* DISABLED duplicate case */ <<64-1:
+       }
+}
+
+func switches1() {
+       fallthrough /* ERROR "fallthrough statement out of place" */
+
+       var x int
+       switch x {
+       case 0:
+               fallthrough /* ERROR "fallthrough statement out of place" */
+               break
+       case 1:
+               fallthrough
+       case 2:
+       default:
+               fallthrough
+       case 3:
+               fallthrough /* ERROR "fallthrough statement out of place" */
+       }
+
+       var y interface{}
+       switch y.(type) {
+       case int:
+               fallthrough /* ERROR "fallthrough statement out of place" */
+       default:
+       }
+
+       switch x {
+       case 0:
+               if x == 0 {
+                       fallthrough /* ERROR "fallthrough statement out of place" */
+               }
+       }
+
+       switch x {
+       case 0:
+               goto L1
+               L1: fallthrough
+       case 1:
+               goto L2
+               goto L3
+               goto L4
+               L2: L3: L4: fallthrough
+       default:
+       }
+
+       switch x {
+       case 0:
+               goto L5
+               L5: fallthrough
+       default:
+               goto L6
+               goto L7
+               goto L8
+               L6: L7: L8: fallthrough /* ERROR "fallthrough statement out of place" */
+       }
+
+       switch x {
+       case 0:
+               {
+                       fallthrough /* ERROR "fallthrough statement out of place" */
+               }
+       default:
+       }
+}
+
+type I interface {
+       m()
+}
+
+type I2 interface {
+       m(int)
+}
+
+type T struct{}
+type T1 struct{}
+type T2 struct{}
+
+func (T) m() {}
+func (T2) m(int) {}
+
+func typeswitches() {
+       var i int
+       var x interface{}
+
+       switch x.(type) {}
+       switch (x /* ERROR "outside type switch" */ .(type)) {}
+
+       switch x.(type) {
+       default:
+       default /* ERROR "multiple defaults" */ :
+       }
+
+       switch x /* ERROR "declared but not used" */ := x.(type) {}
+       switch _ /* ERROR "no new variable on left side of :=" */ := x.(type) {}
+
+       switch x := x.(type) {
+       case int:
+               var y int = x
+               _ = y
+       }
+
+       switch x := i /* ERROR "not an interface" */ .(type) {}
+
+       switch t := x.(type) {
+       case nil:
+               var v bool = t /* ERROR "cannot initialize" */
+               _ = v
+       case int:
+               var v int = t
+               _ = v
+       case float32, complex64:
+               var v float32 = t /* ERROR "cannot initialize" */
+               _ = v
+       default:
+               var v float32 = t /* ERROR "cannot initialize" */
+               _ = v
+       }
+
+       var t I
+       switch t.(type) {
+       case T:
+       case T1 /* ERROR "missing method m" */ :
+       case T2 /* ERROR "wrong type for method m" */ :
+       case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
+       }
+}
+
+// Test that each case clause uses the correct type of the variable
+// declared by the type switch (issue 5504).
+func typeswitch0() {
+       switch y := interface{}(nil).(type) {
+       case int:
+               func() int { return y + 0 }()
+       case float32:
+               func() float32 { return y }()
+       }
+}
+
+// Test correct scope setup.
+// (no redeclaration errors expected in the type switch)
+func typeswitch1() {
+       var t I
+       switch t := t; t := t.(type) {
+       case nil:
+               var _ I = t
+       case T:
+               var _ T = t
+       default:
+               var _ I = t
+       }
+}
+
+// Test correct typeswitch against interface types.
+type A interface { a() }
+type B interface { b() }
+type C interface { a(int) }
+
+func typeswitch2() {
+       switch A(nil).(type) {
+       case A:
+       case B:
+       case C /* STRICT "cannot have dynamic type" */: // only an error in strict mode (issue 8561)
+       }
+}
+
+func typeswitch3(x interface{}) {
+       switch x.(type) {
+       case int:
+       case float64:
+       case int /* ERROR duplicate case */ :
+       }
+
+       switch x.(type) {
+       case nil:
+       case int:
+       case nil /* ERROR duplicate case */ , nil /* ERROR duplicate case */ :
+       }
+
+       type F func(int)
+       switch x.(type) {
+       case nil:
+       case int, func(int):
+       case float32, func /* ERROR duplicate case */ (x int):
+       case F:
+       }
+}
+
+func fors1() {
+       for {}
+       var i string
+       _ = i
+       for i := 0; i < 10; i++ {}
+       for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
+}
+
+func rangeloops1() {
+       var (
+               x int
+               a [10]float32
+               b []string
+               p *[10]complex128
+               pp **[10]complex128
+               s string
+               m map[int]bool
+               c chan int
+               sc chan<- int
+               rc <-chan int
+       )
+
+       for range x /* ERROR "cannot range over" */ {}
+       for _ = range x /* ERROR "cannot range over" */ {}
+       for i := range x /* ERROR "cannot range over" */ {}
+
+       for range a {}
+       for i := range a {
+               var ii int
+               ii = i
+               _ = ii
+       }
+       for i, x := range a {
+               var ii int
+               ii = i
+               _ = ii
+               var xx float64
+               xx = x /* ERROR "cannot assign" */
+               _ = xx
+       }
+       var ii int
+       var xx float32
+       for ii, xx = range a {}
+       _, _ = ii, xx
+
+       for range b {}
+       for i := range b {
+               var ii int
+               ii = i
+               _ = ii
+       }
+       for i, x := range b {
+               var ii int
+               ii = i
+               _ = ii
+               var xx string
+               xx = x
+               _ = xx
+       }
+
+       for range s {}
+       for i := range s {
+               var ii int
+               ii = i
+               _ = ii
+       }
+       for i, x := range s {
+               var ii int
+               ii = i
+               _ = ii
+               var xx rune
+               xx = x
+               _ = xx
+       }
+
+       for range p {}
+       for _, x := range p {
+               var xx complex128
+               xx = x
+               _ = xx
+       }
+
+       for range pp /* ERROR "cannot range over" */ {}
+       for _, x := range pp /* ERROR "cannot range over" */ {}
+
+       for range m {}
+       for k := range m {
+               var kk int32
+               kk = k /* ERROR "cannot assign" */
+               _ = kk
+       }
+       for k, v := range m {
+               var kk int
+               kk = k
+               _ = kk
+               if v {}
+       }
+
+       for range c {}
+       for _, _ /* ERROR "only one iteration variable" */ = range c {}
+       for e := range c {
+               var ee int
+               ee = e
+               _ = ee
+       }
+       for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
+       for _ = range rc {}
+
+       // constant strings
+       const cs = "foo"
+       for range cs {}
+       for range "" {}
+       for i, x := range cs { _, _ = i, x }
+       for i, x := range "" {
+               var ii int
+               ii = i
+               _ = ii
+               var xx rune
+               xx = x
+               _ = xx
+       }
+}
+
+func rangeloops2() {
+       type I int
+       type R rune
+
+       var a [10]int
+       var i I
+       _ = i
+       for i /* ERROR cannot assign */ = range a {}
+       for i /* ERROR cannot assign */ = range &a {}
+       for i /* ERROR cannot assign */ = range a[:] {}
+
+       var s string
+       var r R
+       _ = r
+       for i /* ERROR cannot assign */ = range s {}
+       for i /* ERROR cannot assign */ = range "foo" {}
+       for _, r /* ERROR cannot assign */ = range s {}
+       for _, r /* ERROR cannot assign */ = range "foo" {}
+}
+
+func issue6766b() {
+       for _ := /* ERROR no new variables */ range "" {}
+       for a, a /* ERROR redeclared */ := range "" { _ = a }
+       var a int
+       _ = a
+       for a, a /* ERROR redeclared */ := range []int{1, 2, 3} { _ = a }
+}
+
+// Test that despite errors in the range clause,
+// the loop body is still type-checked (and thus
+// errors reported).
+func issue10148() {
+       for y /* ERROR declared but not used */ := range "" {
+               _ = "" /* ERROR cannot convert */ + 1
+       }
+       for range 1 /* ERROR cannot range over 1 */ {
+               _ = "" /* ERROR cannot convert */ + 1
+       }
+       for y := range 1 /* ERROR cannot range over 1 */ {
+               _ = "" /* ERROR cannot convert */ + 1
+       }
+}
+
+func labels0() {
+       goto L0
+       goto L1
+       L0:
+       L1:
+       L1 /* ERROR "already declared" */ :
+       if true {
+               goto L2         
+               L2:
+               L0 /* ERROR "already declared" */ :
+       }
+       _ = func() {
+               goto L0
+               goto L1
+               goto L2
+               L0:
+               L1:
+               L2:
+       }
+}
+
+func expression_statements(ch chan int) {
+       expression_statements(ch)
+       <-ch
+       println()
+
+       0 /* ERROR "not used" */
+       1 /* ERROR "not used" */ +2
+       cap /* ERROR "not used" */ (ch)
+       println /* ERROR "must be called" */
+}
diff --git a/src/go/types/testdata/stmt1.src b/src/go/types/testdata/stmt1.src
new file mode 100644 (file)
index 0000000..a2955e6
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// terminating statements
+
+package stmt1
+
+func _() {}
+
+func _() int {} /* ERROR "missing return" */
+
+func _() int { panic(0) }
+func _() int { (panic(0)) }
+
+// block statements
+func _(x, y int) (z int) {
+       {
+               return
+       }
+}
+
+func _(x, y int) (z int) {
+       {
+       }
+} /* ERROR "missing return" */
+
+// if statements
+func _(x, y int) (z int) {
+       if x < y { return }
+       return 1
+}
+
+func _(x, y int) (z int) {
+       if x < y { return }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       if x < y {
+       } else { return 1
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       if x < y { return
+       } else { return
+       }
+}
+
+// for statements
+func _(x, y int) (z int) {
+       for x < y {
+               return
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       for {
+               return
+       }
+}
+
+func _(x, y int) (z int) {
+       for {
+               return
+               break
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       for {
+               for { break }
+               return
+       }
+}
+
+func _(x, y int) (z int) {
+L:     for {
+               for { break L }
+               return
+       }
+} /* ERROR "missing return" */
+
+// switch statements
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       default: return
+       }
+}
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       case 1: break
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       default:
+               switch y {
+               case 0: break
+               }
+               panic(0)
+       }
+}
+
+func _(x, y int) (z int) {
+L:     switch x {
+       case 0: return
+       default:
+               switch y {
+               case 0: break L
+               }
+               panic(0)
+       }
+} /* ERROR "missing return" */
+
+// select statements
+func _(ch chan int) (z int) {
+       select {}
+} // nice!
+
+func _(ch chan int) (z int) {
+       select {
+       default: break
+       }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+       select {
+       case <-ch: return
+       default: break
+       }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+       select {
+       case <-ch: return
+       default:
+               for i := 0; i < 10; i++ {
+                       break
+               }
+               return
+       }
+}
+
+func _(ch chan int) (z int) {
+L:     select {
+       case <-ch: return
+       default:
+               for i := 0; i < 10; i++ {
+                       break L
+               }
+               return
+       }
+} /* ERROR "missing return" */
diff --git a/src/go/types/testdata/vardecl.src b/src/go/types/testdata/vardecl.src
new file mode 100644 (file)
index 0000000..fb6b5f7
--- /dev/null
@@ -0,0 +1,186 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vardecl
+
+// Prerequisites.
+import "math"
+func f() {}
+func g() (x, y int) { return }
+var m map[string]int
+
+// Var decls must have a type or an initializer.
+var _ int
+var _, _ int
+
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _, _
+
+// The initializer must be an expression.
+var _ = int /* ERROR "not an expression" */
+var _ = f /* ERROR "used as value" */ ()
+
+// Identifier and expression arity must match.
+var _, _ = 1, 2
+var _ = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+var _ = g /* ERROR "2-valued expr" */ ()
+var _, _ = g()
+var _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+var _ = m["foo"]
+var _, _ = m["foo"]
+var _, _, _ = m  /* ERROR "assignment count mismatch" */ ["foo"]
+
+var _, _ int = 1, 2
+var _ int = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ int = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+
+var (
+       _, _ = 1, 2
+       _ = 1, 2 /* ERROR "extra init expr 2" */
+       _, _ = 1 /* ERROR "assignment count mismatch" */
+       _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+       _ = g /* ERROR "2-valued expr" */ ()
+       _, _ = g()
+       _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+       _ = m["foo"]
+       _, _ = m["foo"]
+       _, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+
+       _, _ int = 1, 2
+       _ int = 1, 2 /* ERROR "extra init expr 2" */
+       _, _ int = 1 /* ERROR "assignment count mismatch" */
+       _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+)
+
+// Variables declared in function bodies must be 'used'.
+type T struct{}
+func (r T) _(a, b, c int) (u, v, w int) {
+       var x1 /* ERROR "declared but not used" */ int
+       var x2 /* ERROR "declared but not used" */ int
+       x1 = 1
+       (x2) = 2
+
+       y1 /* ERROR "declared but not used" */ := 1
+       y2 /* ERROR "declared but not used" */ := 2
+       y1 = 1
+       (y1) = 2
+
+       {
+               var x1 /* ERROR "declared but not used" */ int
+               var x2 /* ERROR "declared but not used" */ int
+               x1 = 1
+               (x2) = 2
+
+               y1 /* ERROR "declared but not used" */ := 1
+               y2 /* ERROR "declared but not used" */ := 2
+               y1 = 1
+               (y1) = 2
+       }
+
+       if x /* ERROR "declared but not used" */ := 0; a < b {}
+
+       switch x /* ERROR "declared but not used" */, y := 0, 1; a {
+       case 0:
+               _ = y
+       case 1:
+               x /* ERROR "declared but not used" */ := 0
+       }
+
+       var t interface{}
+       switch t /* ERROR "declared but not used" */ := t.(type) {}
+
+       switch t /* ERROR "declared but not used" */ := t.(type) {
+       case int:
+       }
+
+       switch t /* ERROR "declared but not used" */ := t.(type) {
+       case int:
+       case float32, complex64:
+               t = nil
+       }
+
+       switch t := t.(type) {
+       case int:
+       case float32, complex64:
+               _ = t
+       }
+
+       switch t := t.(type) {
+       case int:
+       case float32:
+       case string:
+               _ = func() string {
+                       return t
+               }
+       }
+
+       switch t := t; t /* ERROR "declared but not used" */ := t.(type) {}
+
+       var z1 /* ERROR "declared but not used" */ int
+       var z2 int
+       _ = func(a, b, c int) (u, v, w int) {
+               z1 = a
+               (z1) = b
+               a = z2
+               return
+       }
+
+       var s []int
+       var i /* ERROR "declared but not used" */ , j int
+       for i, j = range s {
+               _ = j
+       }
+
+       for i, j /* ERROR "declared but not used" */ := range s {
+               _ = func() int {
+                       return i
+               }
+       }
+       return
+}
+
+// Invalid (unused) expressions must not lead to spurious "declared but not used errors"
+func _() {
+       var a, b, c int
+       var x, y int
+       x, y = a /* ERROR assignment count mismatch */ , b, c
+       _ = x
+       _ = y
+}
+
+func _() {
+       var x int
+       return x /* ERROR no result values expected */
+       return math /* ERROR no result values expected */ .Sin(0)
+}
+
+func _() int {
+       var x, y int
+       return /* ERROR wrong number of return values */ x, y
+}
+
+// Short variable declarations must declare at least one new non-blank variable.
+func _() {
+       _ := /* ERROR no new variables */ 0
+       _, a := 0, 1
+       _, a := /* ERROR no new variables */ 0, 1
+       _, a, b := 0, 1, 2
+       _, _, _ := /* ERROR no new variables */ 0, 1, 2
+
+       _ = a
+       _ = b
+}
+
+// TODO(gri) consolidate other var decl checks in this file
\ No newline at end of file
diff --git a/src/go/types/token_test.go b/src/go/types/token_test.go
new file mode 100644 (file)
index 0000000..705bb29
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file checks invariants of token.Token ordering that we rely on
+// since package go/token doesn't provide any guarantees at the moment.
+
+package types
+
+import (
+       "go/token"
+       "testing"
+)
+
+var assignOps = map[token.Token]token.Token{
+       token.ADD_ASSIGN:     token.ADD,
+       token.SUB_ASSIGN:     token.SUB,
+       token.MUL_ASSIGN:     token.MUL,
+       token.QUO_ASSIGN:     token.QUO,
+       token.REM_ASSIGN:     token.REM,
+       token.AND_ASSIGN:     token.AND,
+       token.OR_ASSIGN:      token.OR,
+       token.XOR_ASSIGN:     token.XOR,
+       token.SHL_ASSIGN:     token.SHL,
+       token.SHR_ASSIGN:     token.SHR,
+       token.AND_NOT_ASSIGN: token.AND_NOT,
+}
+
+func TestZeroTok(t *testing.T) {
+       // zero value for token.Token must be token.ILLEGAL
+       var zero token.Token
+       if token.ILLEGAL != zero {
+               t.Errorf("%s == %d; want 0", token.ILLEGAL, zero)
+       }
+}
+
+func TestAssignOp(t *testing.T) {
+       // there are fewer than 256 tokens
+       for i := 0; i < 256; i++ {
+               tok := token.Token(i)
+               got := assignOp(tok)
+               want := assignOps[tok]
+               if got != want {
+                       t.Errorf("for assignOp(%s): got %s; want %s", tok, got, want)
+               }
+       }
+}
diff --git a/src/go/types/type.go b/src/go/types/type.go
new file mode 100644 (file)
index 0000000..4b4e5f6
--- /dev/null
@@ -0,0 +1,452 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+import "sort"
+
+// TODO(gri) Revisit factory functions - make sure they have all relevant parameters.
+
+// A Type represents a type of Go.
+// All types implement the Type interface.
+type Type interface {
+       // Underlying returns the underlying type of a type.
+       Underlying() Type
+
+       // String returns a string representation of a type.
+       String() string
+}
+
+// BasicKind describes the kind of basic type.
+type BasicKind int
+
+const (
+       Invalid BasicKind = iota // type is invalid
+
+       // predeclared types
+       Bool
+       Int
+       Int8
+       Int16
+       Int32
+       Int64
+       Uint
+       Uint8
+       Uint16
+       Uint32
+       Uint64
+       Uintptr
+       Float32
+       Float64
+       Complex64
+       Complex128
+       String
+       UnsafePointer
+
+       // types for untyped values
+       UntypedBool
+       UntypedInt
+       UntypedRune
+       UntypedFloat
+       UntypedComplex
+       UntypedString
+       UntypedNil
+
+       // aliases
+       Byte = Uint8
+       Rune = Int32
+)
+
+// BasicInfo is a set of flags describing properties of a basic type.
+type BasicInfo int
+
+// Properties of basic types.
+const (
+       IsBoolean BasicInfo = 1 << iota
+       IsInteger
+       IsUnsigned
+       IsFloat
+       IsComplex
+       IsString
+       IsUntyped
+
+       IsOrdered   = IsInteger | IsFloat | IsString
+       IsNumeric   = IsInteger | IsFloat | IsComplex
+       IsConstType = IsBoolean | IsNumeric | IsString
+)
+
+// A Basic represents a basic type.
+type Basic struct {
+       kind BasicKind
+       info BasicInfo
+       name string
+}
+
+// Kind returns the kind of basic type b.
+func (b *Basic) Kind() BasicKind { return b.kind }
+
+// Info returns information about properties of basic type b.
+func (b *Basic) Info() BasicInfo { return b.info }
+
+// Name returns the name of basic type b.
+func (b *Basic) Name() string { return b.name }
+
+// An Array represents an array type.
+type Array struct {
+       len  int64
+       elem Type
+}
+
+// NewArray returns a new array type for the given element type and length.
+func NewArray(elem Type, len int64) *Array { return &Array{len, elem} }
+
+// Len returns the length of array a.
+func (a *Array) Len() int64 { return a.len }
+
+// Elem returns element type of array a.
+func (a *Array) Elem() Type { return a.elem }
+
+// A Slice represents a slice type.
+type Slice struct {
+       elem Type
+}
+
+// NewSlice returns a new slice type for the given element type.
+func NewSlice(elem Type) *Slice { return &Slice{elem} }
+
+// Elem returns the element type of slice s.
+func (s *Slice) Elem() Type { return s.elem }
+
+// A Struct represents a struct type.
+type Struct struct {
+       fields []*Var
+       tags   []string // field tags; nil if there are no tags
+       // TODO(gri) access to offsets is not threadsafe - fix this
+       offsets []int64 // field offsets in bytes, lazily initialized
+}
+
+// NewStruct returns a new struct with the given fields and corresponding field tags.
+// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be
+// only as long as required to hold the tag with the largest index i. Consequently,
+// if no field has a tag, tags may be nil.
+func NewStruct(fields []*Var, tags []string) *Struct {
+       var fset objset
+       for _, f := range fields {
+               if f.name != "_" && fset.insert(f) != nil {
+                       panic("multiple fields with the same name")
+               }
+       }
+       if len(tags) > len(fields) {
+               panic("more tags than fields")
+       }
+       return &Struct{fields: fields, tags: tags}
+}
+
+// NumFields returns the number of fields in the struct (including blank and anonymous fields).
+func (s *Struct) NumFields() int { return len(s.fields) }
+
+// Field returns the i'th field for 0 <= i < NumFields().
+func (s *Struct) Field(i int) *Var { return s.fields[i] }
+
+// Tag returns the i'th field tag for 0 <= i < NumFields().
+func (s *Struct) Tag(i int) string {
+       if i < len(s.tags) {
+               return s.tags[i]
+       }
+       return ""
+}
+
+// A Pointer represents a pointer type.
+type Pointer struct {
+       base Type // element type
+}
+
+// NewPointer returns a new pointer type for the given element (base) type.
+func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} }
+
+// Elem returns the element type for the given pointer p.
+func (p *Pointer) Elem() Type { return p.base }
+
+// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple.
+// Tuples are used as components of signatures and to represent the type of multiple
+// assignments; they are not first class types of Go.
+type Tuple struct {
+       vars []*Var
+}
+
+// NewTuple returns a new tuple for the given variables.
+func NewTuple(x ...*Var) *Tuple {
+       if len(x) > 0 {
+               return &Tuple{x}
+       }
+       return nil
+}
+
+// Len returns the number variables of tuple t.
+func (t *Tuple) Len() int {
+       if t != nil {
+               return len(t.vars)
+       }
+       return 0
+}
+
+// At returns the i'th variable of tuple t.
+func (t *Tuple) At(i int) *Var { return t.vars[i] }
+
+// A Signature represents a (non-builtin) function or method type.
+type Signature struct {
+       scope    *Scope // function scope, always present
+       recv     *Var   // nil if not a method
+       params   *Tuple // (incoming) parameters from left to right; or nil
+       results  *Tuple // (outgoing) results from left to right; or nil
+       variadic bool   // true if the last parameter's type is of the form ...T (or string, for append built-in only)
+}
+
+// NewSignature returns a new function type for the given receiver, parameters,
+// and results, either of which may be nil. If variadic is set, the function
+// is variadic, it must have at least one parameter, and the last parameter
+// must be of unnamed slice type.
+func NewSignature(scope *Scope, recv *Var, params, results *Tuple, variadic bool) *Signature {
+       // TODO(gri) Should we rely on the correct (non-nil) incoming scope
+       //           or should this function allocate and populate a scope?
+       if variadic {
+               n := params.Len()
+               if n == 0 {
+                       panic("types.NewSignature: variadic function must have at least one parameter")
+               }
+               if _, ok := params.At(n - 1).typ.(*Slice); !ok {
+                       panic("types.NewSignature: variadic parameter must be of unnamed slice type")
+               }
+       }
+       return &Signature{scope, recv, params, results, variadic}
+}
+
+// Recv returns the receiver of signature s (if a method), or nil if a
+// function.
+//
+// For an abstract method, Recv returns the enclosing interface either
+// as a *Named or an *Interface.  Due to embedding, an interface may
+// contain methods whose receiver type is a different interface.
+func (s *Signature) Recv() *Var { return s.recv }
+
+// Params returns the parameters of signature s, or nil.
+func (s *Signature) Params() *Tuple { return s.params }
+
+// Results returns the results of signature s, or nil.
+func (s *Signature) Results() *Tuple { return s.results }
+
+// Variadic reports whether the signature s is variadic.
+func (s *Signature) Variadic() bool { return s.variadic }
+
+// An Interface represents an interface type.
+type Interface struct {
+       methods   []*Func  // ordered list of explicitly declared methods
+       embeddeds []*Named // ordered list of explicitly embedded types
+
+       allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
+}
+
+// NewInterface returns a new interface for the given methods and embedded types.
+func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
+       typ := new(Interface)
+
+       var mset objset
+       for _, m := range methods {
+               if mset.insert(m) != nil {
+                       panic("multiple methods with the same name")
+               }
+               // set receiver
+               // TODO(gri) Ideally, we should use a named type here instead of
+               // typ, for less verbose printing of interface method signatures.
+               m.typ.(*Signature).recv = NewVar(m.pos, m.pkg, "", typ)
+       }
+       sort.Sort(byUniqueMethodName(methods))
+
+       if embeddeds == nil {
+               sort.Sort(byUniqueTypeName(embeddeds))
+       }
+
+       typ.methods = methods
+       typ.embeddeds = embeddeds
+       return typ
+}
+
+// NumExplicitMethods returns the number of explicitly declared methods of interface t.
+func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
+
+// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
+
+// NumEmbeddeds returns the number of embedded types in interface t.
+func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
+
+// Embedded returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
+// The types are ordered by the corresponding TypeName's unique Id.
+func (t *Interface) Embedded(i int) *Named { return t.embeddeds[i] }
+
+// NumMethods returns the total number of methods of interface t.
+func (t *Interface) NumMethods() int { return len(t.allMethods) }
+
+// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) Method(i int) *Func { return t.allMethods[i] }
+
+// Empty returns true if t is the empty interface.
+func (t *Interface) Empty() bool { return len(t.allMethods) == 0 }
+
+// Complete computes the interface's method set. It must be called by users of
+// NewInterface after the interface's embedded types are fully defined and
+// before using the interface type in any way other than to form other types.
+// Complete returns the receiver.
+func (t *Interface) Complete() *Interface {
+       if t.allMethods != nil {
+               return t
+       }
+
+       var allMethods []*Func
+       if t.embeddeds == nil {
+               if t.methods == nil {
+                       allMethods = make([]*Func, 0, 1)
+               } else {
+                       allMethods = t.methods
+               }
+       } else {
+               allMethods = append(allMethods, t.methods...)
+               for _, et := range t.embeddeds {
+                       it := et.Underlying().(*Interface)
+                       it.Complete()
+                       for _, tm := range it.allMethods {
+                               // Make a copy of the method and adjust its receiver type.
+                               newm := *tm
+                               newmtyp := *tm.typ.(*Signature)
+                               newm.typ = &newmtyp
+                               newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t)
+                               allMethods = append(allMethods, &newm)
+                       }
+               }
+               sort.Sort(byUniqueMethodName(allMethods))
+       }
+       t.allMethods = allMethods
+
+       return t
+}
+
+// A Map represents a map type.
+type Map struct {
+       key, elem Type
+}
+
+// NewMap returns a new map for the given key and element types.
+func NewMap(key, elem Type) *Map {
+       return &Map{key, elem}
+}
+
+// Key returns the key type of map m.
+func (m *Map) Key() Type { return m.key }
+
+// Elem returns the element type of map m.
+func (m *Map) Elem() Type { return m.elem }
+
+// A Chan represents a channel type.
+type Chan struct {
+       dir  ChanDir
+       elem Type
+}
+
+// A ChanDir value indicates a channel direction.
+type ChanDir int
+
+// The direction of a channel is indicated by one of the following constants.
+const (
+       SendRecv ChanDir = iota
+       SendOnly
+       RecvOnly
+)
+
+// NewChan returns a new channel type for the given direction and element type.
+func NewChan(dir ChanDir, elem Type) *Chan {
+       return &Chan{dir, elem}
+}
+
+// Dir returns the direction of channel c.
+func (c *Chan) Dir() ChanDir { return c.dir }
+
+// Elem returns the element type of channel c.
+func (c *Chan) Elem() Type { return c.elem }
+
+// A Named represents a named type.
+type Named struct {
+       obj        *TypeName // corresponding declared object
+       underlying Type      // possibly a *Named during setup; never a *Named once set up completely
+       methods    []*Func   // methods declared for this type (not the method set of this type)
+}
+
+// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
+// The underlying type must not be a *Named.
+func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
+       if _, ok := underlying.(*Named); ok {
+               panic("types.NewNamed: underlying type must not be *Named")
+       }
+       typ := &Named{obj: obj, underlying: underlying, methods: methods}
+       if obj.typ == nil {
+               obj.typ = typ
+       }
+       return typ
+}
+
+// TypeName returns the type name for the named type t.
+func (t *Named) Obj() *TypeName { return t.obj }
+
+// NumMethods returns the number of explicit methods whose receiver is named type t.
+func (t *Named) NumMethods() int { return len(t.methods) }
+
+// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
+func (t *Named) Method(i int) *Func { return t.methods[i] }
+
+// SetUnderlying sets the underlying type and marks t as complete.
+// TODO(gri) determine if there's a better solution rather than providing this function
+func (t *Named) SetUnderlying(underlying Type) {
+       if underlying == nil {
+               panic("types.Named.SetUnderlying: underlying type must not be nil")
+       }
+       if _, ok := underlying.(*Named); ok {
+               panic("types.Named.SetUnderlying: underlying type must not be *Named")
+       }
+       t.underlying = underlying
+}
+
+// AddMethod adds method m unless it is already in the method list.
+// TODO(gri) find a better solution instead of providing this function
+func (t *Named) AddMethod(m *Func) {
+       if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
+               t.methods = append(t.methods, m)
+       }
+}
+
+// Implementations for Type methods.
+
+func (t *Basic) Underlying() Type     { return t }
+func (t *Array) Underlying() Type     { return t }
+func (t *Slice) Underlying() Type     { return t }
+func (t *Struct) Underlying() Type    { return t }
+func (t *Pointer) Underlying() Type   { return t }
+func (t *Tuple) Underlying() Type     { return t }
+func (t *Signature) Underlying() Type { return t }
+func (t *Interface) Underlying() Type { return t }
+func (t *Map) Underlying() Type       { return t }
+func (t *Chan) Underlying() Type      { return t }
+func (t *Named) Underlying() Type     { return t.underlying }
+
+func (t *Basic) String() string     { return TypeString(nil, t) }
+func (t *Array) String() string     { return TypeString(nil, t) }
+func (t *Slice) String() string     { return TypeString(nil, t) }
+func (t *Struct) String() string    { return TypeString(nil, t) }
+func (t *Pointer) String() string   { return TypeString(nil, t) }
+func (t *Tuple) String() string     { return TypeString(nil, t) }
+func (t *Signature) String() string { return TypeString(nil, t) }
+func (t *Interface) String() string { return TypeString(nil, t) }
+func (t *Map) String() string       { return TypeString(nil, t) }
+func (t *Chan) String() string      { return TypeString(nil, t) }
+func (t *Named) String() string     { return TypeString(nil, t) }
diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go
new file mode 100644 (file)
index 0000000..9a537e8
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements printing of types.
+
+package types
+
+import (
+       "bytes"
+       "fmt"
+)
+
+// If GcCompatibilityMode is set, printing of types is modified
+// to match the representation of some types in the gc compiler:
+//
+//     - byte and rune lose their alias name and simply stand for
+//       uint8 and int32 respectively
+//     - embedded interfaces get flattened (the embedding info is lost,
+//       and certain recursive interface types cannot be printed anymore)
+//
+// This makes it easier to compare packages computed with the type-
+// checker vs packages imported from gc export data.
+//
+// Caution: This flag affects all uses of WriteType, globally.
+// It is only provided for testing in conjunction with
+// gc-generated data. It may be removed at any time.
+var GcCompatibilityMode bool
+
+// TypeString returns the string representation of typ.
+// Named types are printed package-qualified if they
+// do not belong to this package.
+func TypeString(this *Package, typ Type) string {
+       var buf bytes.Buffer
+       WriteType(&buf, this, typ)
+       return buf.String()
+}
+
+// WriteType writes the string representation of typ to buf.
+// Named types are printed package-qualified if they
+// do not belong to this package.
+func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
+       writeType(buf, this, typ, make([]Type, 8))
+}
+
+func writeType(buf *bytes.Buffer, this *Package, typ Type, visited []Type) {
+       // Theoretically, this is a quadratic lookup algorithm, but in
+       // practice deeply nested composite types with unnamed component
+       // types are uncommon. This code is likely more efficient than
+       // using a map.
+       for _, t := range visited {
+               if t == typ {
+                       fmt.Fprintf(buf, "â—‹%T", typ) // cycle to typ
+                       return
+               }
+       }
+       visited = append(visited, typ)
+
+       switch t := typ.(type) {
+       case nil:
+               buf.WriteString("<nil>")
+
+       case *Basic:
+               if t.kind == UnsafePointer {
+                       buf.WriteString("unsafe.")
+               }
+               if GcCompatibilityMode {
+                       // forget the alias names
+                       switch t.kind {
+                       case Byte:
+                               t = Typ[Uint8]
+                       case Rune:
+                               t = Typ[Int32]
+                       }
+               }
+               buf.WriteString(t.name)
+
+       case *Array:
+               fmt.Fprintf(buf, "[%d]", t.len)
+               writeType(buf, this, t.elem, visited)
+
+       case *Slice:
+               buf.WriteString("[]")
+               writeType(buf, this, t.elem, visited)
+
+       case *Struct:
+               buf.WriteString("struct{")
+               for i, f := range t.fields {
+                       if i > 0 {
+                               buf.WriteString("; ")
+                       }
+                       if !f.anonymous {
+                               buf.WriteString(f.name)
+                               buf.WriteByte(' ')
+                       }
+                       writeType(buf, this, f.typ, visited)
+                       if tag := t.Tag(i); tag != "" {
+                               fmt.Fprintf(buf, " %q", tag)
+                       }
+               }
+               buf.WriteByte('}')
+
+       case *Pointer:
+               buf.WriteByte('*')
+               writeType(buf, this, t.base, visited)
+
+       case *Tuple:
+               writeTuple(buf, this, t, false, visited)
+
+       case *Signature:
+               buf.WriteString("func")
+               writeSignature(buf, this, t, visited)
+
+       case *Interface:
+               // We write the source-level methods and embedded types rather
+               // than the actual method set since resolved method signatures
+               // may have non-printable cycles if parameters have anonymous
+               // interface types that (directly or indirectly) embed the
+               // current interface. For instance, consider the result type
+               // of m:
+               //
+               //     type T interface{
+               //         m() interface{ T }
+               //     }
+               //
+               buf.WriteString("interface{")
+               if GcCompatibilityMode {
+                       // print flattened interface
+                       // (useful to compare against gc-generated interfaces)
+                       for i, m := range t.allMethods {
+                               if i > 0 {
+                                       buf.WriteString("; ")
+                               }
+                               buf.WriteString(m.name)
+                               writeSignature(buf, this, m.typ.(*Signature), visited)
+                       }
+               } else {
+                       // print explicit interface methods and embedded types
+                       for i, m := range t.methods {
+                               if i > 0 {
+                                       buf.WriteString("; ")
+                               }
+                               buf.WriteString(m.name)
+                               writeSignature(buf, this, m.typ.(*Signature), visited)
+                       }
+                       for i, typ := range t.embeddeds {
+                               if i > 0 || len(t.methods) > 0 {
+                                       buf.WriteString("; ")
+                               }
+                               writeType(buf, this, typ, visited)
+                       }
+               }
+               buf.WriteByte('}')
+
+       case *Map:
+               buf.WriteString("map[")
+               writeType(buf, this, t.key, visited)
+               buf.WriteByte(']')
+               writeType(buf, this, t.elem, visited)
+
+       case *Chan:
+               var s string
+               var parens bool
+               switch t.dir {
+               case SendRecv:
+                       s = "chan "
+                       // chan (<-chan T) requires parentheses
+                       if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
+                               parens = true
+                       }
+               case SendOnly:
+                       s = "chan<- "
+               case RecvOnly:
+                       s = "<-chan "
+               default:
+                       panic("unreachable")
+               }
+               buf.WriteString(s)
+               if parens {
+                       buf.WriteByte('(')
+               }
+               writeType(buf, this, t.elem, visited)
+               if parens {
+                       buf.WriteByte(')')
+               }
+
+       case *Named:
+               s := "<Named w/o object>"
+               if obj := t.obj; obj != nil {
+                       if pkg := obj.pkg; pkg != nil && pkg != this {
+                               buf.WriteString(pkg.path)
+                               buf.WriteByte('.')
+                       }
+                       // TODO(gri): function-local named types should be displayed
+                       // differently from named types at package level to avoid
+                       // ambiguity.
+                       s = obj.name
+               }
+               buf.WriteString(s)
+
+       default:
+               // For externally defined implementations of Type.
+               buf.WriteString(t.String())
+       }
+}
+
+func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, visited []Type) {
+       buf.WriteByte('(')
+       if tup != nil {
+               for i, v := range tup.vars {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       if v.name != "" {
+                               buf.WriteString(v.name)
+                               buf.WriteByte(' ')
+                       }
+                       typ := v.typ
+                       if variadic && i == len(tup.vars)-1 {
+                               if s, ok := typ.(*Slice); ok {
+                                       buf.WriteString("...")
+                                       typ = s.elem
+                               } else {
+                                       // special case:
+                                       // append(s, "foo"...) leads to signature func([]byte, string...)
+                                       if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
+                                               panic("internal error: string type expected")
+                                       }
+                                       writeType(buf, this, typ, visited)
+                                       buf.WriteString("...")
+                                       continue
+                               }
+                       }
+                       writeType(buf, this, typ, visited)
+               }
+       }
+       buf.WriteByte(')')
+}
+
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// Named types are printed package-qualified if they
+// do not belong to this package.
+func WriteSignature(buf *bytes.Buffer, this *Package, sig *Signature) {
+       writeSignature(buf, this, sig, make([]Type, 8))
+}
+
+func writeSignature(buf *bytes.Buffer, this *Package, sig *Signature, visited []Type) {
+       writeTuple(buf, this, sig.params, sig.variadic, visited)
+
+       n := sig.results.Len()
+       if n == 0 {
+               // no result
+               return
+       }
+
+       buf.WriteByte(' ')
+       if n == 1 && sig.results.vars[0].name == "" {
+               // single unnamed result
+               writeType(buf, this, sig.results.vars[0].typ, visited)
+               return
+       }
+
+       // multiple or named result(s)
+       writeTuple(buf, this, sig.results, false, visited)
+}
diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go
new file mode 100644 (file)
index 0000000..5db9714
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "testing"
+
+       . "go/types"
+       _ "go/types/internal/gcimporter"
+)
+
+const filename = "<src>"
+
+func makePkg(t *testing.T, src string) (*Package, error) {
+       fset := token.NewFileSet()
+       file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
+       if err != nil {
+               return nil, err
+       }
+       // use the package name as package path
+       return Check(file.Name.Name, fset, []*ast.File{file})
+}
+
+type testEntry struct {
+       src, str string
+}
+
+// dup returns a testEntry where both src and str are the same.
+func dup(s string) testEntry {
+       return testEntry{s, s}
+}
+
+// types that don't depend on any other type declarations
+var independentTestTypes = []testEntry{
+       // basic types
+       dup("int"),
+       dup("float32"),
+       dup("string"),
+
+       // arrays
+       dup("[10]int"),
+
+       // slices
+       dup("[]int"),
+       dup("[][]int"),
+
+       // structs
+       dup("struct{}"),
+       dup("struct{x int}"),
+       {`struct {
+               x, y int
+               z float32 "foo"
+       }`, `struct{x int; y int; z float32 "foo"}`},
+       {`struct {
+               string
+               elems []complex128
+       }`, `struct{string; elems []complex128}`},
+
+       // pointers
+       dup("*int"),
+       dup("***struct{}"),
+       dup("*struct{a int; b float32}"),
+
+       // functions
+       dup("func()"),
+       dup("func(x int)"),
+       {"func(x, y int)", "func(x int, y int)"},
+       {"func(x, y int, z string)", "func(x int, y int, z string)"},
+       dup("func(int)"),
+       {"func(int, string, byte)", "func(int, string, byte)"},
+
+       dup("func() int"),
+       {"func() (string)", "func() string"},
+       dup("func() (u int)"),
+       {"func() (u, v int, w string)", "func() (u int, v int, w string)"},
+
+       dup("func(int) string"),
+       dup("func(x int) string"),
+       dup("func(x int) (u string)"),
+       {"func(x, y int) (u string)", "func(x int, y int) (u string)"},
+
+       dup("func(...int) string"),
+       dup("func(x ...int) string"),
+       dup("func(x ...int) (u string)"),
+       {"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},
+
+       // interfaces
+       dup("interface{}"),
+       dup("interface{m()}"),
+       dup(`interface{String() string; m(int) float32}`),
+
+       // maps
+       dup("map[string]int"),
+       {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
+
+       // channels
+       dup("chan<- chan int"),
+       dup("chan<- <-chan int"),
+       dup("<-chan <-chan int"),
+       dup("chan (<-chan int)"),
+       dup("chan<- func()"),
+       dup("<-chan []func() int"),
+}
+
+// types that depend on other type declarations (src in TestTypes)
+var dependentTestTypes = []testEntry{
+       // interfaces
+       dup(`interface{io.Reader; io.Writer}`),
+       dup(`interface{m() int; io.Writer}`),
+       {`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
+}
+
+func TestTypeString(t *testing.T) {
+       var tests []testEntry
+       tests = append(tests, independentTestTypes...)
+       tests = append(tests, dependentTestTypes...)
+
+       for _, test := range tests {
+               src := `package p; import "io"; type _ io.Writer; type T ` + test.src
+               pkg, err := makePkg(t, src)
+               if err != nil {
+                       t.Errorf("%s: %s", src, err)
+                       continue
+               }
+               typ := pkg.Scope().Lookup("T").Type().Underlying()
+               if got := typ.String(); got != test.str {
+                       t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+               }
+       }
+}
+
+func TestQualifiedTypeString(t *testing.T) {
+       p, _ := pkgFor("p.go", "package p; type T int", nil)
+       q, _ := pkgFor("q.go", "package q", nil)
+
+       pT := p.Scope().Lookup("T").Type()
+       for _, test := range []struct {
+               typ  Type
+               this *Package
+               want string
+       }{
+               {pT, nil, "p.T"},
+               {pT, p, "T"},
+               {pT, q, "p.T"},
+               {NewPointer(pT), p, "*T"},
+               {NewPointer(pT), q, "*p.T"},
+       } {
+               if got := TypeString(test.this, test.typ); got != test.want {
+                       t.Errorf("TypeString(%s, %s) = %s, want %s",
+                               test.this, test.typ, got, test.want)
+               }
+       }
+}
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
new file mode 100644 (file)
index 0000000..1577cce
--- /dev/null
@@ -0,0 +1,721 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements type-checking of identifiers and type expressions.
+
+package types
+
+import (
+       "go/ast"
+       "go/token"
+       "sort"
+       "strconv"
+
+       "go/exact"
+)
+
+// ident type-checks identifier e and initializes x with the value or type of e.
+// If an error occurred, x.mode is set to invalid.
+// For the meaning of def and path, see check.typ, below.
+//
+func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeName) {
+       x.mode = invalid
+       x.expr = e
+
+       scope, obj := check.scope.LookupParent(e.Name)
+       if obj == nil {
+               if e.Name == "_" {
+                       check.errorf(e.Pos(), "cannot use _ as value or type")
+               } else {
+                       check.errorf(e.Pos(), "undeclared name: %s", e.Name)
+               }
+               return
+       }
+       check.recordUse(e, obj)
+
+       check.objDecl(obj, def, path)
+       typ := obj.Type()
+       assert(typ != nil)
+
+       // The object may be dot-imported: If so, remove its package from
+       // the map of unused dot imports for the respective file scope.
+       // (This code is only needed for dot-imports. Without them,
+       // we only have to mark variables, see *Var case below).
+       if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil {
+               delete(check.unusedDotImports[scope], pkg)
+       }
+
+       switch obj := obj.(type) {
+       case *PkgName:
+               check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
+               return
+
+       case *Const:
+               check.addDeclDep(obj)
+               if typ == Typ[Invalid] {
+                       return
+               }
+               if obj == universeIota {
+                       if check.iota == nil {
+                               check.errorf(e.Pos(), "cannot use iota outside constant declaration")
+                               return
+                       }
+                       x.val = check.iota
+               } else {
+                       x.val = obj.val
+               }
+               assert(x.val != nil)
+               x.mode = constant
+
+       case *TypeName:
+               x.mode = typexpr
+               // check for cycle
+               // (it's ok to iterate forward because each named type appears at most once in path)
+               for i, prev := range path {
+                       if prev == obj {
+                               check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
+                               // print cycle
+                               for _, obj := range path[i:] {
+                                       check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+                               }
+                               check.errorf(obj.Pos(), "\t%s", obj.Name())
+                               // maintain x.mode == typexpr despite error
+                               typ = Typ[Invalid]
+                               break
+                       }
+               }
+
+       case *Var:
+               if obj.pkg == check.pkg {
+                       obj.used = true
+               }
+               check.addDeclDep(obj)
+               if typ == Typ[Invalid] {
+                       return
+               }
+               x.mode = variable
+
+       case *Func:
+               check.addDeclDep(obj)
+               x.mode = value
+
+       case *Builtin:
+               x.id = obj.id
+               x.mode = builtin
+
+       case *Nil:
+               x.mode = value
+
+       default:
+               unreachable()
+       }
+
+       x.typ = typ
+}
+
+// typExpr type-checks the type expression e and returns its type, or Typ[Invalid].
+// If def != nil, e is the type specification for the named type def, declared
+// in a type declaration, and def.underlying will be set to the type of e before
+// any components of e are type-checked. Path contains the path of named types
+// referring to this type.
+//
+func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) {
+       if trace {
+               check.trace(e.Pos(), "%s", e)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(e.Pos(), "=> %s", T)
+               }()
+       }
+
+       T = check.typExprInternal(e, def, path)
+       assert(isTyped(T))
+       check.recordTypeAndValue(e, typexpr, T, nil)
+
+       return
+}
+
+func (check *Checker) typ(e ast.Expr) Type {
+       return check.typExpr(e, nil, nil)
+}
+
+// funcType type-checks a function or method type and returns its signature.
+func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) *Signature {
+       scope := NewScope(check.scope, "function")
+       check.recordScope(ftyp, scope)
+
+       recvList, _ := check.collectParams(scope, recvPar, false)
+       params, variadic := check.collectParams(scope, ftyp.Params, true)
+       results, _ := check.collectParams(scope, ftyp.Results, false)
+
+       if recvPar != nil {
+               // recv parameter list present (may be empty)
+               // spec: "The receiver is specified via an extra parameter section preceeding the
+               // method name. That parameter section must declare a single parameter, the receiver."
+               var recv *Var
+               switch len(recvList) {
+               case 0:
+                       check.error(recvPar.Pos(), "method is missing receiver")
+                       recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
+               default:
+                       // more than one receiver
+                       check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+                       fallthrough // continue with first receiver
+               case 1:
+                       recv = recvList[0]
+               }
+               // spec: "The receiver type must be of the form T or *T where T is a type name."
+               // (ignore invalid types - error was reported before)
+               if t, _ := deref(recv.typ); t != Typ[Invalid] {
+                       var err string
+                       if T, _ := t.(*Named); T != nil {
+                               // spec: "The type denoted by T is called the receiver base type; it must not
+                               // be a pointer or interface type and it must be declared in the same package
+                               // as the method."
+                               if T.obj.pkg != check.pkg {
+                                       err = "type not defined in this package"
+                               } else {
+                                       // TODO(gri) This is not correct if the underlying type is unknown yet.
+                                       switch u := T.underlying.(type) {
+                                       case *Basic:
+                                               // unsafe.Pointer is treated like a regular pointer
+                                               if u.kind == UnsafePointer {
+                                                       err = "unsafe.Pointer"
+                                               }
+                                       case *Pointer, *Interface:
+                                               err = "pointer or interface type"
+                                       }
+                               }
+                       } else {
+                               err = "basic or unnamed type"
+                       }
+                       if err != "" {
+                               check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
+                               // ok to continue
+                       }
+               }
+               sig.recv = recv
+       }
+
+       sig.scope = scope
+       sig.params = NewTuple(params...)
+       sig.results = NewTuple(results...)
+       sig.variadic = variadic
+
+       return sig
+}
+
+// typExprInternal drives type checking of types.
+// Must only be called by typExpr.
+//
+func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName) Type {
+       switch e := e.(type) {
+       case *ast.BadExpr:
+               // ignore - error reported before
+
+       case *ast.Ident:
+               var x operand
+               check.ident(&x, e, def, path)
+
+               switch x.mode {
+               case typexpr:
+                       typ := x.typ
+                       def.setUnderlying(typ)
+                       return typ
+               case invalid:
+                       // ignore - error reported before
+               case novalue:
+                       check.errorf(x.pos(), "%s used as type", &x)
+               default:
+                       check.errorf(x.pos(), "%s is not a type", &x)
+               }
+
+       case *ast.SelectorExpr:
+               var x operand
+               check.selector(&x, e)
+
+               switch x.mode {
+               case typexpr:
+                       typ := x.typ
+                       def.setUnderlying(typ)
+                       return typ
+               case invalid:
+                       // ignore - error reported before
+               case novalue:
+                       check.errorf(x.pos(), "%s used as type", &x)
+               default:
+                       check.errorf(x.pos(), "%s is not a type", &x)
+               }
+
+       case *ast.ParenExpr:
+               return check.typExpr(e.X, def, path)
+
+       case *ast.ArrayType:
+               if e.Len != nil {
+                       typ := new(Array)
+                       def.setUnderlying(typ)
+                       typ.len = check.arrayLength(e.Len)
+                       typ.elem = check.typExpr(e.Elt, nil, path)
+                       return typ
+
+               } else {
+                       typ := new(Slice)
+                       def.setUnderlying(typ)
+                       typ.elem = check.typ(e.Elt)
+                       return typ
+               }
+
+       case *ast.StructType:
+               typ := new(Struct)
+               def.setUnderlying(typ)
+               check.structType(typ, e, path)
+               return typ
+
+       case *ast.StarExpr:
+               typ := new(Pointer)
+               def.setUnderlying(typ)
+               typ.base = check.typ(e.X)
+               return typ
+
+       case *ast.FuncType:
+               typ := new(Signature)
+               def.setUnderlying(typ)
+               check.funcType(typ, nil, e)
+               return typ
+
+       case *ast.InterfaceType:
+               typ := new(Interface)
+               def.setUnderlying(typ)
+               check.interfaceType(typ, e, def, path)
+               return typ
+
+       case *ast.MapType:
+               typ := new(Map)
+               def.setUnderlying(typ)
+
+               typ.key = check.typ(e.Key)
+               typ.elem = check.typ(e.Value)
+
+               // spec: "The comparison operators == and != must be fully defined
+               // for operands of the key type; thus the key type must not be a
+               // function, map, or slice."
+               //
+               // Delay this check because it requires fully setup types;
+               // it is safe to continue in any case (was issue 6667).
+               check.delay(func() {
+                       if !Comparable(typ.key) {
+                               check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
+                       }
+               })
+
+               return typ
+
+       case *ast.ChanType:
+               typ := new(Chan)
+               def.setUnderlying(typ)
+
+               dir := SendRecv
+               switch e.Dir {
+               case ast.SEND | ast.RECV:
+                       // nothing to do
+               case ast.SEND:
+                       dir = SendOnly
+               case ast.RECV:
+                       dir = RecvOnly
+               default:
+                       check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir)
+                       // ok to continue
+               }
+
+               typ.dir = dir
+               typ.elem = check.typ(e.Value)
+               return typ
+
+       default:
+               check.errorf(e.Pos(), "%s is not a type", e)
+       }
+
+       typ := Typ[Invalid]
+       def.setUnderlying(typ)
+       return typ
+}
+
+// typeOrNil type-checks the type expression (or nil value) e
+// and returns the typ of e, or nil.
+// If e is neither a type nor nil, typOrNil returns Typ[Invalid].
+//
+func (check *Checker) typOrNil(e ast.Expr) Type {
+       var x operand
+       check.rawExpr(&x, e, nil)
+       switch x.mode {
+       case invalid:
+               // ignore - error reported before
+       case novalue:
+               check.errorf(x.pos(), "%s used as type", &x)
+       case typexpr:
+               return x.typ
+       case value:
+               if x.isNil() {
+                       return nil
+               }
+               fallthrough
+       default:
+               check.errorf(x.pos(), "%s is not a type", &x)
+       }
+       return Typ[Invalid]
+}
+
+func (check *Checker) arrayLength(e ast.Expr) int64 {
+       var x operand
+       check.expr(&x, e)
+       if x.mode != constant {
+               if x.mode != invalid {
+                       check.errorf(x.pos(), "array length %s must be constant", &x)
+               }
+               return 0
+       }
+       if !x.isInteger() {
+               check.errorf(x.pos(), "array length %s must be integer", &x)
+               return 0
+       }
+       n, ok := exact.Int64Val(x.val)
+       if !ok || n < 0 {
+               check.errorf(x.pos(), "invalid array length %s", &x)
+               return 0
+       }
+       return n
+}
+
+func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
+       if list == nil {
+               return
+       }
+
+       var named, anonymous bool
+       for i, field := range list.List {
+               ftype := field.Type
+               if t, _ := ftype.(*ast.Ellipsis); t != nil {
+                       ftype = t.Elt
+                       if variadicOk && i == len(list.List)-1 {
+                               variadic = true
+                       } else {
+                               check.invalidAST(field.Pos(), "... not permitted")
+                               // ignore ... and continue
+                       }
+               }
+               typ := check.typ(ftype)
+               // The parser ensures that f.Tag is nil and we don't
+               // care if a constructed AST contains a non-nil tag.
+               if len(field.Names) > 0 {
+                       // named parameter
+                       for _, name := range field.Names {
+                               if name.Name == "" {
+                                       check.invalidAST(name.Pos(), "anonymous parameter")
+                                       // ok to continue
+                               }
+                               par := NewParam(name.Pos(), check.pkg, name.Name, typ)
+                               check.declare(scope, name, par)
+                               params = append(params, par)
+                       }
+                       named = true
+               } else {
+                       // anonymous parameter
+                       par := NewParam(ftype.Pos(), check.pkg, "", typ)
+                       check.recordImplicit(field, par)
+                       params = append(params, par)
+                       anonymous = true
+               }
+       }
+
+       if named && anonymous {
+               check.invalidAST(list.Pos(), "list contains both named and anonymous parameters")
+               // ok to continue
+       }
+
+       // For a variadic function, change the last parameter's type from T to []T.
+       if variadic && len(params) > 0 {
+               last := params[len(params)-1]
+               last.typ = &Slice{elem: last.typ}
+       }
+
+       return
+}
+
+func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool {
+       if alt := oset.insert(obj); alt != nil {
+               check.errorf(pos, "%s redeclared", obj.Name())
+               check.reportAltDecl(alt)
+               return false
+       }
+       return true
+}
+
+func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, path []*TypeName) {
+       // empty interface: common case
+       if ityp.Methods == nil {
+               return
+       }
+
+       // The parser ensures that field tags are nil and we don't
+       // care if a constructed AST contains non-nil tags.
+
+       // use named receiver type if available (for better error messages)
+       var recvTyp Type = iface
+       if def != nil {
+               recvTyp = def
+       }
+
+       // Phase 1: Collect explicitly declared methods, the corresponding
+       //          signature (AST) expressions, and the list of embedded
+       //          type (AST) expressions. Do not resolve signatures or
+       //          embedded types yet to avoid cycles referring to this
+       //          interface.
+
+       var (
+               mset       objset
+               signatures []ast.Expr // list of corresponding method signatures
+               embedded   []ast.Expr // list of embedded types
+       )
+       for _, f := range ityp.Methods.List {
+               if len(f.Names) > 0 {
+                       // The parser ensures that there's only one method
+                       // and we don't care if a constructed AST has more.
+                       name := f.Names[0]
+                       pos := name.Pos()
+                       // spec: "As with all method sets, in an interface type,
+                       // each method must have a unique non-blank name."
+                       if name.Name == "_" {
+                               check.errorf(pos, "invalid method name _")
+                               continue
+                       }
+                       // Don't type-check signature yet - use an
+                       // empty signature now and update it later.
+                       // Since we know the receiver, set it up now
+                       // (required to avoid crash in ptrRecv; see
+                       // e.g. test case for issue 6638).
+                       // TODO(gri) Consider marking methods signatures
+                       // as incomplete, for better error messages. See
+                       // also the T4 and T5 tests in testdata/cycles2.src.
+                       sig := new(Signature)
+                       sig.recv = NewVar(pos, check.pkg, "", recvTyp)
+                       m := NewFunc(pos, check.pkg, name.Name, sig)
+                       if check.declareInSet(&mset, pos, m) {
+                               iface.methods = append(iface.methods, m)
+                               iface.allMethods = append(iface.allMethods, m)
+                               signatures = append(signatures, f.Type)
+                               check.recordDef(name, m)
+                       }
+               } else {
+                       // embedded type
+                       embedded = append(embedded, f.Type)
+               }
+       }
+
+       // Phase 2: Resolve embedded interfaces. Because an interface must not
+       //          embed itself (directly or indirectly), each embedded interface
+       //          can be fully resolved without depending on any method of this
+       //          interface (if there is a cycle or another error, the embedded
+       //          type resolves to an invalid type and is ignored).
+       //          In particular, the list of methods for each embedded interface
+       //          must be complete (it cannot depend on this interface), and so
+       //          those methods can be added to the list of all methods of this
+       //          interface.
+
+       for _, e := range embedded {
+               pos := e.Pos()
+               typ := check.typExpr(e, nil, path)
+               named, _ := typ.(*Named)
+               if named == nil {
+                       if typ != Typ[Invalid] {
+                               check.invalidAST(pos, "%s is not named type", typ)
+                       }
+                       continue
+               }
+               // determine underlying (possibly incomplete) type
+               // by following its forward chain
+               u := underlying(named)
+               embed, _ := u.(*Interface)
+               if embed == nil {
+                       if u != Typ[Invalid] {
+                               check.errorf(pos, "%s is not an interface", named)
+                       }
+                       continue
+               }
+               iface.embeddeds = append(iface.embeddeds, named)
+               // collect embedded methods
+               for _, m := range embed.allMethods {
+                       if check.declareInSet(&mset, pos, m) {
+                               iface.allMethods = append(iface.allMethods, m)
+                       }
+               }
+       }
+
+       // Phase 3: At this point all methods have been collected for this interface.
+       //          It is now safe to type-check the signatures of all explicitly
+       //          declared methods, even if they refer to this interface via a cycle
+       //          and embed the methods of this interface in a parameter of interface
+       //          type.
+
+       for i, m := range iface.methods {
+               expr := signatures[i]
+               typ := check.typ(expr)
+               sig, _ := typ.(*Signature)
+               if sig == nil {
+                       if typ != Typ[Invalid] {
+                               check.invalidAST(expr.Pos(), "%s is not a method signature", typ)
+                       }
+                       continue // keep method with empty method signature
+               }
+               // update signature, but keep recv that was set up before
+               old := m.typ.(*Signature)
+               sig.recv = old.recv
+               *old = *sig // update signature (don't replace it!)
+       }
+
+       // TODO(gri) The list of explicit methods is only sorted for now to
+       // produce the same Interface as NewInterface. We may be able to
+       // claim source order in the future. Revisit.
+       sort.Sort(byUniqueMethodName(iface.methods))
+
+       // TODO(gri) The list of embedded types is only sorted for now to
+       // produce the same Interface as NewInterface. We may be able to
+       // claim source order in the future. Revisit.
+       sort.Sort(byUniqueTypeName(iface.embeddeds))
+
+       sort.Sort(byUniqueMethodName(iface.allMethods))
+}
+
+// byUniqueTypeName named type lists can be sorted by their unique type names.
+type byUniqueTypeName []*Named
+
+func (a byUniqueTypeName) Len() int           { return len(a) }
+func (a byUniqueTypeName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueTypeName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+// byUniqueMethodName method lists can be sorted by their unique method names.
+type byUniqueMethodName []*Func
+
+func (a byUniqueMethodName) Len() int           { return len(a) }
+func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() }
+func (a byUniqueMethodName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+func (check *Checker) tag(t *ast.BasicLit) string {
+       if t != nil {
+               if t.Kind == token.STRING {
+                       if val, err := strconv.Unquote(t.Value); err == nil {
+                               return val
+                       }
+               }
+               check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
+       }
+       return ""
+}
+
+func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeName) {
+       list := e.Fields
+       if list == nil {
+               return
+       }
+
+       // struct fields and tags
+       var fields []*Var
+       var tags []string
+
+       // for double-declaration checks
+       var fset objset
+
+       // current field typ and tag
+       var typ Type
+       var tag string
+       // anonymous != nil indicates an anonymous field.
+       add := func(field *ast.Field, ident *ast.Ident, anonymous *TypeName, pos token.Pos) {
+               if tag != "" && tags == nil {
+                       tags = make([]string, len(fields))
+               }
+               if tags != nil {
+                       tags = append(tags, tag)
+               }
+
+               name := ident.Name
+               fld := NewField(pos, check.pkg, name, typ, anonymous != nil)
+               // spec: "Within a struct, non-blank field names must be unique."
+               if name == "_" || check.declareInSet(&fset, pos, fld) {
+                       fields = append(fields, fld)
+                       check.recordDef(ident, fld)
+               }
+               if anonymous != nil {
+                       check.recordUse(ident, anonymous)
+               }
+       }
+
+       for _, f := range list.List {
+               typ = check.typExpr(f.Type, nil, path)
+               tag = check.tag(f.Tag)
+               if len(f.Names) > 0 {
+                       // named fields
+                       for _, name := range f.Names {
+                               add(f, name, nil, name.Pos())
+                       }
+               } else {
+                       // anonymous field
+                       name := anonymousFieldIdent(f.Type)
+                       pos := f.Type.Pos()
+                       t, isPtr := deref(typ)
+                       switch t := t.(type) {
+                       case *Basic:
+                               if t == Typ[Invalid] {
+                                       // error was reported before
+                                       continue
+                               }
+                               // unsafe.Pointer is treated like a regular pointer
+                               if t.kind == UnsafePointer {
+                                       check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+                                       continue
+                               }
+                               add(f, name, Universe.Lookup(t.name).(*TypeName), pos)
+
+                       case *Named:
+                               // spec: "An embedded type must be specified as a type name
+                               // T or as a pointer to a non-interface type name *T, and T
+                               // itself may not be a pointer type."
+                               switch u := t.underlying.(type) {
+                               case *Basic:
+                                       // unsafe.Pointer is treated like a regular pointer
+                                       if u.kind == UnsafePointer {
+                                               check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+                                               continue
+                                       }
+                               case *Pointer:
+                                       check.errorf(pos, "anonymous field type cannot be a pointer")
+                                       continue
+                               case *Interface:
+                                       if isPtr {
+                                               check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
+                                               continue
+                                       }
+                               }
+                               add(f, name, t.obj, pos)
+
+                       default:
+                               check.invalidAST(pos, "anonymous field type %s must be named", typ)
+                       }
+               }
+       }
+
+       styp.fields = fields
+       styp.tags = tags
+}
+
+func anonymousFieldIdent(e ast.Expr) *ast.Ident {
+       switch e := e.(type) {
+       case *ast.Ident:
+               return e
+       case *ast.StarExpr:
+               return anonymousFieldIdent(e.X)
+       case *ast.SelectorExpr:
+               return e.Sel
+       }
+       return nil // invalid anonymous field
+}
diff --git a/src/go/types/universe.go b/src/go/types/universe.go
new file mode 100644 (file)
index 0000000..139592c
--- /dev/null
@@ -0,0 +1,224 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the universe and unsafe package scopes.
+
+package types
+
+import (
+       "go/token"
+       "strings"
+
+       "go/exact"
+)
+
+var (
+       Universe     *Scope
+       Unsafe       *Package
+       universeIota *Const
+       UniverseByte *Basic // uint8 alias, but has name "byte"
+       UniverseRune *Basic // int32 alias, but has name "rune"
+)
+
+var Typ = [...]*Basic{
+       Invalid: {Invalid, 0, "invalid type"},
+
+       Bool:          {Bool, IsBoolean, "bool"},
+       Int:           {Int, IsInteger, "int"},
+       Int8:          {Int8, IsInteger, "int8"},
+       Int16:         {Int16, IsInteger, "int16"},
+       Int32:         {Int32, IsInteger, "int32"},
+       Int64:         {Int64, IsInteger, "int64"},
+       Uint:          {Uint, IsInteger | IsUnsigned, "uint"},
+       Uint8:         {Uint8, IsInteger | IsUnsigned, "uint8"},
+       Uint16:        {Uint16, IsInteger | IsUnsigned, "uint16"},
+       Uint32:        {Uint32, IsInteger | IsUnsigned, "uint32"},
+       Uint64:        {Uint64, IsInteger | IsUnsigned, "uint64"},
+       Uintptr:       {Uintptr, IsInteger | IsUnsigned, "uintptr"},
+       Float32:       {Float32, IsFloat, "float32"},
+       Float64:       {Float64, IsFloat, "float64"},
+       Complex64:     {Complex64, IsComplex, "complex64"},
+       Complex128:    {Complex128, IsComplex, "complex128"},
+       String:        {String, IsString, "string"},
+       UnsafePointer: {UnsafePointer, 0, "Pointer"},
+
+       UntypedBool:    {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
+       UntypedInt:     {UntypedInt, IsInteger | IsUntyped, "untyped int"},
+       UntypedRune:    {UntypedRune, IsInteger | IsUntyped, "untyped rune"},
+       UntypedFloat:   {UntypedFloat, IsFloat | IsUntyped, "untyped float"},
+       UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
+       UntypedString:  {UntypedString, IsString | IsUntyped, "untyped string"},
+       UntypedNil:     {UntypedNil, IsUntyped, "untyped nil"},
+}
+
+var aliases = [...]*Basic{
+       {Byte, IsInteger | IsUnsigned, "byte"},
+       {Rune, IsInteger, "rune"},
+}
+
+func defPredeclaredTypes() {
+       for _, t := range Typ {
+               def(NewTypeName(token.NoPos, nil, t.name, t))
+       }
+       for _, t := range aliases {
+               def(NewTypeName(token.NoPos, nil, t.name, t))
+       }
+
+       // Error has a nil package in its qualified name since it is in no package
+       res := NewVar(token.NoPos, nil, "", Typ[String])
+       sig := &Signature{results: NewTuple(res)}
+       err := NewFunc(token.NoPos, nil, "Error", sig)
+       typ := &Named{underlying: NewInterface([]*Func{err}, nil).Complete()}
+       sig.recv = NewVar(token.NoPos, nil, "", typ)
+       def(NewTypeName(token.NoPos, nil, "error", typ))
+}
+
+var predeclaredConsts = [...]struct {
+       name string
+       kind BasicKind
+       val  exact.Value
+}{
+       {"true", UntypedBool, exact.MakeBool(true)},
+       {"false", UntypedBool, exact.MakeBool(false)},
+       {"iota", UntypedInt, exact.MakeInt64(0)},
+}
+
+func defPredeclaredConsts() {
+       for _, c := range predeclaredConsts {
+               def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val))
+       }
+}
+
+func defPredeclaredNil() {
+       def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}})
+}
+
+// A builtinId is the id of a builtin function.
+type builtinId int
+
+const (
+       // universe scope
+       _Append builtinId = iota
+       _Cap
+       _Close
+       _Complex
+       _Copy
+       _Delete
+       _Imag
+       _Len
+       _Make
+       _New
+       _Panic
+       _Print
+       _Println
+       _Real
+       _Recover
+
+       // package unsafe
+       _Alignof
+       _Offsetof
+       _Sizeof
+
+       // testing support
+       _Assert
+       _Trace
+)
+
+var predeclaredFuncs = [...]struct {
+       name     string
+       nargs    int
+       variadic bool
+       kind     exprKind
+}{
+       _Append:  {"append", 1, true, expression},
+       _Cap:     {"cap", 1, false, expression},
+       _Close:   {"close", 1, false, statement},
+       _Complex: {"complex", 2, false, expression},
+       _Copy:    {"copy", 2, false, statement},
+       _Delete:  {"delete", 2, false, statement},
+       _Imag:    {"imag", 1, false, expression},
+       _Len:     {"len", 1, false, expression},
+       _Make:    {"make", 1, true, expression},
+       _New:     {"new", 1, false, expression},
+       _Panic:   {"panic", 1, false, statement},
+       _Print:   {"print", 0, true, statement},
+       _Println: {"println", 0, true, statement},
+       _Real:    {"real", 1, false, expression},
+       _Recover: {"recover", 0, false, statement},
+
+       _Alignof:  {"Alignof", 1, false, expression},
+       _Offsetof: {"Offsetof", 1, false, expression},
+       _Sizeof:   {"Sizeof", 1, false, expression},
+
+       _Assert: {"assert", 1, false, statement},
+       _Trace:  {"trace", 0, true, statement},
+}
+
+func defPredeclaredFuncs() {
+       for i := range predeclaredFuncs {
+               id := builtinId(i)
+               if id == _Assert || id == _Trace {
+                       continue // only define these in testing environment
+               }
+               def(newBuiltin(id))
+       }
+}
+
+// DefPredeclaredTestFuncs defines the assert and trace built-ins.
+// These built-ins are intended for debugging and testing of this
+// package only.
+func DefPredeclaredTestFuncs() {
+       if Universe.Lookup("assert") != nil {
+               return // already defined
+       }
+       def(newBuiltin(_Assert))
+       def(newBuiltin(_Trace))
+}
+
+func init() {
+       Universe = NewScope(nil, "universe")
+       Unsafe = NewPackage("unsafe", "unsafe")
+       Unsafe.complete = true
+
+       defPredeclaredTypes()
+       defPredeclaredConsts()
+       defPredeclaredNil()
+       defPredeclaredFuncs()
+
+       universeIota = Universe.Lookup("iota").(*Const)
+       UniverseByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
+       UniverseRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
+}
+
+// Objects with names containing blanks are internal and not entered into
+// a scope. Objects with exported names are inserted in the unsafe package
+// scope; other objects are inserted in the universe scope.
+//
+func def(obj Object) {
+       name := obj.Name()
+       if strings.Index(name, " ") >= 0 {
+               return // nothing to do
+       }
+       // fix Obj link for named types
+       if typ, ok := obj.Type().(*Named); ok {
+               typ.obj = obj.(*TypeName)
+       }
+       // exported identifiers go into package unsafe
+       scope := Universe
+       if obj.Exported() {
+               scope = Unsafe.scope
+               // set Pkg field
+               switch obj := obj.(type) {
+               case *TypeName:
+                       obj.pkg = Unsafe
+               case *Builtin:
+                       obj.pkg = Unsafe
+               default:
+                       unreachable()
+               }
+       }
+       if scope.Insert(obj) != nil {
+               panic("internal error: double declaration")
+       }
+}