From 80f18fc933cf3f3e829c5455a1023d69f7b86e52 Mon Sep 17 00:00:00 2001 From: Ondřej Surý Date: Tue, 13 Sep 2011 13:11:55 +0200 Subject: Imported Upstream version 60 --- src/pkg/go/types/check.go | 233 ---------------------------------------------- 1 file changed, 233 deletions(-) delete mode 100644 src/pkg/go/types/check.go (limited to 'src/pkg/go/types/check.go') diff --git a/src/pkg/go/types/check.go b/src/pkg/go/types/check.go deleted file mode 100644 index 02d662926..000000000 --- a/src/pkg/go/types/check.go +++ /dev/null @@ -1,233 +0,0 @@ -// 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 implements the Check function, which typechecks a package. - -package types - -import ( - "fmt" - "go/ast" - "go/scanner" - "go/token" - "os" - "strconv" -) - - -const debug = false - - -type checker struct { - fset *token.FileSet - scanner.ErrorVector - types map[ast.Expr]Type -} - - -func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string { - msg := fmt.Sprintf(format, args...) - c.Error(c.fset.Position(pos), msg) - return msg -} - - -// collectFields collects struct fields tok = token.STRUCT), interface methods -// (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC). -func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) { - if list != nil { - for _, field := range list.List { - ftype := field.Type - if t, ok := ftype.(*ast.Ellipsis); ok { - ftype = t.Elt - isVariadic = true - } - typ := c.makeType(ftype, cycleOk) - tag := "" - if field.Tag != nil { - assert(field.Tag.Kind == token.STRING) - tag, _ = strconv.Unquote(field.Tag.Value) - } - if len(field.Names) > 0 { - // named fields - for _, name := range field.Names { - obj := name.Obj - obj.Type = typ - fields = append(fields, obj) - if tok == token.STRUCT { - tags = append(tags, tag) - } - } - } else { - // anonymous field - switch tok { - case token.STRUCT: - tags = append(tags, tag) - fallthrough - case token.FUNC: - obj := ast.NewObj(ast.Var, "") - obj.Type = typ - fields = append(fields, obj) - case token.INTERFACE: - utyp := Underlying(typ) - if typ, ok := utyp.(*Interface); ok { - // TODO(gri) This is not good enough. Check for double declarations! - fields = append(fields, typ.Methods...) - } else if _, ok := utyp.(*Bad); !ok { - // if utyp is Bad, don't complain (the root cause was reported before) - c.errorf(ftype.Pos(), "interface contains embedded non-interface type") - } - default: - panic("unreachable") - } - } - } - } - return -} - - -// makeType makes a new type for an AST type specification x or returns -// the type referred to by a type name x. If cycleOk is set, a type may -// refer to itself directly or indirectly; otherwise cycles are errors. -// -func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) { - if debug { - fmt.Printf("makeType (cycleOk = %v)\n", cycleOk) - ast.Print(c.fset, x) - defer func() { - fmt.Printf("-> %T %v\n\n", typ, typ) - }() - } - - switch t := x.(type) { - case *ast.BadExpr: - return &Bad{} - - case *ast.Ident: - // type name - obj := t.Obj - if obj == nil { - // unresolved identifier (error has been reported before) - return &Bad{Msg: "unresolved identifier"} - } - if obj.Kind != ast.Typ { - msg := c.errorf(t.Pos(), "%s is not a type", t.Name) - return &Bad{Msg: msg} - } - c.checkObj(obj, cycleOk) - if !cycleOk && obj.Type.(*Name).Underlying == nil { - // TODO(gri) Enable this message again once its position - // is independent of the underlying map implementation. - // msg := c.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name) - msg := "illegal cycle" - return &Bad{Msg: msg} - } - return obj.Type.(Type) - - case *ast.ParenExpr: - return c.makeType(t.X, cycleOk) - - case *ast.SelectorExpr: - // qualified identifier - // TODO (gri) eventually, this code belongs to expression - // type checking - here for the time being - if ident, ok := t.X.(*ast.Ident); ok { - if obj := ident.Obj; obj != nil { - if obj.Kind != ast.Pkg { - msg := c.errorf(ident.Pos(), "%s is not a package", obj.Name) - return &Bad{Msg: msg} - } - // TODO(gri) we have a package name but don't - // have the mapping from package name to package - // scope anymore (created in ast.NewPackage). - return &Bad{} // for now - } - } - // TODO(gri) can this really happen (the parser should have excluded this)? - msg := c.errorf(t.Pos(), "expected qualified identifier") - return &Bad{Msg: msg} - - case *ast.StarExpr: - return &Pointer{Base: c.makeType(t.X, true)} - - case *ast.ArrayType: - if t.Len != nil { - // TODO(gri) compute length - return &Array{Elt: c.makeType(t.Elt, cycleOk)} - } - return &Slice{Elt: c.makeType(t.Elt, true)} - - case *ast.StructType: - fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk) - return &Struct{Fields: fields, Tags: tags} - - case *ast.FuncType: - params, _, _ := c.collectFields(token.FUNC, t.Params, true) - results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true) - return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic} - - case *ast.InterfaceType: - methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk) - methods.Sort() - return &Interface{Methods: methods} - - case *ast.MapType: - return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)} - - case *ast.ChanType: - return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)} - } - - panic(fmt.Sprintf("unreachable (%T)", x)) -} - - -// checkObj type checks an object. -func (c *checker) checkObj(obj *ast.Object, ref bool) { - if obj.Type != nil { - // object has already been type checked - return - } - - switch obj.Kind { - case ast.Bad: - // ignore - - case ast.Con: - // TODO(gri) complete this - - case ast.Typ: - typ := &Name{Obj: obj} - obj.Type = typ // "mark" object so recursion terminates - typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref)) - - case ast.Var: - // TODO(gri) complete this - - case ast.Fun: - // TODO(gri) complete this - - default: - panic("unreachable") - } -} - - -// Check typechecks a package. -// It augments the AST by assigning types to all ast.Objects and returns a map -// of types for all expression nodes in statements, and a scanner.ErrorList if -// there are errors. -// -func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err os.Error) { - var c checker - c.fset = fset - c.types = make(map[ast.Expr]Type) - - for _, obj := range pkg.Scope.Objects { - c.checkObj(obj, false) - } - - return c.types, c.GetError(scanner.NoMultiples) -} -- cgit v1.2.3