--- /dev/null
+// 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 typechecks a package.
+
+package types
+
+import (
+       "fmt"
+       "go/ast"
+       "go/scanner"
+       "go/token"
+       "sort"
+)
+
+type checker struct {
+       fset   *token.FileSet
+       pkg    *ast.Package
+       errors scanner.ErrorList
+       types  map[ast.Expr]Type
+}
+
+// declare declares an object of the given kind and name (ident) in scope;
+// decl is the corresponding declaration in the AST. An error is reported
+// if the object was declared before.
+//
+// TODO(gri) This is very similar to the declare function in go/parser; it
+// is only used to associate methods with their respective receiver base types.
+// In a future version, it might be simpler and cleaner do to all the resolution
+// in the type-checking phase. It would simplify the parser, AST, and also
+// reduce some amount of code duplication.
+//
+func (check *checker) declare(scope *ast.Scope, kind ast.ObjKind, ident *ast.Ident, decl ast.Decl) {
+       assert(ident.Obj == nil) // identifier already declared or resolved
+       obj := ast.NewObj(kind, ident.Name)
+       obj.Decl = decl
+       ident.Obj = obj
+       if ident.Name != "_" {
+               if alt := scope.Insert(obj); alt != nil {
+                       prevDecl := ""
+                       if pos := alt.Pos(); pos.IsValid() {
+                               prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", check.fset.Position(pos))
+                       }
+                       check.errorf(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
+               }
+       }
+}
+
+func (check *checker) decl(pos token.Pos, obj *ast.Object, lhs []*ast.Ident, typ ast.Expr, rhs []ast.Expr, iota int) {
+       if len(lhs) == 0 {
+               check.invalidAST(pos, "missing lhs in declaration")
+               return
+       }
+
+       var t Type
+       if typ != nil {
+               t = check.typ(typ, false)
+       }
+
+       // len(lhs) >= 1
+       if len(lhs) == len(rhs) {
+               // check only corresponding lhs and rhs
+               var l, r ast.Expr
+               for i, ident := range lhs {
+                       if ident.Obj == obj {
+                               l = lhs[i]
+                               r = rhs[i]
+                               break
+                       }
+               }
+               assert(l != nil)
+               obj.Type = t
+               // check rhs
+               var x operand
+               check.expr(&x, r, t, iota)
+               // assign to lhs
+               check.assignment(l, &x, true)
+               return
+       }
+
+       if t != nil {
+               for _, name := range lhs {
+                       name.Obj.Type = t
+               }
+       }
+
+       // check initial values, if any
+       if len(rhs) > 0 {
+               // TODO(gri) should try to avoid this conversion
+               lhx := make([]ast.Expr, len(lhs))
+               for i, e := range lhs {
+                       lhx[i] = e
+               }
+               check.assignNtoM(lhx, rhs, true, iota)
+       }
+}
+
+// specValues returns the list of initialization expressions
+// for the given part (spec) of a constant declaration.
+// TODO(gri) Make this more efficient by caching results
+// (using a map in checker).
+func (check *checker) specValues(spec *ast.ValueSpec) []ast.Expr {
+       if len(spec.Values) > 0 {
+               return spec.Values
+       }
+
+       // find the corresponding values
+       for _, file := range check.pkg.Files {
+               for _, d := range file.Decls {
+                       if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.CONST {
+                               var values []ast.Expr
+                               for _, s := range d.Specs {
+                                       if s, ok := s.(*ast.ValueSpec); ok {
+                                               if len(s.Values) > 0 {
+                                                       values = s.Values
+                                               }
+                                               if s == spec {
+                                                       return values
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       check.invalidAST(spec.Pos(), "no initialization values provided")
+       return nil
+}
+
+// obj type checks an object.
+func (check *checker) obj(obj *ast.Object, cycleOk bool) {
+       if trace {
+               fmt.Printf("obj(%s)\n", obj.Name)
+       }
+
+       if obj.Type != nil {
+               // object has already been type checked
+               return
+       }
+
+       switch obj.Kind {
+       case ast.Bad, ast.Pkg:
+               // nothing to do
+
+       case ast.Con:
+               if obj.Data == nil {
+                       check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
+                       return
+               }
+               spec, ok := obj.Decl.(*ast.ValueSpec)
+               assert(ok)
+               // The Data stored with the constant is the value of iota for that
+               // ast.ValueSpec. Use it for the evaluation of the initialization
+               // expressions.
+               iota := obj.Data.(int)
+               obj.Data = nil
+               check.decl(spec.Pos(), obj, spec.Names, spec.Type, check.specValues(spec), iota)
+
+       case ast.Var:
+               // TODO(gri) missing cycle detection
+               spec, ok := obj.Decl.(*ast.ValueSpec)
+               if !ok {
+                       // TODO(gri) the assertion fails for "x, y := 1, 2, 3" it seems
+                       fmt.Printf("var = %s\n", obj.Name)
+               }
+               assert(ok)
+               check.decl(spec.Pos(), obj, spec.Names, spec.Type, spec.Values, 0)
+
+       case ast.Typ:
+               typ := &NamedType{Obj: obj}
+               obj.Type = typ // "mark" object so recursion terminates
+               typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
+               // collect associated methods, if any
+               if obj.Data != nil {
+                       scope := obj.Data.(*ast.Scope)
+                       // struct fields must not conflict with methods
+                       if t, ok := typ.Underlying.(*Struct); ok {
+                               for _, f := range t.Fields {
+                                       if m := scope.Lookup(f.Name); m != nil {
+                                               check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
+                                       }
+                               }
+                       }
+                       // collect methods
+                       methods := make(ObjList, len(scope.Objects))
+                       i := 0
+                       for _, m := range scope.Objects {
+                               methods[i] = m
+                               i++
+                       }
+                       methods.Sort()
+                       typ.Methods = methods
+                       // methods cannot be associated with an interface type
+                       // (do this check after sorting for reproducible error positions - needed for testing)
+                       if _, ok := typ.Underlying.(*Interface); ok {
+                               for _, m := range methods {
+                                       recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
+                                       check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
+                               }
+                       }
+               }
+
+       case ast.Fun:
+               fdecl := obj.Decl.(*ast.FuncDecl)
+               ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
+               obj.Type = ftyp
+               if fdecl.Recv != nil {
+                       // TODO(gri) handle method receiver
+               }
+               check.stmt(fdecl.Body)
+
+       default:
+               panic("unreachable")
+       }
+}
+
+func check(fset *token.FileSet, pkg *ast.Package, types map[ast.Expr]Type) error {
+       var check checker
+       check.fset = fset
+       check.pkg = pkg
+       check.types = types
+
+       // Compute sorted list of file names so that
+       // package file iterations are reproducible (needed for testing).
+       filenames := make([]string, len(pkg.Files))
+       {
+               i := 0
+               for filename := range pkg.Files {
+                       filenames[i] = filename
+                       i++
+               }
+               sort.Strings(filenames)
+       }
+
+       // Associate methods with types
+       // TODO(gri) All other objects are resolved by the parser.
+       //           Consider doing this in the parser (and provide the info
+       //           in the AST. In the long-term (might require Go 1 API
+       //           changes) it's probably easier to do all the resolution
+       //           in one place in the type checker. See also comment
+       //           with checker.declare.
+       for _, filename := range filenames {
+               file := pkg.Files[filename]
+               for _, decl := range file.Decls {
+                       if meth, ok := decl.(*ast.FuncDecl); ok && meth.Recv != nil {
+                               // The receiver type is one of the following (enforced by parser):
+                               // - *ast.Ident
+                               // - *ast.StarExpr{*ast.Ident}
+                               // - *ast.BadExpr (parser error)
+                               typ := meth.Recv.List[0].Type
+                               if ptr, ok := typ.(*ast.StarExpr); ok {
+                                       typ = ptr.X
+                               }
+                               // determine receiver base type object (or nil if error)
+                               var obj *ast.Object
+                               if ident, ok := typ.(*ast.Ident); ok && ident.Obj != nil {
+                                       obj = ident.Obj
+                                       if obj.Kind != ast.Typ {
+                                               check.errorf(ident.Pos(), "%s is not a type", ident.Name)
+                                               obj = nil
+                                       }
+                                       // TODO(gri) determine if obj was defined in this package
+                                       /*
+                                               if check.notLocal(obj) {
+                                                       check.errorf(ident.Pos(), "cannot define methods on non-local type %s", ident.Name)
+                                                       obj = nil
+                                               }
+                                       */
+                               } else {
+                                       // If it's not an identifier or the identifier wasn't declared/resolved,
+                                       // the parser/resolver already reported an error. Nothing to do here.
+                               }
+                               // determine base type scope (or nil if error)
+                               var scope *ast.Scope
+                               if obj != nil {
+                                       if obj.Data != nil {
+                                               scope = obj.Data.(*ast.Scope)
+                                       } else {
+                                               scope = ast.NewScope(nil)
+                                               obj.Data = scope
+                                       }
+                               } else {
+                                       // use a dummy scope so that meth can be declared in
+                                       // presence of an error and get an associated object
+                                       // (always use a new scope so that we don't get double
+                                       // declaration errors)
+                                       scope = ast.NewScope(nil)
+                               }
+                               check.declare(scope, ast.Fun, meth.Name, meth)
+                       }
+               }
+       }
+
+       // Sort objects so that we get reproducible error
+       // positions (this is only needed for testing).
+       // TODO(gri): Consider ast.Scope implementation that
+       // provides both a list and a map for fast lookup.
+       // Would permit the use of scopes instead of ObjMaps
+       // elsewhere.
+       list := make(ObjList, len(pkg.Scope.Objects))
+       {
+               i := 0
+               for _, obj := range pkg.Scope.Objects {
+                       list[i] = obj
+                       i++
+               }
+               list.Sort()
+       }
+
+       // Check global objects.
+       for _, obj := range list {
+               check.obj(obj, false)
+       }
+
+       // TODO(gri) Missing pieces:
+       // - blank (_) objects and init functions are not in scopes but should be type-checked
+
+       // do not remove multiple errors per line - depending on
+       // order or error reporting this may hide the real error
+       return check.errors.Err()
+}
 
--- /dev/null
+// 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 operations on constant values.
+
+package types
+
+import (
+       "fmt"
+       "go/token"
+       "math/big"
+       "strconv"
+)
+
+// TODO(gri) At the moment, constants are different types
+// passed around as interface{} values. Consider introducing
+// a Const type and use methods instead of xConst functions.
+
+// Representation of constant values.
+//
+// bool     ->  bool (true, false)
+// numeric  ->  int64, *big.Int, *big.Rat, complex (ordered by increasing data structure "size")
+// string   ->  string
+// nil      ->  nilType (nilConst)
+//
+// Numeric constants are normalized after each operation such
+// that they are represented by the "smallest" data structure
+// required to represent the constant, independent of actual
+// type. Non-numeric constants are always normalized.
+
+// Representation of complex numbers. 
+type complex struct {
+       re, im *big.Rat
+}
+
+func (c complex) String() string {
+       if c.re.Sign() == 0 {
+               return fmt.Sprintf("%si", c.im)
+       }
+       // normalized complex values always have an imaginary part
+       return fmt.Sprintf("(%s + %si)", c.re, c.im)
+}
+
+// Representation of nil.
+type nilType struct{}
+
+func (nilType) String() string {
+       return "nil"
+}
+
+// Frequently used constants.
+var (
+       zeroConst     = int64(0)
+       oneConst      = int64(1)
+       minusOneConst = int64(-1)
+       nilConst      = new(nilType)
+)
+
+// int64 bounds
+var (
+       minInt64 = big.NewInt(-1 << 63)
+       maxInt64 = big.NewInt(1<<63 - 1)
+)
+
+// normalizeIntConst returns the smallest constant representation
+// for the specific value of x; either an int64 or a *big.Int value.
+//
+func normalizeIntConst(x *big.Int) interface{} {
+       if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
+               return x.Int64()
+       }
+       return x
+}
+
+// normalizeRatConst returns the smallest constant representation
+// for the specific value of x; either an int64, *big.Int value,
+// or *big.Rat value.
+//
+func normalizeRatConst(x *big.Rat) interface{} {
+       if x.IsInt() {
+               return normalizeIntConst(x.Num())
+       }
+       return x
+}
+
+// normalizeComplexConst returns the smallest constant representation
+// for the specific value of x; either an int64, *big.Int value, *big.Rat,
+// or complex value.
+//
+func normalizeComplexConst(x complex) interface{} {
+       if x.im.Sign() == 0 {
+               return normalizeRatConst(x.re)
+       }
+       return x
+}
+
+// makeRuneConst returns the int64 code point for the rune literal
+// lit. The result is nil if lit is not a correct rune literal.
+//
+func makeRuneConst(lit string) interface{} {
+       if n := len(lit); n >= 2 {
+               if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil {
+                       return int64(code)
+               }
+       }
+       return nil
+}
+
+// makeRuneConst returns the smallest integer constant representation
+// (int64, *big.Int) for the integer literal lit. The result is nil if
+// lit is not a correct integer literal.
+//
+func makeIntConst(lit string) interface{} {
+       if x, err := strconv.ParseInt(lit, 0, 64); err == nil {
+               return x
+       }
+       if x, ok := new(big.Int).SetString(lit, 0); ok {
+               return x
+       }
+       return nil
+}
+
+// makeFloatConst returns the smallest floating-point constant representation
+// (int64, *big.Int, *big.Rat) for the floating-point literal lit. The result
+// is nil if lit is not a correct floating-point literal.
+//
+func makeFloatConst(lit string) interface{} {
+       if x, ok := new(big.Rat).SetString(lit); ok {
+               return normalizeRatConst(x)
+       }
+       return nil
+}
+
+// makeComplexConst returns the complex constant representation (complex) for
+// the imaginary literal lit. The result is nil if lit is not a correct imaginary
+// literal.
+//
+func makeComplexConst(lit string) interface{} {
+       n := len(lit)
+       if n > 0 && lit[n-1] == 'i' {
+               if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok {
+                       return normalizeComplexConst(complex{big.NewRat(0, 1), im})
+               }
+       }
+       return nil
+}
+
+// makeStringConst returns the string constant representation (string) for
+// the string literal lit. The result is nil if lit is not a correct string
+// literal.
+//
+func makeStringConst(lit string) interface{} {
+       if s, err := strconv.Unquote(lit); err == nil {
+               return s
+       }
+       return nil
+}
+
+// isZeroConst reports whether the value of constant x is 0.
+// x must be normalized.
+//
+func isZeroConst(x interface{}) bool {
+       i, ok := x.(int64) // good enough since constants are normalized
+       return ok && i == 0
+}
+
+// isRepresentableConst reports whether the value of constant x can
+// be represented as a value of the basic type Typ[as] without loss
+// of precision.
+//
+func isRepresentableConst(x interface{}, as BasicKind) bool {
+       const intBits = 32 // TODO(gri) implementation-specific constant
+       const ptrBits = 64 // TODO(gri) implementation-specific constant
+
+       switch x := x.(type) {
+       case bool:
+               return as == Bool || as == UntypedBool
+
+       case int64:
+               switch as {
+               case Int:
+                       return -1<<(intBits-1) <= x && x <= 1<<(intBits-1)-1
+               case Int8:
+                       return -1<<(8-1) <= x && x <= 1<<(8-1)-1
+               case Int16:
+                       return -1<<(16-1) <= x && x <= 1<<(16-1)-1
+               case Int32, UntypedRune:
+                       return -1<<(32-1) <= x && x <= 1<<(32-1)-1
+               case Int64:
+                       return true
+               case Uint:
+                       return 0 <= x && x <= 1<<intBits-1
+               case Uint8:
+                       return 0 <= x && x <= 1<<8-1
+               case Uint16:
+                       return 0 <= x && x <= 1<<16-1
+               case Uint32:
+                       return 0 <= x && x <= 1<<32-1
+               case Uint64:
+                       return 0 <= x
+               case Uintptr:
+                       assert(ptrBits == 64)
+                       return 0 <= x
+               case Float32:
+                       return true // TODO(gri) fix this
+               case Float64:
+                       return true // TODO(gri) fix this
+               case Complex64:
+                       return true // TODO(gri) fix this
+               case Complex128:
+                       return true // TODO(gri) fix this
+               case UntypedInt, UntypedFloat, UntypedComplex:
+                       return true
+               }
+
+       case *big.Int:
+               switch as {
+               case Uint:
+                       return x.Sign() >= 0 && x.BitLen() <= intBits
+               case Uint64:
+                       return x.Sign() >= 0 && x.BitLen() <= 64
+               case Uintptr:
+                       return x.Sign() >= 0 && x.BitLen() <= ptrBits
+               case Float32:
+                       return true // TODO(gri) fix this
+               case Float64:
+                       return true // TODO(gri) fix this
+               case Complex64:
+                       return true // TODO(gri) fix this
+               case Complex128:
+                       return true // TODO(gri) fix this
+               case UntypedInt, UntypedFloat, UntypedComplex:
+                       return true
+               }
+
+       case *big.Rat:
+               switch as {
+               case Float32:
+                       return true // TODO(gri) fix this
+               case Float64:
+                       return true // TODO(gri) fix this
+               case Complex64:
+                       return true // TODO(gri) fix this
+               case Complex128:
+                       return true // TODO(gri) fix this
+               case UntypedFloat, UntypedComplex:
+                       return true
+               }
+
+       case complex:
+               switch as {
+               case Complex64:
+                       return true // TODO(gri) fix this
+               case Complex128:
+                       return true // TODO(gri) fix this
+               case UntypedComplex:
+                       return true
+               }
+
+       case string:
+               return as == String || as == UntypedString
+
+       case nilType:
+               return as == UntypedNil
+
+       default:
+               unreachable()
+       }
+
+       return false
+}
+
+var (
+       int1 = big.NewInt(1)
+       rat0 = big.NewRat(0, 1)
+)
+
+// complexity returns a measure of representation complexity for constant x.
+func complexity(x interface{}) int {
+       switch x.(type) {
+       case bool, string, nilType:
+               return 1
+       case int64:
+               return 2
+       case *big.Int:
+               return 3
+       case *big.Rat:
+               return 4
+       case complex:
+               return 5
+       }
+       unreachable()
+       return 0
+}
+
+// matchConst returns the matching representation (same type) with the
+// smallest complexity for two constant values x and y. They must be
+// of the same "kind" (boolean, numeric, string, or nilType).
+// 
+func matchConst(x, y interface{}) (_, _ interface{}) {
+       if complexity(x) > complexity(y) {
+               y, x = matchConst(y, x)
+               return x, y
+       }
+       // complexity(x) <= complexity(y)
+
+       switch x := x.(type) {
+       case bool, complex, string, nilType:
+               return x, y
+
+       case int64:
+               switch y := y.(type) {
+               case int64:
+                       return x, y
+               case *big.Int:
+                       return big.NewInt(x), y
+               case *big.Rat:
+                       return big.NewRat(x, 1), y
+               case complex:
+                       return complex{big.NewRat(x, 1), rat0}, y
+               }
+
+       case *big.Int:
+               switch y := y.(type) {
+               case *big.Int:
+                       return x, y
+               case *big.Rat:
+                       return new(big.Rat).SetFrac(x, int1), y
+               case complex:
+                       return complex{new(big.Rat).SetFrac(x, int1), rat0}, y
+               }
+
+       case *big.Rat:
+               switch y := y.(type) {
+               case *big.Rat:
+                       return x, y
+               case complex:
+                       return complex{x, rat0}, y
+               }
+       }
+
+       unreachable()
+       return nil, nil
+}
+
+// is32bit reports whether x can be represented using 32 bits.
+func is32bit(x int64) bool {
+       return -1<<31 <= x && x <= 1<<31-1
+}
+
+// is63bit reports whether x can be represented using 63 bits.
+func is63bit(x int64) bool {
+       return -1<<62 <= x && x <= 1<<62-1
+}
+
+// binaryOpConst returns the result of the constant evaluation x op y;
+// both operands must be of the same "kind" (boolean, numeric, or string).
+// If intDiv is true, division (op == token.QUO) is using integer division
+// (and the result is guaranteed to be integer) rather than floating-point
+// division. Division by zero leads to a run-time panic.
+//
+func binaryOpConst(x, y interface{}, op token.Token, intDiv bool) interface{} {
+       x, y = matchConst(x, y)
+
+       switch x := x.(type) {
+       case bool:
+               y := y.(bool)
+               switch op {
+               case token.LAND:
+                       return x && y
+               case token.LOR:
+                       return x || y
+               default:
+                       unreachable()
+               }
+
+       case int64:
+               y := y.(int64)
+               switch op {
+               case token.ADD:
+                       // TODO(gri) can do better than this
+                       if is63bit(x) && is63bit(y) {
+                               return x + y
+                       }
+                       return normalizeIntConst(new(big.Int).Add(big.NewInt(x), big.NewInt(y)))
+               case token.SUB:
+                       // TODO(gri) can do better than this
+                       if is63bit(x) && is63bit(y) {
+                               return x - y
+                       }
+                       return normalizeIntConst(new(big.Int).Sub(big.NewInt(x), big.NewInt(y)))
+               case token.MUL:
+                       // TODO(gri) can do better than this
+                       if is32bit(x) && is32bit(y) {
+                               return x * y
+                       }
+                       return normalizeIntConst(new(big.Int).Mul(big.NewInt(x), big.NewInt(y)))
+               case token.REM:
+                       return x % y
+               case token.QUO:
+                       if intDiv {
+                               return x / y
+                       }
+                       return normalizeRatConst(new(big.Rat).SetFrac(big.NewInt(x), big.NewInt(y)))
+               case token.AND:
+                       return x & y
+               case token.OR:
+                       return x | y
+               case token.XOR:
+                       return x ^ y
+               case token.AND_NOT:
+                       return x &^ y
+               default:
+                       unreachable()
+               }
+
+       case *big.Int:
+               y := y.(*big.Int)
+               var z big.Int
+               switch op {
+               case token.ADD:
+                       z.Add(x, y)
+               case token.SUB:
+                       z.Sub(x, y)
+               case token.MUL:
+                       z.Mul(x, y)
+               case token.REM:
+                       z.Rem(x, y)
+               case token.QUO:
+                       if intDiv {
+                               z.Quo(x, y)
+                       } else {
+                               return normalizeRatConst(new(big.Rat).SetFrac(x, y))
+                       }
+               case token.AND:
+                       z.And(x, y)
+               case token.OR:
+                       z.Or(x, y)
+               case token.XOR:
+                       z.Xor(x, y)
+               case token.AND_NOT:
+                       z.AndNot(x, y)
+               default:
+                       unreachable()
+               }
+               return normalizeIntConst(&z)
+
+       case *big.Rat:
+               y := y.(*big.Rat)
+               var z big.Rat
+               switch op {
+               case token.ADD:
+                       z.Add(x, y)
+               case token.SUB:
+                       z.Sub(x, y)
+               case token.MUL:
+                       z.Mul(x, y)
+               case token.QUO:
+                       z.Quo(x, y)
+               default:
+                       unreachable()
+               }
+               return normalizeRatConst(&z)
+
+       case complex:
+               y := y.(complex)
+               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 big.Rat
+                       ac.Mul(a, c)
+                       bd.Mul(b, d)
+                       bc.Mul(b, c)
+                       ad.Mul(a, d)
+                       s.Add(c.Mul(c, c), d.Mul(d, d))
+                       re.Add(&ac, &bd)
+                       re.Quo(&re, &s)
+                       im.Sub(&bc, &ad)
+                       im.Quo(&im, &s)
+               default:
+                       unreachable()
+               }
+               return normalizeComplexConst(complex{&re, &im})
+
+       case string:
+               if op == token.ADD {
+                       return x + y.(string)
+               }
+       }
+
+       unreachable()
+       return nil
+}
+
+// shiftConst returns the result of the constant evaluation x op s
+// where op is token.SHL or token.SHR (<< or >>). x must be an
+// integer constant.
+//
+func shiftConst(x interface{}, s uint, op token.Token) interface{} {
+       switch x := x.(type) {
+       case int64:
+               switch op {
+               case token.SHL:
+                       z := big.NewInt(x)
+                       return normalizeIntConst(z.Lsh(z, s))
+               case token.SHR:
+                       return x >> s
+               }
+
+       case *big.Int:
+               var z big.Int
+               switch op {
+               case token.SHL:
+                       return normalizeIntConst(z.Lsh(x, s))
+               case token.SHR:
+                       return normalizeIntConst(z.Rsh(x, s))
+               }
+       }
+
+       unreachable()
+       return nil
+}
+
+// compareConst returns the result of the constant comparison x op y;
+// both operands must be of the same "kind" (boolean, numeric, string,
+// or nilType).
+//
+func compareConst(x, y interface{}, op token.Token) (z bool) {
+       x, y = matchConst(x, y)
+
+       // x == y  =>  x == y
+       // x != y  =>  x != y
+       // x >  y  =>  y <  x
+       // x >= y  =>  u <= x
+       swap := false
+       switch op {
+       case token.GTR:
+               swap = true
+               op = token.LSS
+       case token.GEQ:
+               swap = true
+               op = token.LEQ
+       }
+
+       // x == y  =>    x == y
+       // x != y  =>  !(x == y)
+       // x <  y  =>    x <  y
+       // x <= y  =>  !(y <  x)
+       negate := false
+       switch op {
+       case token.NEQ:
+               negate = true
+               op = token.EQL
+       case token.LEQ:
+               swap = !swap
+               negate = true
+               op = token.LSS
+       }
+
+       if negate {
+               defer func() { z = !z }()
+       }
+
+       if swap {
+               x, y = y, x
+       }
+
+       switch x := x.(type) {
+       case bool:
+               if op == token.EQL {
+                       return x == y.(bool)
+               }
+
+       case int64:
+               y := y.(int64)
+               switch op {
+               case token.EQL:
+                       return x == y
+               case token.LSS:
+                       return x < y
+               }
+
+       case *big.Int:
+               s := x.Cmp(y.(*big.Int))
+               switch op {
+               case token.EQL:
+                       return s == 0
+               case token.LSS:
+                       return s < 0
+               }
+
+       case *big.Rat:
+               s := x.Cmp(y.(*big.Rat))
+               switch op {
+               case token.EQL:
+                       return s == 0
+               case token.LSS:
+                       return s < 0
+               }
+
+       case complex:
+               y := y.(complex)
+               if op == token.EQL {
+                       return x.re.Cmp(y.re) == 0 && x.im.Cmp(y.im) == 0
+               }
+
+       case string:
+               y := y.(string)
+               switch op {
+               case token.EQL:
+                       return x == y
+               case token.LSS:
+                       return x < y
+               }
+
+       case nilType:
+               if op == token.EQL {
+                       return x == y.(nilType)
+               }
+       }
+
+       fmt.Printf("x = %s (%T), y = %s (%T)\n", x, x, y, y)
+       unreachable()
+       return
+}
 
--- /dev/null
+// 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 (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/token"
+)
+
+// debugging flags
+const debug = false
+const trace = false
+
+func assert(p bool) {
+       if !p {
+               panic("assertion failed")
+       }
+}
+
+func unimplemented() {
+       if debug {
+               panic("unimplemented")
+       }
+}
+
+func unreachable() {
+       panic("unreachable")
+}
+
+// dump is only needed for debugging
+func (check *checker) dump(format string, args ...interface{}) {
+       if n := len(format); n > 0 && format[n-1] != '\n' {
+               format += "\n"
+       }
+       check.convertArgs(args)
+       fmt.Printf(format, args...)
+}
+
+func (check *checker) errorf(pos token.Pos, format string, args ...interface{}) {
+       check.convertArgs(args)
+       msg := fmt.Sprintf(format, args...)
+       check.errors.Add(check.fset.Position(pos), msg)
+}
+
+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...)
+}
+
+func (check *checker) convertArgs(args []interface{}) {
+       for i, arg := range args {
+               switch a := arg.(type) {
+               case token.Pos:
+                       args[i] = check.fset.Position(a)
+               case ast.Expr:
+                       args[i] = exprString(a)
+               case Type:
+                       args[i] = typeString(a)
+               case operand:
+                       panic("internal error: should always pass *operand")
+               }
+       }
+}
+
+// exprString returns a (simplified) string representation for an expression.
+func exprString(expr ast.Expr) string {
+       var buf bytes.Buffer
+       writeExpr(&buf, expr)
+       return buf.String()
+}
+
+// TODO(gri) Need to merge with typeString since some expressions are types (try: ([]int)(a))
+func writeExpr(buf *bytes.Buffer, expr ast.Expr) {
+       switch x := expr.(type) {
+       case *ast.Ident:
+               buf.WriteString(x.Name)
+
+       case *ast.BasicLit:
+               buf.WriteString(x.Value)
+
+       case *ast.FuncLit:
+               buf.WriteString("(func literal)")
+
+       case *ast.CompositeLit:
+               buf.WriteString("(composite literal)")
+
+       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)
+               }
+               buf.WriteByte(']')
+
+       case *ast.TypeAssertExpr:
+               writeExpr(buf, x.X)
+               buf.WriteString(".(...)")
+
+       case *ast.CallExpr:
+               writeExpr(buf, x.Fun)
+               buf.WriteByte('(')
+               for i, arg := range x.Args {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       writeExpr(buf, arg)
+               }
+               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:
+               // The AST preserves source-level parentheses so there is
+               // no need to introduce parentheses here for correctness.
+               writeExpr(buf, x.X)
+               buf.WriteByte(' ')
+               buf.WriteString(x.Op.String())
+               buf.WriteByte(' ')
+               writeExpr(buf, x.Y)
+
+       default:
+               fmt.Fprintf(buf, "<expr %T>", x)
+       }
+}
+
+// typeString returns a string representation for typ.
+func typeString(typ Type) string {
+       var buf bytes.Buffer
+       writeType(&buf, typ)
+       return buf.String()
+}
+
+func writeParams(buf *bytes.Buffer, params ObjList, isVariadic bool) {
+       buf.WriteByte('(')
+       for i, par := range params {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               if par.Name != "" {
+                       buf.WriteString(par.Name)
+                       buf.WriteByte(' ')
+               }
+               if isVariadic && i == len(params)-1 {
+                       buf.WriteString("...")
+               }
+               writeType(buf, par.Type.(Type))
+       }
+       buf.WriteByte(')')
+}
+
+func writeSignature(buf *bytes.Buffer, sig *Signature) {
+       writeParams(buf, sig.Params, sig.IsVariadic)
+       if len(sig.Results) == 0 {
+               // no result
+               return
+       }
+
+       buf.WriteByte(' ')
+       if len(sig.Results) == 1 && sig.Results[0].Name == "" {
+               // single unnamed result
+               writeType(buf, sig.Results[0].Type.(Type))
+               return
+       }
+
+       // multiple or named result(s)
+       writeParams(buf, sig.Results, false)
+}
+
+func writeType(buf *bytes.Buffer, typ Type) {
+       switch t := typ.(type) {
+       case nil:
+               buf.WriteString("<nil>")
+
+       case *Basic:
+               buf.WriteString(t.Name)
+
+       case *Array:
+               fmt.Fprintf(buf, "[%d]", t.Len)
+               writeType(buf, t.Elt)
+
+       case *Slice:
+               buf.WriteString("[]")
+               writeType(buf, t.Elt)
+
+       case *Struct:
+               buf.WriteString("struct{")
+               for i, f := range t.Fields {
+                       if i > 0 {
+                               buf.WriteString("; ")
+                       }
+                       if !f.IsAnonymous {
+                               buf.WriteString(f.Name)
+                               buf.WriteByte(' ')
+                       }
+                       writeType(buf, f.Type)
+                       if f.Tag != "" {
+                               fmt.Fprintf(buf, " %q", f.Tag)
+                       }
+               }
+               buf.WriteByte('}')
+
+       case *Pointer:
+               buf.WriteByte('*')
+               writeType(buf, t.Base)
+
+       case *tuple:
+               buf.WriteByte('(')
+               for i, typ := range t.list {
+                       if i > 0 {
+                               buf.WriteString("; ")
+                       }
+                       writeType(buf, typ)
+               }
+               buf.WriteByte(')')
+
+       case *Signature:
+               buf.WriteString("func")
+               writeSignature(buf, t)
+
+       case *builtin:
+               fmt.Fprintf(buf, "<type of %s>", t.name)
+
+       case *Interface:
+               buf.WriteString("interface{")
+               for i, m := range t.Methods {
+                       if i > 0 {
+                               buf.WriteString("; ")
+                       }
+                       buf.WriteString(m.Name)
+                       writeSignature(buf, m.Type.(*Signature))
+               }
+               buf.WriteByte('}')
+
+       case *Map:
+               buf.WriteString("map[")
+               writeType(buf, t.Key)
+               buf.WriteByte(']')
+               writeType(buf, t.Elt)
+
+       case *Chan:
+               var s string
+               switch t.Dir {
+               case ast.SEND:
+                       s = "chan<- "
+               case ast.RECV:
+                       s = "<-chan "
+               default:
+                       s = "chan "
+               }
+               buf.WriteString(s)
+               writeType(buf, t.Elt)
+
+       case *NamedType:
+               buf.WriteString(t.Obj.Name)
+
+       default:
+               fmt.Fprintf(buf, "<type %T>", t)
+       }
+}
 
