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: document when selectors have types #11944

Closed
dvyukov opened this issue Jul 30, 2015 · 3 comments
Closed

go/types: document when selectors have types #11944

dvyukov opened this issue Jul 30, 2015 · 3 comments

Comments

@dvyukov
Copy link
Member

@dvyukov dvyukov commented Jul 30, 2015

The following program:

package main

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

func main() {
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "test.go", src, 0)
    if err != nil {
        panic(err)
    }
    info := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
    cfg := &types.Config{}
    _, err = cfg.Check("test", fset, []*ast.File{f}, info)
    if err != nil {
        panic(err)
    }
    for n, t := range info.Types {
        fmt.Printf("%+v: %v\n", n, t)
    }
}

const src = `
package x

type X struct {
    f int
}

func foo(x *X) int {
    return x.f
}

outputs:

int: {3 int <nil>}
x: {5 *test.X <nil>}
&{X:x Sel:f}: {5 int <nil>}
int: {3 int <nil>}
&{Struct:20 Fields:0xc820014660 Incomplete:false}: {3 struct{f int} <nil>}
X: {3 test.X <nil>}
&{Star:50 X:X}: {3 *test.X <nil>}

You can see that selector f in expression x.f did not get type.
It should have a type, when you recursively walk an expression you expect that all subexpressions are typed or constants. But these are completely unindentified.

The spec says that selectors have types; and in fact type of the selector expression itself is determined by type of the selector:

For a primary expression x that is not a package name, the selector expression
x.f
denotes the field or method f of the value x (or sometimes *x; see below). The identifier f is called the (field or method) selector; it must not be the blank identifier. The type of the selector expression is the type of f. If x is a package name, see the section on qualified identifiers.

go version devel +b7205b9 Thu Jul 30 05:57:37 2015 +0000 linux/amd64

@ianlancetaylor ianlancetaylor added this to the Go1.6 milestone Jul 30, 2015
@griesemer
Copy link
Contributor

@griesemer griesemer commented Jul 31, 2015

The information is in the Defs and Uses maps. But I agree that a) the documentation needs to be clearer; and b) the fields may have to show up in TypesAndValues as well (TBD).

Here's a more elaborate example:

package main

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

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

    info := &types.Info{Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Types: make(map[ast.Expr]types.TypeAndValue)}
    cfg := &types.Config{}
    _, err = cfg.Check("test", fset, []*ast.File{f}, info)
    if err != nil {
        panic(err)
    }

    fmt.Println("Defs")
    for n, obj := range info.Defs {
        fmt.Printf("%s: %+v => %v\n", fset.Position(n.Pos()), n, obj)
    }
    fmt.Println()

    fmt.Println("Uses")
    for n, obj := range info.Uses {
        fmt.Printf("%s: %+v => %v\n", fset.Position(n.Pos()), n, obj)
    }
    fmt.Println()

    fmt.Println("Types and values")
    for n, typ := range info.Types {
        fmt.Printf("%s: %+v (%T) => %v\n", fset.Position(n.Pos()), n, n, typ)
    }
    fmt.Println()
}

const src = `
package x

type X struct {
    f int
}

func foo(x *X) int {
    return x.f
}
`

with the output:

Defs
test.go:5:5: f => field f int
test.go:8:10: x => var x *test.X
test.go:2:9: x => <nil>
test.go:4:6: X => type test.X struct{f int}
test.go:8:6: foo => func test.foo(x *test.X) int

Uses
test.go:5:7: int => type int int
test.go:8:13: X => type test.X struct{f int}
test.go:8:16: int => type int int
test.go:9:12: x => var x *test.X
test.go:9:14: f => field f int

Types and values
test.go:8:12: &{Star:53 X:X} (*ast.StarExpr) => {3 *test.X <nil>}
test.go:8:16: int (*ast.Ident) => {3 int <nil>}
test.go:9:12: x (*ast.Ident) => {5 *test.X <nil>}
test.go:9:12: &{X:x Sel:f} (*ast.SelectorExpr) => {5 int <nil>}
test.go:5:7: int (*ast.Ident) => {3 int <nil>}
test.go:4:8: &{Struct:20 Fields:0x8203ee510 Incomplete:false} (*ast.StructType) => {3 struct{f int} <nil>}
test.go:8:13: X (*ast.Ident) => {3 test.X <nil>}

Loading

@rsc rsc added this to the Unplanned milestone Nov 30, 2015
@rsc rsc removed this from the Go1.6 milestone Nov 30, 2015
@rsc
Copy link
Contributor

@rsc rsc commented May 9, 2016

It sounds like the fix here is to make the documentation clearer about describing the current behavior.

Loading

@rsc rsc added this to the Go1.8Maybe milestone May 9, 2016
@rsc rsc removed this from the Unplanned milestone May 9, 2016
@rsc rsc added the NeedsFix label May 9, 2016
@rsc rsc changed the title go/types: does not give types to selectors go/types: document when selectors have types Nov 2, 2016
@gopherbot
Copy link

@gopherbot gopherbot commented Nov 8, 2016

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

Loading

@gopherbot gopherbot closed this in 8a2a999 Nov 8, 2016
@golang golang locked and limited conversation to collaborators Nov 8, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants