OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [exp/] [types/] [check.go] - Rev 747

Compare with Previous | Blame | View Log

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

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.