Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/types: Config.Check says Object.Pkg is in the "go/importer" package #13898

Closed
zncoder opened this issue Jan 10, 2016 · 7 comments
Closed

go/types: Config.Check says Object.Pkg is in the "go/importer" package #13898

zncoder opened this issue Jan 10, 2016 · 7 comments
Milestone

Comments

@zncoder
Copy link

zncoder commented Jan 10, 2016

The output of this program is,

use@main.go:39:24: id=Pkg obj=func (interface).Pkg() *go/types.Package in pkg=go/importer

But this looks wrong. Pkg is a method of the interface types.Object, and its package should be "go/types".

package main

import (
    "fmt"
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
    "log"
)

func main() {
    pkg, fn := "main", "main.go"

    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, fn, src, 0)
    if err != nil {
        log.Fatalf("parse file=%s err=%v", fn, err)
    }

    cfg := types.Config{
        Importer: importer.Default(),
        Error: func(err error) {
            log.Printf("check err=%v", err)
        },
    }

    info := types.Info{
        Uses: make(map[*ast.Ident]types.Object),
    }

    if _, err = cfg.Check(pkg, fset, []*ast.File{f}, &info); err != nil {
        log.Printf("cfg check err=%v", err)
    }

    for id, obj := range info.Uses {
        var pn string
        if obj != nil && obj.Pkg() != nil {
            pn = obj.Pkg().Path()
        }
        if id.Name == "Pkg" {
            fmt.Printf("use@%v: id=%s obj=%v in pkg=%s\n", fset.Position(id.Pos()), id.Name, obj, pn)
        }
    }
}

var src = `package main

import (
    "fmt"
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
    "log"
)

func main() {
    pkg, fn := "main", "main.go"

    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, fn, src, 0)
    if err != nil {
        log.Fatalf("parse file=%s err=%v", fn, err)
    }

    cfg := types.Config{
        Importer: importer.Default(),
        Error: func(err error) {
            log.Printf("check err=%v", err)
        },
    }

    info := types.Info{
        Uses: make(map[*ast.Ident]types.Object),
    }

    if _, err = cfg.Check(pkg, fset, []*ast.File{f}, &info); err != nil {
        log.Printf("cfg check err=%v", err)
    }

    for id, obj := range info.Uses {
        var pn string
        if obj != nil && obj.Pkg() != nil {
            pn = obj.Pkg().Path()
        }
        if id.Name == "Pkg" {
            fmt.Printf("use@%v: id=%s obj=%v in pkg=%s\n", fset.Position(id.Pos()), id.Name, obj, pn)
        }
    }
}
`
@zncoder
Copy link
Author

zncoder commented Jan 11, 2016

The go version is, "go version go1.5.2 linux/amd64"

@griesemer
Copy link
Contributor

There may be an issue here, but your example is convoluted. For one, it doesn't type-check w/o errors: The source you are providing doesn't define "src". Please simplify the test case.

@griesemer griesemer self-assigned this Jan 11, 2016
@griesemer
Copy link
Contributor

Simpler:

package main

import (
    "fmt"
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
)

func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "main.go", nil, 0)
    if err != nil {
        panic(err)
    }

    cfg := types.Config{
        Importer: importer.Default(),
        Error: func(err error) {
            panic(err)
        },
    }

    info := types.Info{
        Uses: make(map[*ast.Ident]types.Object),
    }

    if _, err = cfg.Check("main", fset, []*ast.File{f}, &info); err != nil {
        panic(err)
    }

    for id, obj := range info.Uses {
        if id.Name != "Pkg" {
            //continue
        }
        fmt.Printf("%s: id = %s, obj = %v, obj.Pkg = %v\n", fset.Position(id.Pos()), id.Name, obj, obj.Pkg())
    }
}

@griesemer
Copy link
Contributor

This is more subtle. The original (shortened) example works correctly if the import order is changed. In other words, the declaration:

import (
    "fmt"
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
)

leads to:

main.go:38:98: id = Pkg, obj = func (interface).Pkg() *go/types.Package, obj.Pkg = package importer ("go/importer")

But the declaration:

import (
    "fmt"
    "go/ast"
    "go/types"
    "go/importer"
    "go/parser"
    "go/token"
)

(go/types imported before go/importer) leads to the correct output:

main.go:38:98: id = Pkg, obj = func (interface).Pkg() *go/types.Package, obj.Pkg = package types ("go/types")

@griesemer
Copy link
Contributor

Complete repro case:

package main

import (
    "fmt"
    "go/ast"
    "go/importer"
    "go/parser"
    "go/token"
    "go/types"
)

var src1 = `
package main

import (
    "go/importer"
    "go/types"
)

func main() {
    var info types.Info
    for _, obj := range info.Uses {
        _ = obj.Pkg()
    }
}
`

var src2 = `
package main

import (
    "go/types"
    "go/importer"
)

func main() {
    var info types.Info
    for _, obj := range info.Uses {
        _ = obj.Pkg()
    }
}
`

func f(src string) {
    fset := token.NewFileSet()
    f, _ := parser.ParseFile(fset, "", src, 0)
    cfg := types.Config{Importer: importer.Default()}
    info := types.Info{Uses: make(map[*ast.Ident]types.Object)}
    cfg.Check("main", fset, []*ast.File{f}, &info)
    for id, obj := range info.Uses {
        if id.Name == "Pkg" {
            fmt.Println(obj.Pkg())
        }
    }
}

func main() {
    f(src1)
    f(src2)
}

The output is:

package importer ("go/importer")
package types ("go/types")

But it should be:

package types ("go/types")
package types ("go/types")

@griesemer griesemer added this to the Go1.6 milestone Jan 11, 2016
@zncoder
Copy link
Author

zncoder commented Jan 12, 2016

This is fast! Awesome!

@gopherbot
Copy link

CL https://golang.org/cl/18549 mentions this issue.

gopherbot pushed a commit that referenced this issue Jan 13, 2016
This is the equivalent of https://golang.org/cl/18549 for
the binary importer (which is usually not used because by
default the gc compiler produces the traditional textual
export format).

For #13898.

Change-Id: Idb6b515f2ee49e6d0362c71846994b0bd4dae8f7
Reviewed-on: https://go-review.googlesource.com/18598
Reviewed-by: Alan Donovan <adonovan@google.com>
Run-TryBot: Robert Griesemer <gri@golang.org>
@golang golang locked and limited conversation to collaborators Jan 13, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants