blob: 303ada4e57bd7df7112f1f4854a308ab56466adb [file] [log] [blame]
// 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 sets up the universe scope and the unsafe package.
package types
import (
"go/constant"
"go/token"
"strings"
)
// The Universe scope contains all predeclared objects of Go.
// It is the outermost scope of any chain of nested scopes.
var Universe *Scope
// The Unsafe package is the package returned by an importer
// for the import path "unsafe".
var Unsafe *Package
var (
universeIota Object
universeByte Type // uint8 alias, but has name "byte"
universeRune Type // int32 alias, but has name "rune"
universeAny Object
universeError Type
universeComparable Object
)
// Typ contains the predeclared *Basic types indexed by their
// corresponding BasicKind.
//
// The *Basic type for Typ[Byte] will have the name "uint8".
// Use Universe.Lookup("byte").Type() to obtain the specific
// alias basic type named "byte" (and analogous for "rune").
var Typ = []*Basic{
Invalid: {Invalid, 0, "invalid type"},
Bool: {Bool, IsBoolean, "bool"},
Int: {Int, IsInteger, "int"},
Int8: {Int8, IsInteger, "int8"},
Int16: {Int16, IsInteger, "int16"},
Int32: {Int32, IsInteger, "int32"},
Int64: {Int64, IsInteger, "int64"},
Uint: {Uint, IsInteger | IsUnsigned, "uint"},
Uint8: {Uint8, IsInteger | IsUnsigned, "uint8"},
Uint16: {Uint16, IsInteger | IsUnsigned, "uint16"},
Uint32: {Uint32, IsInteger | IsUnsigned, "uint32"},
Uint64: {Uint64, IsInteger | IsUnsigned, "uint64"},
Uintptr: {Uintptr, IsInteger | IsUnsigned, "uintptr"},
Float32: {Float32, IsFloat, "float32"},
Float64: {Float64, IsFloat, "float64"},
Complex64: {Complex64, IsComplex, "complex64"},
Complex128: {Complex128, IsComplex, "complex128"},
String: {String, IsString, "string"},
UnsafePointer: {UnsafePointer, 0, "Pointer"},
UntypedBool: {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
UntypedInt: {UntypedInt, IsInteger | IsUntyped, "untyped int"},
UntypedRune: {UntypedRune, IsInteger | IsUntyped, "untyped rune"},
UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, "untyped float"},
UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
UntypedString: {UntypedString, IsString | IsUntyped, "untyped string"},
UntypedNil: {UntypedNil, IsUntyped, "untyped nil"},
}
var aliases = [...]*Basic{
{Byte, IsInteger | IsUnsigned, "byte"},
{Rune, IsInteger, "rune"},
}
func defPredeclaredTypes() {
for _, t := range Typ {
def(NewTypeName(token.NoPos, nil, t.name, t))
}
for _, t := range aliases {
def(NewTypeName(token.NoPos, nil, t.name, t))
}
// type any = interface{}
// Note: don't use &emptyInterface for the type of any. Using a unique
// pointer allows us to detect any and format it as "any" rather than
// interface{}, which clarifies user-facing error messages significantly.
def(NewTypeName(token.NoPos, nil, "any", &Interface{complete: true, tset: &topTypeSet}))
// type error interface{ Error() string }
{
obj := NewTypeName(token.NoPos, nil, "error", nil)
obj.setColor(black)
typ := NewNamed(obj, nil, nil)
// error.Error() string
recv := NewVar(token.NoPos, nil, "", typ)
res := NewVar(token.NoPos, nil, "", Typ[String])
sig := NewSignatureType(recv, nil, nil, nil, NewTuple(res), false)
err := NewFunc(token.NoPos, nil, "Error", sig)
// interface{ Error() string }
ityp := &Interface{obj: obj, methods: []*Func{err}, complete: true}
computeInterfaceTypeSet(nil, token.NoPos, ityp) // prevent races due to lazy computation of tset
typ.SetUnderlying(ityp)
def(obj)
}
// type comparable interface{} // marked as comparable
{
obj := NewTypeName(token.NoPos, nil, "comparable", nil)
obj.setColor(black)
typ := NewNamed(obj, nil, nil)
// interface{} // marked as comparable
ityp := &Interface{obj: obj, complete: true, tset: &_TypeSet{nil, allTermlist, true}}
typ.SetUnderlying(ityp)
def(obj)
}
}
var predeclaredConsts = [...]struct {
name string
kind BasicKind
val constant.Value
}{
{"true", UntypedBool, constant.MakeBool(true)},
{"false", UntypedBool, constant.MakeBool(false)},
{"iota", UntypedInt, constant.MakeInt64(0)},
}
func defPredeclaredConsts() {
for _, c := range predeclaredConsts {
def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val))
}
}
func defPredeclaredNil() {
def(&Nil{object{name: "nil", typ: Typ[UntypedNil], color_: black}})
}
// A builtinId is the id of a builtin function.
type builtinId int
const (
// universe scope
_Append builtinId = iota
_Cap
_Close
_Complex
_Copy
_Delete
_Imag
_Len
_Make
_New
_Panic
_Print
_Println
_Real
_Recover
// package unsafe
_Add
_Alignof
_Offsetof
_Sizeof
_Slice
// testing support
_Assert
_Trace
)
var predeclaredFuncs = [...]struct {
name string
nargs int
variadic bool
kind exprKind
}{
_Append: {"append", 1, true, expression},
_Cap: {"cap", 1, false, expression},
_Close: {"close", 1, false, statement},
_Complex: {"complex", 2, false, expression},
_Copy: {"copy", 2, false, statement},
_Delete: {"delete", 2, false, statement},
_Imag: {"imag", 1, false, expression},
_Len: {"len", 1, false, expression},
_Make: {"make", 1, true, expression},
_New: {"new", 1, false, expression},
_Panic: {"panic", 1, false, statement},
_Print: {"print", 0, true, statement},
_Println: {"println", 0, true, statement},
_Real: {"real", 1, false, expression},
_Recover: {"recover", 0, false, statement},
_Add: {"Add", 2, false, expression},
_Alignof: {"Alignof", 1, false, expression},
_Offsetof: {"Offsetof", 1, false, expression},
_Sizeof: {"Sizeof", 1, false, expression},
_Slice: {"Slice", 2, false, expression},
_Assert: {"assert", 1, false, statement},
_Trace: {"trace", 0, true, statement},
}
func defPredeclaredFuncs() {
for i := range predeclaredFuncs {
id := builtinId(i)
if id == _Assert || id == _Trace {
continue // only define these in testing environment
}
def(newBuiltin(id))
}
}
// DefPredeclaredTestFuncs defines the assert and trace built-ins.
// These built-ins are intended for debugging and testing of this
// package only.
func DefPredeclaredTestFuncs() {
if Universe.Lookup("assert") != nil {
return // already defined
}
def(newBuiltin(_Assert))
def(newBuiltin(_Trace))
}
func init() {
Universe = NewScope(nil, token.NoPos, token.NoPos, "universe")
Unsafe = NewPackage("unsafe", "unsafe")
Unsafe.complete = true
defPredeclaredTypes()
defPredeclaredConsts()
defPredeclaredNil()
defPredeclaredFuncs()
universeIota = Universe.Lookup("iota")
universeByte = Universe.Lookup("byte").Type()
universeRune = Universe.Lookup("rune").Type()
universeAny = Universe.Lookup("any")
universeError = Universe.Lookup("error").Type()
universeComparable = Universe.Lookup("comparable")
}
// 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) {
assert(obj.color() == black)
name := obj.Name()
if strings.Contains(name, " ") {
return // nothing to do
}
// fix Obj link for named types
if typ, _ := obj.Type().(*Named); typ != nil {
typ.obj = obj.(*TypeName)
}
// exported identifiers go into package unsafe
scope := Universe
if obj.Exported() {
scope = Unsafe.scope
// set Pkg field
switch obj := obj.(type) {
case *TypeName:
obj.pkg = Unsafe
case *Builtin:
obj.pkg = Unsafe
default:
unreachable()
}
}
if scope.Insert(obj) != nil {
panic("double declaration of predeclared identifier")
}
}