| // 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 |
| } |