summaryrefslogtreecommitdiff
path: root/libgo/go/exp/eval/typec.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/exp/eval/typec.go')
-rw-r--r--libgo/go/exp/eval/typec.go409
1 files changed, 409 insertions, 0 deletions
diff --git a/libgo/go/exp/eval/typec.go b/libgo/go/exp/eval/typec.go
new file mode 100644
index 000000000..de90cf664
--- /dev/null
+++ b/libgo/go/exp/eval/typec.go
@@ -0,0 +1,409 @@
+// 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 initailizers 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
+}