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: conf.check complains about a function is not declared in a package #19334

Closed
jzhu077 opened this issue Mar 1, 2017 · 9 comments
Closed

Comments

@jzhu077
Copy link

jzhu077 commented Mar 1, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.7.4 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/jzhu/projects"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build240680793=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"

What did you do?

	conf := types.Config{Importer: importer.Default()}
	info := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
	if _, err := conf.Check(filepath, fset, []*ast.File{f}, info); err != nil {
		log.Fatal(err) // type error
	}

hello.go

package main

import (
	"fmt"
	"github.com/codelingo/sandbox/test1/animal"
)

func main() {
	a := animal.New()
	c := a.Name
	fmt.Println(c)
	//d := animal.Num()
	//fmt.Println(d)
}

animal.go

package animal

type ani struct {
	Limbs int
	Eyes  int
	Name  string
}

func New() *ani {
	return &ani{
		Limbs: 4,
		Eyes:  2,
		Name:  "cat",
	}
}

//func Num() int {
//	return 6
//}

What did you expect to see? ### What did you see instead?

It runs perfectly without those commented lines, however when I uncomment them. The config.check gives an error

hello.go:12:7: Num not declared by package animal

I have tested it with

go run hello.go 

after uncomment those lines. It does what it suppose to do.

@jzhu077
Copy link
Author

jzhu077 commented Mar 1, 2017

ps: one work around is uncomment those lines and rename the package reference to "animall" instead of "animal" it would work. BUT I really don't want to rename my package every time when I add a new function in the package.

@ianlancetaylor ianlancetaylor changed the title go/types conf.check complains about a function is not declared in a package go/types: conf.check complains about a function is not declared in a package Mar 1, 2017
@ianlancetaylor
Copy link
Contributor

Show us how you get the error. Show us the precise files you use. Show us the complete code you use to call the go/types package, with func main and everything. Show us the exact commands you run. Show us the exact results.

I ask this because as far as I can tell everything should work. Experience tells me that you are doing something that I do not expect. If you show us precisely what you are doing, we can figure out what that is. Thanks.

@jzhu077
Copy link
Author

jzhu077 commented Mar 1, 2017

main.go

package main

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

//!+input
const input = `
package main

var m = make(map[string]int)

func main() {
	v, ok := m["hello, " + "world"]
	print(rune(v), ok)
}
`

//!-input

var fset = token.NewFileSet()

func main() {
	f, err := parser.ParseFile(fset, "hello.go", nil, 0)
	if err != nil {
		log.Fatal(err) // parse error
	}

	conf := types.Config{Importer: importer.Default()}
	info := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
	if _, err := conf.Check("hello", fset, []*ast.File{f}, info); err != nil {
		log.Fatal(err) // type error
	}
	//ast.Print(fset, f)
	//!+inspect
	// f is a parsed, type-checked *ast.File.
	ast.Inspect(f, func(n ast.Node) bool {
		if expr, ok := n.(ast.Expr); ok {
			if tv, ok := info.Types[expr]; ok {
				fmt.Printf("%-24s\tmode:  %s\n", nodeString(expr), mode(tv))
				fmt.Printf("\t\t\t\ttype:  %v\n", tv.Type)
				if tv.Value != nil {
					fmt.Printf("\t\t\t\tvalue: %v\n", tv.Value)
				}
			}
			return true

		}
		return true
	})
	//!-inspect
}

// nodeString formats a syntax tree in the style of gofmt.
func nodeString(n ast.Node) string {
	var buf bytes.Buffer
	format.Node(&buf, fset, n)
	return buf.String()
}

// mode returns a string describing the mode of an expression.
func mode(tv types.TypeAndValue) string {
	s := ""
	if tv.IsVoid() {
		s += ",void"
	}
	if tv.IsType() {
		s += ",type"
	}
	if tv.IsBuiltin() {
		s += ",builtin"
	}
	if tv.IsValue() {
		s += ",value"
	}
	if tv.IsNil() {
		s += ",nil"
	}
	if tv.Addressable() {
		s += ",addressable"
	}
	if tv.Assignable() {
		s += ",assignable"
	}
	if tv.HasOk() {
		s += ",ok"
	}
	return s[1:]
}

The error occurs when I try to implement a new function in package animal and try to use it in hello.go after I resolve types for the first time.
eg. go run main.go
everything looks good, type resolved

now
add a new function in animal.go

SomeFunc()int{return 4} 

in hello.go

x := animal.SomeFunc()
fmt.Println(x)

now go run main.go
error message: hello.go:12:7: SomeFunc not declared by package animal

ps: hello.go and animal.go has provided in the issue description. main.go and hello.go are in the same folder. animal.go is in a subdirectory called animal.

I guess it keeps a record of the ast file of the dependency in the first run. After I modify the dependency it still tries to read the old ast file for types, thus it complains about there is not such "modified/new" function in the dependency/package.

@ianlancetaylor
Copy link
Contributor

Where does the file animal.go live?

Did you ever run go install animal?

@griesemer
Copy link
Contributor

As @ianlancetaylor is hinting at, I suspect you did not re-install the updated package animal. Without installing it, the type-checker will just see the old version. The type-checker does not automatically use the animal package's source code for import (this is issue #11415).

As of a couple of days, instead of types.Config{Importer: importer.Default()} you can use types.Config{Importer: importer.For("source", nil)} and then the type-checker will use the current source code of packages that are imported, as long as they are in directories per the usual Go setup conventions. This requires that you use the latest version of the std library at tip, though (doesn't work in Go 1.8).

@jzhu077
Copy link
Author

jzhu077 commented Mar 2, 2017

@ianlancetaylor Thanks for your reply. I was a bit confused about your last sentence. Are you suggesting I should use the latest std library with my current go version(1.7.4) It seems the functionality you described only exist in 1.8 and yet it does not work in 1.8

@griesemer
Copy link
Contributor

@jzhu077 I believe you meant to address me with your recent comment.

I was suggesting that you could use the latest std library at tip (not yet released, requires installation from source), which is where the new functionality exists. It does not work in 1.8 (which is the latest released library).

That said, if this sentence confused you, feel free to ignore it. Again, I believe your error is that you changed the package animal w/o installing it before running your program again.

@jzhu077
Copy link
Author

jzhu077 commented Mar 2, 2017

@griesemer haha you are right. Cheers

@griesemer
Copy link
Contributor

I am going to close this as working as intended.

@golang golang locked and limited conversation to collaborators Mar 2, 2018
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

4 participants