+++ /dev/null
-// 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
-
-import (
-       "bytes"
-       "fmt"
-       "go/ast"
-)
-
-// exprString returns a (simplified) string representation for an expression.
-func exprString(expr ast.Expr) string {
-       var buf bytes.Buffer
-       writeExpr(&buf, expr)
-       return buf.String()
-}
-
-// TODO(gri) Need to merge with typeString since some expressions are types (try: ([]int)(a))
-func writeExpr(buf *bytes.Buffer, expr ast.Expr) {
-       switch x := expr.(type) {
-       case *ast.Ident:
-               buf.WriteString(x.Name)
-
-       case *ast.BasicLit:
-               buf.WriteString(x.Value)
-
-       case *ast.FuncLit:
-               buf.WriteString("(func literal)")
-
-       case *ast.CompositeLit:
-               buf.WriteString("(composite literal)")
-
-       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)
-               }
-               buf.WriteByte(']')
-
-       case *ast.TypeAssertExpr:
-               writeExpr(buf, x.X)
-               buf.WriteString(".(...)")
-
-       case *ast.CallExpr:
-               writeExpr(buf, x.Fun)
-               buf.WriteByte('(')
-               for i, arg := range x.Args {
-                       if i > 0 {
-                               buf.WriteString(", ")
-                       }
-                       writeExpr(buf, arg)
-               }
-               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:
-               // The AST preserves source-level parentheses so there is
-               // no need to introduce parentheses here for correctness.
-               writeExpr(buf, x.X)
-               buf.WriteByte(' ')
-               buf.WriteString(x.Op.String())
-               buf.WriteByte(' ')
-               writeExpr(buf, x.Y)
-
-       default:
-               fmt.Fprintf(buf, "<expr %T>", x)
-       }
-}
 
