diff options
Diffstat (limited to 'libgo/go/exp/eval/typec.go')
-rw-r--r-- | libgo/go/exp/eval/typec.go | 409 |
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 +} |