blob: 0ed24a8d27cd5051118e76085979b2ab849568f9 [file] [log] [blame]
// Copyright 2009 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 eval
import (
"go/ast"
"go/token"
"log"
)
/*
* Type compiler
*/
type typeCompiler struct {
*compiler
block *block
// Check to be performed after a type declaration is compiled.
//
// TODO(austin) This will probably have to change after we
// eliminate forward declarations.
lateCheck func() bool
}
func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
_, _, def := a.block.Lookup(x.Name)
if def == nil {
a.diagAt(x.Pos(), "%s: undefined", x.Name)
return nil
}
switch def := def.(type) {
case *Constant:
a.diagAt(x.Pos(), "constant %v used as type", x.Name)
return nil
case *Variable:
a.diagAt(x.Pos(), "variable %v used as type", x.Name)
return nil
case *NamedType:
if !allowRec && def.incomplete {
a.diagAt(x.Pos(), "illegal recursive type")
return nil
}
if !def.incomplete && def.Def == nil {
// Placeholder type from an earlier error
return nil
}
return def
case Type:
return def
}
log.Panicf("name %s has unknown type %T", x.Name, def)
return nil
}
func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
// Compile element type
elem := a.compileType(x.Elt, allowRec)
// Compile length expression
if x.Len == nil {
if elem == nil {
return nil
}
return NewSliceType(elem)
}
if _, ok := x.Len.(*ast.Ellipsis); ok {
a.diagAt(x.Len.Pos(), "... array initializers not implemented")
return nil
}
l, ok := a.compileArrayLen(a.block, x.Len)
if !ok {
return nil
}
if l < 0 {
a.diagAt(x.Len.Pos(), "array length must be non-negative")
return nil
}
if elem == nil {
return nil
}
return NewArrayType(l, elem)
}
func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Pos, bool) {
n := fields.NumFields()
ts := make([]Type, n)
ns := make([]*ast.Ident, n)
ps := make([]token.Pos, n)
bad := false
if fields != nil {
i := 0
for _, f := range fields.List {
t := a.compileType(f.Type, allowRec)
if t == nil {
bad = true
}
if f.Names == nil {
ns[i] = nil
ts[i] = t
ps[i] = f.Type.Pos()
i++
continue
}
for _, n := range f.Names {
ns[i] = n
ts[i] = t
ps[i] = n.Pos()
i++
}
}
}
return ts, ns, ps, bad
}
func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type {
ts, names, poss, bad := a.compileFields(x.Fields, allowRec)
// XXX(Spec) The spec claims that field identifiers must be
// unique, but 6g only checks this when they are accessed. I
// think the spec is better in this regard: if I write two
// fields with the same name in the same struct type, clearly
// that's a mistake. This definition does *not* descend into
// anonymous fields, so it doesn't matter if those change.
// There's separate language in the spec about checking
// uniqueness of field names inherited from anonymous fields
// at use time.
fields := make([]StructField, len(ts))
nameSet := make(map[string]token.Pos, len(ts))
for i := range fields {
// Compute field name and check anonymous fields
var name string
if names[i] != nil {
name = names[i].Name
} else {
if ts[i] == nil {
continue
}
var nt *NamedType
// [For anonymous fields,] the unqualified
// type name acts as the field identifier.
switch t := ts[i].(type) {
case *NamedType:
name = t.Name
nt = t
case *PtrType:
switch t := t.Elem.(type) {
case *NamedType:
name = t.Name
nt = t
}
}
// [An anonymous field] must be specified as a
// type name T or as a pointer to a type name
// *T, and T itself, may not be a pointer or
// interface type.
if nt == nil {
a.diagAt(poss[i], "embedded type must T or *T, where T is a named type")
bad = true
continue
}
// The check for embedded pointer types must
// be deferred because of things like
// type T *struct { T }
lateCheck := a.lateCheck
a.lateCheck = func() bool {
if _, ok := nt.lit().(*PtrType); ok {
a.diagAt(poss[i], "embedded type %v is a pointer type", nt)
return false
}
return lateCheck()
}
}
// Check name uniqueness
if prev, ok := nameSet[name]; ok {
a.diagAt(poss[i], "field %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
bad = true
continue
}
nameSet[name] = poss[i]
// Create field
fields[i].Name = name
fields[i].Type = ts[i]
fields[i].Anonymous = (names[i] == nil)
}
if bad {
return nil
}
return NewStructType(fields)
}
func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type {
elem := a.compileType(x.X, true)
if elem == nil {
return nil
}
return NewPtrType(elem)
}
func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl {
// TODO(austin) Variadic function types
// The types of parameters and results must be complete.
//
// TODO(austin) It's not clear they actually have to be complete.
in, inNames, _, inBad := a.compileFields(x.Params, allowRec)
out, outNames, _, outBad := a.compileFields(x.Results, allowRec)
if inBad || outBad {
return nil
}
return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames}
}
func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) *InterfaceType {
ts, names, poss, bad := a.compileFields(x.Methods, allowRec)
methods := make([]IMethod, len(ts))
nameSet := make(map[string]token.Pos, len(ts))
embeds := make([]*InterfaceType, len(ts))
var nm, ne int
for i := range ts {
if ts[i] == nil {
continue
}
if names[i] != nil {
name := names[i].Name
methods[nm].Name = name
methods[nm].Type = ts[i].(*FuncType)
nm++
if prev, ok := nameSet[name]; ok {
a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
bad = true
continue
}
nameSet[name] = poss[i]
} else {
// Embedded interface
it, ok := ts[i].lit().(*InterfaceType)
if !ok {
a.diagAt(poss[i], "embedded type must be an interface")
bad = true
continue
}
embeds[ne] = it
ne++
for _, m := range it.methods {
if prev, ok := nameSet[m.Name]; ok {
a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, a.fset.Position(prev))
bad = true
continue
}
nameSet[m.Name] = poss[i]
}
}
}
if bad {
return nil
}
methods = methods[0:nm]
embeds = embeds[0:ne]
return NewInterfaceType(methods, embeds)
}
func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
key := a.compileType(x.Key, true)
val := a.compileType(x.Value, true)
if key == nil || val == nil {
return nil
}
// XXX(Spec) The Map types section explicitly lists all types
// that can be map keys except for function types.
switch key.lit().(type) {
case *StructType:
a.diagAt(x.Pos(), "map key cannot be a struct type")
return nil
case *ArrayType:
a.diagAt(x.Pos(), "map key cannot be an array type")
return nil
case *SliceType:
a.diagAt(x.Pos(), "map key cannot be a slice type")
return nil
}
return NewMapType(key, val)
}
func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
switch x := x.(type) {
case *ast.BadExpr:
// Error already reported by parser
a.silentErrors++
return nil
case *ast.Ident:
return a.compileIdent(x, allowRec)
case *ast.ArrayType:
return a.compileArrayType(x, allowRec)
case *ast.StructType:
return a.compileStructType(x, allowRec)
case *ast.StarExpr:
return a.compilePtrType(x)
case *ast.FuncType:
fd := a.compileFuncType(x, allowRec)
if fd == nil {
return nil
}
return fd.Type
case *ast.InterfaceType:
return a.compileInterfaceType(x, allowRec)
case *ast.MapType:
return a.compileMapType(x)
case *ast.ChanType:
goto notimpl
case *ast.ParenExpr:
return a.compileType(x.X, allowRec)
case *ast.Ellipsis:
a.diagAt(x.Pos(), "illegal use of ellipsis")
return nil
}
a.diagAt(x.Pos(), "expression used as type")
return nil
notimpl:
a.diagAt(x.Pos(), "compileType: %T not implemented", x)
return nil
}
/*
* Type compiler interface
*/
func noLateCheck() bool { return true }
func (a *compiler) compileType(b *block, typ ast.Expr) Type {
tc := &typeCompiler{a, b, noLateCheck}
t := tc.compileType(typ, false)
if !tc.lateCheck() {
t = nil
}
return t
}
func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
ok := true
for _, spec := range decl.Specs {
spec := spec.(*ast.TypeSpec)
// Create incomplete type for this type
nt := b.DefineType(spec.Name.Name, spec.Name.Pos(), nil)
if nt != nil {
nt.(*NamedType).incomplete = true
}
// Compile type
tc := &typeCompiler{a, b, noLateCheck}
t := tc.compileType(spec.Type, false)
if t == nil {
// Create a placeholder type
ok = false
}
// Fill incomplete type
if nt != nil {
nt.(*NamedType).Complete(t)
}
// Perform late type checking with complete type
if !tc.lateCheck() {
ok = false
if nt != nil {
// Make the type a placeholder
nt.(*NamedType).Def = nil
}
}
}
return ok
}
func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
tc := &typeCompiler{a, b, noLateCheck}
res := tc.compileFuncType(typ, false)
if res != nil {
if !tc.lateCheck() {
res = nil
}
}
return res
}