--- /dev/null
+// 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"
+       "fmt"
+       "go/ast"
+       "go/token"
+)
+
+// An operandMode specifies the (addressing) mode of an operand.
+type operandMode int
+
+const (
+       invalid  operandMode = iota // operand is invalid (due to an earlier error) - ignore
+       novalue                     // operand represents no value (result of a function call w/o result)
+       typexpr                     // operand is a type
+       constant                    // operand is a constant; the operand's typ is a Basic type
+       variable                    // operand is an addressable variable
+       value                       // operand is a computed value
+       valueok                     // like mode == value, but operand may be used in a comma,ok expression
+)
+
+var operandModeString = [...]string{
+       invalid:  "invalid",
+       novalue:  "no value",
+       typexpr:  "type",
+       constant: "constant",
+       variable: "variable",
+       value:    "value",
+       valueok:  "value,ok",
+}
+
+// An operand represents an intermediate value during type checking.
+// Operands have an (addressing) mode, the expression evaluating to
+// the operand, the operand's type, and for constants a constant value.
+//
+type operand struct {
+       mode operandMode
+       expr ast.Expr
+       typ  Type
+       val  interface{}
+}
+
+// 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()
+}
+
+func (x *operand) String() string {
+       if x.mode == invalid {
+               return "invalid operand"
+       }
+       var buf bytes.Buffer
+       if x.expr != nil {
+               buf.WriteString(exprString(x.expr))
+               buf.WriteString(" (")
+       }
+       buf.WriteString(operandModeString[x.mode])
+       if x.mode == constant {
+               fmt.Fprintf(&buf, " %v", x.val)
+       }
+       if x.mode != novalue && (x.mode != constant || !isUntyped(x.typ)) {
+               fmt.Fprintf(&buf, " of type %s", typeString(x.typ))
+       }
+       if x.expr != nil {
+               buf.WriteByte(')')
+       }
+       return buf.String()
+}
+
+// setConst sets x to the untyped constant for literal lit. 
+func (x *operand) setConst(tok token.Token, lit string) {
+       x.mode = invalid
+
+       var kind BasicKind
+       var val interface{}
+       switch tok {
+       case token.INT:
+               kind = UntypedInt
+               val = makeIntConst(lit)
+
+       case token.FLOAT:
+               kind = UntypedFloat
+               val = makeFloatConst(lit)
+
+       case token.IMAG:
+               kind = UntypedComplex
+               val = makeComplexConst(lit)
+
+       case token.CHAR:
+               kind = UntypedRune
+               val = makeRuneConst(lit)
+
+       case token.STRING:
+               kind = UntypedString
+               val = makeStringConst(lit)
+       }
+
+       if val != nil {
+               x.mode = constant
+               x.typ = Typ[kind]
+               x.val = val
+       }
+}
+
+// implements reports whether x implements interface T.
+func (x *operand) implements(T *Interface) bool {
+       if x.mode == invalid {
+               return true // avoid spurious errors
+       }
+
+       unimplemented()
+       return true
+}
+
+// isAssignable reports whether x is assignable to a variable of type T.
+func (x *operand) isAssignable(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 isIdentical(V, T) {
+               return true
+       }
+
+       Vu := underlying(V)
+       Tu := underlying(T)
+
+       // x's type V and T have identical underlying types
+       // and at least one of V or T is not a named type
+       if isIdentical(Vu, Tu) {
+               return !isNamed(V) || !isNamed(T)
+       }
+
+       // T is an interface type and x implements T
+       if Ti, ok := Tu.(*Interface); ok && x.implements(Ti) {
+               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 == ast.SEND|ast.RECV {
+               if Tc, ok := Tu.(*Chan); ok && isIdentical(Vc.Elt, Tc.Elt) {
+                       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.typ == Typ[UntypedNil] {
+               switch Tu.(type) {
+               case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface:
+                       return true
+               }
+               return false
+       }
+
+       // x is an untyped constant representable by a value of type T
+       // - this is taken care of in the assignment check
+       // TODO(gri) double-check - isAssignable is used elsewhere
+
+       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 && isRepresentableConst(x.val, UntypedInt)
+}
+
+// lookupField returns the struct field with the given name in typ.
+// If no such field exists, the result is nil.
+// TODO(gri) should this be a method of Struct?
+//
+func lookupField(typ *Struct, name string) *StructField {
+       // TODO(gri) deal with embedding and conflicts - this is
+       //           a very basic version to get going for now.
+       for _, f := range typ.Fields {
+               if f.Name == name {
+                       return f
+               }
+       }
+       return nil
+}
 
        return false
 }
 
-// underlying returns the underlying type of typ.
-func underlying(typ Type) Type {
-       // Basic types are representing themselves directly even though they are named.
-       if typ, ok := typ.(*NamedType); ok {
-               return typ.Underlying // underlying types are never NamedTypes
-       }
-       return typ
-}
-
-// deref returns a pointer's base type; otherwise it returns typ.
-func deref(typ Type) Type {
-       if typ, ok := underlying(typ).(*Pointer); ok {
-               return typ.Base
-       }
-       return typ
-}
-
 // identical returns true if x and y are identical.
 func isIdentical(x, y Type) bool {
        if x == y {
        }
        return false
 }
+
+// underlying returns the underlying type of typ.
+func underlying(typ Type) Type {
+       // Basic types are representing themselves directly even though they are named.
+       if typ, ok := typ.(*NamedType); ok {
+               return typ.Underlying // underlying types are never NamedTypes
+       }
+       return typ
+}
+
+// deref returns a pointer's base type; otherwise it returns typ.
+func deref(typ Type) Type {
+       if typ, ok := underlying(typ).(*Pointer); ok {
+               return typ.Base
+       }
+       return typ
+}
+
+// defaultType returns the default "typed" type for an "untyped" type;
+// it returns the argument typ for all other types.
+func defaultType(typ Type) Type {
+       if t, ok := typ.(*Basic); ok {
+               var k BasicKind
+               switch t.Kind {
+               case UntypedBool:
+                       k = Bool
+               case UntypedRune:
+                       k = Rune
+               case UntypedInt:
+                       k = Int
+               case UntypedFloat:
+                       k = Float64
+               case UntypedComplex:
+                       k = Complex128
+               case UntypedString:
+                       k = String
+               default:
+                       unreachable()
+               }
+               typ = Typ[k]
+       }
+       return typ
+}
 
--- /dev/null
+// 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 contains unimplemented stubs so that the
+// code in exp/types/staging compiles.
+
+package types
+
+import "go/ast"
+
+// expr typechecks expression e and initializes x with the expression
+// value or type. If an error occured, x.mode is set to invalid.
+// A hint != nil is used as operand type for untyped shifted operands;
+// iota >= 0 indicates that the expression is part of a constant declaration.
+// cycleOk indicates whether it is ok for a type expression to refer to itself.
+//
+func (check *checker) exprOrType(x *operand, e ast.Expr, hint Type, iota int, cycleOk bool) {
+       unimplemented()
+}
+
+// expr is like exprOrType but also checks that e represents a value (rather than a type).
+func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) {
+       unimplemented()
+}
+
+// typ is like exprOrType but also checks that e represents a type (rather than a value).
+// If an error occured, the result is Typ[Invalid].
+//
+func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
+       unimplemented()
+       return nil
+}
+
+// assignNtoM typechecks a general assignment. If decl is set, the lhs operands
+// must be identifiers. If their types are not set, they are deduced from the
+// types of the corresponding rhs expressions. iota >= 0 indicates that the
+// "assignment" is part of a constant declaration.
+//
+func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int) {
+       unimplemented()
+}
+
+// assignment typechecks a single assignment of the form lhs := x. If decl is set,
+// the lhs operand must be an identifier. If its type is not set, it is deduced
+// from the type or value of x.
+//
+func (check *checker) assignment(lhs ast.Expr, x *operand, decl bool) {
+       unimplemented()
+}
+
+// stmt typechecks statement s.
+func (check *checker) stmt(s ast.Stmt) {
+       unimplemented()
+}
 
 // the expression appears in the AST.
 //
 func Check(fset *token.FileSet, pkg *ast.Package, types map[ast.Expr]Type) error {
-       // return check(fset, pkg, types) // commented out for now to make it compile
-       return nil
+       return check(fset, pkg, types)
 }
 
 // All types implement the Type interface.
        implementsType
        Kind BasicKind
        Info BasicInfo
