I'm guessing here, but you probably do need the full type-checker for that, depending on what you mean by "a native type".
In go we can alias types in two ways. type A uint8 type B = uint8 There are subtle differences between the two which I don't claim to understand... In any case, AFAIK both are essentially built-in types at runtime. Suppose these types are declared in a third-party package on GitHub and another package uses A and B (since they're exported) to declare a struct like this. import "github.com/foo/bar" type MyStruct struct { Byte1 bar.A Byte2 bar.B } AFAIK, the compiler cannot tell whether Byte1 and Byte2 are builtin types or a struct without seeing their definition hosted on GitHub. Which means downloading, parsing, and type-checking the code from GitHub. But it gets a little worse. Type-checking the remote code entails downloading any of its dependencies recursively and doing the same thing... I'm sure you can see how this can take some time -- especially for large projects. Anyway, it sounds to me like what you're asking to do requires the use of the type-checker and because of the dependency management involved I believe the most convenient route to type-checking (at this time) lives in the packages package. Happy to learn if anyone else knows otherwise. On Sun, Oct 17, 2021, 5:00 AM Steven Hartland <ste...@multiplay.co.uk> wrote: > I need to be able to tell the types of fields, in particular are fields of > a struct a native type or a struct themselves. > > The ast parse even with a simple importer don’t provide that info. > > On Sat, 16 Oct 2021 at 21:06, 'Richard Oudkerk' via golang-nuts < > golang-nuts@googlegroups.com> wrote: > >> I am not sure what "import external packages" means. >> >> Apart dot imports (which I have never seen used for real) why would you >> need to load the imported packages? >> >> On Saturday, 16 October 2021 at 20:34:17 UTC+1 Steven Hartland wrote: >> >>> Thanks Richard, that allowed me to replace a hand rolled >>> universe scope 👍 >>> >>> My importer varies from yours in that for correct lookups for versioned >>> packages or those with '-' in I had to copy ImportPathToAssumedName >>> from x/tools/internal/imports/fix.go. >>> >>> func simpleImporter(imports map[string]*ast.Object, path string) >>> (*ast.Object, error) { >>> pkg := imports[path] >>> if pkg == nil { >>> pkg = ast.NewObj(ast.Pkg, ImportPathToAssumedName(path)) >>> pkg.Data = ast.NewScope(nil) // required by >>> ast.NewPackage for dot-import >>> imports[path] = pkg >>> } >>> return pkg, nil >>> } >>> >>> This now works for all cases which don't import external packages. So >>> now I just need to do the on demand load of packages, which I suspect will >>> lead me right back to packages.Load. >>> >>> On Sat, 16 Oct 2021 at 15:59, 'Richard Oudkerk' via golang-nuts < >>> golan...@googlegroups.com> wrote: >>> >>>> You could try building the universe scope for ast.NewPackage from >>>> types.Universe. For example >>>> >>>> https://play.golang.org/p/1E5Iu4vW3g9 >>>> >>>> func NewPackage(fset *token.FileSet, files map[string]*ast.File) >>>> (*ast.Package, error) { >>>> univ, err := universe() >>>> if err != nil { >>>> return nil, err >>>> } >>>> return ast.NewPackage(fset, files, dummyImporter, univ) >>>> } >>>> >>>> func dummyImporter(imports map[string]*ast.Object, importPath string) >>>> (*ast.Object, error) { >>>> pkg := imports[importPath] >>>> if pkg == nil { >>>> pkg = ast.NewObj(ast.Pkg, path.Base(importPath)) >>>> pkg.Data = ast.NewScope(nil) >>>> imports[importPath] = pkg >>>> } >>>> return pkg, nil >>>> } >>>> >>>> func universe() (*ast.Scope, error) { >>>> u := ast.NewScope(nil) >>>> for _, name := range types.Universe.Names() { >>>> o := types.Universe.Lookup(name) >>>> if o == nil { >>>> return nil, fmt.Errorf("failed to lookup %s in universe scope", name) >>>> } >>>> var objKind ast.ObjKind >>>> switch o.(type) { >>>> case *types.Const, *types.Nil: >>>> objKind = ast.Con >>>> case *types.TypeName: >>>> objKind = ast.Typ >>>> case *types.Builtin: >>>> objKind = ast.Fun >>>> default: >>>> return nil, fmt.Errorf("unexpected builtin %s of type %T", o.Name(), o) >>>> } >>>> obj := ast.NewObj(objKind, name) >>>> if u.Insert(obj) != nil { >>>> return nil, fmt.Errorf("types internal error: double declaration") >>>> } >>>> obj.Decl = u >>>> } >>>> return u, nil >>>> } >>>> >>>> On Saturday, 16 October 2021 at 14:38:43 UTC+1 eli...@gmail.com wrote: >>>> >>>>> On Fri, Oct 15, 2021 at 2:13 PM Steven Hartland < >>>>> ste...@multiplay.co.uk> wrote: >>>>> >>>>>> I converted my code to x/tools/go/packages >>>>>> <https://pkg.go.dev/golang.org/x/tools@v0.1.7/go/packages> and while >>>>>> it did solve the problem it's VERY slow in comparison. >>>>>> >>>>>> I have a set of 21 tests operating on a single package which has at >>>>>> most two very basic types, no imports and using go/parser >>>>>> <https://pkg.go.dev/go/parser> they take 0.011s but with go/packages >>>>>> <https://pkg.go.dev/golang.org/x/tools@v0.1.7/go/packages> that >>>>>> increases to 3.548s a 300x slow down. >>>>>> >>>>>> I'm setting a basic mode: packages.NeedName | packages.NeedSyntax >>>>>> >>>>>> The package.Load call takes ~220ms whereas ast.NewPackage only >>>>>> takes 2.7µs. >>>>>> >>>>> >>>>> Could you post a reproducer of your target package and analysis >>>>> somewhere? 220ms for packages.Load sounds like a lot. It's true that >>>>> packages does a lot more work than just the parser (*), but it's not >>>>> supposed to be that slow. In my tests a simple Load with more >>>>> functionality >>>>> takes 60-70ms >>>>> >>>>> (*) The type checking takes a bit of time over just parsing to AST, >>>>> but the biggest difference is loading multiple files from imports. For >>>>> type >>>>> checking you need to know, when you see: >>>>> >>>>> import foo >>>>> >>>>> x := foo.Foo() >>>>> >>>>> What the type of `x` is, so go/packages has to analyze the `foo` >>>>> package as well. >>>>> >>>>> >>>>> >>>>>> >>>>>> As the resulting ast.File's are pretty much the same, I'm wondering >>>>>> if for my use case packages.Load is doing way more than I need? >>>>>> >>>>>> Another downside is for tests run in a temporary directory outside of >>>>>> the package space package.Load fails with: >>>>>> directory /tmp/tests76985775 outside available modules >>>>>> >>>>>> I fixed it by calling ioutil.TempDir with "." but that's not ideal. >>>>>> >>>>>> Thoughts? >>>>>> >>>>>> On Tue, 12 Oct 2021 at 13:42, Steven Hartland <ste...@multiplay.co.uk> >>>>>> wrote: >>>>>> >>>>>>> Thanks David, much appreciated, I will have a look at both. >>>>>>> >>>>>>> When migrating from go/ast to go/types did you hit anything of note >>>>>>> I should look out for? >>>>>>> >>>>>>> On Mon, 11 Oct 2021 at 17:06, David Finkel <david....@gmail.com> >>>>>>> wrote: >>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> On Mon, Oct 11, 2021 at 5:48 AM Steven Hartland < >>>>>>>> ste...@multiplay.co.uk> wrote: >>>>>>>> >>>>>>>>> If the ast.Files passed to ast.NewPackage includes built in types >>>>>>>>> such as int it returns an error e.g. >>>>>>>>> file1.go:5:6: undeclared name: int >>>>>>>>> >>>>>>>>> Is there a way to prevent that? >>>>>>>>> >>>>>>>> >>>>>>>> Generally, I always add the `builtin` package to the list of >>>>>>>> packages I'm parsing. >>>>>>>> I wrote a little library for exactly this kind of package loading a >>>>>>>> few years ago: >>>>>>>> https://gitlab.com/dfinkel/goastpkg/-/blob/master/go_ast_parser.go >>>>>>>> (https://pkg.go.dev/golang.spin-2.net/astpkg) >>>>>>>> >>>>>>>>> >>>>>>>>> Playground example: https://play.golang.org/p/Yg30TTzoLHP >>>>>>>>> >>>>>>>>> My goal is to take multiple files, resolve inter file dependencies >>>>>>>>> e.g. a type referencing another type in a different file and process >>>>>>>>> the >>>>>>>>> resulting ast.Files. So if there is a better way to achieve this I'm >>>>>>>>> all >>>>>>>>> ears. >>>>>>>>> >>>>>>>> >>>>>>>> In general, I've stopped using the `go/ast` internal references as >>>>>>>> much and have started using resolved `go/types` references as they're >>>>>>>> more >>>>>>>> reliable and better-specified. >>>>>>>> (golang.org/x/tools/go/packages >>>>>>>> <https://pkg.go.dev/golang.org/x/tools@v0.1.7/go/packages> has a >>>>>>>> LoadMode flag for generating `go/types.Info` (NeedTypesInfo >>>>>>>> <https://pkg.go.dev/golang.org/x/tools@v0.1.7/go/packages#NeedTypesInfo> >>>>>>>> )) >>>>>>>> >>>>>>>>> >>>>>>>>> Regards >>>>>>>>> Steve >>>>>>>>> >>>>>>>>> -- >>>>>>>>> You received this message because you are subscribed to the Google >>>>>>>>> Groups "golang-nuts" group. >>>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>> send an email to golang-nuts...@googlegroups.com. >>>>>>>>> To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/golang-nuts/CAHEMsqbJoJxuo3c-mofMtzXXJhYCzV2skW2ZB3ZPY6WtA8%2BxHw%40mail.gmail.com >>>>>>>>> <https://groups.google.com/d/msgid/golang-nuts/CAHEMsqbJoJxuo3c-mofMtzXXJhYCzV2skW2ZB3ZPY6WtA8%2BxHw%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>>>>>>> . >>>>>>>>> >>>>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "golang-nuts" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>> send an email to golang-nuts...@googlegroups.com. >>>>>> >>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/golang-nuts/CAHEMsqYMSBUfuOUvptv6UrvBFTwFxjOhJZ5sMN-omOx5ESL5hw%40mail.gmail.com >>>>>> <https://groups.google.com/d/msgid/golang-nuts/CAHEMsqYMSBUfuOUvptv6UrvBFTwFxjOhJZ5sMN-omOx5ESL5hw%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>>>> . >>>>> >>>>> >>>>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "golang-nuts" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to golang-nuts...@googlegroups.com. >>>> >>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/golang-nuts/d570a7ce-a780-46d8-a323-f9c26a6c2561n%40googlegroups.com >>>> <https://groups.google.com/d/msgid/golang-nuts/d570a7ce-a780-46d8-a323-f9c26a6c2561n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/6aaa7c3a-7ef5-47ea-9f29-75443a4599b6n%40googlegroups.com >> <https://groups.google.com/d/msgid/golang-nuts/6aaa7c3a-7ef5-47ea-9f29-75443a4599b6n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/CAHEMsqaQ9%3Dia2MXrVEXt--Qk3Nrx1UXK2JYU0D2BxBcZX%2B5mxw%40mail.gmail > <https://groups.google.com/d/msgid/golang-nuts/CAHEMsqaQ9%3Dia2MXrVEXt--Qk3Nrx1UXK2JYU0D2BxBcZX%2B5mxw%40mail.gmail.com?utm_medium=email&utm_source=footer> > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CALJzkY_StxPKx7Riaz10RjfKwFAYtrYQ_zSmHRHvwLRi5JFsUw%40mail.gmail.com.