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
Labels
Documentation FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@dvyukov
Copy link
Member

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

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

@rsc rsc modified the milestones: Unplanned, Go1.6 Nov 30, 2015
@rsc
Copy link
Contributor

rsc commented May 9, 2016

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

@rsc rsc modified the milestones: Go1.8Maybe, Unplanned May 9, 2016
@rsc rsc added the NeedsFix The path to resolution is known, but the work has not been done. 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

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

@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.
Labels
Documentation FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants