Commit 4ce79096 authored by Rob Pike's avatar Rob Pike

go/types: delete from main repo; part of move to go.exp

See also https://golang.org/cl/7656044

R=golang-dev, gri, rsc
CC=golang-dev
https://golang.org/cl/7625048
parent bfe80e21
......@@ -5,13 +5,16 @@
// +build gotypes
// This file contains the pieces of the tool that require the go/types package.
// To compile this file, you must first run
// $ go get code.google.com/p/go.exp/go/types
package main
import (
"go/ast"
"go/token"
"go/types"
"code.google.com/p/go.exp/go/types"
)
// Type is equivalent to go/types.Type. Repeating it here allows us to avoid
......
......@@ -134,15 +134,14 @@ echo
if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
# TODO: Drop the -tags gotypes before releasing Go 1.1. It is to allow type checking in go vet.
GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
"$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -tags gotypes -v std
"$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
echo
fi
echo "# Building packages and commands for $GOOS/$GOARCH."
# TODO: Drop the -tags gotypes before releasing Go 1.1. It is to allow type checking in go vet.
"$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -tags gotypes -v std
"$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
echo
rm -f "$GOTOOLDIR"/go_bootstrap
......
......@@ -90,16 +90,14 @@ echo # Building tools for local system. %GOHOSTOS%/%GOHOSTARCH%
setlocal
set GOOS=%GOHOSTOS%
set GOARCH=%GOHOSTARCH%
:: TODO: Drop the -tags gotypes before releasing Go 1.1. It is to allow type checking in go vet.
"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -tags gotypes -v std
"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -v std
endlocal
if errorlevel 1 goto fail
echo.
:mainbuild
echo # Building packages and commands.
:: TODO: Drop the -tags gotypes before releasing Go 1.1. It is to allow type checking in go vet.
"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -tags gotypes -v std
"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -v std
if errorlevel 1 goto fail
del "%GOTOOLDIR%\go_bootstrap.exe"
echo.
......
// 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 structures for representing
// Go types and implements typechecking of package files.
//
// WARNING: THE TYPES API IS SUBJECT TO CHANGE.
//
package types
import (
"go/ast"
"go/token"
)
// A Context specifies the supporting context for type checking.
// An empty Context is a ready-to-use default context.
type Context struct {
// If Error != nil, it is called with each error found
// during type checking. The error strings of errors with
// detailed position information are formatted as follows:
// filename:line:column: message
Error func(err error)
// If Ident != nil, it is called for each identifier id
// denoting an Object in the files provided to Check, and
// obj is the denoted object.
// Ident is not called for fields and methods in struct or
// interface types or composite literals, or for blank (_)
// or dot (.) identifiers in dot-imports.
// TODO(gri) Consider making Fields and Methods ordinary
// Objects - than we could lift this restriction.
Ident func(id *ast.Ident, obj Object)
// If Expr != nil, it is called exactly once for each expression x
// that is type-checked: typ is the expression type, and val is the
// value if x is constant, val is nil otherwise.
//
// If x is a literal value (constant, composite literal), typ is always
// the dynamic type of x (never an interface type). Otherwise, typ is x's
// static type (possibly an interface type).
//
// Constants are represented as follows:
//
// bool -> bool
// numeric -> int64, *big.Int, *big.Rat, Complex
// string -> string
// nil -> NilType
//
// Constant values are normalized, that is, they are represented
// using the "smallest" possible type that can represent the value.
// For instance, 1.0 is represented as an int64 because it can be
// represented accurately as an int64.
Expr func(x ast.Expr, typ Type, val interface{})
// If Import != nil, it is called for each imported package.
// Otherwise, GcImporter is called.
Import Importer
// If Alignof != nil, it is called to determine the alignment
// of the given type. Otherwise DefaultAlignmentof is called.
// Alignof must implement the alignment guarantees required by
// the spec.
Alignof func(Type) int64
// If Offsetsof != nil, it is called to determine the offsets
// of the given struct fields, in bytes. Otherwise DefaultOffsetsof
// is called. Offsetsof must implement the offset guarantees
// required by the spec.
Offsetsof func(fields []*Field) []int64
// If Sizeof != nil, it is called to determine the size of the
// given type. Otherwise, DefaultSizeof is called. Sizeof must
// implement the size guarantees required by the spec.
Sizeof func(Type) int64
}
// An Importer resolves import paths to Package objects.
// The imports map records the packages already imported,
// indexed by package id (canonical import path).
// An Importer must determine the canonical import path and
// check the map to see if it is already present in the imports map.
// If so, the Importer can return the map entry. Otherwise, the
// Importer should load the package data for the given path into
// a new *Package, record pkg in the imports map, and then
// return pkg.
type Importer func(imports map[string]*Package, path string) (pkg *Package, err error)
// Check resolves and typechecks a set of package files within the given
// context. It returns the package and the first error encountered, if
// any. If the context's Error handler is nil, Check terminates as soon
// as the first error is encountered; otherwise it continues until the
// entire package is checked. If there are errors, the package may be
// only partially type-checked, and the resulting package may be incomplete
// (missing objects, imports, etc.).
func (ctxt *Context) Check(fset *token.FileSet, files []*ast.File) (*Package, error) {
return check(ctxt, fset, files)
}
// Check is shorthand for ctxt.Check where ctxt is a default (empty) context.
func Check(fset *token.FileSet, files []*ast.File) (*Package, error) {
var ctxt Context
return ctxt.Check(fset, files)
}
// 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"
)
// TODO(gri): Several built-ins are missing assignment checks. As a result,
// non-constant shift arguments may not be properly type-checked.
// builtin typechecks a built-in call. The built-in type is bin, and iota is the current
// value of iota or -1 if iota doesn't have a value in the current context. The result
// of the call is returned via x. If the call has type errors, the returned x is marked
// as invalid (x.mode == invalid).
//
func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota int) {
args := call.Args
id := bin.id
// declare before goto's
var arg0 ast.Expr // first argument, if present
// check argument count
n := len(args)
msg := ""
if n < bin.nargs {
msg = "not enough"
} else if !bin.isVariadic && n > bin.nargs {
msg = "too many"
}
if msg != "" {
check.invalidOp(call.Pos(), msg+" arguments for %s (expected %d, found %d)", call, bin.nargs, n)
goto Error
}
// common case: evaluate first argument if present;
// if it is an expression, x has the expression value
if n > 0 {
arg0 = args[0]
switch id {
case _Make, _New, _Print, _Println, _Offsetof, _Trace:
// respective cases below do the work
default:
// argument must be an expression
check.expr(x, arg0, nil, iota)
if x.mode == invalid {
goto Error
}
}
}
switch id {
case _Append:
if _, ok := underlying(x.typ).(*Slice); !ok {
check.invalidArg(x.pos(), "%s is not a typed slice", x)
goto Error
}
resultTyp := x.typ
for _, arg := range args[1:] {
check.expr(x, arg, nil, iota)
if x.mode == invalid {
goto Error
}
// TODO(gri) check assignability
}
x.mode = value
x.typ = resultTyp
case _Cap, _Len:
mode := invalid
var val interface{}
switch typ := implicitArrayDeref(underlying(x.typ)).(type) {
case *Basic:
if isString(typ) && id == _Len {
if x.mode == constant {
mode = constant
val = int64(len(x.val.(string)))
} 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.containsCallsOrReceives(arg0) {
mode = constant
val = typ.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)
goto Error
}
x.mode = mode
x.typ = Typ[Int]
x.val = val
case _Close:
ch, ok := underlying(x.typ).(*Chan)
if !ok {
check.invalidArg(x.pos(), "%s is not a channel", x)
goto Error
}
if ch.Dir&ast.SEND == 0 {
check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
goto Error
}
x.mode = novalue
case _Complex:
if !check.complexArg(x) {
goto Error
}
var y operand
check.expr(&y, args[1], nil, iota)
if y.mode == invalid {
goto Error
}
if !check.complexArg(&y) {
goto Error
}
check.convertUntyped(x, y.typ)
if x.mode == invalid {
goto Error
}
check.convertUntyped(&y, x.typ)
if y.mode == invalid {
goto Error
}
if !IsIdentical(x.typ, y.typ) {
check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
goto Error
}
typ := underlying(x.typ).(*Basic)
if x.mode == constant && y.mode == constant {
x.val = binaryOpConst(x.val, toImagConst(y.val), token.ADD, typ)
} else {
x.mode = value
}
switch typ.Kind {
case Float32:
x.typ = Typ[Complex64]
case Float64:
x.typ = Typ[Complex128]
case UntypedInt, UntypedRune, UntypedFloat:
x.typ = Typ[UntypedComplex]
default:
check.invalidArg(x.pos(), "float32 or float64 arguments expected")
goto Error
}
// arguments have final type
check.updateExprType(args[0], typ, true)
check.updateExprType(args[1], typ, true)
case _Copy:
var y operand
check.expr(&y, args[1], nil, iota)
if y.mode == invalid {
goto Error
}
var dst, src Type
if t, ok := underlying(x.typ).(*Slice); ok {
dst = t.Elt
}
switch t := underlying(y.typ).(type) {
case *Basic:
if isString(y.typ) {
src = Typ[Byte]
}
case *Slice:
src = t.Elt
}
if dst == nil || src == nil {
check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
goto Error
}
if !IsIdentical(dst, src) {
check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
goto Error
}
x.mode = value
x.typ = Typ[Int]
case _Delete:
m, ok := underlying(x.typ).(*Map)
if !ok {
check.invalidArg(x.pos(), "%s is not a map", x)
goto Error
}
check.expr(x, args[1], nil, iota)
if x.mode == invalid {
goto Error
}
if !x.isAssignable(check.ctxt, m.Key) {
check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.Key)
goto Error
}
x.mode = novalue
case _Imag, _Real:
if !isComplex(x.typ) {
check.invalidArg(x.pos(), "%s must be a complex number", x)
goto Error
}
if x.mode == constant {
// nothing to do for x.val == 0
if !isZeroConst(x.val) {
c := x.val.(Complex)
if id == _Real {
x.val = c.Re
} else {
x.val = c.Im
}
}
} else {
x.mode = value
}
k := Invalid
switch underlying(x.typ).(*Basic).Kind {
case Complex64:
k = Float32
case Complex128:
k = Float64
case UntypedComplex:
k = UntypedFloat
default:
unreachable()
}
x.typ = Typ[k]
case _Make:
resultTyp := check.typ(arg0, false)
if resultTyp == Typ[Invalid] {
goto Error
}
var min int // minimum number of arguments
switch underlying(resultTyp).(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)
goto Error
}
if n := len(args); n < min || min+1 < n {
check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, n)
goto Error
}
var sizes []int64 // constant integer arguments, if any
for _, arg := range args[1:] {
if s, ok := check.index(arg, -1, iota); ok && s >= 0 {
sizes = append(sizes, s)
}
}
if len(sizes) == 2 && sizes[0] > sizes[1] {
check.invalidArg(args[1].Pos(), "length and capacity swapped")
// safe to continue
}
x.mode = variable
x.typ = resultTyp
case _New:
resultTyp := check.typ(arg0, false)
if resultTyp == Typ[Invalid] {
goto Error
}
x.mode = variable
x.typ = &Pointer{Base: resultTyp}
case _Panic:
x.mode = novalue
case _Print, _Println:
for _, arg := range args {
check.expr(x, arg, nil, -1)
if x.mode == invalid {
goto Error
}
}
x.mode = novalue
case _Recover:
x.mode = value
x.typ = new(Interface)
case _Alignof:
x.mode = constant
x.val = check.ctxt.alignof(x.typ)
x.typ = Typ[Uintptr]
case _Offsetof:
arg, ok := unparen(arg0).(*ast.SelectorExpr)
if !ok {
check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
goto Error
}
check.expr(x, arg.X, nil, -1)
if x.mode == invalid {
goto Error
}
sel := arg.Sel.Name
res := lookupField(x.typ, QualifiedName{check.pkg, arg.Sel.Name})
if res.index == nil {
check.invalidArg(x.pos(), "%s has no single field %s", x, sel)
goto Error
}
offs := check.ctxt.offsetof(deref(x.typ), res.index)
if offs < 0 {
check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, x)
goto Error
}
x.mode = constant
x.val = offs
x.typ = Typ[Uintptr]
case _Sizeof:
x.mode = constant
x.val = check.ctxt.sizeof(x.typ)
x.typ = Typ[Uintptr]
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)
goto Error
}
pred, ok := x.val.(bool)
if !ok {
check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
goto Error
}
if !pred {
check.errorf(call.Pos(), "%s failed", call)
// compile-time assertion failure - safe to continue
}
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.
if len(args) == 0 {
check.dump("%s: trace() without arguments", call.Pos())
x.mode = novalue
x.expr = call
return
}
var t operand
x1 := x
for _, arg := range args {
check.rawExpr(x1, arg, nil, iota, true) // 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
}
default:
check.invalidAST(call.Pos(), "unknown builtin id %d", id)
goto Error
}
x.expr = call
return
Error:
x.mode = invalid
x.expr = call
}
// 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 := underlying(p.Base).(*Array); ok {
return a
}
}
return typ
}
// containsCallsOrReceives reports if x contains function calls or channel receives.
// Expects that x was type-checked already.
//
func (check *checker) containsCallsOrReceives(x ast.Expr) (found bool) {
ast.Inspect(x, func(x ast.Node) bool {
switch x := x.(type) {
case *ast.CallExpr:
// calls and conversions look the same
if !check.conversions[x] {
found = true
}
case *ast.UnaryExpr:
if x.Op == token.ARROW {
found = true
}
}
return !found // no need to continue if found
})
return
}
// unparen removes any parentheses surrounding an expression and returns
// the naked expression.
//
func unparen(x ast.Expr) ast.Expr {
if p, ok := x.(*ast.ParenExpr); ok {
return unparen(p.X)
}
return x
}
func (check *checker) complexArg(x *operand) bool {
t, _ := underlying(x.typ).(*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
}
// 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/token"
)
// debugging support
const (
debug = true // leave on during development
trace = false // turn on for detailed type resolution traces
)
// exprInfo stores type and constant value for an untyped expression.
type exprInfo struct {
isConst bool // expression has a, possibly unknown, constant value
isLhs bool // expression is lhs operand of a shift with delayed type check
typ *Basic
val interface{} // constant value (may be nil if unknown); valid if isConst
}
// A checker is an instance of the type checker.
type checker struct {
ctxt *Context
fset *token.FileSet
files []*ast.File
// lazily initialized
pkg *Package // current package
firsterr error // first error encountered
idents map[*ast.Ident]Object // maps identifiers to their unique object
objects map[*ast.Object]Object // maps *ast.Objects to their unique object
initspecs map[*ast.ValueSpec]*ast.ValueSpec // "inherited" type and initialization expressions for constant declarations
methods map[*TypeName]*Scope // maps type names to associated methods
conversions map[*ast.CallExpr]bool // set of type-checked conversions (to distinguish from calls)
untyped map[ast.Expr]exprInfo // map of expressions without final type
// functions
funclist []function // list of functions/methods with correct signatures and non-empty bodies
funcsig *Signature // signature of currently typechecked function
pos []token.Pos // stack of expr positions; debugging support, used if trace is set
}
func (check *checker) register(id *ast.Ident, obj Object) {
// When an expression is evaluated more than once (happens
// in rare cases, e.g. for statement expressions, see
// comment in stmt.go), the object has been registered
// before. Don't do anything in that case.
if alt := check.idents[id]; alt != nil {
assert(alt == obj)
return
}
check.idents[id] = obj
if f := check.ctxt.Ident; f != nil {
f(id, obj)
}
}
// lookup returns the unique Object denoted by the identifier.
// For identifiers without assigned *ast.Object, it uses the
// checker.idents map; for identifiers with an *ast.Object it
// uses the checker.objects map.
//
// TODO(gri) Once identifier resolution is done entirely by
// the typechecker, only the idents map is needed.
//
func (check *checker) lookup(ident *ast.Ident) Object {
obj := check.idents[ident]
astObj := ident.Obj
if obj != nil {
assert(astObj == nil || check.objects[astObj] == nil || check.objects[astObj] == obj)
return obj
}
if astObj == nil {
return nil
}
if obj = check.objects[astObj]; obj == nil {
obj = newObj(check.pkg, astObj)
check.objects[astObj] = obj
}
check.register(ident, obj)
return obj
}
type function struct {
obj *Func // for debugging/tracing only
sig *Signature
body *ast.BlockStmt
}
// later adds a function with non-empty body to the list of functions
// that need to be processed after all package-level declarations
// are typechecked.
//
func (check *checker) later(f *Func, sig *Signature, body *ast.BlockStmt) {
// functions implemented elsewhere (say in assembly) have no body
if body != nil {
check.funclist = append(check.funclist, function{f, sig, body})
}
}
func (check *checker) declareIdent(scope *Scope, ident *ast.Ident, obj Object) {
assert(check.lookup(ident) == nil) // identifier already declared or resolved
check.register(ident, obj)
if ident.Name != "_" {
if alt := scope.Insert(obj); alt != nil {
prevDecl := ""
if pos := alt.GetPos(); 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) valueSpec(pos token.Pos, obj Object, lhs []*ast.Ident, spec *ast.ValueSpec, iota int) {
if len(lhs) == 0 {
check.invalidAST(pos, "missing lhs in declaration")
return
}
// determine type for all of lhs, if any
// (but only set it for the object we typecheck!)
var typ Type
if spec.Type != nil {
typ = check.typ(spec.Type, false)
}
// len(lhs) > 0
rhs := spec.Values
if len(lhs) == len(rhs) {
// check only lhs and rhs corresponding to obj
var l, r ast.Expr
for i, name := range lhs {
if check.lookup(name) == obj {
l = lhs[i]
r = rhs[i]
break
}
}
assert(l != nil)
switch obj := obj.(type) {
case *Const:
obj.Type = typ
case *Var:
obj.Type = typ
default:
unreachable()
}
check.assign1to1(l, r, nil, true, iota)
return
}
// there must be a type or initialization expressions
if typ == nil && len(rhs) == 0 {
check.invalidAST(pos, "missing type or initialization expression")
typ = Typ[Invalid]
}
// if we have a type, mark all of lhs
if typ != nil {
for _, name := range lhs {
switch obj := check.lookup(name).(type) {
case *Const:
obj.Type = typ
case *Var:
obj.Type = typ
default:
unreachable()
}
}
}
// 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)
}
}
// object typechecks an object by assigning it a type.
//
func (check *checker) object(obj Object, cycleOk bool) {
switch obj := obj.(type) {
case *Package:
// nothing to do
case *Const:
if obj.Type != nil {
return // already checked
}
// The obj.Val field for constants is initialized to its respective
// iota value (type int) by the parser.
// If the object's type is Typ[Invalid], the object value is ignored.
// If the object's type is valid, the object value must be a legal
// constant value; it may be nil to indicate that we don't know the
// value of the constant (e.g., in: "const x = float32("foo")" we
// know that x is a constant and has type float32, but we don't
// have a value due to the error in the conversion).
if obj.visited {
check.errorf(obj.GetPos(), "illegal cycle in initialization of constant %s", obj.Name)
obj.Type = Typ[Invalid]
return
}
obj.visited = true
spec := obj.spec
iota := obj.Val.(int)
obj.Val = nil // set to a valid (but unknown) constant value
// determine spec for type and initialization expressions
init := spec
if len(init.Values) == 0 {
init = check.initspecs[spec]
}
check.valueSpec(spec.Pos(), obj, spec.Names, init, iota)
case *Var:
if obj.Type != nil {
return // already checked
}
if obj.visited {
check.errorf(obj.GetPos(), "illegal cycle in initialization of variable %s", obj.Name)
obj.Type = Typ[Invalid]
return
}
obj.visited = true
switch d := obj.decl.(type) {
case *ast.Field:
unreachable() // function parameters are always typed when collected
case *ast.ValueSpec:
check.valueSpec(d.Pos(), obj, d.Names, d, 0)
case *ast.AssignStmt:
unreachable() // assign1to1 sets the type for failing short var decls
default:
unreachable() // see also function newObj
}
case *TypeName:
if obj.Type != nil {
return // already checked
}
typ := &NamedType{Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = underlying(check.typ(obj.spec.Type, cycleOk))
// typecheck associated method signatures
if scope := check.methods[obj]; scope != nil {
switch t := typ.Underlying.(type) {
case *Struct:
// struct fields must not conflict with methods
for _, f := range t.Fields {
if m := scope.Lookup(f.Name); m != nil {
check.errorf(m.GetPos(), "type %s has both field and method named %s", obj.Name, f.Name)
// ok to continue
}
}
case *Interface:
// methods cannot be associated with an interface type
for _, m := range scope.Entries {
recv := m.(*Func).decl.Recv.List[0].Type
check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
// ok to continue
}
}
// typecheck method signatures
var methods []*Method
for _, obj := range scope.Entries {
m := obj.(*Func)
sig := check.typ(m.decl.Type, cycleOk).(*Signature)
params, _ := check.collectParams(m.decl.Recv, false)
sig.Recv = params[0] // the parser/assocMethod ensure there is exactly one parameter
m.Type = sig
methods = append(methods, &Method{QualifiedName{check.pkg, m.Name}, sig})
check.later(m, sig, m.decl.Body)
}
typ.Methods = methods
delete(check.methods, obj) // we don't need this scope anymore
}
case *Func:
if obj.Type != nil {
return // already checked
}
fdecl := obj.decl
// methods are typechecked when their receivers are typechecked
if fdecl.Recv == nil {
sig := check.typ(fdecl.Type, cycleOk).(*Signature)
if obj.Name == "init" && (len(sig.Params) != 0 || len(sig.Results) != 0) {
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
// ok to continue
}
obj.Type = sig
check.later(obj, sig, fdecl.Body)
}
default:
unreachable()
}
}
// assocInitvals associates "inherited" initialization expressions
// with the corresponding *ast.ValueSpec in the check.initspecs map
// for constant declarations without explicit initialization expressions.
//
func (check *checker) assocInitvals(decl *ast.GenDecl) {
var last *ast.ValueSpec
for _, s := range decl.Specs {
if s, ok := s.(*ast.ValueSpec); ok {
if len(s.Values) > 0 {
last = s
} else {
check.initspecs[s] = last
}
}
}
if last == nil {
check.invalidAST(decl.Pos(), "no initialization values provided")
}
}
// assocMethod associates a method declaration with the respective
// receiver base type. meth.Recv must exist.
//
func (check *checker) assocMethod(meth *ast.FuncDecl) {
// 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 name
ident, ok := typ.(*ast.Ident)
if !ok {
// not an identifier - parser reported error already
return // ignore this method
}
// determine receiver base type object
var tname *TypeName
if obj := check.lookup(ident); obj != nil {
obj, ok := obj.(*TypeName)
if !ok {
check.errorf(ident.Pos(), "%s is not a type", ident.Name)
return // ignore this method
}
if obj.spec == nil {
check.errorf(ident.Pos(), "cannot define method on non-local type %s", ident.Name)
return // ignore this method
}
tname = obj
} else {
// identifier not declared/resolved - parser reported error already
return // ignore this method
}
// declare method in receiver base type scope
scope := check.methods[tname]
if scope == nil {
scope = new(Scope)
check.methods[tname] = scope
}
check.declareIdent(scope, meth.Name, &Func{Pkg: check.pkg, Name: meth.Name.Name, decl: meth})
}
func (check *checker) decl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.BadDecl:
// ignore
case *ast.GenDecl:
for _, spec := range d.Specs {
switch s := spec.(type) {
case *ast.ImportSpec:
// nothing to do (handled by check.resolve)
case *ast.ValueSpec:
for _, name := range s.Names {
check.object(check.lookup(name), false)
}
case *ast.TypeSpec:
check.object(check.lookup(s.Name), false)
default:
check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
}
}
case *ast.FuncDecl:
// methods are checked when their respective base types are checked
if d.Recv != nil {
return
}
obj := check.lookup(d.Name)
// Initialization functions don't have an object associated with them
// since they are not in any scope. Create a dummy object for them.
if d.Name.Name == "init" {
assert(obj == nil) // all other functions should have an object
obj = &Func{Pkg: check.pkg, Name: d.Name.Name, decl: d}
check.register(d.Name, obj)
}
check.object(obj, false)
default:
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
}
}
// A bailout panic is raised to indicate early termination.
type bailout struct{}
func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package, err error) {
// initialize checker
check := checker{
ctxt: ctxt,
fset: fset,
files: files,
idents: make(map[*ast.Ident]Object),
objects: make(map[*ast.Object]Object),
initspecs: make(map[*ast.ValueSpec]*ast.ValueSpec),
methods: make(map[*TypeName]*Scope),
conversions: make(map[*ast.CallExpr]bool),
untyped: make(map[ast.Expr]exprInfo),
}
// set results and handle panics
defer func() {
pkg = check.pkg
switch p := recover().(type) {
case nil, bailout:
// normal return or early exit
err = check.firsterr
default:
// unexpected panic: don't crash clients
if debug {
check.dump("INTERNAL PANIC: %v", p)
panic(p)
}
// TODO(gri) add a test case for this scenario
err = fmt.Errorf("types internal error: %v", p)
}
}()
// resolve identifiers
imp := ctxt.Import
if imp == nil {
imp = GcImport
}
methods := check.resolve(imp)
// associate methods with types
for _, m := range methods {
check.assocMethod(m)
}
// typecheck all declarations
for _, f := range check.files {
for _, d := range f.Decls {
check.decl(d)
}
}
// typecheck all function/method bodies
// (funclist may grow when checking statements - do not use range clause!)
for i := 0; i < len(check.funclist); i++ {
f := check.funclist[i]
if trace {
s := "<function literal>"
if f.obj != nil {
s = f.obj.Name
}
fmt.Println("---", s)
}
check.funcsig = f.sig
check.stmtList(f.body.List)
if len(f.sig.Results) > 0 && f.body != nil && !check.isTerminating(f.body, "") {
check.errorf(f.body.Rbrace, "missing return")
}
}
// remaining untyped expressions must indeed be untyped
if debug {
for x, info := range check.untyped {
if !isUntyped(info.typ) {
check.dump("%s: %s (type %s) is not untyped", x.Pos(), x, info.typ)
panic(0)
}
}
}
// notify client of any untyped types left
// TODO(gri) Consider doing this before and
// after function body checking for smaller
// map size and more immediate feedback.
if ctxt.Expr != nil {
for x, info := range check.untyped {
var val interface{}
if info.isConst {
val = info.val
}
ctxt.Expr(x, info.typ, val)
}
}
return
}
// 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
// }
package types
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/scanner"
"go/token"
"io/ioutil"
"os"
"regexp"
"testing"
)
var listErrors = flag.Bool("list", false, "list errors")
// 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.
var tests = []struct {
name string
files []string
}{
{"decls0", []string{"testdata/decls0.src"}},
{"decls1", []string{"testdata/decls1.src"}},
{"decls2", []string{"testdata/decls2a.src", "testdata/decls2b.src"}},
{"decls3", []string{"testdata/decls3.src"}},
{"const0", []string{"testdata/const0.src"}},
{"expr0", []string{"testdata/expr0.src"}},
{"expr1", []string{"testdata/expr1.src"}},
{"expr2", []string{"testdata/expr2.src"}},
{"expr3", []string{"testdata/expr3.src"}},
{"shifts", []string{"testdata/shifts.src"}},
{"builtins", []string{"testdata/builtins.src"}},
{"conversions", []string{"testdata/conversions.src"}},
{"stmt0", []string{"testdata/stmt0.src"}},
{"stmt1", []string{"testdata/stmt1.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, testname string, filenames []string) ([]*ast.File, []error) {
var files []*ast.File
var errlist []error
for _, filename := range filenames {
file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors|parser.AllErrors)
if file == nil {
t.Fatalf("%s: could not parse file %s", testname, filename)
}
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 be of the form /* ERROR "rx" */ and rx is
// a regular expression that matches the expected error message.
//
var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
// 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, fset.Base(), len(src)), src, nil, scanner.ScanComments)
var prev string // position string of last non-comment, non-semicolon token
scanFile:
for {
pos, tok, lit := s.Scan()
switch tok {
case token.EOF:
break scanFile
case token.COMMENT:
if s := errRx.FindStringSubmatch(lit); len(s) == 2 {
errmap[prev] = append(errmap[prev], s[1])
}
case token.SEMICOLON:
// ignore automatically inserted semicolon
if lit == "\n" {
continue scanFile
}
fallthrough
default:
prev = fset.Position(pos).String()
}
}
}
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, testname string, testfiles []string) {
// parse files and collect parser errors
files, errlist := parseFiles(t, testname, testfiles)
// typecheck and collect typechecker errors
var ctxt Context
ctxt.Error = func(err error) { errlist = append(errlist, err) }
ctxt.Check(fset, files)
if *listErrors {
t.Errorf("--- %s: %d errors found:", testname, len(errlist))
for _, err := range errlist {
t.Error(err)
}
return
}
// match and eliminate errors;
// we are expecting the following errors
errmap := errMap(t, testname, 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:", testname, len(errmap))
for pos, list := range errmap {
for _, rx := range list {
t.Errorf("%s: %q", pos, rx)
}
}
}
}
var testBuiltinsDeclared = false
func TestCheck(t *testing.T) {
// Declare builtins for testing.
// Not done in an init func to avoid an init race with
// the construction of the Universe var.
if !testBuiltinsDeclared {
testBuiltinsDeclared = true
// Pkg == nil for Universe objects
def(&Func{Name: "assert", Type: &builtin{_Assert, "assert", 1, false, true}})
def(&Func{Name: "trace", Type: &builtin{_Trace, "trace", 0, true, true}})
}
// For easy debugging w/o changing the testing code,
// if there is a local test file, only test that file.
const testfile = "testdata/test.go"
if fi, err := os.Stat(testfile); err == nil && !fi.IsDir() {
fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile)
checkFiles(t, testfile, []string{testfile})
return
}
// Otherwise, run all the tests.
for _, test := range tests {
checkFiles(t, test.name, test.files)
}
}
// 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. Introduce a Const
// interface and use methods instead of xConst functions.
// Representation of constant values.
//
// invalid -> nil (i.e., we don't know the constant value; this can only happen in erroneous programs)
// 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 values.
var (
nilConst = NilType{}
zeroConst = int64(0)
)
// 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,
// or *big.Rat value.
//
func normalizeRatConst(x *big.Rat) interface{} {
if x.IsInt() {
return normalizeIntConst(x.Num())
}
return x
}
// newComplex returns the smallest constant representation
// for the specific value re + im*i; either an int64, *big.Int,
// *big.Rat, or complex value.
//
func newComplex(re, im *big.Rat) interface{} {
if im.Sign() == 0 {
return normalizeRatConst(re)
}
return Complex{re, im}
}
// 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 newComplex(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
}
// toImagConst returns the constant Complex(0, x) for a non-complex x.
func toImagConst(x interface{}) interface{} {
var im *big.Rat
switch x := x.(type) {
case nil:
im = rat0
case int64:
im = big.NewRat(x, 1)
case *big.Int:
im = new(big.Rat).SetFrac(x, int1)
case *big.Rat:
im = x
default:
unreachable()
}
return Complex{rat0, im}
}
// 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{}, ctxt *Context, as BasicKind) bool {
if x == nil {
return true // avoid spurious errors
}
switch x := x.(type) {
case bool:
return as == Bool || as == UntypedBool
case int64:
switch as {
case Int:
var s = uint(ctxt.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:
var s = uint(ctxt.sizeof(Typ[as])) * 8
return 0 <= x && x <= int64(1)<<(s-1)-1
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:
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, Uintptr:
var s = uint(ctxt.sizeof(Typ[as])) * 8
return x.Sign() >= 0 && x.BitLen() <= int(s)
case Uint64:
return x.Sign() >= 0 && x.BitLen() <= 64
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 || as == UnsafePointer
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
}
// unaryOpConst returns the result of the constant evaluation op x where x is of the given type.
func unaryOpConst(x interface{}, ctxt *Context, op token.Token, typ *Basic) interface{} {
if x == nil {
return nil
}
switch op {
case token.ADD:
return x // nothing to do
case token.SUB:
switch x := x.(type) {
case int64:
if z := -x; z != x {
return z // no overflow
}
// overflow - need to convert to big.Int
return normalizeIntConst(new(big.Int).Neg(big.NewInt(x)))
case *big.Int:
return normalizeIntConst(new(big.Int).Neg(x))
case *big.Rat:
return normalizeRatConst(new(big.Rat).Neg(x))
case Complex:
return newComplex(new(big.Rat).Neg(x.Re), new(big.Rat).Neg(x.Im))
}
case token.XOR:
var z big.Int
switch x := x.(type) {
case int64:
z.Not(big.NewInt(x))
case *big.Int:
z.Not(x)
default:
unreachable()
}
// For unsigned types, the result will be negative and
// thus "too large": We must limit the result size to
// the type's size.
if typ.Info&IsUnsigned != 0 {
s := uint(ctxt.sizeof(typ)) * 8
z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), s)) // z &^= (-1)<<s
}
return normalizeIntConst(&z)
case token.NOT:
return !x.(bool)
}
unreachable()
return nil
}
// binaryOpConst returns the result of the constant evaluation x op y;
// both operands must be of the same constant "kind" (boolean, numeric, or string).
// If typ is an integer type, 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, typ *Basic) interface{} {
if x == nil || y == nil {
return nil
}
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
}
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 typ.Info&IsInteger != 0 {
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
}
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 typ.Info&IsInteger != 0 {
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 newComplex(&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 nil:
return nil
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) {
if x == nil || y == nil {
return false
}
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
}
// 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/ast"
)
// conversion typechecks the type conversion conv to type typ. iota is the current
// value of iota or -1 if iota doesn't have a value in the current context. The result
// of the conversion is returned via x. If the conversion has type errors, the returned
// x is marked as invalid (x.mode == invalid).
//
func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota int) {
// all conversions have one argument
if len(conv.Args) != 1 {
check.invalidOp(conv.Pos(), "%s conversion requires exactly one argument", conv)
goto Error
}
// evaluate argument
check.expr(x, conv.Args[0], nil, iota)
if x.mode == invalid {
goto Error
}
if x.mode == constant && isConstType(typ) {
// constant conversion
typ := underlying(typ).(*Basic)
// For now just implement string(x) where x is an integer,
// as a temporary work-around for issue 4982, which is a
// common issue.
if typ.Kind == String {
switch {
case x.isInteger():
codepoint, ok := x.val.(int64)
if !ok {
// absolute value too large (or unknown) for conversion;
// same as converting any other out-of-range value - let
// string(codepoint) do the work
codepoint = -1
}
x.val = string(codepoint)
case isString(x.typ):
// nothing to do
default:
goto ErrorMsg
}
}
// TODO(gri) verify the remaining conversions.
} else {
// non-constant conversion
if !x.isConvertible(check.ctxt, typ) {
goto ErrorMsg
}
x.mode = value
}
// the conversion argument types are final
check.updateExprType(x.expr, x.typ, true)
check.conversions[conv] = true // for cap/len checking
x.expr = conv
x.typ = typ
return
ErrorMsg:
check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ)
Error:
x.mode = invalid
x.expr = conv
}
func (x *operand) isConvertible(ctxt *Context, T Type) bool {
// "x is assignable to T"
if x.isAssignable(ctxt, T) {
return true
}
// "x's type and T have identical underlying types"
V := x.typ
Vu := underlying(V)
Tu := underlying(T)
if IsIdentical(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 IsIdentical(underlying(V.Base), underlying(T.Base)) {
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.(*Basic)
return ok && t.Kind == Uintptr
}
func isUnsafePointer(typ Type) bool {
t, ok := typ.(*Basic)
return ok && t.Kind == UnsafePointer
}
func isPointer(typ Type) bool {
_, ok := typ.(*Pointer)
return ok
}
func isBytesOrRunes(typ Type) bool {
if s, ok := typ.(*Slice); ok {
t, ok := underlying(s.Elt).(*Basic)
return ok && (t.Kind == Byte || t.Kind == Rune)
}
return false
}
// 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"
)
// TODO(gri) eventually assert and unimplemented should disappear.
func assert(p bool) {
if !p {
panic("assertion failed")
}
}
func unreachable() {
panic("unreachable")
}
func (check *checker) printTrace(format string, args []interface{}) {
const dots = ". . . . . . . . . . . . . . . . . . . . "
n := len(check.pos) - 1
i := 3 * n
for i > len(dots) {
fmt.Print(dots)
i -= len(dots)
}
// i <= len(dots)
fmt.Printf("%s:\t", check.fset.Position(check.pos[n]))
fmt.Print(dots[0:i])
fmt.Println(check.formatMsg(format, args))
}
func (check *checker) trace(pos token.Pos, format string, args ...interface{}) {
check.pos = append(check.pos, pos)
check.printTrace(format, args)
}
func (check *checker) untrace(format string, args ...interface{}) {
if len(format) > 0 {
check.printTrace(format, args)
}
check.pos = check.pos[:len(check.pos)-1]
}
func (check *checker) formatMsg(format string, args []interface{}) string {
for i, arg := range args {
switch a := arg.(type) {
case token.Pos:
args[i] = check.fset.Position(a).String()
case ast.Expr:
args[i] = exprString(a)
case Type:
args[i] = typeString(a)
case operand:
panic("internal error: should always pass *operand")
}
}
return fmt.Sprintf(format, args...)
}
// dump is only needed for debugging
func (check *checker) dump(format string, args ...interface{}) {
fmt.Println(check.formatMsg(format, args))
}
func (check *checker) err(err error) {
if check.firsterr == nil {
check.firsterr = err
}
f := check.ctxt.Error
if f == nil {
panic(bailout{}) // report only first error
}
f(err)
}
func (check *checker) errorf(pos token.Pos, format string, args ...interface{}) {
check.err(fmt.Errorf("%s: %s", check.fset.Position(pos), check.formatMsg(format, args)))
}
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...)
}
// 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 []*Var, 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)
}
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 *Result:
writeParams(buf, t.Values, false)
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)
}
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:
s := "<NamedType w/o object>"
if obj := t.Obj; obj != nil {
if obj.Pkg != nil && obj.Pkg.Path != "" {
buf.WriteString(obj.Pkg.Path)
buf.WriteString(".")
}
s = t.Obj.GetName()
}
buf.WriteString(s)
default:
fmt.Fprintf(buf, "<type %T>", t)
}
}
func (t *Array) String() string { return typeString(t) }
func (t *Basic) String() string { return typeString(t) }
func (t *Chan) String() string { return typeString(t) }
func (t *Interface) String() string { return typeString(t) }
func (t *Map) String() string { return typeString(t) }
func (t *NamedType) String() string { return typeString(t) }
func (t *Pointer) String() string { return typeString(t) }
func (t *Result) String() string { return typeString(t) }
func (t *Signature) String() string { return typeString(t) }
func (t *Slice) String() string { return typeString(t) }
func (t *Struct) String() string { return typeString(t) }
func (t *builtin) String() string { return typeString(t) }
// 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 FindGcExportData.
package types
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
}
// FindGcExportData 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 FindGcExportData(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, which should
// be second archive entry.
var name string
var size int
// First entry should be __.GOSYMDEF.
// Older archives used __.SYMDEF, so allow that too.
// Read and discard.
if name, size, err = readGopackHeader(r); err != nil {
return
}
if name != "__.SYMDEF" && name != "__.GOSYMDEF" {
err = errors.New("go archive does not begin with __.SYMDEF or __.GOSYMDEF")
return
}
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
}
// Second entry should be __.PKGDEF.
if name, size, err = readGopackHeader(r); err != nil {
return
}
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
}
// 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 (
"go/ast"
"go/token"
"strconv"
)
// TODO(gri) Cleanups
// - don't print error messages referring to invalid types (they are likely spurious errors)
// - simplify invalid handling: maybe just use Typ[Invalid] as marker, get rid of invalid Mode for values?
// - rethink error handling: should all callers check if x.mode == valid after making a call?
// - at the moment, iota is passed around almost everywhere - in many places we know it cannot be used
// - use "" or "_" consistently for anonymous identifiers? (e.g. reeceivers that have no name)
// - consider storing error messages in invalid operands for better error messages/debugging output
// TODO(gri) API issues
// - clients need access to builtins type information
// - API tests are missing (e.g., identifiers should be handled as expressions in callbacks)
/*
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).
If an iota argument >= 0 is present, it is the value of iota for the
specific expression.
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,
if present the Context.Expr method is invoked to notify a go/types client.
*/
func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params []*Var, isVariadic bool) {
if list == nil {
return
}
var last *Var
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 {
isVariadic = true
} else {
check.invalidAST(field.Pos(), "... not permitted")
// ok to continue
}
}
// the parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag
typ := check.typ(ftype, true)
if len(field.Names) > 0 {
// named parameter
for _, name := range field.Names {
par := check.lookup(name).(*Var)
par.Type = typ
last = par
copy := *par
params = append(params, &copy)
}
} else {
// anonymous parameter
par := &Var{Type: typ}
last = nil // not accessible inside function
params = append(params, par)
}
}
// For a variadic function, change the last parameter's object type
// from T to []T (this is the type used inside the function), but
// keep the params list unchanged (this is the externally visible type).
if isVariadic && last != nil {
last.Type = &Slice{Elt: last.Type}
}
return
}
func (check *checker) collectMethods(list *ast.FieldList) (methods []*Method) {
if list == nil {
return
}
for _, f := range list.List {
typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces
// the parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag
if len(f.Names) > 0 {
// methods (the parser ensures that there's only one
// and we don't care if a constructed AST has more)
sig, ok := typ.(*Signature)
if !ok {
check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ)
continue
}
for _, name := range f.Names {
methods = append(methods, &Method{QualifiedName{check.pkg, name.Name}, sig})
}
} else {
// embedded interface
utyp := underlying(typ)
if ityp, ok := utyp.(*Interface); ok {
methods = append(methods, ityp.Methods...)
} else if utyp != Typ[Invalid] {
// if utyp is invalid, don't complain (the root cause was reported before)
check.errorf(f.Type.Pos(), "%s is not an interface type", typ)
}
}
}
// Check for double declarations.
// The parser inserts methods into an interface-local scope, so local
// double declarations are reported by the parser already. We need to
// check again for conflicts due to embedded interfaces. This will lead
// to a 2nd error message if the double declaration was reported before
// by the parser.
// TODO(gri) clean this up a bit
seen := make(map[string]bool)
for _, m := range methods {
if seen[m.Name] {
check.errorf(list.Pos(), "multiple methods named %s", m.Name)
return // keep multiple entries, lookup will only return the first entry
}
seen[m.Name] = true
}
return
}
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) collectFields(list *ast.FieldList, cycleOk bool) (fields []*Field) {
if list == nil {
return
}
var typ Type // current field typ
var tag string // current field tag
add := func(name string, isAnonymous bool) {
fields = append(fields, &Field{QualifiedName{check.pkg, name}, typ, tag, isAnonymous})
}
for _, f := range list.List {
typ = check.typ(f.Type, cycleOk)
tag = check.tag(f.Tag)
if len(f.Names) > 0 {
// named fields
for _, name := range f.Names {
add(name.Name, false)
}
} else {
// anonymous field
switch t := deref(typ).(type) {
case *Basic:
add(t.Name, true)
case *NamedType:
add(t.Obj.GetName(), true)
default:
if typ != Typ[Invalid] {
check.invalidAST(f.Type.Pos(), "anonymous field type %s must be named", typ)
}
}
}
}
return
}
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
}
if x.mode != variable {
check.invalidOp(x.pos(), "cannot take address of %s", x)
goto Error
}
x.typ = &Pointer{Base: x.typ}
return
case token.ARROW:
typ, ok := underlying(x.typ).(*Chan)
if !ok {
check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
goto Error
}
if typ.Dir&ast.RECV == 0 {
check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
goto Error
}
x.mode = valueok
x.typ = typ.Elt
return
}
if !check.op(unaryOpPredicates, x, op) {
goto Error
}
if x.mode == constant {
typ := underlying(x.typ).(*Basic)
x.val = unaryOpConst(x.val, check.ctxt, op, typ)
// Typed constants must be representable in
// their type after each constant operation.
check.isRepresentable(x, typ)
return
}
x.mode = value
// x.typ remains unchanged
return
Error:
x.mode = invalid
}
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
}
// isRepresentable checks that a constant operand is representable in the given type.
func (check *checker) isRepresentable(x *operand, typ *Basic) {
if x.mode != constant || isUntyped(typ) {
return
}
if !isRepresentableConst(x.val, check.ctxt, typ.Kind) {
var msg string
if isNumeric(x.typ) && isNumeric(typ) {
msg = "%s overflows (or cannot be accurately represented as) %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), Context.Expr is invoked, if present.
// 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.isConst {
break
}
check.updateExprType(x.X, typ, final)
case *ast.BinaryExpr:
if old.isConst {
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 = underlying(typ).(*Basic)
check.untyped[x] = old
return
}
// Otherwise we have the final (typed or untyped type).
// Remove it from the map.
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, notify client of final type for x.
if f := check.ctxt.Expr; f != nil {
var val interface{}
if old.isConst {
val = old.val
}
f(x, typ, val)
}
}
// 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 || !isUntyped(x.typ) {
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 := underlying(target).(type) {
case nil:
// We may reach here due to previous type errors.
// Be conservative and don't crash.
x.mode = invalid
return
case *Basic:
check.isRepresentable(x, t)
if x.mode == invalid {
return // error already reported
}
case *Interface:
if !x.isNil() && len(t.Methods) > 0 /* 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 len(t.Methods) > 0 {
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:
if debug {
check.dump("convertUntyped(x = %v, target = %v)", x, target)
}
unreachable()
}
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) {
// TODO(gri) deal with interface vs non-interface comparison
valid := false
if x.isAssignable(check.ctxt, y.typ) || y.isAssignable(check.ctxt, x.typ) {
switch op {
case token.EQL, token.NEQ:
valid = isComparable(x.typ) ||
x.isNil() && hasNil(y.typ) ||
y.isNil() && hasNil(x.typ)
case token.LSS, token.LEQ, token.GTR, token.GEQ:
valid = isOrdered(x.typ)
default:
unreachable()
}
}
if !valid {
check.invalidOp(x.pos(), "cannot compare %s %s %s", x, op, y)
x.mode = invalid
return
}
if x.mode == constant && y.mode == constant {
x.val = compareConst(x.val, y.val, op)
} else {
x.mode = value
}
// The result type of a comparison is always boolean and
// independent of the argument types. They have now their
// final types (untyped or typed): update the respective
// expression trees.
check.updateExprType(x.expr, x.typ, true)
check.updateExprType(y.expr, y.typ, true)
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 || !isRepresentableConst(x.val, nil, UntypedInt)) {
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 {
if untypedx {
x.typ = Typ[UntypedInt]
}
if x.val != nil && y.val != nil {
// rhs must be within reasonable bounds
const stupidShift = 1024
s, ok := y.val.(int64)
if !ok || s < 0 || s >= stupidShift {
check.invalidOp(y.pos(), "%s: stupid shift", y)
x.mode = invalid
return
}
// everything's ok
x.val = shiftConst(x.val, uint(s), op)
} else {
x.val = nil
}
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;
// the type is int if it cannot be determined from the context (for
// instance, if the shift expression is an operand in a comparison
// against an untyped constant)".
// 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.
if info, ok := check.untyped[x.expr]; ok {
info.isLhs = true
check.untyped[x.expr] = info
} else {
unreachable()
}
// keep x's type
x.mode = value
return
}
}
// 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
}
// non-constant shift
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, iota int) {
var y operand
check.expr(x, lhs, nil, iota)
check.expr(&y, rhs, nil, iota)
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 !IsIdentical(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) && y.mode == constant && isZeroConst(y.val) {
check.invalidOp(y.pos(), "division by zero")
x.mode = invalid
return
}
if x.mode == constant && y.mode == constant {
typ := underlying(x.typ).(*Basic)
x.val = binaryOpConst(x.val, y.val, op, typ)
// Typed constants must be representable in
// their type after each constant operation.
check.isRepresentable(x, typ)
return
}
x.mode = value
// x.typ is unchanged
}
// index checks an index/size expression arg for validity.
// If length >= 0, it is the upper bound for arg.
// TODO(gri): Do we need iota?
func (check *checker) index(arg ast.Expr, length int64, iota int) (i int64, ok bool) {
var x operand
check.expr(&x, arg, nil, iota)
// an untyped constant must be representable as Int
check.convertUntyped(&x, Typ[Int])
if x.mode == invalid {
return
}
// the index/size must be of integer type
if !isInteger(x.typ) {
check.invalidArg(x.pos(), "%s must be integer", &x)
return
}
// a constant index/size i must be 0 <= i < length
if x.mode == constant && x.val != nil {
i = x.val.(int64)
if i < 0 {
check.invalidArg(x.pos(), "%s must not be negative", &x)
return
}
if length >= 0 && i >= length {
check.errorf(x.pos(), "index %s is out of bounds (>= %d)", &x, length)
return
}
// 0 <= i [ && i < length ]
return i, true
}
return -1, true
}
// compositeLitKey resolves unresolved composite literal keys.
// For details, see comment in go/parser/parser.go, method parseElement.
func (check *checker) compositeLitKey(key ast.Expr) {
if ident, ok := key.(*ast.Ident); ok && ident.Obj == nil {
if obj := check.pkg.Scope.Lookup(ident.Name); obj != nil {
check.register(ident, obj)
} else if obj := Universe.Lookup(ident.Name); obj != nil {
check.register(ident, obj)
} else {
check.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
}
}
}
// 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, iota int) 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 {
check.compositeLitKey(kv.Key)
if i, ok := check.index(kv.Key, length, iota); ok {
if i >= 0 {
index = i
}
validIndex = true
}
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.expr(&x, eval, typ, iota)
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
}
// argument typechecks passing an argument arg (if arg != nil) or
// x (if arg == nil) to the i'th parameter of the given signature.
// If passSlice is set, the argument is followed by ... in the call.
//
func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand, passSlice bool) {
// determine parameter
var par *Var
n := len(sig.Params)
if i < n {
par = sig.Params[i]
} else if sig.IsVariadic {
par = sig.Params[n-1]
} else {
check.errorf(arg.Pos(), "too many arguments")
return
}
// determine argument
var z operand
z.mode = variable
z.expr = nil // TODO(gri) can we do better here? (for good error messages)
z.typ = par.Type
if arg != nil {
check.expr(x, arg, z.typ, -1)
}
if x.mode == invalid {
return // ignore this argument
}
// check last argument of the form x...
if passSlice {
if i+1 != n {
check.errorf(x.pos(), "can only use ... with matching parameter")
return // ignore this argument
}
// spec: "If the final argument is assignable to a slice type []T,
// it may be passed unchanged as the value for a ...T parameter if
// the argument is followed by ..."
z.typ = &Slice{Elt: z.typ} // change final parameter type to []T
}
if !check.assignment(x, z.typ) && x.mode != invalid {
check.errorf(x.pos(), "cannot pass argument %s to %s", x, &z)
}
}
var emptyResult Result
func (check *checker) callExpr(x *operand) {
// convert x into a user-friendly set of values
var typ Type
var val interface{}
switch x.mode {
case invalid:
return // nothing to do
case novalue:
typ = &emptyResult
case constant:
typ = x.typ
val = x.val
default:
typ = x.typ
}
// if the operand is untyped, delay notification
// until it becomes typed or until the end of
// type checking
if isUntyped(typ) {
check.untyped[x.expr] = exprInfo{x.mode == constant, false, typ.(*Basic), val}
return
}
// TODO(gri) ensure that literals always report
// their dynamic (never interface) type.
// This is not the case yet.
if check.ctxt.Expr != nil {
check.ctxt.Expr(x.expr, typ, val)
}
}
// 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.
// 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) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycleOk bool) {
if trace {
c := ""
if cycleOk {
c = " ⨁"
}
check.trace(e.Pos(), "%s (%s, %d%s)", e, typeString(hint), iota, c)
defer check.untrace("=> %s", x)
}
// record final type of x if untyped, notify clients of type otherwise
defer check.callExpr(x)
switch e := e.(type) {
case *ast.BadExpr:
goto Error // error was reported before
case *ast.Ident:
if e.Name == "_" {
check.invalidOp(e.Pos(), "cannot use _ as value or type")
goto Error
}
obj := check.lookup(e)
if obj == nil {
goto Error // error was reported before
}
check.object(obj, cycleOk)
switch obj := obj.(type) {
case *Package:
check.errorf(e.Pos(), "use of package %s not in selector", obj.Name)
goto Error
case *Const:
if obj.Type == Typ[Invalid] {
goto Error
}
x.mode = constant
if obj == universeIota {
if iota < 0 {
check.invalidAST(e.Pos(), "cannot use iota outside constant declaration")
goto Error
}
x.val = int64(iota)
} else {
x.val = obj.Val // may be nil if we don't know the constant value
}
case *TypeName:
x.mode = typexpr
if !cycleOk && underlying(obj.Type) == nil {
check.errorf(obj.spec.Pos(), "illegal cycle in declaration of %s", obj.Name)
x.expr = e
x.typ = Typ[Invalid]
return // don't goto Error - need x.mode == typexpr
}
case *Var:
x.mode = variable
case *Func:
x.mode = value
default:
unreachable()
}
x.typ = obj.GetType()
case *ast.Ellipsis:
// ellipses are handled explicitly where they are legal
// (array composite literals and parameter lists)
check.errorf(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, false).(*Signature); ok {
x.mode = value
x.typ = sig
check.later(nil, sig, e.Body)
} 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, Elt: check.typ(atyp.Elt, cycleOk)}
openArray = true
}
}
if typ == nil {
typ = check.typ(e.Type, false)
}
}
if typ == nil {
check.errorf(e.Pos(), "missing type in composite literal")
goto Error
}
switch utyp := underlying(deref(typ)).(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.errorf(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 := utyp.fieldIndex(QualifiedName{check.pkg, key.Name})
if i < 0 {
check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
continue
}
// 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, nil, iota)
etyp := fields[i].Type
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.errorf(kv.Pos(), "mixture of field:value and value elements in struct literal")
continue
}
check.expr(x, e, nil, iota)
if i >= len(fields) {
check.errorf(x.pos(), "too many values in struct literal")
break // cannot continue
}
// i < len(fields)
etyp := fields[i].Type
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.errorf(e.Rbrace, "too few values in struct literal")
// ok to continue
}
}
case *Array:
n := check.indexedElts(e.Elts, utyp.Elt, utyp.Len, iota)
// 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.Elt, -1, iota)
case *Map:
visited := make(map[interface{}]bool, len(e.Elts))
for _, e := range e.Elts {
kv, _ := e.(*ast.KeyValueExpr)
if kv == nil {
check.errorf(e.Pos(), "missing key in map literal")
continue
}
check.compositeLitKey(kv.Key)
check.expr(x, kv.Key, nil, iota)
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 && x.val != nil {
if visited[x.val] {
check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
continue
}
visited[x.val] = true
}
check.expr(x, kv.Value, utyp.Elt, iota)
if !check.assignment(x, utyp.Elt) {
if x.mode != invalid {
check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.Elt)
}
continue
}
}
default:
check.errorf(e.Pos(), "%s is not a valid composite literal type", typ)
goto Error
}
x.mode = value
x.typ = typ
case *ast.ParenExpr:
check.rawExpr(x, e.X, nil, iota, cycleOk)
case *ast.SelectorExpr:
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 {
if pkg, ok := check.lookup(ident).(*Package); ok {
exp := pkg.Scope.Lookup(sel)
// gcimported package scopes contain non-exported
// objects such as types used in partially exported
// objects - do not accept them
if exp == nil || !ast.IsExported(exp.GetName()) {
check.errorf(e.Pos(), "cannot refer to unexported %s", e)
goto Error
}
check.register(e.Sel, exp)
// Simplified version of the code for *ast.Idents:
// - imported packages use types.Scope and types.Objects
// - imported objects are always fully initialized
switch exp := exp.(type) {
case *Const:
assert(exp.Val != nil)
x.mode = constant
x.typ = exp.Type
x.val = exp.Val
case *TypeName:
x.mode = typexpr
x.typ = exp.Type
case *Var:
x.mode = variable
x.typ = exp.Type
case *Func:
x.mode = value
x.typ = exp.Type
default:
unreachable()
}
x.expr = e
return
}
}
check.exprOrType(x, e.X, iota, false)
if x.mode == invalid {
goto Error
}
res := lookupField(x.typ, QualifiedName{check.pkg, sel})
if res.mode == invalid {
check.invalidOp(e.Pos(), "%s has no single field or method %s", x, sel)
goto Error
}
if x.mode == typexpr {
// method expression
sig, ok := res.typ.(*Signature)
if !ok {
check.invalidOp(e.Pos(), "%s has no method %s", x, sel)
goto Error
}
// the receiver type becomes the type of the first function
// argument of the method expression's function type
// TODO(gri) at the moment, method sets don't correctly track
// pointer vs non-pointer receivers => typechecker is too lenient
x.mode = value
x.typ = &Signature{
Params: append([]*Var{{Type: x.typ}}, sig.Params...),
Results: sig.Results,
IsVariadic: sig.IsVariadic,
}
} else {
// regular selector
x.mode = res.mode
x.typ = res.typ
}
case *ast.IndexExpr:
check.expr(x, e.X, nil, iota)
if x.mode == invalid {
goto Error
}
valid := false
length := int64(-1) // valid if >= 0
switch typ := underlying(x.typ).(type) {
case *Basic:
if isString(typ) {
valid = true
if x.mode == constant && x.val != nil {
length = int64(len(x.val.(string)))
}
// 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 = Typ[Byte]
}
case *Array:
valid = true
length = typ.Len
if x.mode != variable {
x.mode = value
}
x.typ = typ.Elt
case *Pointer:
if typ, _ := underlying(typ.Base).(*Array); typ != nil {
valid = true
length = typ.Len
x.mode = variable
x.typ = typ.Elt
}
case *Slice:
valid = true
x.mode = variable
x.typ = typ.Elt
case *Map:
var key operand
check.expr(&key, e.Index, nil, iota)
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 = valueok
x.typ = typ.Elt
x.expr = e
return
}
if !valid {
check.invalidOp(x.pos(), "cannot index %s", x)
goto Error
}
if e.Index == nil {
check.invalidAST(e.Pos(), "missing index expression for %s", x)
return
}
check.index(e.Index, length, iota)
// ok to continue
case *ast.SliceExpr:
check.expr(x, e.X, nil, iota)
if x.mode == invalid {
goto Error
}
valid := false
length := int64(-1) // valid if >= 0
switch typ := underlying(x.typ).(type) {
case *Basic:
if isString(typ) {
valid = true
if x.mode == constant && x.val != nil {
length = int64(len(x.val.(string))) + 1 // +1 for slice
}
// a sliced string always yields a string value
// of the same type as the original string (not
// a constant) even if the string and the indices
// are constant
x.mode = value
// x.typ doesn't change, but if it is an untyped
// string it becomes string (see also issue 4913).
if typ.Kind == UntypedString {
x.typ = Typ[String]
}
}
case *Array:
valid = true
length = typ.Len + 1 // +1 for slice
if x.mode != variable {
check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
goto Error
}
x.typ = &Slice{Elt: typ.Elt}
case *Pointer:
if typ, _ := underlying(typ.Base).(*Array); typ != nil {
valid = true
length = typ.Len + 1 // +1 for slice
x.mode = variable
x.typ = &Slice{Elt: typ.Elt}
}
case *Slice:
valid = true
x.mode = variable
// x.typ doesn't change
}
if !valid {
check.invalidOp(x.pos(), "cannot slice %s", x)
goto Error
}
lo := int64(0)
if e.Low != nil {
if i, ok := check.index(e.Low, length, iota); ok && i >= 0 {
lo = i
}
}
hi := int64(-1)
if e.High != nil {
if i, ok := check.index(e.High, length, iota); ok && i >= 0 {
hi = i
}
} else if length >= 0 {
hi = length
}
if lo >= 0 && hi >= 0 && lo > hi {
check.errorf(e.Low.Pos(), "inverted slice range: %d > %d", lo, hi)
// ok to continue
}
case *ast.TypeAssertExpr:
check.expr(x, e.X, nil, iota)
if x.mode == invalid {
goto Error
}
var T *Interface
if T, _ = underlying(x.typ).(*Interface); T == 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.errorf(e.Pos(), "use of .(type) outside type switch")
goto Error
}
typ := check.typ(e.Type, false)
if typ == Typ[Invalid] {
goto Error
}
if method, wrongType := missingMethod(typ, T); method != nil {
var msg string
if wrongType {
msg = "%s cannot have dynamic type %s (wrong type for method %s)"
} else {
msg = "%s cannot have dynamic type %s (missing method %s)"
}
check.errorf(e.Type.Pos(), msg, x, typ, method.Name)
// ok to continue
}
x.mode = valueok
x.expr = e
x.typ = typ
case *ast.CallExpr:
check.exprOrType(x, e.Fun, iota, false)
if x.mode == invalid {
goto Error
} else if x.mode == typexpr {
check.conversion(x, e, x.typ, iota)
} else if sig, ok := underlying(x.typ).(*Signature); ok {
// check parameters
// If we have a trailing ... at the end of the parameter
// list, the last argument must match the parameter type
// []T of a variadic function parameter x ...T.
passSlice := false
if e.Ellipsis.IsValid() {
if sig.IsVariadic {
passSlice = true
} else {
check.errorf(e.Ellipsis, "cannot use ... in call to %s", e.Fun)
// ok to continue
}
}
// If we have a single argument that is a function call
// we need to handle it separately. Determine if this
// is the case without checking the argument.
var call *ast.CallExpr
if len(e.Args) == 1 {
call, _ = unparen(e.Args[0]).(*ast.CallExpr)
}
n := 0 // parameter count
if call != nil {
// We have a single argument that is a function call.
check.expr(x, call, nil, -1)
if x.mode == invalid {
goto Error // TODO(gri): we can do better
}
if t, _ := x.typ.(*Result); t != nil {
// multiple result values
n = len(t.Values)
for i, obj := range t.Values {
x.mode = value
x.expr = nil // TODO(gri) can we do better here? (for good error messages)
x.typ = obj.Type
check.argument(sig, i, nil, x, passSlice && i+1 == n)
}
} else {
// single result value
n = 1
check.argument(sig, 0, nil, x, passSlice)
}
} else {
// We don't have a single argument or it is not a function call.
n = len(e.Args)
for i, arg := range e.Args {
check.argument(sig, i, arg, x, passSlice && i+1 == n)
}
}
// determine if we have enough arguments
if sig.IsVariadic {
// a variadic function accepts an "empty"
// last argument: count one extra
n++
}
if n < len(sig.Params) {
check.errorf(e.Fun.Pos(), "too few arguments in call to %s", e.Fun)
// ok to continue
}
// determine result
switch len(sig.Results) {
case 0:
x.mode = novalue
case 1:
x.mode = value
x.typ = sig.Results[0].Type
default:
x.mode = value
x.typ = &Result{Values: sig.Results}
}
} else if bin, ok := x.typ.(*builtin); ok {
check.builtin(x, e, bin, iota)
} else {
check.invalidOp(x.pos(), "cannot call non-function %s", x)
goto Error
}
case *ast.StarExpr:
check.exprOrType(x, e.X, iota, true)
switch x.mode {
case invalid:
goto Error
case typexpr:
x.typ = &Pointer{Base: x.typ}
default:
if typ, ok := underlying(x.typ).(*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, nil, iota)
if x.mode == invalid {
goto Error
}
check.unary(x, e.Op)
if x.mode == invalid {
goto Error
}
case *ast.BinaryExpr:
check.binary(x, e.X, e.Y, e.Op, iota)
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:
if e.Len != nil {
check.expr(x, e.Len, nil, iota)
if x.mode == invalid {
goto Error
}
if x.mode != constant {
if x.mode != invalid {
check.errorf(x.pos(), "array length %s must be constant", x)
}
goto Error
}
n, ok := x.val.(int64)
if !ok || n < 0 {
check.errorf(x.pos(), "invalid array length %s", x)
goto Error
}
x.typ = &Array{Len: n, Elt: check.typ(e.Elt, cycleOk)}
} else {
x.typ = &Slice{Elt: check.typ(e.Elt, true)}
}
x.mode = typexpr
case *ast.StructType:
x.mode = typexpr
x.typ = &Struct{Fields: check.collectFields(e.Fields, cycleOk)}
case *ast.FuncType:
params, isVariadic := check.collectParams(e.Params, true)
results, _ := check.collectParams(e.Results, false)
x.mode = typexpr
x.typ = &Signature{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
case *ast.InterfaceType:
x.mode = typexpr
x.typ = &Interface{Methods: check.collectMethods(e.Methods)}
case *ast.MapType:
x.mode = typexpr
x.typ = &Map{Key: check.typ(e.Key, true), Elt: check.typ(e.Value, true)}
case *ast.ChanType:
x.mode = typexpr
x.typ = &Chan{Dir: e.Dir, Elt: check.typ(e.Value, true)}
default:
if debug {
check.dump("expr = %v (%T)", e, e)
}
unreachable()
}
// everything went well
x.expr = e
return
Error:
x.mode = invalid
x.expr = e
}
// exprOrType is like rawExpr but reports an error if e doesn't represents a value or type.
func (check *checker) exprOrType(x *operand, e ast.Expr, iota int, cycleOk bool) {
check.rawExpr(x, e, nil, iota, cycleOk)
if x.mode == novalue {
check.errorf(x.pos(), "%s used as value or type", x)
x.mode = invalid
}
}
// expr is like rawExpr but reports an error if e doesn't represents a value.
func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) {
check.rawExpr(x, e, hint, iota, false)
switch x.mode {
case novalue:
check.errorf(x.pos(), "%s used as value", x)
x.mode = invalid
case typexpr:
check.errorf(x.pos(), "%s is not an expression", x)
x.mode = invalid
}
}
func (check *checker) rawTyp(e ast.Expr, cycleOk, nilOk bool) Type {
var x operand
check.rawExpr(&x, e, nil, -1, cycleOk)
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 constant:
if nilOk && x.isNil() {
return nil
}
fallthrough
default:
check.errorf(x.pos(), "%s is not a type", &x)
}
return Typ[Invalid]
}
// typOrNil is like rawExpr but reports an error if e doesn't represents a type or the predeclared value nil.
// It returns e's type, nil, or Typ[Invalid] if an error occurred.
//
func (check *checker) typOrNil(e ast.Expr, cycleOk bool) Type {
return check.rawTyp(e, cycleOk, true)
}
// typ is like rawExpr but reports an error if e doesn't represents a type.
// It returns e's type, or Typ[Invalid] if an error occurred.
//
func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
return check.rawTyp(e, cycleOk, false)
}
// 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 an Importer for gc-generated object files.
package types
import (
"bufio"
"errors"
"fmt"
"go/ast"
"go/build"
"go/token"
"io"
"math/big"
"os"
"path/filepath"
"strconv"
"strings"
"text/scanner"
)
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
}
// GcImportData 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 GcImportData(imports map[string]*Package, filename, id string, data *bufio.Reader) (pkg *Package, err error) {
// support for gcParser error handling
defer func() {
if r := recover(); r != nil {
err = r.(importError) // will re-panic if r is not an importError
}
}()
var p gcParser
p.init(filename, id, data, imports)
pkg = p.parseExport()
return
}
// GcImport 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.
// GcImport satisfies the ast.Importer signature.
//
func GcImport(imports map[string]*Package, path string) (pkg *Package, err error) {
if path == "unsafe" {
return Unsafe, nil
}
srcDir := "."
if build.IsLocalImport(path) {
srcDir, err = os.Getwd()
if err != nil {
return
}
}
filename, id := FindPkg(path, srcDir)
if filename == "" {
err = errors.New("can't find import: " + 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 = FindGcExportData(buf); err != nil {
return
}
pkg, err = GcImportData(imports, filename, id, buf)
return
}
// ----------------------------------------------------------------------------
// gcParser
// gcParser parses the exports inside a gc compiler-produced
// object/archive file and populates its scope with the results.
type gcParser 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]*Package // package id -> package object
}
func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*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
// leave for debugging
if false {
// check consistency of imports map
for _, pkg := range imports {
if pkg.Name == "" {
fmt.Printf("no package name for %s\n", pkg.Path)
}
}
}
}
func (p *gcParser) 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 = ""
}
// leave for debugging
if false {
fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
}
}
func declConst(pkg *Package, name string) *Const {
// the constant may have been imported before - if it exists
// already in the respective scope, return that constant
scope := pkg.Scope
if obj := scope.Lookup(name); obj != nil {
return obj.(*Const)
}
// otherwise create a new constant and insert it into the scope
obj := &Const{Pkg: pkg, Name: name}
scope.Insert(obj)
return obj
}
func declTypeName(pkg *Package, name string) *TypeName {
scope := pkg.Scope
if obj := scope.Lookup(name); obj != nil {
return obj.(*TypeName)
}
obj := &TypeName{Pkg: pkg, Name: name}
// a named type may be referred to before the underlying type
// is known - set it up
obj.Type = &NamedType{Obj: obj}
scope.Insert(obj)
return obj
}
func declVar(pkg *Package, name string) *Var {
scope := pkg.Scope
if obj := scope.Lookup(name); obj != nil {
return obj.(*Var)
}
obj := &Var{Pkg: pkg, Name: name}
scope.Insert(obj)
return obj
}
func declFunc(pkg *Package, name string) *Func {
scope := pkg.Scope
if obj := scope.Lookup(name); obj != nil {
return obj.(*Func)
}
obj := &Func{Pkg: pkg, Name: name}
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 *gcParser) 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 *gcParser) errorf(format string, args ...interface{}) {
p.error(fmt.Sprintf(format, args...))
}
func (p *gcParser) 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 *gcParser) 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 *gcParser) 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 *gcParser) 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 *gcParser) parsePackageName() string {
return p.expect(scanner.Ident)
}
// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
func (p *gcParser) 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 *gcParser) parseQualifiedName() (id, name string) {
p.expect('@')
id = p.parsePackageId()
p.expect('.')
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 *gcParser) getPkg(id, name string) *Package {
// package unsafe is not in the imports map - handle explicitly
if id == "unsafe" {
return Unsafe
}
pkg := p.imports[id]
if pkg == nil && name != "" {
pkg = &Package{Name: name, Path: id, Scope: new(Scope)}
p.imports[id] = pkg
}
return pkg
}
// parseExportedName is like parseQualifiedName, but
// the package id is resolved to an imported *Package.
//
func (p *gcParser) parseExportedName() (pkg *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 *gcParser) parseBasicType() Type {
id := p.expect(scanner.Ident)
obj := Universe.Lookup(id)
if obj, ok := obj.(*TypeName); ok {
return obj.Type
}
p.errorf("not a basic type: %s", id)
return nil
}
// ArrayType = "[" int_lit "]" Type .
//
func (p *gcParser) parseArrayType() Type {
// "[" already consumed and lookahead known not to be "]"
lit := p.expect(scanner.Int)
p.expect(']')
elt := p.parseType()
n, err := strconv.ParseInt(lit, 10, 64)
if err != nil {
p.error(err)
}
return &Array{Len: n, Elt: elt}
}
// MapType = "map" "[" Type "]" Type .
//
func (p *gcParser) parseMapType() Type {
p.expectKeyword("map")
p.expect('[')
key := p.parseType()
p.expect(']')
elt := p.parseType()
return &Map{Key: key, Elt: elt}
}
// Name = identifier | "?" | QualifiedName .
//
// If materializePkg is set, a package is returned for fully qualified names.
// That 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
// for QualifiedNames. Fake packages are created when the package id is not
// found in the p.imports map; we cannot create a real package in that case
// because we don't have a package name.
//
// TODO(gri): consider changing QualifiedIdents to (path, name) pairs to
// simplify this code.
//
func (p *gcParser) parseName(materializePkg bool) (pkg *Package, name string) {
switch p.tok {
case scanner.Ident:
name = p.lit
p.next()
case '?':
// anonymous
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 = &Package{Path: id}
}
}
default:
p.error("name expected")
}
return
}
// Field = Name Type [ string_lit ] .
//
func (p *gcParser) parseField() *Field {
var f Field
f.Pkg, f.Name = p.parseName(true)
f.Type = p.parseType()
if p.tok == scanner.String {
f.Tag = p.expect(scanner.String)
}
if f.Name == "" {
// anonymous field - typ must be T or *T and T must be a type name
if typ, ok := deref(f.Type).(*NamedType); ok && typ.Obj != nil {
f.Name = typ.Obj.GetName()
f.IsAnonymous = true
} else {
p.errorf("anonymous field expected")
}
}
return &f
}
// StructType = "struct" "{" [ FieldList ] "}" .
// FieldList = Field { ";" Field } .
//
func (p *gcParser) parseStructType() Type {
var fields []*Field
p.expectKeyword("struct")
p.expect('{')
for p.tok != '}' {
if len(fields) > 0 {
p.expect(';')
}
fields = append(fields, p.parseField())
}
p.expect('}')
return &Struct{Fields: fields}
}
// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
//
func (p *gcParser) parseParameter() (par *Var, isVariadic bool) {
_, name := p.parseName(false)
if name == "" {
name = "_" // cannot access unnamed identifiers
}
if p.tok == '.' {
p.expectSpecial("...")
isVariadic = true
}
typ := p.parseType()
// ignore argument tag (e.g. "noescape")
if p.tok == scanner.String {
p.next()
}
par = &Var{Name: name, Type: typ} // Pkg == nil
return
}
// Parameters = "(" [ ParameterList ] ")" .
// ParameterList = { Parameter "," } Parameter .
//
func (p *gcParser) parseParameters() (list []*Var, isVariadic bool) {
p.expect('(')
for p.tok != ')' {
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 *gcParser) parseSignature() *Signature {
params, isVariadic := p.parseParameters()
// optional result type
var results []*Var
if p.tok == '(' {
var variadic bool
results, variadic = p.parseParameters()
if variadic {
p.error("... not permitted on result type")
}
}
return &Signature{Params: params, Results: results, IsVariadic: 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 *gcParser) parseInterfaceType() Type {
var methods []*Method
p.expectKeyword("interface")
p.expect('{')
for p.tok != '}' {
if len(methods) > 0 {
p.expect(';')
}
pkg, name := p.parseName(true)
typ := p.parseSignature()
methods = append(methods, &Method{QualifiedName{pkg, name}, typ})
}
p.expect('}')
return &Interface{Methods: methods}
}
// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
//
func (p *gcParser) parseChanType() Type {
dir := ast.SEND | ast.RECV
if p.tok == scanner.Ident {
p.expectKeyword("chan")
if p.tok == '<' {
p.expectSpecial("<-")
dir = ast.SEND
}
} else {
p.expectSpecial("<-")
p.expectKeyword("chan")
dir = ast.RECV
}
elt := p.parseType()
return &Chan{Dir: dir, Elt: elt}
}
// 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 *gcParser) parseType() 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()
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 &Slice{Elt: p.parseType()}
}
return p.parseArrayType()
case '*':
// PointerType
p.next()
return &Pointer{Base: 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 *gcParser) parseImportDecl() {
p.expectKeyword("import")
name := p.parsePackageName()
p.getPkg(p.parsePackageId(), name)
}
// int_lit = [ "+" | "-" ] { "0" ... "9" } .
//
func (p *gcParser) parseInt() (neg bool, val string) {
switch p.tok {
case '-':
neg = true
fallthrough
case '+':
p.next()
}
val = p.expect(scanner.Int)
return
}
// number = int_lit [ "p" int_lit ] .
//
func (p *gcParser) parseNumber() (x operand) {
x.mode = constant
// mantissa
neg, val := p.parseInt()
mant, ok := new(big.Int).SetString(val, 0)
assert(ok)
if neg {
mant.Neg(mant)
}
if p.lit == "p" {
// exponent (base 2)
p.next()
neg, val = p.parseInt()
exp64, err := strconv.ParseUint(val, 10, 0)
if err != nil {
p.error(err)
}
exp := uint(exp64)
if neg {
denom := big.NewInt(1)
denom.Lsh(denom, exp)
x.typ = Typ[UntypedFloat]
x.val = normalizeRatConst(new(big.Rat).SetFrac(mant, denom))
return
}
if exp > 0 {
mant.Lsh(mant, exp)
}
x.typ = Typ[UntypedFloat]
x.val = normalizeIntConst(mant)
return
}
x.typ = Typ[UntypedInt]
x.val = normalizeIntConst(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 *gcParser) parseConstDecl() {
p.expectKeyword("const")
pkg, name := p.parseExportedName()
obj := declConst(pkg, name)
var x operand
if p.tok != '=' {
obj.Type = p.parseType()
}
p.expect('=')
switch p.tok {
case scanner.Ident:
// bool_lit
if p.lit != "true" && p.lit != "false" {
p.error("expected true or false")
}
x.typ = Typ[UntypedBool]
x.val = p.lit == "true"
p.next()
case '-', scanner.Int:
// int_lit
x = p.parseNumber()
case '(':
// complex_lit or rune_lit
p.next()
if p.tok == scanner.Char {
p.next()
p.expect('+')
x = p.parseNumber()
x.typ = Typ[UntypedRune]
p.expect(')')
break
}
re := p.parseNumber()
p.expect('+')
im := p.parseNumber()
p.expectKeyword("i")
p.expect(')')
x.typ = Typ[UntypedComplex]
// TODO(gri) fix this
_, _ = re, im
x.val = zeroConst
case scanner.Char:
// rune_lit
x.setConst(token.CHAR, p.lit)
p.next()
case scanner.String:
// string_lit
x.setConst(token.STRING, p.lit)
p.next()
default:
p.errorf("expected literal got %s", scanner.TokenString(p.tok))
}
if obj.Type == nil {
obj.Type = x.typ
}
assert(x.val != nil)
obj.Val = x.val
}
// TypeDecl = "type" ExportedName Type .
//
func (p *gcParser) 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.(*NamedType); name.Underlying == nil {
name.Underlying = typ
}
}
// VarDecl = "var" ExportedName Type .
//
func (p *gcParser) parseVarDecl() {
p.expectKeyword("var")
pkg, name := p.parseExportedName()
obj := declVar(pkg, name)
obj.Type = p.parseType()
}
// Func = Signature [ Body ] .
// Body = "{" ... "}" .
//
func (p *gcParser) parseFunc() *Signature {
sig := p.parseSignature()
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 *gcParser) parseMethodDecl() {
// "func" already consumed
p.expect('(')
recv, _ := p.parseParameter() // receiver
p.expect(')')
// determine receiver base type object
typ := recv.Type
if ptr, ok := typ.(*Pointer); ok {
typ = ptr.Base
}
base := typ.(*NamedType)
// parse method name, signature, and possibly inlined body
pkg, name := p.parseName(true) // unexported method names in imports are qualified with their package.
sig := p.parseFunc()
sig.Recv = recv
// add method to type unless type was imported before
// and method exists already
// TODO(gri) investigate if this can be avoided
for _, m := range base.Methods {
if m.Name == name {
return // method was added before
}
}
base.Methods = append(base.Methods, &Method{QualifiedName{pkg, name}, sig})
}
// FuncDecl = "func" ExportedName Func .
//
func (p *gcParser) parseFuncDecl() {
// "func" already consumed
pkg, name := p.parseExportedName()
typ := p.parseFunc()
declFunc(pkg, name).Type = typ
}
// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
//
func (p *gcParser) parseDecl() {
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 *gcParser) parseExport() *Package {
p.expectKeyword("package")
name := p.parsePackageName()
if p.tok != '\n' {
// A package is safe if it was compiled with the -u flag,
// which disables the unsafe package.
// TODO(gri) remember "safe" package
p.expectKeyword("safe")
}
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.Complete = true
return pkg
}
// 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 (
"go/ast"
"go/build"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
)
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]*Package)
func testPath(t *testing.T, path string) bool {
t0 := time.Now()
_, err := GcImport(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 TestGcImport(t *testing.T) {
// 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
kind ast.ObjKind
typ string
}{
{"unsafe.Pointer", ast.Typ, "Pointer"},
{"math.Pi", ast.Con, "untyped float"},
{"io.Reader", ast.Typ, "interface{Read(p []byte) (n int, err error)}"},
{"io.ReadWriter", ast.Typ, "interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
{"math.Sin", ast.Fun, "func(x·2 float64) (_ float64)"},
// TODO(gri) add more tests
}
func TestGcImportedTypes(t *testing.T) {
// This package does not yet know how to read 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 := GcImport(imports, importPath)
if err != nil {
t.Error(err)
continue
}
obj := pkg.Scope.Lookup(objName)
// TODO(gri) should define an accessor on Object
var kind ast.ObjKind
var typ Type
switch obj := obj.(type) {
case *Const:
kind = ast.Con
typ = obj.Type
case *TypeName:
kind = ast.Typ
typ = obj.Type
case *Var:
kind = ast.Var
typ = obj.Type
case *Func:
kind = ast.Fun
typ = obj.Type
default:
unreachable()
}
if kind != test.kind {
t.Errorf("%s: got kind = %q; want %q", test.name, kind, test.kind)
}
str := typeString(underlying(typ))
if str != test.typ {
t.Errorf("%s: got type = %q; want %q", test.name, typ, test.typ)
}
}
}
// 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"
)
// 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 {
GetPkg() *Package
GetName() string
GetType() Type
GetPos() token.Pos
anObject()
}
// A Package represents the contents (objects) of a Go package.
type Package struct {
Name string
Path string // import path, "" for current (non-imported) package
Scope *Scope // package-level scope
Imports map[string]*Package // map of import paths to imported packages
Complete bool // if set, this package was imported completely
spec *ast.ImportSpec
}
// A Const represents a declared constant.
type Const struct {
Pkg *Package
Name string
Type Type
Val interface{} // nil means unknown constant value due to type error
visited bool // for initialization cycle detection
spec *ast.ValueSpec
}
// A TypeName represents a declared type.
type TypeName struct {
Pkg *Package
Name string
Type Type // *NamedType or *Basic
spec *ast.TypeSpec
}
// A Variable represents a declared variable (including function parameters and results).
type Var struct {
Pkg *Package // nil for parameters
Name string
Type Type
visited bool // for initialization cycle detection
decl interface{}
}
// A Func represents a declared function.
type Func struct {
Pkg *Package
Name string
Type Type // *Signature or *Builtin
decl *ast.FuncDecl
}
func (obj *Package) GetPkg() *Package { return obj }
func (obj *Const) GetPkg() *Package { return obj.Pkg }
func (obj *TypeName) GetPkg() *Package { return obj.Pkg }
func (obj *Var) GetPkg() *Package { return obj.Pkg }
func (obj *Func) GetPkg() *Package { return obj.Pkg }
func (obj *Package) GetName() string { return obj.Name }
func (obj *Const) GetName() string { return obj.Name }
func (obj *TypeName) GetName() string { return obj.Name }
func (obj *Var) GetName() string { return obj.Name }
func (obj *Func) GetName() string { return obj.Name }
func (obj *Package) GetType() Type { return Typ[Invalid] }
func (obj *Const) GetType() Type { return obj.Type }
func (obj *TypeName) GetType() Type { return obj.Type }
func (obj *Var) GetType() Type { return obj.Type }
func (obj *Func) GetType() Type { return obj.Type }
func (obj *Package) GetPos() token.Pos {
if obj.spec != nil {
return obj.spec.Pos()
}
return token.NoPos
}
func (obj *Const) GetPos() token.Pos {
for _, n := range obj.spec.Names {
if n.Name == obj.Name {
return n.Pos()
}
}
return token.NoPos
}
func (obj *TypeName) GetPos() token.Pos {
if obj.spec != nil {
return obj.spec.Pos()
}
return token.NoPos
}
func (obj *Var) GetPos() token.Pos {
switch d := obj.decl.(type) {
case *ast.Field:
for _, n := range d.Names {
if n.Name == obj.Name {
return n.Pos()
}
}
case *ast.ValueSpec:
for _, n := range d.Names {
if n.Name == obj.Name {
return n.Pos()
}
}
case *ast.AssignStmt:
for _, x := range d.Lhs {
if ident, isIdent := x.(*ast.Ident); isIdent && ident.Name == obj.Name {
return ident.Pos()
}
}
}
return token.NoPos
}
func (obj *Func) GetPos() token.Pos {
if obj.decl != nil && obj.decl.Name != nil {
return obj.decl.Name.Pos()
}
return token.NoPos
}
func (*Package) anObject() {}
func (*Const) anObject() {}
func (*TypeName) anObject() {}
func (*Var) anObject() {}
func (*Func) anObject() {}
// newObj returns a new Object for a given *ast.Object.
// It does not canonicalize them (it always returns a new one).
// For canonicalization, see check.lookup.
//
// TODO(gri) Once we do identifier resolution completely in
// in the typechecker, this functionality can go.
//
func newObj(pkg *Package, astObj *ast.Object) Object {
assert(pkg != nil)
name := astObj.Name
typ, _ := astObj.Type.(Type)
switch astObj.Kind {
case ast.Bad:
// ignore
case ast.Pkg:
unreachable()
case ast.Con:
return &Const{Pkg: pkg, Name: name, Type: typ, Val: astObj.Data, spec: astObj.Decl.(*ast.ValueSpec)}
case ast.Typ:
return &TypeName{Pkg: pkg, Name: name, Type: typ, spec: astObj.Decl.(*ast.TypeSpec)}
case ast.Var:
switch astObj.Decl.(type) {
case *ast.Field: // function parameters
case *ast.ValueSpec: // proper variable declarations
case *ast.AssignStmt: // short variable declarations
default:
unreachable() // everything else is not ok
}
return &Var{Pkg: pkg, Name: name, Type: typ, decl: astObj.Decl}
case ast.Fun:
return &Func{Pkg: pkg, Name: name, Type: typ, decl: astObj.Decl.(*ast.FuncDecl)}
case ast.Lbl:
unreachable() // for now
}
unreachable()
return nil
}
// 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 {
format := " %v"
if isString(x.typ) {
format = " %q"
}
fmt.Fprintf(&buf, format, 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
}
}
// isNil reports whether x is the predeclared nil constant.
func (x *operand) isNil() bool {
return x.mode == constant && x.val == nilConst
}
// TODO(gri) The functions operand.isAssignable, checker.convertUntyped,
// checker.isRepresentable, and checker.assignOperand are
// overlapping in functionality. Need to simplify and clean up.
// isAssignable reports whether x is assignable to a variable of type T.
func (x *operand) isAssignable(ctxt *Context, 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 {
if m, _ := missingMethod(x.typ, Ti); m == nil {
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.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.isRepresentable. Need to clean up.
if isUntyped(Vu) {
switch t := Tu.(type) {
case *Basic:
if x.mode == constant {
return isRepresentableConst(x.val, ctxt, t.Kind)
}
// 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() || len(t.Methods) == 0
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 && isRepresentableConst(x.val, nil, UntypedInt) // no context required for UntypedInt
}
// lookupResult represents the result of a struct field/method lookup.
type lookupResult struct {
mode operandMode
typ Type
index []int // field index sequence; nil for methods
}
type embeddedType struct {
typ *NamedType
index []int // field index sequence
multiples bool // if set, typ is embedded multiple times at the same level
}
// lookupFieldBreadthFirst searches all types in list for a single entry (field
// or method) of the given name from the given package. If such a field is found,
// the result describes the field mode and type; otherwise the result mode is invalid.
// (This function is similar in structure to FieldByNameFunc in reflect/type.go)
//
func lookupFieldBreadthFirst(list []embeddedType, name QualifiedName) (res lookupResult) {
// visited records the types that have been searched already.
visited := make(map[*NamedType]bool)
// embedded types of the next lower level
var next []embeddedType
// potentialMatch is invoked every time a match is found.
potentialMatch := func(multiples bool, mode operandMode, typ Type) bool {
if multiples || res.mode != invalid {
// name appeared already at this level - annihilate
res.mode = invalid
return false
}
// first appearance of name
res.mode = mode
res.typ = typ
res.index = nil
return true
}
// Search the current level if there is any work to do and collect
// embedded types of the next lower level in the next list.
for len(list) > 0 {
// The res.mode indicates whether we have found a match already
// on this level (mode != invalid), or not (mode == invalid).
assert(res.mode == invalid)
// start with empty next list (don't waste underlying array)
next = next[:0]
// look for name in all types at this level
for _, e := range list {
typ := e.typ
if visited[typ] {
continue
}
visited[typ] = true
// look for a matching attached method
for _, m := range typ.Methods {
if name.IsSame(m.QualifiedName) {
assert(m.Type != nil)
if !potentialMatch(e.multiples, value, m.Type) {
return // name collision
}
}
}
switch t := typ.Underlying.(type) {
case *Struct:
// look for a matching field and collect embedded types
for i, f := range t.Fields {
if name.IsSame(f.QualifiedName) {
assert(f.Type != nil)
if !potentialMatch(e.multiples, variable, f.Type) {
return // name collision
}
var index []int
index = append(index, e.index...) // copy e.index
index = append(index, i)
res.index = index
continue
}
// Collect embedded struct fields for searching the next
// lower level, 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 level; 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 typ appeared multiple times at
// this level, f.Type appears multiple times at the next
// level.
if f.IsAnonymous && res.mode == invalid {
// Ignore embedded basic types - only user-defined
// named types can have methods or have struct fields.
if t, _ := deref(f.Type).(*NamedType); t != nil {
var index []int
index = append(index, e.index...) // copy e.index
index = append(index, i)
next = append(next, embeddedType{t, index, e.multiples})
}
}
}
case *Interface:
// look for a matching method
for _, m := range t.Methods {
if name.IsSame(m.QualifiedName) {
assert(m.Type != nil)
if !potentialMatch(e.multiples, value, m.Type) {
return // name collision
}
}
}
}
}
if res.mode != invalid {
// we found a single match on this level
return
}
// No match and no collision so far.
// Compute the list to search for the next level.
list = list[:0] // don't waste underlying array
for _, e := range next {
// Instead of adding the same type multiple times, look for
// it in the list and mark it as multiple if it was added
// before.
// We use a sequential search (instead of a map for next)
// because the lists tend to be small, can easily be reused,
// and explicit search appears to be faster in this case.
if alt := findType(list, e.typ); alt != nil {
alt.multiples = true
} else {
list = append(list, e)
}
}
}
return
}
func findType(list []embeddedType, typ *NamedType) *embeddedType {
for i := range list {
if p := &list[i]; p.typ == typ {
return p
}
}
return nil
}
func lookupField(typ Type, name QualifiedName) lookupResult {
typ = deref(typ)
if t, ok := typ.(*NamedType); ok {
for _, m := range t.Methods {
if name.IsSame(m.QualifiedName) {
assert(m.Type != nil)
return lookupResult{value, m.Type, nil}
}
}
typ = t.Underlying
}
switch t := typ.(type) {
case *Struct:
var next []embeddedType
for i, f := range t.Fields {
if name.IsSame(f.QualifiedName) {
return lookupResult{variable, f.Type, []int{i}}
}
if f.IsAnonymous {
// Possible optimization: If the embedded type
// is a pointer to the current type we could
// ignore it.
// Ignore embedded basic types - only user-defined
// named types can have methods or have struct fields.
if t, _ := deref(f.Type).(*NamedType); t != nil {
next = append(next, embeddedType{t, []int{i}, false})
}
}
}
if len(next) > 0 {
return lookupFieldBreadthFirst(next, name)
}
case *Interface:
for _, m := range t.Methods {
if name.IsSame(m.QualifiedName) {
return lookupResult{value, m.Type, nil}
}
}
}
// not found
return lookupResult{mode: invalid}
}
// 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
func isNamed(typ Type) bool {
if _, ok := typ.(*Basic); ok {
return ok
}
_, ok := typ.(*NamedType)
return ok
}
func isBoolean(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsBoolean != 0
}
func isInteger(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsInteger != 0
}
func isUnsigned(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsUnsigned != 0
}
func isFloat(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsFloat != 0
}
func isComplex(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsComplex != 0
}
func isNumeric(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsNumeric != 0
}
func isString(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsString != 0
}
func isUntyped(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsUntyped != 0
}
func isOrdered(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsOrdered != 0
}
func isConstType(typ Type) bool {
t, ok := underlying(typ).(*Basic)
return ok && t.Info&IsConstType != 0
}
func isComparable(typ Type) bool {
switch t := underlying(typ).(type) {
case *Basic:
return t.Kind != Invalid && t.Kind != UntypedNil
case *Pointer, *Interface, *Chan:
// assumes types are equal for pointers and channels
return true
case *Struct:
for _, f := range t.Fields {
if !isComparable(f.Type) {
return false
}
}
return true
case *Array:
return isComparable(t.Elt)
}
return false
}
func hasNil(typ Type) bool {
switch underlying(typ).(type) {
case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
return true
}
return false
}
// IsIdentical returns true if x and y are identical.
func IsIdentical(x, y Type) 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 && IsIdentical(x.Elt, y.Elt)
}
case *Slice:
// Two slice types are identical if they have identical element types.
if y, ok := y.(*Slice); ok {
return IsIdentical(x.Elt, y.Elt)
}
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 len(x.Fields) == len(y.Fields) {
for i, f := range x.Fields {
g := y.Fields[i]
if !f.QualifiedName.IsSame(g.QualifiedName) ||
!IsIdentical(f.Type, g.Type) ||
f.Tag != g.Tag ||
f.IsAnonymous != g.IsAnonymous {
return false
}
}
return true
}
}
case *Pointer:
// Two pointer types are identical if they have identical base types.
if y, ok := y.(*Pointer); ok {
return IsIdentical(x.Base, y.Base)
}
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 identicalTypes(x.Params, y.Params) &&
identicalTypes(x.Results, y.Results) &&
x.IsVariadic == y.IsVariadic
}
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 {
return identicalMethods(x.Methods, y.Methods) // methods are sorted
}
case *Map:
// Two map types are identical if they have identical key and value types.
if y, ok := y.(*Map); ok {
return IsIdentical(x.Key, y.Key) && IsIdentical(x.Elt, y.Elt)
}
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 && IsIdentical(x.Elt, y.Elt)
}
case *NamedType:
// Two named types are identical if their type names originate
// in the same type declaration.
if y, ok := y.(*NamedType); ok {
return x.Obj == y.Obj
}
}
return false
}
// identicalTypes returns true if both lists a and b have the
// same length and corresponding objects have identical types.
func identicalTypes(a, b []*Var) bool {
if len(a) != len(b) {
return false
}
for i, x := range a {
y := b[i]
if !IsIdentical(x.Type, y.Type) {
return false
}
}
return true
}
// identicalMethods returns true if both lists a and b have the
// same length and corresponding methods have identical types.
// TODO(gri) make this more efficient
func identicalMethods(a, b []*Method) bool {
if len(a) != len(b) {
return false
}
m := make(map[QualifiedName]*Method)
for _, x := range a {
assert(m[x.QualifiedName] == nil) // method list must not have duplicate entries
m[x.QualifiedName] = x
}
for _, y := range b {
if x := m[y.QualifiedName]; x == nil || !IsIdentical(x.Type, y.Type) {
return false
}
}
return true
}
// 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 incoming type for all other types. If there is no
// corresponding untyped type, the result is Typ[Invalid].
//
func defaultType(typ Type) Type {
if t, ok := typ.(*Basic); ok {
k := Invalid
switch t.Kind {
// case UntypedNil:
// There is no default type for nil. For a good error message,
// catch this case before calling this function.
case UntypedBool:
k = Bool
case UntypedInt:
k = Int
case UntypedRune:
k = Rune
case UntypedFloat:
k = Float64
case UntypedComplex:
k = Complex128
case UntypedString:
k = String
}
typ = Typ[k]
}
return typ
}
// missingMethod returns (nil, false) if typ implements T, otherwise
// it returns the first missing method required by T and whether it
// is missing or simply has the wrong type.
//
func missingMethod(typ Type, T *Interface) (method *Method, wrongType bool) {
// TODO(gri): this needs to correctly compare method names (taking package into account)
// TODO(gri): distinguish pointer and non-pointer receivers
// an interface type implements T if it has no methods with conflicting signatures
// Note: This is stronger than the current spec. Should the spec require this?
if ityp, _ := underlying(typ).(*Interface); ityp != nil {
for _, m := range T.Methods {
res := lookupField(ityp, m.QualifiedName) // TODO(gri) no need to go via lookupField
if res.mode != invalid && !IsIdentical(res.typ, m.Type) {
return m, true
}
}
return
}
// a concrete type implements T if it implements all methods of T.
for _, m := range T.Methods {
res := lookupField(typ, m.QualifiedName)
if res.mode == invalid {
return m, false
}
if !IsIdentical(res.typ, m.Type) {
return m, true
}
}
return
}
// 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"
"go/ast"
"go/token"
"strconv"
)
func (check *checker) declareObj(scope, altScope *Scope, obj Object, dotImport token.Pos) {
alt := scope.Insert(obj)
if alt == nil && altScope != nil {
// see if there is a conflicting declaration in altScope
alt = altScope.Lookup(obj.GetName())
}
if alt != nil {
prevDecl := ""
// for dot-imports, local declarations are declared first - swap messages
if dotImport.IsValid() {
if pos := alt.GetPos(); pos.IsValid() {
check.errorf(pos, fmt.Sprintf("%s redeclared in this block by dot-import at %s",
obj.GetName(), check.fset.Position(dotImport)))
return
}
// get by w/o other position
check.errorf(dotImport, fmt.Sprintf("dot-import redeclares %s", obj.GetName()))
return
}
if pos := alt.GetPos(); pos.IsValid() {
prevDecl = fmt.Sprintf("\n\tother declaration at %s", check.fset.Position(pos))
}
check.errorf(obj.GetPos(), fmt.Sprintf("%s redeclared in this block%s", obj.GetName(), prevDecl))
}
}
func (check *checker) resolveIdent(scope *Scope, ident *ast.Ident) bool {
for ; scope != nil; scope = scope.Outer {
if obj := scope.Lookup(ident.Name); obj != nil {
check.register(ident, obj)
return true
}
}
return false
}
func (check *checker) resolve(importer Importer) (methods []*ast.FuncDecl) {
pkg := &Package{Scope: &Scope{Outer: Universe}, Imports: make(map[string]*Package)}
check.pkg = pkg
// complete package scope
i := 0
for _, file := range check.files {
// package names must match
switch name := file.Name.Name; {
case pkg.Name == "":
pkg.Name = name
case name != pkg.Name:
check.errorf(file.Package, "package %s; expected %s", name, pkg.Name)
continue // ignore this file
}
// keep this file
check.files[i] = file
i++
// the package identifier denotes the current package
check.register(file.Name, pkg)
// insert top-level file objects in package scope
// (the parser took care of declaration errors)
for _, decl := range file.Decls {
switch d := decl.(type) {
case *ast.BadDecl:
// ignore
case *ast.GenDecl:
if d.Tok == token.CONST {
check.assocInitvals(d)
}
for _, spec := range d.Specs {
switch s := spec.(type) {
case *ast.ImportSpec:
// handled separately below
case *ast.ValueSpec:
for _, name := range s.Names {
if name.Name == "_" {
continue
}
pkg.Scope.Insert(check.lookup(name))
}
case *ast.TypeSpec:
if s.Name.Name == "_" {
continue
}
pkg.Scope.Insert(check.lookup(s.Name))
default:
check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
}
}
case *ast.FuncDecl:
if d.Recv != nil {
// collect method
methods = append(methods, d)
continue
}
if d.Name.Name == "_" || d.Name.Name == "init" {
continue // blank (_) and init functions are inaccessible
}
pkg.Scope.Insert(check.lookup(d.Name))
default:
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
}
}
}
check.files = check.files[0:i]
// complete file scopes with imports and resolve identifiers
for _, file := range check.files {
// build file scope by processing all imports
importErrors := false
fileScope := &Scope{Outer: pkg.Scope}
for _, spec := range file.Imports {
if importer == nil {
importErrors = true
continue
}
path, _ := strconv.Unquote(spec.Path.Value)
imp, err := importer(pkg.Imports, path)
if err != nil {
check.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
importErrors = true
continue
}
// TODO(gri) If a local package name != "." is provided,
// global identifier resolution could proceed even if the
// import failed. Consider adjusting the logic here a bit.
// local name overrides imported package name
name := imp.Name
if spec.Name != nil {
name = spec.Name.Name
}
// add import to file scope
if name == "." {
// merge imported scope with file scope
for _, obj := range imp.Scope.Entries {
// gcimported package scopes contain non-exported
// objects such as types used in partially exported
// objects - do not accept them
if ast.IsExported(obj.GetName()) {
check.declareObj(fileScope, pkg.Scope, obj, spec.Pos())
}
}
// TODO(gri) consider registering the "." identifier
// if we have Context.Ident callbacks for say blank
// (_) identifiers
// check.register(spec.Name, pkg)
} else if name != "_" {
// declare imported package object in file scope
// (do not re-use imp in the file scope but create
// a new object instead; the Decl field is different
// for different files)
obj := &Package{Name: name, Scope: imp.Scope, spec: spec}
check.declareObj(fileScope, pkg.Scope, obj, token.NoPos)
}
}
// resolve identifiers
if importErrors {
// don't use the universe scope without correct imports
// (objects in the universe may be shadowed by imports;
// with missing imports, identifiers might get resolved
// incorrectly to universe objects)
pkg.Scope.Outer = nil
}
i := 0
for _, ident := range file.Unresolved {
if !check.resolveIdent(fileScope, ident) {
check.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
file.Unresolved[i] = ident
i++
}
}
file.Unresolved = file.Unresolved[0:i]
pkg.Scope.Outer = Universe // reset outer scope (is nil if there were importErrors)
}
return
}
// 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 (
"go/ast"
"go/parser"
"go/token"
"testing"
)
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"
func f() string {
_ = "foo"
return fmt.Sprintf("%d", g())
}
func g() (x int) { return }
`,
`
package p
import . "go/parser"
import "sync"
func g() 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() {}
`,
}
var pkgnames = []string{
"fmt",
"math",
}
func TestResolveQualifiedIdents(t *testing.T) {
// parse package files
fset := token.NewFileSet()
var files []*ast.File
for _, src := range sources {
f, err := parser.ParseFile(fset, "", src, parser.DeclarationErrors)
if err != nil {
t.Fatal(err)
}
files = append(files, f)
}
// resolve and type-check package AST
idents := make(map[*ast.Ident]Object)
var ctxt Context
ctxt.Ident = func(id *ast.Ident, obj Object) { idents[id] = obj }
pkg, err := ctxt.Check(fset, files)
if err != nil {
t.Fatal(err)
}
// check that all packages were imported
for _, name := range pkgnames {
if pkg.Imports[name] == nil {
t.Errorf("package %s not imported", name)
}
}
// check that there are no top-level unresolved identifiers
for _, f := range files {
for _, x := range f.Unresolved {
t.Errorf("%s: unresolved global identifier %s", fset.Position(x.Pos()), x.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 := idents[x]
if obj == nil {
t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name)
return false
}
if _, ok := obj.(*Package); ok && idents[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
})
}
// Currently, the Check API doesn't call Ident for fields, methods, and composite literal keys.
// Introduce them artifically so that we can run the check below.
for _, f := range files {
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.StructType:
for _, list := range x.Fields.List {
for _, f := range list.Names {
assert(idents[f] == nil)
idents[f] = &Var{Pkg: pkg, Name: f.Name}
}
}
case *ast.InterfaceType:
for _, list := range x.Methods.List {
for _, f := range list.Names {
assert(idents[f] == nil)
idents[f] = &Func{Pkg: pkg, Name: f.Name}
}
}
case *ast.CompositeLit:
for _, e := range x.Elts {
if kv, ok := e.(*ast.KeyValueExpr); ok {
if k, ok := kv.Key.(*ast.Ident); ok {
assert(idents[k] == nil)
idents[k] = &Var{Pkg: pkg, Name: k.Name}
}
}
}
}
return true
})
}
// check that each identifier in the source is enumerated by the Context.Ident callback
for _, f := range files {
ast.Inspect(f, func(n ast.Node) bool {
if x, ok := n.(*ast.Ident); ok && x.Name != "_" && x.Name != "." {
obj := idents[x]
if obj == nil {
t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name)
} else {
delete(idents, x)
}
return false
}
return true
})
}
// TODO(gri) enable code below
// At the moment, the type checker introduces artifical identifiers which are not
// present in the source. Once it doesn't do that anymore, enable the checks below.
/*
for x := range idents {
t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
}
*/
}
// 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 panic() function is terminating
if call, _ := s.X.(*ast.CallExpr); call != nil {
if id, _ := call.Fun.(*ast.Ident); id != nil {
if obj := check.lookup(id); obj != nil {
// TODO(gri) Predeclared functions should be modelled as objects
// rather then ordinary functions that have a predeclared
// function type. This would simplify code here and else-
// where.
if f, _ := obj.(*Func); f != nil && f.Type == predeclaredFunctions[_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
}
// 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"
)
// A Scope maintains the set of named language entities declared
// in the scope and a link to the immediately surrounding (outer)
// scope.
//
type Scope struct {
Outer *Scope
Entries []Object // scope entries in insertion order
large map[string]Object // for fast lookup - only used for larger scopes
}
// Lookup returns the object with the given name if it is
// found in scope s, otherwise it returns nil. Outer scopes
// are ignored.
//
func (s *Scope) Lookup(name string) Object {
if s.large != nil {
return s.large[name]
}
for _, obj := range s.Entries {
if obj.GetName() == name {
return obj
}
}
return nil
}
// Insert attempts to insert an object obj into scope s.
// If s already contains an object with the same name,
// Insert leaves s unchanged and returns that object.
// Otherwise it inserts obj and returns nil.
//
func (s *Scope) Insert(obj Object) Object {
name := obj.GetName()
if alt := s.Lookup(name); alt != nil {
return alt
}
s.Entries = append(s.Entries, obj)
// If the scope size reaches a threshold, use a map for faster lookups.
const threshold = 20
if len(s.Entries) > threshold {
if s.large == nil {
m := make(map[string]Object, len(s.Entries))
for _, obj := range s.Entries {
m[obj.GetName()] = obj
}
s.large = m
}
s.large[name] = obj
}
return nil
}
// Debugging support
func (s *Scope) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "scope %p {", s)
if s != nil && len(s.Entries) > 0 {
fmt.Fprintln(&buf)
for _, obj := range s.Entries {
fmt.Fprintf(&buf, "\t%s\t%T\n", obj.GetName(), obj)
}
}
fmt.Fprintf(&buf, "}\n")
return buf.String()
}
// 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 support for (unsafe) Alignof, Offsetof, and Sizeof.
package types
func (ctxt *Context) alignof(typ Type) int64 {
if f := ctxt.Alignof; f != nil {
if a := f(typ); a >= 1 {
return a
}
panic("Context.Alignof returned an alignment < 1")
}
return DefaultAlignof(typ)
}
func (ctxt *Context) offsetsof(s *Struct) []int64 {
offsets := s.offsets
if offsets == nil {
// compute offsets on demand
if f := ctxt.Offsetsof; f != nil {
offsets = f(s.Fields)
// sanity checks
if len(offsets) != len(s.Fields) {
panic("Context.Offsetsof returned the wrong number of offsets")
}
for _, o := range offsets {
if o < 0 {
panic("Context.Offsetsof returned an offset < 0")
}
}
} else {
offsets = DefaultOffsetsof(s.Fields)
}
s.offsets = offsets
}
return offsets
}
// offsetof returns the offset of the field specified via
// the index sequence relative to typ. It returns a value
// < 0 if the field is in an embedded pointer type.
func (ctxt *Context) offsetof(typ Type, index []int) int64 {
var o int64
for _, i := range index {
s, _ := underlying(typ).(*Struct)
if s == nil {
return -1
}
o += ctxt.offsetsof(s)[i]
typ = s.Fields[i].Type
}
return o
}
func (ctxt *Context) sizeof(typ Type) int64 {
if f := ctxt.Sizeof; f != nil {
if s := f(typ); s >= 0 {
return s
}
panic("Context.Sizeof returned a size < 0")
}
return DefaultSizeof(typ)
}
// DefaultMaxAlign is the default maximum alignment, in bytes,
// used by DefaultAlignof.
const DefaultMaxAlign = 8
// DefaultAlignof implements the default alignment computation
// for unsafe.Alignof. It is used if Context.Alignof == nil.
func DefaultAlignof(typ Type) int64 {
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
switch t := underlying(typ).(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 DefaultAlignof(t.Elt)
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 := DefaultAlignof(f.Type); a > max {
max = a
}
}
return max
}
a := DefaultSizeof(typ) // 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 > DefaultMaxAlign {
return DefaultMaxAlign
}
return a
}
// 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
}
// DefaultOffsetsof implements the default field offset computation
// for unsafe.Offsetof. It is used if Context.Offsetsof == nil.
func DefaultOffsetsof(fields []*Field) []int64 {
offsets := make([]int64, len(fields))
var o int64
for i, f := range fields {
a := DefaultAlignof(f.Type)
o = align(o, a)
offsets[i] = o
o += DefaultSizeof(f.Type)
}
return offsets
}
// DefaultPtrSize is the default size of ints, uint, and pointers, in bytes,
// used by DefaultSizeof.
const DefaultPtrSize = 8
// DefaultSizeof implements the default size computation
// for unsafe.Sizeof. It is used if Context.Sizeof == nil.
func DefaultSizeof(typ Type) int64 {
switch t := underlying(typ).(type) {
case *Basic:
if s := t.size; s > 0 {
return s
}
if t.Kind == String {
return DefaultPtrSize * 2
}
case *Array:
a := DefaultAlignof(t.Elt)
s := DefaultSizeof(t.Elt)
return align(s, a) * t.Len // may be 0
case *Slice:
return DefaultPtrSize * 3
case *Struct:
n := len(t.Fields)
if n == 0 {
return 0
}
offsets := t.offsets
if t.offsets == nil {
// compute offsets on demand
offsets = DefaultOffsetsof(t.Fields)
t.offsets = offsets
}
return offsets[n-1] + DefaultSizeof(t.Fields[n-1].Type)
case *Signature:
return DefaultPtrSize * 2
}
return DefaultPtrSize // catch-all
}
// 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.
package types
import (
"flag"
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/scanner"
"go/token"
"io/ioutil"
"path/filepath"
"runtime"
"testing"
"time"
)
var verbose = flag.Bool("types.v", false, "verbose mode")
var (
pkgCount int // number of packages processed
start = time.Now()
)
func TestStdlib(t *testing.T) {
walkDirs(t, filepath.Join(runtime.GOROOT(), "src/pkg"))
if *verbose {
fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
}
}
// Package paths of excluded packages.
var excluded = map[string]bool{
"builtin": true,
}
// typecheck typechecks the given package files.
func typecheck(t *testing.T, filenames []string) {
fset := token.NewFileSet()
// parse package files
var files []*ast.File
for _, filename := range filenames {
file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors|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 *verbose {
if len(files) == 0 {
fmt.Println("package", file.Name.Name)
}
fmt.Println("\t", filename)
}
files = append(files, file)
}
// typecheck package files
ctxt := Context{
Error: func(err error) { t.Error(err) },
}
ctxt.Check(fset, files)
pkgCount++
}
// pkgfiles returns the list of package files for the given directory.
func pkgfiles(t *testing.T, dir string) []string {
ctxt := build.Default
ctxt.CgoEnabled = false
pkg, err := ctxt.ImportDir(dir, 0)
if err != nil {
if _, nogo := err.(*build.NoGoError); !nogo {
t.Error(err)
}
return nil
}
if excluded[pkg.ImportPath] {
return 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
}
// 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
if files := pkgfiles(t, dir); files != nil {
typecheck(t, 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()))
}
}
}
// 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 (
"go/ast"
"go/token"
)
// assigment reports whether x can be assigned to a variable of type 'to',
// 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.
// TODO(gri) This latter behavior is for historic reasons and complicates
// callers. Needs to be cleaned up.
func (check *checker) assignment(x *operand, to Type) bool {
if x.mode == invalid {
return false
}
if t, ok := x.typ.(*Result); ok {
// TODO(gri) elsewhere we use "assignment count mismatch" (consolidate)
check.errorf(x.pos(), "%d-valued expression %s used as single value", len(t.Values), x)
x.mode = invalid
return false
}
check.convertUntyped(x, to)
return x.mode != invalid && x.isAssignable(check.ctxt, to)
}
// assign1to1 typechecks a single assignment of the form lhs = rhs (if rhs != nil), or
// lhs = x (if rhs == nil). If decl is set, the lhs expression must be an identifier;
// if its type is not set, it is deduced from the type of x or set to Typ[Invalid] in
// case of an error.
//
func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota int) {
// Start with rhs so we have an expression type
// for declarations with implicit type.
if x == nil {
x = new(operand)
check.expr(x, rhs, nil, iota)
// don't exit for declarations - we need the lhs first
if x.mode == invalid && !decl {
return
}
}
// x.mode == valid || decl
// lhs may be an identifier
ident, _ := lhs.(*ast.Ident)
// regular assignment; we know x is valid
if !decl {
// anything can be assigned to the blank identifier
if ident != nil && ident.Name == "_" {
// the rhs has its final type
check.updateExprType(rhs, x.typ, true)
return
}
var z operand
check.expr(&z, lhs, nil, -1)
if z.mode == invalid {
return
}
// TODO(gri) verify that all other z.mode values
// that may appear here are legal
if z.mode == constant || !check.assignment(x, z.typ) {
if x.mode != invalid {
check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
}
}
return
}
// declaration with initialization; lhs must be an identifier
if ident == nil {
check.errorf(lhs.Pos(), "cannot declare %s", lhs)
return
}
// Determine typ of lhs: If the object doesn't have a type
// yet, determine it from the type of x; if x is invalid,
// set the object type to Typ[Invalid].
var typ Type
obj := check.lookup(ident)
switch obj := obj.(type) {
default:
unreachable()
case nil:
// TODO(gri) is this really unreachable?
unreachable()
case *Const:
typ = obj.Type // may already be Typ[Invalid]
if typ == nil {
typ = Typ[Invalid]
if x.mode != invalid {
typ = x.typ
}
obj.Type = typ
}
case *Var:
typ = obj.Type // may already be Typ[Invalid]
if typ == nil {
typ = Typ[Invalid]
if x.mode != invalid {
typ = x.typ
if isUntyped(typ) {
// convert untyped types to default types
if typ == Typ[UntypedNil] {
check.errorf(x.pos(), "use of untyped nil")
typ = Typ[Invalid]
} else {
typ = defaultType(typ)
}
}
}
obj.Type = typ
}
}
// nothing else to check if we don't have a valid lhs or rhs
if typ == Typ[Invalid] || x.mode == invalid {
return
}
if !check.assignment(x, typ) {
if x.mode != invalid {
if x.typ != Typ[Invalid] && typ != Typ[Invalid] {
check.errorf(x.pos(), "cannot initialize %s (type %s) with %s", ident.Name, typ, x)
}
}
return
}
// for constants, set their value
if obj, _ := obj.(*Const); obj != nil {
obj.Val = nil // failure case: we don't know the constant value
if x.mode == constant {
if isConstType(x.typ) {
obj.Val = x.val
} else if x.typ != Typ[Invalid] {
check.errorf(x.pos(), "%s has invalid constant type", x)
}
} else if x.mode != invalid {
check.errorf(x.pos(), "%s is not constant", x)
}
}
}
// assignNtoM typechecks a general assignment. If decl is set, the lhs expressions
// must be identifiers; if their types are not set, they are deduced from the types
// of the corresponding rhs expressions, or set to Typ[Invalid] in case of an error.
// Precondition: len(lhs) > 0 .
//
func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int) {
assert(len(lhs) > 0)
// If the lhs and rhs have corresponding expressions, treat each
// matching pair as an individual pair.
if len(lhs) == len(rhs) {
for i, e := range rhs {
check.assign1to1(lhs[i], e, nil, decl, iota)
}
return
}
// Otherwise, the rhs must be a single expression (possibly
// a function call returning multiple values, or a comma-ok
// expression).
if len(rhs) == 1 {
// len(lhs) > 1
// Start with rhs so we have expression types
// for declarations with implicit types.
var x operand
check.expr(&x, rhs[0], nil, iota)
if x.mode == invalid {
goto Error
}
if t, _ := x.typ.(*Result); t != nil && len(lhs) == len(t.Values) {
// function result
x.mode = value
for i, obj := range t.Values {
x.expr = nil // TODO(gri) should do better here
x.typ = obj.Type
check.assign1to1(lhs[i], nil, &x, decl, iota)
}
return
}
if x.mode == valueok && len(lhs) == 2 {
// comma-ok expression
x.mode = value
check.assign1to1(lhs[0], nil, &x, decl, iota)
x.typ = Typ[UntypedBool]
check.assign1to1(lhs[1], nil, &x, decl, iota)
return
}
}
check.errorf(lhs[0].Pos(), "assignment count mismatch: %d = %d", len(lhs), len(rhs))
Error:
// In case of a declaration, set all lhs types to Typ[Invalid].
if decl {
for _, e := range lhs {
ident, _ := e.(*ast.Ident)
if ident == nil {
check.errorf(e.Pos(), "cannot declare %s", e)
continue
}
switch obj := check.lookup(ident).(type) {
case *Const:
obj.Type = Typ[Invalid]
case *Var:
obj.Type = Typ[Invalid]
default:
unreachable()
}
}
}
}
func (check *checker) optionalStmt(s ast.Stmt) {
if s != nil {
check.stmt(s)
}
}
func (check *checker) stmtList(list []ast.Stmt) {
for _, s := range list {
check.stmt(s)
}
}
func (check *checker) call(call *ast.CallExpr) {
var x operand
check.rawExpr(&x, call, nil, -1, false) // don't check if value is used
// TODO(gri) If a builtin is called, the builtin must be valid in statement context.
}
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
}
}
}
}
// stmt typechecks statement s.
func (check *checker) stmt(s ast.Stmt) {
switch s := s.(type) {
case *ast.BadStmt, *ast.EmptyStmt:
// ignore
case *ast.DeclStmt:
d, _ := s.Decl.(*ast.GenDecl)
if d == nil || (d.Tok != token.CONST && d.Tok != token.TYPE && d.Tok != token.VAR) {
check.invalidAST(token.NoPos, "const, type, or var declaration expected")
return
}
if d.Tok == token.CONST {
check.assocInitvals(d)
}
check.decl(d)
case *ast.LabeledStmt:
// TODO(gri) anything to do with label itself?
check.stmt(s.Stmt)
case *ast.ExprStmt:
var x operand
used := false
switch e := unparen(s.X).(type) {
case *ast.CallExpr:
// function calls are permitted
used = true
// but some builtins are excluded
// (Caution: This evaluates e.Fun twice, once here and once
// below as part of s.X. This has consequences for
// check.register. Perhaps this can be avoided.)
check.expr(&x, e.Fun, nil, -1)
if x.mode != invalid {
if b, ok := x.typ.(*builtin); ok && !b.isStatement {
used = false
}
}
case *ast.UnaryExpr:
// receive operations are permitted
if e.Op == token.ARROW {
used = true
}
}
if !used {
check.errorf(s.Pos(), "%s not used", s.X)
// ok to continue
}
check.rawExpr(&x, s.X, nil, -1, false)
if x.mode == typexpr {
check.errorf(x.pos(), "%s is not an expression", &x)
}
case *ast.SendStmt:
var ch, x operand
check.expr(&ch, s.Chan, nil, -1)
check.expr(&x, s.Value, nil, -1)
if ch.mode == invalid || x.mode == invalid {
return
}
if tch, ok := underlying(ch.typ).(*Chan); !ok || tch.Dir&ast.SEND == 0 || !check.assignment(&x, tch.Elt) {
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, -1)
if x.mode == invalid {
return
}
check.assign1to1(s.X, nil, &x, false, -1)
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
}
check.assignNtoM(s.Lhs, s.Rhs, s.Tok == token.DEFINE, -1)
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
}
// TODO(gri) make this conversion more efficient
var op token.Token
switch s.Tok {
case token.ADD_ASSIGN:
op = token.ADD
case token.SUB_ASSIGN:
op = token.SUB
case token.MUL_ASSIGN:
op = token.MUL
case token.QUO_ASSIGN:
op = token.QUO
case token.REM_ASSIGN:
op = token.REM
case token.AND_ASSIGN:
op = token.AND
case token.OR_ASSIGN:
op = token.OR
case token.XOR_ASSIGN:
op = token.XOR
case token.SHL_ASSIGN:
op = token.SHL
case token.SHR_ASSIGN:
op = token.SHR
case token.AND_NOT_ASSIGN:
op = token.AND_NOT
default:
check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
return
}
var x operand
check.binary(&x, s.Lhs[0], s.Rhs[0], op, -1)
if x.mode == invalid {
return
}
check.assign1to1(s.Lhs[0], nil, &x, false, -1)
}
case *ast.GoStmt:
check.call(s.Call)
case *ast.DeferStmt:
check.call(s.Call)
case *ast.ReturnStmt:
sig := check.funcsig
if n := len(sig.Results); n > 0 {
// TODO(gri) should not have to compute lhs, named every single time - clean this up
lhs := make([]ast.Expr, n)
named := false // if set, function has named results
for i, res := range sig.Results {
if len(res.Name) > 0 {
// a blank (_) result parameter is a named result
named = true
}
name := ast.NewIdent(res.Name)
name.NamePos = s.Pos()
check.register(name, &Var{Name: res.Name, Type: res.Type}) // Pkg == nil
lhs[i] = name
}
if len(s.Results) > 0 || !named {
// TODO(gri) assignNtoM should perhaps not require len(lhs) > 0
check.assignNtoM(lhs, s.Results, false, -1)
}
} else if len(s.Results) > 0 {
check.errorf(s.Pos(), "no result values expected")
}
case *ast.BranchStmt:
// TODO(gri) implement this
case *ast.BlockStmt:
check.stmtList(s.List)
case *ast.IfStmt:
check.optionalStmt(s.Init)
var x operand
check.expr(&x, s.Cond, nil, -1)
if x.mode != invalid && !isBoolean(x.typ) {
check.errorf(s.Cond.Pos(), "non-boolean condition in if statement")
}
check.stmt(s.Body)
check.optionalStmt(s.Else)
case *ast.SwitchStmt:
check.optionalStmt(s.Init)
var x operand
tag := s.Tag
if tag == nil {
// use fake true tag value and position it at the opening { of the switch
ident := &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
check.register(ident, Universe.Lookup("true"))
tag = ident
}
check.expr(&x, tag, nil, -1)
check.multipleDefaults(s.Body.List)
// TODO(gri) check also correct use of fallthrough
seen := make(map[interface{}]token.Pos)
for _, s := range s.Body.List {
clause, _ := s.(*ast.CaseClause)
if clause == nil {
continue // error reported before
}
if x.mode != invalid {
for _, expr := range clause.List {
x := x // copy of x (don't modify original)
var y operand
check.expr(&y, expr, nil, -1)
if y.mode == invalid {
continue // error reported before
}
// If we have a constant case value, it must appear only
// once in the switch statement. Determine if there is a
// duplicate entry, but only report an error if there are
// no other errors.
var dupl token.Pos
var yy operand
if y.mode == constant {
// TODO(gri) This code doesn't work correctly for
// large integer, floating point, or
// complex values - the respective struct
// comparisons are shallow. Need to use a
// hash function to index the map.
dupl = seen[y.val]
seen[y.val] = y.pos()
yy = y // remember y
}
// 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 {
continue // error reported before
}
check.convertUntyped(&x, y.typ)
if x.mode == invalid {
continue // error reported before
}
check.comparison(&y, &x, token.EQL)
if y.mode != invalid && dupl.IsValid() {
check.errorf(yy.pos(), "%s is duplicate case (previous at %s)",
&yy, check.fset.Position(dupl))
}
}
}
check.stmtList(clause.Body)
}
case *ast.TypeSwitchStmt:
check.optionalStmt(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 *Var // lhs variable 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
}
ident, _ := guard.Lhs[0].(*ast.Ident)
if ident == nil {
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
lhs = check.lookup(ident).(*Var)
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, nil, -1)
if x.mode == invalid {
return
}
var T *Interface
if T, _ = underlying(x.typ).(*Interface); T == nil {
check.errorf(x.pos(), "%s is not an interface", &x)
return
}
check.multipleDefaults(s.Body.List)
for _, s := range s.Body.List {
clause, _ := s.(*ast.CaseClause)
if clause == nil {
continue // error reported before
}
// Check each type in this type switch case.
var typ Type
for _, expr := range clause.List {
typ = check.typOrNil(expr, false)
if typ != nil && typ != Typ[Invalid] {
if method, wrongType := missingMethod(typ, T); method != nil {
var msg string
if wrongType {
msg = "%s cannot have dynamic type %s (wrong type for method %s)"
} else {
msg = "%s cannot have dynamic type %s (missing method %s)"
}
check.errorf(expr.Pos(), msg, &x, typ, method.Name)
// ok to continue
}
}
}
// If lhs exists, set its type for each clause.
if lhs != nil {
// 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 || typ == nil {
typ = x.typ
}
lhs.Type = typ
}
check.stmtList(clause.Body)
}
// There is only one object (lhs) associated with a lhs identifier, but that object
// assumes different types for different clauses. Set it back to the type of the
// TypeSwitchGuard expression so that that variable always has a valid type.
if lhs != nil {
lhs.Type = x.typ
}
case *ast.SelectStmt:
check.multipleDefaults(s.Body.List)
for _, s := range s.Body.List {
clause, _ := s.(*ast.CommClause)
if clause == nil {
continue // error reported before
}
check.optionalStmt(clause.Comm) // TODO(gri) check correctness of c.Comm (must be Send/RecvStmt)
check.stmtList(clause.Body)
}
case *ast.ForStmt:
check.optionalStmt(s.Init)
if s.Cond != nil {
var x operand
check.expr(&x, s.Cond, nil, -1)
if x.mode != invalid && !isBoolean(x.typ) {
check.errorf(s.Cond.Pos(), "non-boolean condition in for statement")
}
}
check.optionalStmt(s.Post)
check.stmt(s.Body)
case *ast.RangeStmt:
// check expression to iterate over
decl := s.Tok == token.DEFINE
var x operand
check.expr(&x, s.X, nil, -1)
if x.mode == invalid {
// if we don't have a declaration, we can still check the loop's body
if !decl {
check.stmt(s.Body)
}
return
}
// determine key/value types
var key, val Type
switch typ := underlying(x.typ).(type) {
case *Basic:
if isString(typ) {
key = Typ[UntypedInt]
val = Typ[UntypedRune]
}
case *Array:
key = Typ[UntypedInt]
val = typ.Elt
case *Slice:
key = Typ[UntypedInt]
val = typ.Elt
case *Pointer:
if typ, _ := underlying(typ.Base).(*Array); typ != nil {
key = Typ[UntypedInt]
val = typ.Elt
}
case *Map:
key = typ.Key
val = typ.Elt
case *Chan:
key = typ.Elt
if typ.Dir&ast.RECV == 0 {
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)
// if we don't have a declaration, we can still check the loop's body
if !decl {
check.stmt(s.Body)
}
return
}
// check assignment to/declaration of iteration variables
// TODO(gri) The error messages/positions are not great here,
// they refer to the expression in the range clause.
// Should give better messages w/o too much code
// duplication (assignment checking).
x.mode = value
if s.Key != nil {
x.typ = key
x.expr = s.Key
check.assign1to1(s.Key, nil, &x, decl, -1)
} else {
check.invalidAST(s.Pos(), "range clause requires index iteration variable")
// ok to continue
}
if s.Value != nil {
x.typ = val
x.expr = s.Value
check.assign1to1(s.Value, nil, &x, decl, -1)
}
check.stmt(s.Body)
default:
check.errorf(s.Pos(), "invalid statement")
}
}
// 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 _append() {
var x int
var s []byte
_0 := append /* ERROR "argument" */ ()
_1 := append("foo" /* ERROR "not a typed slice" */)
_2 := append(nil /* ERROR "not a typed slice" */, s)
_3 := append(x /* ERROR "not a typed slice" */, s)
_4 := append(s)
append /* ERROR "not used" */ (s)
}
func _cap() {
var a [10]bool
var p *[20]int
var s []int
var c chan string
_0 := cap /* ERROR "argument" */ ()
_1 := cap /* ERROR "argument" */ (1, 2)
_2 := cap(42 /* ERROR "invalid" */)
const _3 = cap(a)
assert(_3 == 10)
const _4 = cap(p)
assert(_4 == 20)
_5 := cap(c)
cap /* ERROR "not used" */ (c)
// issue 4744
type T struct{ a [10]int }
const _ = cap(((*T)(nil)).a)
}
func _close() {
var c chan int
var r <-chan int
close /* ERROR "argument" */ ()
close /* ERROR "argument" */ (1, 2)
close(42 /* ERROR "not a channel" */)
close(r /* ERROR "receive-only channel" */)
close(c)
}
func _complex() {
var i32 int32
var f32 float32
var f64 float64
var c64 complex64
var c128 complex128
_ = complex /* ERROR "argument" */ ()
_ = complex /* ERROR "argument" */ (1)
_ = 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)
}
func _copy() {
copy /* ERROR "not enough arguments" */ ()
copy /* ERROR "not enough arguments" */ ("foo")
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")
}
func _delete() {
var m map[string]int
var s string
delete /* ERROR "argument" */ ()
delete /* ERROR "argument" */ (1)
delete /* ERROR "argument" */ (1, 2, 3)
delete(m, 0 /* ERROR "not assignable" */)
delete(m, s)
}
func _imag() {
var f32 float32
var f64 float64
var c64 complex64
var c128 complex128
_ = imag /* ERROR "argument" */ ()
_ = imag /* ERROR "argument" */ (1, 2)
_ = 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)
}
func _len() {
const c = "foobar"
var a [10]bool
var p *[20]int
var s []int
var m map[string]complex128
_ = len /* ERROR "argument" */ ()
_ = len /* ERROR "argument" */ (1, 2)
_ = 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 /* ERROR "failed" */ (n == 10)
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)
}
func _make() {
var n int
var m float32
var s uint
_ = make /* ERROR "argument" */ ()
_ = 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 "overflows" */)
_ = 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" */ )
// 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)
// 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 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 "not used" */ ([]int, 10)
}
func _new() {
_ = new /* ERROR "argument" */ ()
_ = new /* ERROR "argument" */ (1, 2)
_ = new("foo" /* ERROR "not a type" */)
p := new(float64)
_ = new(struct{ x, y int })
q := new(*float64)
_ = *p == **q
new /* ERROR "not used" */ (int)
}
func _panic() {
panic /* ERROR "arguments" */ ()
panic /* ERROR "arguments" */ (1, 2)
panic(0)
panic("foo")
panic(false)
}
func _print() {
print()
print(1)
print(1, 2)
print("foo")
print(2.718281828)
print(false)
}
func _println() {
println()
println(1)
println(1, 2)
println("foo")
println(2.718281828)
println(false)
}
func _real() {
var f32 float32
var f64 float64
var c64 complex64
var c128 complex128
_ = real /* ERROR "argument" */ ()
_ = real /* ERROR "argument" */ (1, 2)
_ = 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)
}
func _recover() {
_ = recover()
_ = recover /* ERROR "argument" */ (10)
recover()
}
// 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
func _Alignof() {
var x int
_ = unsafe /* ERROR "argument" */ .Alignof()
_ = unsafe /* ERROR "argument" */ .Alignof(1, 2)
_ = unsafe.Alignof(int /* ERROR "not an expression" */)
_ = unsafe.Alignof(42)
_ = unsafe.Alignof(new(struct{}))
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)
}
func _Offsetof() {
var x struct{ f int }
_ = unsafe /* ERROR "argument" */ .Offsetof()
_ = unsafe /* ERROR "argument" */ .Offsetof(1, 2)
_ = unsafe.Offsetof(int /* ERROR "not a selector expression" */)
_ = unsafe.Offsetof(x /* 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 y2 S2
assert(unsafe.Offsetof(y2.S1) == 0)
_ = unsafe.Offsetof(y2 /* ERROR "embedded via a pointer" */ .x)
}
func _Sizeof() {
var x int
_ = unsafe /* ERROR "argument" */ .Sizeof()
_ = unsafe /* ERROR "argument" */ .Sizeof(1, 2)
_ = unsafe.Sizeof(int /* ERROR "not an expression" */)
_ = unsafe.Sizeof(42)
_ = unsafe.Sizeof(new(complex128))
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)
}
// self-testing only
func _assert() {
var x int
assert /* ERROR "argument" */ ()
assert /* ERROR "argument" */ (1, 2)
assert("foo" /* ERROR "boolean constant" */ )
assert(x /* ERROR "boolean constant" */)
assert(true)
assert /* ERROR "failed" */ (false)
}
// self-testing only
func _trace() {
// 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")
}
// 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" */
// 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
// 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 "cannot compare" */ == 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 "cycle" */ = a
b /* ERROR "cycle" */ , c /* ERROR "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
_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)
)
// special cases
const (
_n0 = nil /* ERROR "invalid constant type" */
_n1 = [ /* ERROR "not constant" */ ]int{}
)
\ No newline at end of file
// 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
// argument count
var (
_ = int /* ERROR "one argument" */ ()
_ = int /* ERROR "one argument" */ (1, 2)
)
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 /* ERROR "cannot convert" */ (true)
const _ = string /* ERROR "cannot convert" */ (1.2)
const _ = string /* ERROR "cannot convert" */ (nil)
}
//
var (
_ = int8(0)
)
\ No newline at end of file
// 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"
// we can have multiple blank imports (was bug)
_ "math"
_ "net/rpc"
// reflect defines a type "flag" which shows up in the gc export data
"reflect"
. "reflect"
)
// reflect.flag must not be visible in this package
type flag int
type _ reflect /* ERROR "cannot refer to unexported" */ .flag
// dot-imported exported objects may conflict with local objects
type Value /* ERROR "redeclared in this block by dot-import" */ struct{}
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" */ }
)
// 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 "invalid array length" */ ]string
)
type (
p1 pi /* ERROR "no single 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 {
U // anonymous field
// TODO(gri) recognize double-declaration below
// U /* 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 { /* ERROR "multiple methods named m1" */
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
}
// Use I09 (rather than I9) because it appears lexically before
// I10 so that we get the illegal cycle here rather then in the
// declaration of I10. If the implementation sorts by position
// rather than name, the error message will still be here.
I09 /* ERROR "illegal cycle" */ interface {
I10
}
I10 interface {
I11
}
I11 interface {
I09
}
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
)
// 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 "unexported" */ .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" */ ()
)
// 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 /* ERROR "assignment count mismatch" */ , ok2, ok3 = iface.(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 /* ERROR "assignment count mismatch" */ , m2b, m2c = 1, 2
m3a /* ERROR "assignment count mismatch" */ , m3b = 1, 2, 3
)
// 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 /* ERROR "cannot convert" */ }
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 }
// 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"
// T1 declared before its methods.
type T1 struct{
f int
}
func (T1) m() {}
func (T1) m /* ERROR "redeclared" */ () {}
func (x *T1) f /* ERROR "field and method" */ () {}
// 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 }
// TODO(gri) blank idents not fully checked - disabled for now
// func (_ /* ERROR "cannot use _" */) m() {}
// func (_ /* ERROR "cannot use _" */) m() {}
// 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 non-local or unnamed types.
func (int /* ERROR "non-local type" */ ) m() {}
func ([ /* ERROR "expected" */ ]int) m() {}
func (time /* ERROR "expected" */ .Time) m() {}
func (x interface /* ERROR "expected" */ {}) m() {}
// 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
const pi = 3.1415
func (T1) m /* ERROR "redeclared" */ () {}
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()
}
\ No newline at end of file
// 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
// 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 "no single field or method" */ .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 "no single field or method" */ .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 "no single field or method" */ .X
}
// 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
}
// 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 single field or method" */ {}{}.Foo
_ = S0{}.A
_ = S0 /* ERROR "no single field or method" */ {}.D
_ = S1{}.A
_ = S1{}.B
_ = S1{}.S0
_ = S1{}.C
_ = S2{}.A
_ = S2{}.S1
_ = S2{}.B
_ = S2{}.C
_ = S2 /* ERROR "no single field or method" */ {}.D
_ = S3 /* ERROR "no single field or method" */ {}.S1
_ = S3{}.A
_ = S3 /* ERROR "no single field or method" */ {}.B
_ = S3{}.D
_ = S3{}.E
_ = S4{}.A
_ = S4 /* ERROR "no single field or method" */ {}.B
_ = S5 /* ERROR "no single field or method" */ {}.X
_ = S5{}.Y
_ = S10 /* ERROR "no single field or method" */ {}.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 "no single field or method" */ {}.X
\ No newline at end of file
// 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()
// 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
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" */
// 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 /* ERROR not defined */
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 /* ERROR not defined */
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 /* ERROR "cannot indirect" */
s6 = &s4
s7 = *s6
s8 = <-s7 /* ERROR "cannot receive" */
// 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" */
)
// 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
)
// 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
// 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
_ = struct{b bool}{x < y}
}
// corner cases
var (
v0 = nil /* ERROR "cannot compare" */ == nil
)
\ No newline at end of file
// 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
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 "overflows" */ ]
_ = a[1.0]
_ = a[- /* ERROR "negative" */ 1]
_ = a[- /* ERROR "negative" */ 1 :]
_ = a[: - /* ERROR "negative" */ 1]
var a0 int
a0 = a[0]
var a1 int32
a1 = a /* ERROR "cannot assign" */ [1]
_ = 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]
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]
var b [0]int
_ = b[0 /* ERROR "index .* out of bounds" */ ]
_ = b[:]
_ = b[0:]
_ = b[:0]
_ = b[0:0]
var s []int
_ = s[- /* ERROR "negative" */ 1]
_ = s[- /* ERROR "negative" */ 1 :]
_ = s[: - /* ERROR "negative" */ 1]
_ = s[0]
_ = s[1 : 2]
_ = s[2 /* ERROR "inverted slice range" */ : 1]
_ = s[2 :]
_ = s[: 1 /* ERROR "overflows" */ <<100]
_ = s[1 /* ERROR "overflows" */ <<100 :]
_ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
var t string
_ = t[- /* ERROR "negative" */ 1]
_ = t[- /* ERROR "negative" */ 1 :]
_ = t[: - /* ERROR "negative" */ 1]
var t0 byte
t0 = t[0]
var t1 rune
t1 = t /* ERROR "cannot assign" */ [2]
_ = ("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]
var c2 float32
c2 = c /* ERROR "cannot assign" */ [2]
_ = c[3 /* ERROR "index .* out of bounds" */ ]
_ = ""[0 /* ERROR "index .* out of bounds" */ ]
_ = 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]
}
type T struct {
x int
}
func (*T) m() {}
func method_expressions() {
_ = T /* ERROR "no single field or method" */ .a
_ = T /* ERROR "has no method" */ .x
_ = T.m
var f func(*T) = (*T).m
var g func(*T) = ( /* ERROR "cannot initialize" */ T).m
}
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" */ }}
_ = 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 "overflows" */}
}
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 "overflows" */ }
_ = A1{"foo" /* ERROR "cannot convert" */ }
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" */
a2 := [...]int{- /* ERROR "negative" */ 1: 0}
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)
// 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 "overflows" */ }
_ = S0{"foo" /* ERROR "cannot convert" */ }
// indices must be resolved correctly
// (for details, see comment in go/parser/parser.go, method parseElement)
index1 := 1
_ = S0{index1: 1}
_ = S0{index2: 2}
_ = S0{index3 /* ERROR "undeclared name" */ : 3}
}
var index2 int = 2
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 keys must be resolved correctly
// (for details, see comment in go/parser/parser.go, method parseElement)
key1 := "foo"
_ = M0{key1: 1}
_ = M0{key2: 2}
_ = M0{key3 /* ERROR "undeclared name" */ : 2}
_ = M1{true: 1, false: 0}
_ = M2{nil: 0, &index2: 1}
}
var key2 string = "bar"
type I interface {
m()
}
type I2 interface {
m(int)
}
type T1 struct{}
type T2 struct{}
func (T2) m(int) {}
func type_asserts() {
var x int
_ = x /* ERROR "not an interface" */ .(int)
var e interface{}
var ok bool
x, ok = e.(int)
var t I
_ = t /* ERROR "use of .* outside type switch" */ .(type)
_ = t.(T)
_ = t.(T1 /* ERROR "missing method m" */ )
_ = t.(T2 /* ERROR "wrong type for method m" */ )
_ = t.(I2 /* ERROR "wrong type for method m" */ )
}
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 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 /* ERROR "too few arguments" */ (3.14)
f2(3.14, "foo")
f2(x /* ERROR "cannot pass" */ , "foo")
f2(g0 /* ERROR "used as value" */ ())
f2 /* ERROR "too few arguments" */ (g1 /* ERROR "cannot pass" */ ())
f2(g2())
fs /* ERROR "too few arguments" */ ()
fs(g0 /* ERROR "used as value" */ ())
fs(g1 /* ERROR "cannot pass" */ ())
// fs(g2()) // TODO(gri) missing position in error message
fs(gs())
fv()
fv(1, 2.0, x)
fv(s /* ERROR "cannot pass" */ )
fv(s...)
fv(1, s /* ERROR "can only use ... with matching parameter" */ ...)
fv(gs /* ERROR "cannot pass" */ ())
fv(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" */ ())
}
// 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 shifts1() {
// basics
var (
i0 int
u0 uint
v0 = 1<<0
v1 = 1<<i0 /* ERROR "must be unsigned" */
v2 = 1<<u0
v3 = 1<<"foo" /* ERROR "cannot convert" */
v4 = 1<<- /* ERROR "stupid shift" */ 1
v5 = 1<<1025 /* ERROR "stupid shift" */
v6 = 1 /* ERROR "overflows" */ <<100
v10 uint = 1 << 0
v11 uint = 1 << u0
v12 float32 = 1 /* ERROR "must be integer" */ << u0
)
}
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
// Disabled test below. gc and gccgo disagree: gc permits it per spec special case,
// gccgo does not (issue 4881). The spec special case seems not justified (issue 4883),
// and go/types agrees with gccgo.
// n = 1.0<<s != 0 // 1.0 has type int; n == false if ints are 32bits in size
n = 1.0 /* ERROR "must be integer" */ <<s != 0
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
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
)
}
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)
}
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 "integer" */ <<s)
_ = float32(1)
_ = float32(1<<s)
_ = float32(1.0)
_ = float32(1.0 /* ERROR "int" */ <<s)
_ = float32(1.1 /* ERROR "int" */ <<s)
var b []int
_ = append(b, 1<<s)
_ = append(b, 1.0<<s)
_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
var c []float32
_ = 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
_ = 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() {
// various originally failing snippets of code from the std library
// from src/pkg/compress/lzw/reader.go:90
{
var d struct {
bits uint32
width uint
}
_ = uint16(d.bits & (1<<d.width - 1))
}
// from src/pkg/debug/dwarf/buf.go:116
{
var ux uint64
var bits uint
x := int64(ux)
if x&(1<<(bits-1)) != 0 {}
}
// from src/pkg/encoding/asn1/asn1.go:160
{
var bytes []byte
if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
}
// from src/pkg/math/big/rat.go:140
{
var exp int
var mantissa uint64
shift := uint64(-1022 - (exp - 1)) // [1..53)
_ = mantissa & (1<<shift - 1)
}
// from src/pkg/net/interface.go:51
{
type Flags uint
var f Flags
var i int
if f&(1<<uint(i)) != 0 {}
}
// from src/pkg/runtime/softfloat64.go:234
{
var gm uint64
var shift uint
_ = gm & (1<<shift - 1)
}
// from src/pkg/strconv/atof.go:326
{
var mant uint64
var mantbits uint
if mant == 2<<mantbits {}
}
// from src/pkg/syscall/route_bsd.go:82
{
var Addrs int32
const rtaRtMask = 1
var i uint
if Addrs&rtaRtMask&(1<<i) == 0 {}
}
// from src/pkg/text/scanner/scanner.go:540
{
var s struct { Whitespace uint64 }
var ch rune
for s.Whitespace&(1<<uint(ch)) != 0 {}
}
}
// 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 _() {
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 /* ERROR "mismatch" */, v1, v2 := 1, 2, 3, 4
b = true
i += 1
i += "foo" /* ERROR "cannot convert.*int" */
f -= 1
f -= "foo" /* ERROR "cannot convert.*float64" */
c *= 1
c /= 0 /* ERROR "division by zero" */
s += "bar"
s += 1 /* ERROR "cannot convert.*string" */
var u64 uint64
u64 += 1<<u64
undeclared /* ERROR "undeclared" */ = 991
}
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
x int
)
select {
case <-ch:
ch <- x
case t, ok := <-ch:
x = t
case <-sc /* ERROR "cannot receive from send-only channel" */ :
}
select {
default:
default /* ERROR "multiple defaults" */ :
}
}
func gos() {
go 1 /* ERROR "expected function/method call" */
go gos()
var c chan int
go close(c)
go len(c) // TODO(gri) this should not be legal
}
func defers() {
defer 1 /* ERROR "expected function/method call" */
defer defers()
var c chan int
defer close(c)
defer len(c) // TODO(gri) this should not be legal
}
func switches() {
var x int
switch x {
default:
default /* ERROR "multiple defaults" */ :
}
switch {
case 1 /* 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 /* ERROR "duplicate case" */ :
case 2, 3, 4:
case 1 /* ERROR "duplicate case" */ :
}
// TODO(gri) duplicate 64bit values that don't fit into an int64 are not yet detected
switch uint64(x) {
case 1<<64-1:
case 1<<64-1:
}
}
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 := x.(type) {}
switch x := x.(type) {
case int:
var y int = x
}
switch x := i /* ERROR "not an interface" */ .(type) {}
switch t := x.(type) {
case nil:
var v bool = t /* ERROR "cannot initialize" */
case int:
var v int = t
case float32, complex64:
var v float32 = t /* ERROR "cannot initialize" */
default:
var v float32 = t /* ERROR "cannot initialize" */
}
var t I
switch t.(type) {
case T:
case T1 /* ERROR "missing method m" */ :
case T2 /* ERROR "wrong type for method m" */ :
case I2 /* ERROR "wrong type for method m" */ :
}
}
func typeswitch0() {
switch y := interface{}(nil).(type) {
case int:
// TODO(gri) y has the wrong type here (type-checking
// of captured variable is delayed)
// func() int { return y + 0 }()
}
}
func rangeloops() {
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 i := range x /* ERROR "cannot range over" */ {}
for i := range a {
var ii int
ii = i
}
for i, x := range a {
var ii int
ii = i
var xx float64
xx = x /* ERROR "cannot assign" */
}
var ii int
var xx float32
for ii, xx := range a {}
for i := range b {
var ii int
ii = i
}
for i, x := range b {
var ii int
ii = i
var xx string
xx = x
}
for i := range s {
var ii int
ii = i
}
for i, x := range s {
var ii int
ii = i
var xx rune
xx = x
}
for _, x := range p {
var xx complex128
xx = x
}
for _, x := range pp /* ERROR "cannot range over" */ {}
for k := range m {
var kk int32
kk = k /* ERROR "cannot assign" */
}
for k, v := range m {
var kk int
kk = k
if v {}
}
for _, _ /* ERROR "only one iteration variable" */ = range c {}
for e := range c {
var ee int
ee = e
}
for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
for _ = range rc {}
// constant strings
const cs = "foo"
for i, x := range cs {}
for i, x := range "" {
var ii int
ii = i
var xx rune
xx = x
}
}
// 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) }
// 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" */
// 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 "go/ast"
// All types implement the Type interface.
type Type interface {
String() string
aType()
}
// 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
size int64 // use DefaultSizeof to get size
Name string
}
// An Array represents an array type [Len]Elt.
type Array struct {
Len int64
Elt Type
}
// A Slice represents a slice type []Elt.
type Slice struct {
Elt Type
}
// A QualifiedName is a name qualified with the package that declared the name.
// Note: Pkg may be a fake package (no name, no scope) because the GC compiler's
// export information doesn't provide full information in some cases.
// TODO(gri): Should change Pkg to PkgPath since it's the only thing we care about.
type QualifiedName struct {
Pkg *Package // nil only for predeclared error.Error (exported)
Name string // unqualified type name for anonymous fields
}
// IsSame reports whether p and q are the same.
func (p QualifiedName) IsSame(q QualifiedName) 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 p.Name != q.Name {
return false
}
// p.Name == q.Name
return ast.IsExported(p.Name) || p.Pkg.Path == q.Pkg.Path
}
// A Field represents a field of a struct.
type Field struct {
QualifiedName
Type Type
Tag string
IsAnonymous bool
}
// A Struct represents a struct type struct{...}.
type Struct struct {
Fields []*Field
offsets []int64 // field offsets in bytes, lazily computed
}
func (typ *Struct) fieldIndex(name QualifiedName) int {
for i, f := range typ.Fields {
if f.QualifiedName.IsSame(name) {
return i
}
}
return -1
}
// A Pointer represents a pointer type *Base.
type Pointer struct {
Base Type
}
// A Result represents a (multi-value) function call result.
type Result struct {
Values []*Var // Signature.Results of the function called
}
// A Signature represents a user-defined function type func(...) (...).
type Signature struct {
Recv *Var // nil if not a method
Params []*Var // (incoming) parameters from left to right; or nil
Results []*Var // (outgoing) results from left to right; or nil
IsVariadic bool // true if the last parameter's type is of the form ...T
}
// builtinId is an id of a builtin function.
type builtinId int
// Predeclared builtin functions.
const (
// Universe scope
_Append builtinId = iota
_Cap
_Close
_Complex
_Copy
_Delete
_Imag
_Len
_Make
_New
_Panic
_Print
_Println
_Real
_Recover
// Unsafe package
_Alignof
_Offsetof
_Sizeof
// Testing support
_Assert
_Trace
)
// A builtin represents the type of a built-in function.
type builtin struct {
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
}
// A Method represents a method.
type Method struct {
QualifiedName
Type *Signature
}
// An Interface represents an interface type interface{...}.
type Interface struct {
Methods []*Method // TODO(gri) consider keeping them in sorted order
}
// A Map represents a map type map[Key]Elt.
type Map struct {
Key, Elt Type
}
// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
type Chan struct {
Dir ast.ChanDir
Elt Type
}
// A NamedType represents a named type as declared in a type declaration.
type NamedType struct {
Obj *TypeName // corresponding declared object
Underlying Type // nil if not fully declared yet; never a *NamedType
Methods []*Method // TODO(gri) consider keeping them in sorted order
}
func (*Basic) aType() {}
func (*Array) aType() {}
func (*Slice) aType() {}
func (*Struct) aType() {}
func (*Pointer) aType() {}
func (*Result) aType() {}
func (*Signature) aType() {}
func (*builtin) aType() {}
func (*Interface) aType() {}
func (*Map) aType() {}
func (*Chan) aType() {}
func (*NamedType) aType() {}
// 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 tests verifying the types associated with an AST after
// type checking.
package types
import (
"go/ast"
"go/parser"
"testing"
)
const filename = "<src>"
func makePkg(t *testing.T, src string) (*Package, error) {
file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
if err != nil {
return nil, err
}
pkg, err := Check(fset, []*ast.File{file})
return pkg, err
}
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}
}
var testTypes = []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 []T
}`, `struct{string; elems []T}`},
// 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{m(int) float32; String() string}`),
// TODO(gri) add test for interface w/ anonymous field
// maps
dup("map[string]int"),
{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
// channels
dup("chan int"),
dup("chan<- func()"),
dup("<-chan []func() int"),
}
func TestTypes(t *testing.T) {
for _, test := range testTypes {
src := "package p; type T " + test.src
pkg, err := makePkg(t, src)
if err != nil {
t.Errorf("%s: %s", src, err)
continue
}
typ := underlying(pkg.Scope.Lookup("T").GetType())
str := typeString(typ)
if str != test.str {
t.Errorf("%s: got %s, want %s", test.src, str, test.str)
}
}
}
var testExprs = []testEntry{
// basic type literals
dup("x"),
dup("true"),
dup("42"),
dup("3.1415"),
dup("2.71828i"),
dup(`'a'`),
dup(`"foo"`),
dup("`bar`"),
// arbitrary expressions
dup("&x"),
dup("*&x"),
dup("(x)"),
dup("x + y"),
dup("x + y * 10"),
dup("t.foo"),
dup("s[0]"),
dup("s[x:y]"),
dup("s[:y]"),
dup("s[x:]"),
dup("s[:]"),
dup("f(1, 2.3)"),
dup("-f(10, 20)"),
dup("f(x + y, +3.1415)"),
{"func(a, b int) {}", "(func literal)"},
{"func(a, b int) []int {}(1, 2)[x]", "(func literal)(1, 2)[x]"},
{"[]int{1, 2, 3}", "(composite literal)"},
{"[]int{1, 2, 3}[x:]", "(composite literal)[x:]"},
{"i.([]string)", "i.(...)"},
}
func TestExprs(t *testing.T) {
for _, test := range testExprs {
src := "package p; var _ = " + test.src + "; var (x, y int; s []string; f func(int, float32) int; i interface{}; t interface { foo() })"
file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
if err != nil {
t.Errorf("%s: %s", src, err)
continue
}
// TODO(gri) writing the code below w/o the decl variable will
// cause a 386 compiler error (out of fixed registers)
decl := file.Decls[0].(*ast.GenDecl)
expr := decl.Specs[0].(*ast.ValueSpec).Values[0]
str := exprString(expr)
if str != test.str {
t.Errorf("%s: got %s, want %s", test.src, str, test.str)
}
}
}
// 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/ast"
"strings"
)
var (
Universe *Scope
Unsafe *Package
universeIota *Const
)
// Predeclared types, indexed by BasicKind.
var Typ = [...]*Basic{
Invalid: {Invalid, 0, 0, "invalid type"},
Bool: {Bool, IsBoolean, 1, "bool"},
Int: {Int, IsInteger, 0, "int"},
Int8: {Int8, IsInteger, 1, "int8"},
Int16: {Int16, IsInteger, 2, "int16"},
Int32: {Int32, IsInteger, 4, "int32"},
Int64: {Int64, IsInteger, 8, "int64"},
Uint: {Uint, IsInteger | IsUnsigned, 0, "uint"},
Uint8: {Uint8, IsInteger | IsUnsigned, 1, "uint8"},
Uint16: {Uint16, IsInteger | IsUnsigned, 2, "uint16"},
Uint32: {Uint32, IsInteger | IsUnsigned, 4, "uint32"},
Uint64: {Uint64, IsInteger | IsUnsigned, 8, "uint64"},
Uintptr: {Uintptr, IsInteger | IsUnsigned, 0, "uintptr"},
Float32: {Float32, IsFloat, 4, "float32"},
Float64: {Float64, IsFloat, 8, "float64"},
Complex64: {Complex64, IsComplex, 8, "complex64"},
Complex128: {Complex128, IsComplex, 16, "complex128"},
String: {String, IsString, 0, "string"},
UnsafePointer: {UnsafePointer, 0, 0, "Pointer"},
UntypedBool: {UntypedBool, IsBoolean | IsUntyped, 0, "untyped boolean"},
UntypedInt: {UntypedInt, IsInteger | IsUntyped, 0, "untyped integer"},
UntypedRune: {UntypedRune, IsInteger | IsUntyped, 0, "untyped rune"},
UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, 0, "untyped float"},
UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, 0, "untyped complex"},
UntypedString: {UntypedString, IsString | IsUntyped, 0, "untyped string"},
UntypedNil: {UntypedNil, IsUntyped, 0, "untyped nil"},
}
var aliases = [...]*Basic{
{Byte, IsInteger | IsUnsigned, 1, "byte"},
{Rune, IsInteger, 4, "rune"},
}
var predeclaredConstants = [...]*Const{
{Name: "true", Type: Typ[UntypedBool], Val: true},
{Name: "false", Type: Typ[UntypedBool], Val: false},
{Name: "iota", Type: Typ[UntypedInt], Val: zeroConst},
{Name: "nil", Type: Typ[UntypedNil], Val: nilConst},
}
var predeclaredFunctions = [...]*builtin{
{_Append, "append", 1, true, false},
{_Cap, "cap", 1, false, false},
{_Close, "close", 1, false, true},
{_Complex, "complex", 2, false, false},
{_Copy, "copy", 2, false, true},
{_Delete, "delete", 2, false, true},
{_Imag, "imag", 1, false, false},
{_Len, "len", 1, false, false},
{_Make, "make", 1, true, false},
{_New, "new", 1, false, false},
{_Panic, "panic", 1, false, true},
{_Print, "print", 0, true, true},
{_Println, "println", 0, true, true},
{_Real, "real", 1, false, false},
{_Recover, "recover", 0, false, true},
{_Alignof, "Alignof", 1, false, false},
{_Offsetof, "Offsetof", 1, false, false},
{_Sizeof, "Sizeof", 1, false, false},
}
func init() {
Universe = new(Scope)
Unsafe = &Package{Name: "unsafe", Scope: new(Scope)}
// predeclared types
for _, t := range Typ {
def(&TypeName{Name: t.Name, Type: t})
}
for _, t := range aliases {
def(&TypeName{Name: t.Name, Type: t})
}
// error type
{
// Error has a nil package in its qualified name since it is in no package
err := &Method{QualifiedName{nil, "Error"}, &Signature{Results: []*Var{{Name: "", Type: Typ[String]}}}}
def(&TypeName{Name: "error", Type: &NamedType{Underlying: &Interface{Methods: []*Method{err}}}})
}
for _, c := range predeclaredConstants {
def(c)
}
for _, f := range predeclaredFunctions {
def(&Func{Name: f.name, Type: f})
}
universeIota = Universe.Lookup("iota").(*Const)
}
// 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.GetName()
if strings.Index(name, " ") >= 0 {
return // nothing to do
}
// fix Obj link for named types
if typ, ok := obj.GetType().(*NamedType); ok {
typ.Obj = obj.(*TypeName)
}
// exported identifiers go into package unsafe
scope := Universe
if ast.IsExported(name) {
scope = Unsafe.Scope
// set Pkg field
switch obj := obj.(type) {
case *TypeName:
obj.Pkg = Unsafe
case *Func:
obj.Pkg = Unsafe
default:
unreachable()
}
}
if scope.Insert(obj) != nil {
panic("internal error: double declaration")
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment