diff options
author | Matthew Dempsky <mdempsky@google.com> | 2021-05-29 15:35:18 -0700 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2021-06-04 04:28:10 +0000 |
commit | 2175e2f57331cbcd32bccc47fa7fe7a6874a69a3 (patch) | |
tree | d16af47d239c050c58628a3f485622400ba2fb8d /src/cmd/compile/internal/types2/instantiate.go | |
parent | 4d2b528795fe2534398d1b1a978e1037d4a9d2f0 (diff) | |
download | go-2175e2f57331cbcd32bccc47fa7fe7a6874a69a3.tar.gz go-2175e2f57331cbcd32bccc47fa7fe7a6874a69a3.zip |
[dev.typeparams] cmd/compile: lazy import resolution for types2
This CL adds three new functions to the types2 API to support lazy
import resolution:
1. A new Scope.InsertLazy method to allow recording that Objects exist
in a particular Scope (in particular, package scopes) without having
to yet fully construct those objects. Instead, types2 will call the
provided `resolve` function if/when the object is actually needed.
2. Similarly, a new NewTypeNameLazy function to create TypeName
objects without yet instantiating their underlying Named
instance.
3. Finally, an InstantiateLazy method, that allows creating type
instances without requiring any of the types to be expanded right
away. Importantly, this requires providing a types2.Checker argument
to handle recursive types correctly.
The APIs as-is are a bit clumsy (esp. NewTypeNameLazy), but seem to
work well for cmd/compile's needs. In particular, they simplify some
of the complexities of handling recursive type definitions within the
importer.
Also, the current prototype is a bit fragile. It uses sync.Once to
manage concurrent lazy resolution, which is frustrating to debug in
the presence of reentrancy issues. It also means the importer needs to
deal with concurrency as well. These aren't issues for types2 though
as cmd/compile only walks the type-checked AST sequentially.
Finally, it looks like some of the details of lazy type names are
similar to the lazy "instance" stuff used for generics, so maybe
there's opportunity for unifying them under a more general (but still
internal) lazy type mechanism.
I had originally intended for this CL to also update the types2
importer, but (1) it doesn't have access to the types2.Checker
instance needed to call InstantiateLazy, and (2) it creates a new
TypeName/TypeParam at each use rather than reusing them, which
evidently works with types2.Instantiate but not
types2.(*Checker).instantiate (i.e., InstantiateLazy). I spent a while
trying to fix these issues, but kept running into more subtle
issues. Instead, I've included my WIP "unified IR" CL as a followup CL
that demonstrates these Lazy methods (see noder/reader2.go).
Updates #46449.
Change-Id: I4d1e8e649f6325a11790d25fd90c39fa07c8d41d
Reviewed-on: https://go-review.googlesource.com/c/go/+/323569
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/types2/instantiate.go')
-rw-r--r-- | src/cmd/compile/internal/types2/instantiate.go | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index 0df52e851c9..85c897a9097 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -23,7 +23,7 @@ func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) { var tparams []*TypeName switch t := typ.(type) { case *Named: - tparams = t.tparams + tparams = t.TParams() case *Signature: tparams = t.tparams defer func() { @@ -61,3 +61,19 @@ func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) { smap := makeSubstMap(tparams, targs) return (*Checker)(nil).subst(pos, typ, smap) } + +// InstantiateLazy is like Instantiate, but avoids actually +// instantiating the type until needed. +func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type) (res Type) { + base := asNamed(typ) + if base == nil { + panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) + } + + return &instance{ + check: check, + pos: pos, + base: base, + targs: targs, + } +} |