+       Size int64 // > 0 if valid
        Name string
 }
 
 // A builtin represents the type of a built-in function.
 type builtin struct {
        implementsType
-       id         builtinId
-       name       string
-       nargs      int // number of arguments (minimum if variadic)
-       isVariadic bool
+       id          builtinId
+       name        string
+       nargs       int // number of arguments (minimum if variadic)
+       isVariadic  bool
+       isStatement bool // true if the built-in is valid as an expression statement
 }
 
 // An Interface represents an interface type interface{...}.
 
+++ /dev/null
-// 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 the TypeString function.
-
-package types
-
-import (
-       "bytes"
-       "fmt"
-       "go/ast"
-)
-
-// typeString returns a string representation for typ.
-func typeString(typ Type) string {
-       var buf bytes.Buffer
-       writeType(&buf, typ)
-       return buf.String()
-}
-
-func writeParams(buf *bytes.Buffer, params ObjList, isVariadic bool) {
-       buf.WriteByte('(')
-       for i, par := range params {
-               if i > 0 {
-                       buf.WriteString(", ")
-               }
-               if par.Name != "" {
-                       buf.WriteString(par.Name)
-                       buf.WriteByte(' ')
-               }
-               if isVariadic && i == len(params)-1 {
-                       buf.WriteString("...")
-               }
-               writeType(buf, par.Type.(Type))
-       }
-       buf.WriteByte(')')
-}
-
-func writeSignature(buf *bytes.Buffer, sig *Signature) {
-       writeParams(buf, sig.Params, sig.IsVariadic)
-       if len(sig.Results) == 0 {
-               // no result
-               return
-       }
-
-       buf.WriteByte(' ')
-       if len(sig.Results) == 1 && sig.Results[0].Name == "" {
-               // single unnamed result
-               writeType(buf, sig.Results[0].Type.(Type))
-               return
-       }
-
-       // multiple or named result(s)
-       writeParams(buf, sig.Results, false)
-}
-
-func writeType(buf *bytes.Buffer, typ Type) {
-       switch t := typ.(type) {
-       case nil:
-               buf.WriteString("<nil>")
-
-       case *Basic:
-               buf.WriteString(t.Name)
-
-       case *Array:
-               fmt.Fprintf(buf, "[%d]", t.Len)
-               writeType(buf, t.Elt)
-
-       case *Slice:
-               buf.WriteString("[]")
-               writeType(buf, t.Elt)
-
-       case *Struct:
-               buf.WriteString("struct{")
-               for i, f := range t.Fields {
-                       if i > 0 {
-                               buf.WriteString("; ")
-                       }
-                       if !f.IsAnonymous {
-                               buf.WriteString(f.Name)
-                               buf.WriteByte(' ')
-                       }
-                       writeType(buf, f.Type)
-                       if f.Tag != "" {
-                               fmt.Fprintf(buf, " %q", f.Tag)
-                       }
-               }
-               buf.WriteByte('}')
-
-       case *Pointer:
-               buf.WriteByte('*')
-               writeType(buf, t.Base)
-
-       case *tuple:
-               buf.WriteByte('(')
-               for i, typ := range t.list {
-                       if i > 0 {
-                               buf.WriteString("; ")
-                       }
-                       writeType(buf, typ)
-               }
-               buf.WriteByte(')')
-
-       case *Signature:
-               buf.WriteString("func")
-               writeSignature(buf, t)
-
-       case *builtin:
-               fmt.Fprintf(buf, "<type of %s>", t.name)
-
-       case *Interface:
-               buf.WriteString("interface{")
-               for i, m := range t.Methods {
-                       if i > 0 {
-                               buf.WriteString("; ")
-                       }
-                       buf.WriteString(m.Name)
-                       writeSignature(buf, m.Type.(*Signature))
-               }
-               buf.WriteByte('}')
-
-       case *Map:
-               buf.WriteString("map[")
-               writeType(buf, t.Key)
-               buf.WriteByte(']')
-               writeType(buf, t.Elt)
-
-       case *Chan:
-               var s string
-               switch t.Dir {
-               case ast.SEND:
-                       s = "chan<- "
-               case ast.RECV:
-                       s = "<-chan "
-               default:
-                       s = "chan "
-               }
-               buf.WriteString(s)
-               writeType(buf, t.Elt)
-
-       case *NamedType:
-               buf.WriteString(t.Obj.Name)
-
-       default:
-               fmt.Fprintf(buf, "<type %T>", t)
-       }
-}
 
 
 // Predeclared types, indexed by BasicKind.
 var Typ = [...]*Basic{
-       Invalid: {aType, Invalid, 0, "invalid type"},
-
-       Bool:          {aType, Bool, IsBoolean, "bool"},
-       Int:           {aType, Int, IsInteger, "int"},
-       Int8:          {aType, Int8, IsInteger, "int8"},
-       Int16:         {aType, Int16, IsInteger, "int16"},
-       Int32:         {aType, Int32, IsInteger, "int32"},
-       Int64:         {aType, Int64, IsInteger, "int64"},
-       Uint:          {aType, Uint, IsInteger | IsUnsigned, "uint"},
-       Uint8:         {aType, Uint8, IsInteger | IsUnsigned, "uint8"},
-       Uint16:        {aType, Uint16, IsInteger | IsUnsigned, "uint16"},
-       Uint32:        {aType, Uint32, IsInteger | IsUnsigned, "uint32"},
-       Uint64:        {aType, Uint64, IsInteger | IsUnsigned, "uint64"},
-       Uintptr:       {aType, Uintptr, IsInteger | IsUnsigned, "uintptr"},
-       Float32:       {aType, Float32, IsFloat, "float32"},
-       Float64:       {aType, Float64, IsFloat, "float64"},
-       Complex64:     {aType, Complex64, IsComplex, "complex64"},
-       Complex128:    {aType, Complex128, IsComplex, "complex128"},
-       String:        {aType, String, IsString, "string"},
-       UnsafePointer: {aType, UnsafePointer, 0, "Pointer"},
-
-       UntypedBool:    {aType, UntypedBool, IsBoolean | IsUntyped, "untyped boolean"},
-       UntypedInt:     {aType, UntypedInt, IsInteger | IsUntyped, "untyped integer"},
-       UntypedRune:    {aType, UntypedRune, IsInteger | IsUntyped, "untyped rune"},
-       UntypedFloat:   {aType, UntypedFloat, IsFloat | IsUntyped, "untyped float"},
-       UntypedComplex: {aType, UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
-       UntypedString:  {aType, UntypedString, IsString | IsUntyped, "untyped string"},
-       UntypedNil:     {aType, UntypedNil, IsUntyped, "untyped nil"},
+       Invalid: {aType, Invalid, 0, 0, "invalid type"},
+
+       Bool:          {aType, Bool, IsBoolean, 1, "bool"},
+       Int:           {aType, Int, IsInteger, 0, "int"},
+       Int8:          {aType, Int8, IsInteger, 1, "int8"},
+       Int16:         {aType, Int16, IsInteger, 2, "int16"},
+       Int32:         {aType, Int32, IsInteger, 4, "int32"},
+       Int64:         {aType, Int64, IsInteger, 8, "int64"},
+       Uint:          {aType, Uint, IsInteger | IsUnsigned, 0, "uint"},
+       Uint8:         {aType, Uint8, IsInteger | IsUnsigned, 1, "uint8"},
+       Uint16:        {aType, Uint16, IsInteger | IsUnsigned, 2, "uint16"},
+       Uint32:        {aType, Uint32, IsInteger | IsUnsigned, 4, "uint32"},
+       Uint64:        {aType, Uint64, IsInteger | IsUnsigned, 8, "uint64"},
+       Uintptr:       {aType, Uintptr, IsInteger | IsUnsigned, 0, "uintptr"},
+       Float32:       {aType, Float32, IsFloat, 4, "float32"},
+       Float64:       {aType, Float64, IsFloat, 8, "float64"},
+       Complex64:     {aType, Complex64, IsComplex, 8, "complex64"},
+       Complex128:    {aType, Complex128, IsComplex, 16, "complex128"},
+       String:        {aType, String, IsString, 0, "string"},
+       UnsafePointer: {aType, UnsafePointer, 0, 0, "Pointer"},
+
+       UntypedBool:    {aType, UntypedBool, IsBoolean | IsUntyped, 0, "untyped boolean"},
+       UntypedInt:     {aType, UntypedInt, IsInteger | IsUntyped, 0, "untyped integer"},
+       UntypedRune:    {aType, UntypedRune, IsInteger | IsUntyped, 0, "untyped rune"},
+       UntypedFloat:   {aType, UntypedFloat, IsFloat | IsUntyped, 0, "untyped float"},
+       UntypedComplex: {aType, UntypedComplex, IsComplex | IsUntyped, 0, "untyped complex"},
+       UntypedString:  {aType, UntypedString, IsString | IsUntyped, 0, "untyped string"},
+       UntypedNil:     {aType, UntypedNil, IsUntyped, 0, "untyped nil"},
 }
 
 var aliases = [...]*Basic{
-       {aType, Uint8, IsInteger | IsUnsigned, "byte"},
-       {aType, Rune, IsInteger, "rune"},
+       {aType, Byte, IsInteger | IsUnsigned, 1, "byte"},
+       {aType, Rune, IsInteger, 4, "rune"},
 }
 
 var predeclaredConstants = [...]*struct {
 }{
        {UntypedBool, "true", true},
        {UntypedBool, "false", false},
-       {UntypedInt, "iota", int64(0)},
-       {UntypedNil, "nil", nil},
+       {UntypedInt, "iota", zeroConst},
+       {UntypedNil, "nil", nilConst},
 }
 
 var predeclaredFunctions = [...]*builtin{
-       {aType, _Append, "append", 1, true},
-       {aType, _Cap, "cap", 1, false},
-       {aType, _Close, "close", 1, false},
-       {aType, _Complex, "complex", 2, false},
-       {aType, _Copy, "copy", 2, false},
-       {aType, _Delete, "delete", 2, false},
-       {aType, _Imag, "imag", 1, false},
-       {aType, _Len, "len", 1, false},
-       {aType, _Make, "make", 1, true},
-       {aType, _New, "new", 1, false},
-       {aType, _Panic, "panic", 1, false},
-       {aType, _Print, "print", 1, true},
-       {aType, _Println, "println", 1, true},
-       {aType, _Real, "real", 1, false},
-       {aType, _Recover, "recover", 0, false},
-
-       {aType, _Alignof, "Alignof", 1, false},
-       {aType, _Offsetof, "Offsetof", 1, false},
-       {aType, _Sizeof, "Sizeof", 1, false},
+       {aType, _Append, "append", 1, true, false},
+       {aType, _Cap, "cap", 1, false, false},
+       {aType, _Close, "close", 1, false, true},
+       {aType, _Complex, "complex", 2, false, false},
+       {aType, _Copy, "copy", 2, false, true},
+       {aType, _Delete, "delete", 2, false, true},
+       {aType, _Imag, "imag", 1, false, false},
+       {aType, _Len, "len", 1, false, false},
+       {aType, _Make, "make", 1, true, false},
+       {aType, _New, "new", 1, false, false},
+       {aType, _Panic, "panic", 1, false, true},
+       {aType, _Print, "print", 1, true, true},
+       {aType, _Println, "println", 1, true, true},
+       {aType, _Real, "real", 1, false, false},
+       {aType, _Recover, "recover", 0, false, true},
+
+       {aType, _Alignof, "Alignof", 1, false, false},
+       {aType, _Offsetof, "Offsetof", 1, false, false},
+       {aType, _Sizeof, "Sizeof", 1, false, false},
 }
 
 // commonly used types