Age | Commit message (Collapse) | Author |
|
Fixes #47948
Change-Id: I446a9548265d195ae4d88aff6b1361474d1b6214
Reviewed-on: https://go-review.googlesource.com/c/go/+/344910
Trust: Alexander Rakoczy <alex@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Alexander Rakoczy <alex@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
Because the Align/Width of pointer types are always set when created,
CalcSize() never descends past a pointer. Therefore, we need to do
CheckSize() at every level when creating type. We need to do this for
types creates by types2-to-types1 conversion and also by type
substitution (mostly for stenciling). We also need to do
Defer/ResumeCheckSize() at the top level in each of these cases to deal
with potentially recursive types.
These changes fix issue #47929 and also allow us to remove the
special-case CheckSize() call that causes the problem for issue #47901.
Fixes #47901
Fixes #47929
Change-Id: Icd8192431c145009cd6df2f4ade6db7da0f4dd3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/344829
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
|
|
Issues 47713 and 47877 were both due to problems with the names used for
instantiated functions/methods, which must be in sync with the names
used by types2.
- Switched to using NameString() for writing out type arguments in
instantiation names. This ensures that we are always adding the
package to type names even for the local package. Previously, we were
explicitly adding the package name for local packages, but that
doesn't handle the case when the local type is embedded inside a
pointer or slice type. By switching to NameString(), we fix #47713.
- types1 and types2 write out 'interface {' differently (vs.
'interface{') and we were already handling that. But we needed to add
similar code to handle 'struct {' vs 'struct{'. This fixes issue
#47877.
While fixing these bugs, I also moved some duplicated code (which
include some of the changes above) into a common function addTargs(). I
also moved InstType() name to subr.go, and renamed: MakeInstName ->
MakeFuncInstSym and MakeDictName -> MakeDictSym.
Also removed a couple of ".inst..inst." prefix checks which are
irrelvant now, since we don't add ".inst." anymore to function
instantiations.
Fixes #47713
Fixes #47877
Fixes #47922
Change-Id: I19e9a073451f3ababd8ec31b6608cd79ba8cba36
Reviewed-on: https://go-review.googlesource.com/c/go/+/344613
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
|
|
other cleanups
The type substituter (typecheck.Typ()) was temporarily substituting from
shapes back to concrete types, but doesn't need to anymore. So, remove
two shape checks, so the type substituter is now only for substituting
type params again.
Several other cleanups:
- renamed makeGenericName() to makeInstName1(), since that function is
a helper to MakeInstName() and MakeDictName() that definitely makes
instantiated names, not generic names.
- removed the logic in makeInstName1() that adds the ".inst." prefix
for concrete type args. We are only specifying concrete type args (as
opposed to shape args) when we are calling from MakeDictName, and
then we immediately strip of the .inst prefix anyway.
- Added a comment on types.Identical that a shape type is considered
identicall to another type if their underlying types are the same, or
they are both pointers.
Change-Id: I3e0206dbd403897797ae7bec3c527ae16b0b930a
Reviewed-on: https://go-review.googlesource.com/c/go/+/341729
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
|
|
types2.Constraint() returns the top-level constraint type, including any
unions or other interface elements. Because of that, we needed to
add/fix some code in the type substituter and generic type instantiater
in the importer to deal with unions and non-method members of an
interface. Also, NewUnion was not correctly setting the HasTParam flag.
I also added a better error message when a symbol is not found in
(*deadcodePass).decodeIfaceMethod().
Change-Id: Id3668dc596dce63690fa05a9e5e42295b5e2bbb5
Reviewed-on: https://go-review.googlesource.com/c/go/+/340670
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
|
|
Do the transformCall using the original types2-derived type of the call
(in particular, the types of the params as non-shapes). Currently, since
we were using the param types of the instantiation, we might add in
interface conversions to an interface with shapes in the one case of a
full-instantiated generic call. So, we do the transformCall() before
installing the shaped-based instantiation. transformCall() works
correctly even in the case of OCALL/FUNCINST.
Fixed two related bugs:
- Fixed case where we still were not correctly substituting the types
for a function instantiation.
- The type substituter needs to copy field flags while substituting in
tstruct.
Change-Id: I14e960737d6840a75846ede480e6650534ba3af3
Reviewed-on: https://go-review.googlesource.com/c/go/+/340259
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
|
|
Put shape types in the top level package called ".shape".
Name them using the serialization of the shape name, instead of
the .shapeN names.
This allows the linker to deduplicate instantiations across packages.
Not sure that this is entirely correct, as shapes in this package
may reference other packages (e.g. a field of a struct). But it seems
to work for now.
For the added test, when you look at the resulting binary (use the -k
option with run.go) it has only one instantiation of F, and 4 call sites:
$ objdump -d a.exe | grep _a\.F
1053cb0: e8 8b 00 00 00 callq 139 <_a.F[.shape.*uint8]>
1053ce9: e8 52 00 00 00 callq 82 <_a.F[.shape.*uint8]>
_a.F[.shape.*uint8]:
1053d90: e8 ab ff ff ff callq -85 <_a.F[.shape.*uint8]>
1053dc9: e8 72 ff ff ff callq -142 <_a.F[.shape.*uint8]>
Change-Id: I627f7e50210aabe4a10d0e2717d87b75ac82e99b
Reviewed-on: https://go-review.googlesource.com/c/go/+/339595
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
- Changed some early returns to asserts (instantiateMethods and Shapify
should never take a shape arg)
- Added suggested change (by Ingo) to use copy() in getInstantiation()
- Clarified that shape types never have methods in Shapify(), removed
some TODO comments.
Change-Id: Ia2164ffe670a777f7797bbb45c7ef5e6e9e15357
Reviewed-on: https://go-review.googlesource.com/c/go/+/338971
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
|
|
with a type flag
Implement HasShape() similar to how HasTParam() is implemented.
Fixes #47456
Change-Id: Icbd538574237faad2c4cd8c8e187725a1df47637
Reviewed-on: https://go-review.googlesource.com/c/go/+/339029
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
|
|
Except unsafe.Pointer. It has a different Kind, which makes it trickier.
Change-Id: I12582afb6e591bea35da9e43ac8d141ed19532a3
Reviewed-on: https://go-review.googlesource.com/c/go/+/338749
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
have the same shape
First baby step to sharing the underlying implementation among several types.
Change-Id: I6a156176d2b7f0131a87285a03b881ce380c26ed
Reviewed-on: https://go-review.googlesource.com/c/go/+/338610
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
types2 doesn't actually give us the type of an instantiated
function/method after the type args have been applied. So, do a
substitution at the point that we create the OFUNCINST nodes.
We also needed to add in translation of the typeparams of a function
signature in the type substituter. If the type params of the function
become all concrete after the substitution, then we just drop them,
since the whole signature must now be concrete.
Change-Id: I6116d2aa248be6924ec9e6d8516678db45aa65c4
Reviewed-on: https://go-review.googlesource.com/c/go/+/336370
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
|
|
Still 1-1 with real types, but now with their own names!
Shape types are implicitly convertible to (and convertible from)
the types they represent.
Change-Id: I0133a8d8fbeb369380574b075a32b3c987e314d5
Reviewed-on: https://go-review.googlesource.com/c/go/+/335170
Run-TryBot: Keith Randall <khr@golang.org>
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
We have almost 200 uses of the "assert" helper functions in noder and
typecheck. Clearly the tiny bit of extra convenience of writing a
one-line assertion rather than an if+panic is helpful, so we might as
well add functions for this to base itself so that it's easier to
write more informative error messages.
Change-Id: I06e2db2f0455af063937b25a53ca42f9413cf496
Reviewed-on: https://go-review.googlesource.com/c/go/+/336050
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
|
|
test/typeparams/mdempsky
1.go, 12.go: similar to calculating type sizes, we delay computing
instantiations during import until we get up to a top-level type, in
order to make sure recursive types are complete. But we should always
delay calculating sizes when we delay instantiating types, since
otherwise we may try to calculate the size of an incomplete type. So,
needed to add Defer/ResumeCheckSize in (*importReader).typ where we also
defer instantiations. (iimport.go)
2.go: when doing type substition, we have to handle named, parameterized
basic types i.e. the type has a type parameter even though the
underlying type is a basic type that doesn't depend on the parameter.
(subr.go)
3.go: for go 1.18, we allow arbitrary types in interfaces. We had
already allowed union types and tilde types, but didn't allow regular
non-interface types in Go 1.17 for compatibility. Just skip an error
in the case of 1.18. (size.go)
5.go: types2 and types1 differ in how they print out interfaces. types1
puts a space between "interface" and "{", types2 does not. So, since
some typenames come from types2 and some from types1, we need to remove
the space when printing out type arguments. (iimport.go/subr.go)
9.go: in subst.node(), we were missing the KeyExpr case where a node has
no type. The assertion is just there, to make sure we understand all the
cases where there is no type to translate. We could just remove the
whole error check. (stencil.go)
13.go: in subst.node(), missed handling the case where a method
expression is immediate called (which of course, is quite unusual, since
then there's no real reason to have used the method expression syntax in
that case). Just needed to add ir.OMETHEXPR in the OCALL switch
statement. (stencil.go)
Change-Id: I202cbe9541dfafe740e3b84b44982d6181738ea0
Reviewed-on: https://go-review.googlesource.com/c/go/+/333165
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
|
|
Separate generation of instantiation and dictionary name generation.
Add code to add subdictionaries to a dictionary. Not quite working
yet, as we need to trigger generation of the subdictionaries for methods.
Change-Id: I0d46053eba695b217630b06ef2f990f6a0b52d83
Reviewed-on: https://go-review.googlesource.com/c/go/+/331209
Trust: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
substituter.
Change-Id: I876933370a6bcb6586eda9d8fc28a081bf31b1cf
Reviewed-on: https://go-review.googlesource.com/c/go/+/328511
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Dan Scales <danscales@google.com>
|
|
This CL implements a few improvements to SSA devirtualization to make
it simpler and more general:
1. Change reflectdata.ITabAddr to now immediately generate the wrapper
functions and write out the itab symbol data. Previously, these were
each handled by separate phases later on.
2. Removes the hack in typecheck where we marked itabs that we
expected to need later. Instead, the calls to ITabAddr in walk now
handle generating the wrappers.
3. Changes the SSA interface call devirtualization algorithm to just
use the itab symbol data (namely, its relocations) to figure out what
pointer is available in memory at the given offset. This decouples it
somewhat from reflectdata.
Change-Id: I8fe06922af8f8a1e7c93f5aff2b60ff59b8e7114
Reviewed-on: https://go-review.googlesource.com/c/go/+/327871
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
|
|
When converting from a type param to an interface, allow it if
the type bound implements that interface.
Query: some conversions go through this path, some use another path?
The test does
var i interface{foo()int} = x
but
i := (interface{foo()int})(x)
works at tip.
Change-Id: I84d497e5228c0e1d1c9d76ffebaedce09dc45e8e
Reviewed-on: https://go-review.googlesource.com/c/go/+/325409
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
better than Kind() == types.TTYPEPARAM
Change-Id: I4f35a177cd0cda3be615a92b7b2af1b5a60a3bbc
Reviewed-on: https://go-review.googlesource.com/c/go/+/325410
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
Deal with export/import of recursive generic types. This includes
typeparams which have bounds that reference the typeparam.
There are three main changes:
- Change export/import of typeparams to have an implicit "declaration"
(doDecl). We need to do a declaration of typeparams (via the
typeparam's package and unique name), because it may be referenced
within its bound during its own definition.
- We delay most of the processing of the Instantiate call until we
finish the creation of the top-most type (similar to the way we
delay CheckSize). This is because we can't do the full instantiation
properly until the base type is fully defined (with methods). The
functions delayDoInst() and resumeDoInst() delay and resume the
processing of the instantiations.
- To do the full needed type substitutions for type instantiations
during import, I had to separate out the type subster in stencil.go
and move it to subr.go in the typecheck package. The subster in
stencil.go now does node substitution and makes use of the type
subster to do type substitutions.
Notable other changes:
- In types/builtins.go, put the newly defined typeparam for a union type
(related to use of real/imag, etc.) in the current package, rather
than the builtin package, so exports/imports work properly.
- In types2, allowed NewTypeParam() to be called with a nil bound, and
allow setting the bound later. (Needed to import a typeparam whose
bound refers to the typeparam itself.)
- During import of typeparams in types2 (importer/import.go), we need
to keep an index of the typeparams by their package and unique name
(with id). Use a new map typParamIndex[] for that. Again, this is
needed to deal with typeparams whose bounds refer to the typeparam
itself.
- Added several new tests absdiffimp.go and orderedmapsimp.go. Some of
the orderemapsimp tests are commented out for now, because there are
some issues with closures inside instantiations (relating to unexported
names of closure structs).
- Renamed some typeparams in test value.go to make them all T (to make
typeparam uniqueness is working fine).
Change-Id: Ib47ed9471c19ee8e9fbb34e8506907dad3021e5a
Reviewed-on: https://go-review.googlesource.com/c/go/+/323029
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
|
|
When converting from a generic function to a concrete implementation,
add a dictionary argument to the generic function (both an actual
argument at each callsite, and a formal argument of each
implementation).
The dictionary argument comes before all other arguments (including
any receiver).
The dictionary argument is checked for validity, but is otherwise unused.
Subsequent CLs will start using the dictionary for, e.g., converting a
value of generic type to interface{}.
Import/export required adding support for LINKSYMOFFSET, which is used
by the dictionary checking code.
Change-Id: I16a7a8d23c7bd6a897e0da87c69f273be9103bd7
Reviewed-on: https://go-review.googlesource.com/c/go/+/323272
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
working
The general idea is that we now export/import typeparams, typeparam
lists for generic types and functions, and instantiated types
(instantiations of generic types with either new typeparams or concrete
types).
This changes the export format -- the next CL in the stack adds the
export versions and checks for it in the appropriate places.
We always export/import generic function bodies, using the same code
that we use for exporting/importing the bodies of inlineable functions.
To avoid complicated scoping, we consider all type params as unique and
give them unique names for types1. We therefore include the types2 ids
(subscripts) in the export format and re-create on import. We always
access the same unique types1 typeParam type for the same typeparam
name.
We create fully-instantiated generic types and functions in the original
source package. We do an extra NeedRuntimeType() call to make sure that
the correct DWARF information is written out. We call SetDupOK(true) for
the functions/methods to have the linker automatically drop duplicate
instantiations.
Other miscellaneous details:
- Export/import of typeparam bounds works for methods (but not
typelists) for now, but will change with the typeset changes.
- Added a new types.Instantiate function roughly analogous to the
types2.Instantiate function recently added.
- Always access methods info from the original/base generic type, since
the methods of an instantiated type are not filled in (in types2 or
types1).
- New field OrigSym in types.Type to keep track of base generic type
that instantiated type was based on. We use the generic type's symbol
(OrigSym) as the link, rather than a Type pointer, since we haven't
always created the base type yet when we want to set the link (during
types2 to types1 conversion).
- Added types2.AsTypeParam(), (*types2.TypeParam).SetId()
- New test minimp.dir, which tests use of generic function Min across
packages. Another test stringimp.dir, which also exports a generic
function Stringify across packages, where the type param has a bound
(Stringer) as well. New test pairimp.dir, which tests use of generic
type Pair (with no methods) across packages.
- New test valimp.dir, which tests use of generic type (with methods
and related functions) across packages.
- Modified several other tests (adder.go, settable.go, smallest.go,
stringable.go, struct.go, sum.go) to export their generic
functions/types to show that generic functions/types can be exported
successfully (but this doesn't test import).
Change-Id: Ie61ce9d54a46d368ddc7a76c41399378963bb57f
Reviewed-on: https://go-review.googlesource.com/c/go/+/319930
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
|
|
Make the base type of targ a *types.Type instead of an ir.Node
containing a type.
Also move makeInstName to typecheck, so it can later be used by
reflectdata for making wrappers.
Change-Id: If148beaa972e5112ead2771d6e32d73f16ca30c1
Reviewed-on: https://go-review.googlesource.com/c/go/+/321209
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
Panic if the slice is too short.
Updates #395
Change-Id: I90f4bff2da5d8f3148ba06d2482084f32b25c29a
Reviewed-on: https://go-review.googlesource.com/c/go/+/301650
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
|
|
types.Type instead
Confusingly, the set of all methods of an interface is currently set in
Fields field of types.Interface. This is true, even though there is
already an allMethods field (and AllMethods method) of types.Type.
Change so the set of all methods of an interface are stored in
Type.allMethods, and Interface.Fields is removed. Update the comments
for Methods and AllMethods.
Change-Id: Ibc32bafae86831cba62606b079a855690612c759
Reviewed-on: https://go-review.googlesource.com/c/go/+/307209
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
|
|
Pull out the transformation part of the typechecking functions for:
- assignment statements
- return statements
- send statements
- select statements
- type conversions
- normal function/method calls
- index operations
The transform functions are like the original typechecking functions,
but with all code removed related to:
- Detecting compile-time errors (already done by types2)
- Setting the actual type of existing nodes (already done based on
info from types2)
- Dealing with untyped constants
Moved all the transformation functions to a separate file, transform.go.
Continuing with the same pattern, we delay transforming a node if it has
any type params in its args, marking it with a typecheck flag of 3, and
do the actual transformation during stenciling.
Assignment statements are tricky, since their transformation must be
delayed if any of the left or right-hands-sides are delayed.
Still to do are:
- selector expressions (OXDOT)
- composite literal expressions (OCOMPLIT)
- builtin function calls
Change-Id: Ie608cadbbc69b40db0067a5536cf707dd974aacc
Reviewed-on: https://go-review.googlesource.com/c/go/+/304049
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
|
|
For additions, compares, and slices, create transform functions that do
just the transformations for those nodes by the typecheck package (given
that the code has been fully typechecked by types2). For nodes that have
no args with typeparams, we call these transform functions directly in
noder2. But for nodes that have args with typeparams, we have to delay
and call the tranform functions during stenciling, since we don't know
the specific types involved.
We indicate that a node still needs transformation by setting Typecheck
to a new value 3. This value means the current type of the node has been
set (via types2), but the node may still need transformation.
Had to export typcheck.IsCmp and typecheck.Assignop from the typecheck
package.
Added new tests list2.go (required delaying compare typecheck/transform
because of != compare in checkList) and adder.go (requires delaying add
typecheck/transform, since it can do addition for numbers or strings).
There are several more transformation functions needed for expressions
(indexing, calls, etc.) and several more complicated ones needed for
statements (mainly various kinds of assignments).
Change-Id: I7d89d13a4108308ea0304a4b815ab60b40c59b0a
Reviewed-on: https://go-review.googlesource.com/c/go/+/303091
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
|
|
ComputeAddrtaken needs to descend into closures, now that imported
bodies can include closures. The bug was that we weren't properly
setting Addrtaken for a variable inside a closure inside a function that
we were importing.
For now, still disable inlining of functions with closures for -G mode.
I'll enable it in a later change -- there are just a few fixes related
to the fact that we don't need to set Ntype for closure functions.
Added a test derived from the cilium repro in the issue.
Fixes #44370
Change-Id: Ida2a403636bf8740b471b3ad68b5474951811e19
Reviewed-on: https://go-review.googlesource.com/c/go/+/296649
Run-TryBot: Dan Scales <danscales@google.com>
Trust: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
|
|
This CL backports a bunch of changes that landed on dev.typeparams,
but are not dependent on types2 or generics. By backporting, we reduce
the divergence between development branches, hopefully improving test
coverage and reducing risk of merge conflicts.
Updates #43866.
Change-Id: I382510855c9b5fac52b17066e44a00bd07fe86f5
Reviewed-on: https://go-review.googlesource.com/c/go/+/286172
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
|
|
recent renames
Went in a semi-automated way through the clearest renames of functions,
and updated comments and error messages where it made sense.
Change-Id: Ied8e152b562b705da7f52f715991a77dab60da35
Reviewed-on: https://go-review.googlesource.com/c/go/+/284216
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
|
|
When exporting signature types, we include the originating package,
because it's exposed via go/types's API. And as a consistency check,
we ensure that the parameter names came from that same package.
However, we were getting this wrong in the case of exported variables
that were initialized with a method value using an imported method. In
this case, when we created the method value wrapper function's
type (which is reused as the variable's type if none is explicitly
provided in the variable declaration), we were reusing the
original (i.e., imported) parameter names, but the newly created
signature type was associated with the current package instead.
The correct fix here is really to preserve the original signature
type's package (along with position and name for its parameters), but
that's awkward to do at the moment because the DeclFunc API requires
an ir representation of the function signature, whereas we only
provide a way to explicitly set packages via the type constructor
APIs.
As an interim fix, we associate the parameters with the current
package, to be consistent with the signature type's package.
Fixes #43479.
Change-Id: Id45a10f8cf64165c9bc7d9598f0a0ee199a5e752
Reviewed-on: https://go-review.googlesource.com/c/go/+/281292
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
|
|
This commit splits up typecheck.Package and moves the code
elsewhere. The type-checking code is moved into noder, so that it can
eventually be interleaved with the noding process. The
non-type-checking code is moved back into package gc, so that it can
be incorporated into appropriate compiler backend phases.
While here, deadcode removal is moved into its own package.
Passes toolstash -cmp.
[git-generate]
cd src/cmd/compile/internal/typecheck
: Split into two functions.
sed -i -e '/Phase 6/i}\n\nfunc postTypecheck() {' typecheck.go
rf '
# Export needed identifiers.
mv deadcode Deadcode
mv loadsys InitRuntime
mv declareUniverse DeclareUniverse
mv dirtyAddrtaken DirtyAddrtaken
mv computeAddrtaken ComputeAddrtaken
mv incrementalAddrtaken IncrementalAddrtaken
# Move into new package.
mv Deadcode deadcodeslice deadcodeexpr deadcode.go
mv deadcode.go cmd/compile/internal/deadcode
# Move top-level type-checking code into noder.
# Move DeclVars there too, now that nothing else uses it.
mv DeclVars Package noder.go
mv noder.go cmd/compile/internal/noder
# Move non-type-checking code back into gc.
mv postTypecheck main.go
mv main.go cmd/compile/internal/gc
'
cd ../deadcode
rf '
# Destutter names.
mv Deadcode Func
mv deadcodeslice stmts
mv deadcodeexpr expr
'
cd ../noder
rf '
# Move functions up, next to their related code.
mv noder.go:/func Package/-1,$ \
noder.go:/makeSrcPosBase translates/-1
mv noder.go:/func DeclVars/-3,$ \
noder.go:/constState tracks/-1
'
cd ../gc
rf '
# Inline postTypecheck code back into gc.Main.
mv main.go:/func postTypecheck/+0,/AllImportedBodies/+1 \
main.go:/Build init task/-1
rm postTypecheck
'
Change-Id: Ie5e992ece4a42204cce6aa98dd6eb52112d098c8
Reviewed-on: https://go-review.googlesource.com/c/go/+/280974
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
|
|
Change-Id: I2732aefe95a21c23d73a907d5596fcb1626d6dd7
Reviewed-on: https://go-review.googlesource.com/c/go/+/275697
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
typechecker
This CL computes a second parallel addrtaken bit that we check
against the old way of doing it. A subsequent CL will rip out the
typechecker code and just use the new way.
Change-Id: I62b7342c44f694144844695386f80088bbd40bf4
Reviewed-on: https://go-review.googlesource.com/c/go/+/275695
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
|
|
typecheck1 is the largest non-machine-generated function in the compiler.
weighing in at 1,747 lines. Since we are destroying the git blame history
anyway, now is a good time to split each different case into its own function,
making future work on this function more manageable.
[git-generate]
cd src/cmd/compile/internal/typecheck
rf '
# Remove tracing print from typecheck1 - the one in typecheck is fine.
# Removing it lets us remove the named result.
# That lets all the cut-out functions not have named results.
rm typecheck.go:/^func typecheck1/+0,/^func typecheck1/+4
sub typecheck.go:/^func typecheck1/+/\(res ir\.Node\)/ ir.Node
mv typecheckselect tcSelect
mv typecheckswitch tcSwitch
mv typecheckrange tcRange
mv typecheckfunc tcFunc
mv checkdefergo tcGoDefer
mv typecheckclosure tcClosure
mv check typecheck
mv typecheckcomplit tcCompLit
mv typecheckas tcAssign
mv typecheckas2 tcAssignList
mv typecheckpartialcall tcCallPart
mv typecheckExprSwitch tcSwitchExpr
mv typecheckTypeSwitch tcSwitchType
mv typecheck1:/^\tcase ir.ORETURN:/+2,/^\tcase /-2 tcReturn
add typecheck.go:/^func tcReturn/-0 \
// tcReturn typechecks an ORETURN node.
mv typecheck1:/^\tcase ir.OIF:/+2,/^\tcase /-2 tcIf
add typecheck.go:/^func tcIf/-0 \
// tcIf typechecks an OIF node.
mv typecheck1:/^\tcase ir.OFOR,/+2,/^\tcase /-2 tcFor
add typecheck.go:/^func tcFor/-0 \
// tcFor typechecks an OFOR node.
mv typecheck1:/^\tcase ir.OSPTR:/+2,/^\tcase /-2 tcSPtr
add typecheck.go:/^func tcSPtr/-0 \
// tcSPtr typechecks an OSPTR node.
mv typecheck1:/^\tcase ir.OITAB:/+2,/^\tcase /-2 tcITab
add typecheck.go:/^func tcITab/-0 \
// tcITab typechecks an OITAB node.
mv typecheck1:/^\tcase ir.ORECOVER:/+2,/^\tcase /-2 tcRecover
add typecheck.go:/^func tcRecover/-0 \
// tcRecover typechecks an ORECOVER node.
mv typecheck1:/^\tcase ir.OPANIC:/+2,/^\tcase /-2 tcPanic
add typecheck.go:/^func tcPanic/-0 \
// tcPanic typechecks an OPANIC node.
mv typecheck1:/^\tcase ir.OPRINT,/+2,/^\tcase /-2 tcPrint
add typecheck.go:/^func tcPrint/-0 \
// tcPrint typechecks an OPRINT or OPRINTN node.
mv typecheck1:/^\tcase ir.ONEW:/+2,/^\tcase /-2 tcNew
add typecheck.go:/^func tcNew/-0 \
// tcNew typechecks an ONEW node.
mv typecheck1:/^\tcase ir.OMAKE:/+2,/^\tcase /-2 tcMake
add typecheck.go:/^func tcMake/-0 \
// tcMake typechecks an OMAKE node.
mv typecheck1:/^\tcase ir.OCONV:/+2,/^\tcase /-2 tcConv
add typecheck.go:/^func tcConv/-0 \
// tcConv typechecks an OCONV node.
mv typecheck1:/^\tcase ir.OCOPY:/+2,/^\tcase /-2 tcCopy
add typecheck.go:/^func tcCopy/-0 \
// tcCopy typechecks an OCOPY node.
mv typecheck1:/^\tcase ir.OAPPEND:/+2,/^\tcase /-2 tcAppend
add typecheck.go:/^func tcAppend/-0 \
// tcAppend typechecks an OAPPEND node.
mv typecheck1:/^\tcase ir.ODELETE:/+2,/^\tcase /-2 tcDelete
add typecheck.go:/^func tcDelete/-0 \
// tcDelete typechecks an ODELETE node.
mv typecheck1:/^\tcase ir.OCLOSE:/+2,/^\tcase /-2 tcClose
add typecheck.go:/^func tcClose/-0 \
// tcClose typechecks an OCLOSE node.
mv typecheck1:/^\tcase ir.OCOMPLEX:/+2,/^\tcase /-2 tcComplex
add typecheck.go:/^func tcComplex/-0 \
// tcComplex typechecks an OCOMPLEX node.
mv typecheck1:/^\tcase ir.OREAL,/+2,/^\tcase /-2 tcRealImag
add typecheck.go:/^func tcRealImag/-0 \
// tcRealImag typechecks an OREAL or OIMAG node.
mv typecheck1:/^\tcase ir.OCAP,/+2,/^\tcase /-2 tcLenCap
add typecheck.go:/^func tcLenCap/-0 \
// tcLenCap typechecks an OLEN or OCAP node.
mv typecheck1:/^\tcase ir.OCALL:/+2,/^\tcase /-2 tcCall
add typecheck.go:/^func tcCall/-0 \
// tcCall typechecks an OCALL node.
mv typecheck1:/^\tcase ir.OSLICE,/+2,/^\tcase /-3 tcSlice
add typecheck.go:/^func tcSlice/-0 \
// tcSlice typechecks an OSLICE or OSLICE3 node.
# move type assertion above comment
mv typecheck1:/^\tcase ir.OMAKESLICECOPY:/+/n := n/-+ typecheck1:/^\tcase ir.OMAKESLICECOPY:/+0
mv typecheck1:/^\tcase ir.OMAKESLICECOPY:/+2,/^\tcase /-2 tcMakeSliceCopy
add typecheck.go:/^func tcMakeSliceCopy/-0 \
// tcMakeSliceCopy typechecks an OMAKESLICECOPY node.
# move type assertion above comment
mv typecheck1:/^\tcase ir.OSLICEHEADER:/+/n := n/-+ typecheck1:/^\tcase ir.OSLICEHEADER:/+0
mv typecheck1:/^\tcase ir.OSLICEHEADER:/+2,/^\tcase /-2 tcSliceHeader
add typecheck.go:/^func tcSliceHeader/-0 \
// tcSliceHeader typechecks an OSLICEHEADER node.
mv typecheck1:/^\tcase ir.OSEND:/+2,/^\tcase /-2 tcSend
add typecheck.go:/^func tcSend/-0 \
// tcSend typechecks an OSEND node.
mv typecheck1:/^\tcase ir.ORECV:/+2,/^\tcase /-2 tcRecv
add typecheck.go:/^func tcRecv/-0 \
// tcRecv typechecks an ORECV node.
mv typecheck1:/^\tcase ir.OINDEX:/+2,/^\tcase /-2 tcIndex
add typecheck.go:/^func tcIndex/-0 \
// tcIndex typechecks an OINDEX node.
mv typecheck1:/^\tcase ir.ODOTTYPE:/+2,/^\tcase /-2 tcDotType
add typecheck.go:/^func tcDotType/-0 \
// tcDotType typechecks an ODOTTYPE node.
mv typecheck1:/^\tcase ir.OXDOT,/+2,/^\tcase /-2 tcDot
add typecheck.go:/^func tcDot/-0 \
// tcDot typechecks an OXDOT or ODOT node.
mv typecheck1:/^\tcase ir.OADDR:/+2,/^\tcase /-2 tcAddr
add typecheck.go:/^func tcAddr/-0 \
// tcAddr typechecks an OADDR node.
mv typecheck1:/^\tcase ir.OBITNOT,/+2,/^\tcase /-3 tcUnaryArith
add typecheck.go:/^func tcUnaryArith/-0 \
// tcUnaryArith typechecks a unary arithmetic expression.
mv typecheck1:/^\t\tir.OXOR:/+1,/^\tcase /-2 tcArith
add typecheck.go:/^func tcArith/-0 \
// tcArith typechecks a binary arithmetic expression.
mv typecheck1:/^\tcase ir.ODEREF:/+2,/^\tcase /-2 tcStar
add typecheck.go:/^func tcStar/-0 \
// tcStar typechecks an ODEREF node, which may be an expression or a type.
mv typecheck1:/^\tcase ir.OTFUNC:/+2,/^\tcase /-2 tcFuncType
add typecheck.go:/^func tcFuncType/-0 \
// tcFuncType typechecks an OTFUNC node.
mv typecheck1:/^\tcase ir.OTINTER:/+2,/^\tcase /-2 tcInterfaceType
add typecheck.go:/^func tcInterfaceType/-0 \
// tcInterfaceType typechecks an OTINTER node.
mv typecheck1:/^\tcase ir.OTSTRUCT:/+2,/^\tcase /-2 tcStructType
add typecheck.go:/^func tcStructType/-0 \
// tcStructType typechecks an OTSTRUCT node.
mv typecheck1:/^\tcase ir.OTCHAN:/+2,/^\tcase /-2 tcChanType
add typecheck.go:/^func tcChanType/-0 \
// tcChanType typechecks an OTCHAN node.
mv typecheck1:/^\tcase ir.OTMAP:/+2,/^\tcase /-2 tcMapType
add typecheck.go:/^func tcMapType/-0 \
// tcMapType typechecks an OTMAP node.
mv typecheck1:/^\tcase ir.OTARRAY:/+2,/^\tcase /-2 tcArrayType
add typecheck.go:/^func tcArrayType/-0 \
// tcArrayType typechecks an OTARRAY node.
mv typecheck1:/^\tcase ir.OTSLICE:/+2,/^\tcase /-2 tcSliceType
add typecheck.go:/^func tcSliceType/-0 \
// tcSliceType typechecks an OTSLICE node.
mv \
tcAssign \
tcAssignList \
tcFor \
tcGoDefer \
tcIf \
tcRange \
tcReturn \
tcSelect \
tcSend \
tcSwitch \
tcSwitchExpr \
tcSwitchType \
typeSet \
typeSetEntry \
typeSet.add \
stmt1.go
mv stmt1.go stmt.go
mv \
tcAddr \
tcArith \
tcArrayType \
tcChanType \
tcClosure \
tcCompLit \
tcConv \
tcDot \
tcDotType \
tcFuncType \
tcITab \
tcIndex \
tcInterfaceType \
tcLenCap \
tcMapType \
tcRecv \
tcSPtr \
tcSlice \
tcSliceHeader \
tcSliceType \
tcStar \
tcStructType \
tcUnaryArith \
expr.go
mv \
tcClosure \
tcCallPart \
tcFunc \
tcCall \
tcAppend \
tcClose \
tcComplex \
tcCopy \
tcDelete \
tcMake \
tcMakeSliceCopy \
tcNew \
tcPanic \
tcPrint \
tcRealImag \
tcRecover \
func1.go
mv func1.go func.go
mv \
tcArrayType \
tcChanType \
tcFuncType \
tcInterfaceType \
tcMapType \
tcSliceType \
tcStructType \
type.go
'
Change-Id: I0fb0a3039005bc1783575291daff1e6c306895ff
Reviewed-on: https://go-review.googlesource.com/c/go/+/279429
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
|
|
This commit splits the typechecking logic into its own package,
the first of a sequence of CLs to break package gc into more
manageable units.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
# The binary import/export has to be part of typechecking,
# because we load inlined function bodies lazily, but "exporter"
# should not be. Move that out of bexport.go.
mv exporter exporter.markObject exporter.markType export.go
# Use the typechecking helpers, so that the calls left behind
# in package gc do not need access to ctxExpr etc.
ex {
import "cmd/compile/internal/ir"
# TODO(rsc): Should not be necessary.
avoid TypecheckExpr
avoid TypecheckStmt
avoid TypecheckExprs
avoid TypecheckStmts
avoid TypecheckAssignExpr
avoid TypecheckCallee
var n ir.Node
var ns []ir.Node
typecheck(n, ctxExpr) -> TypecheckExpr(n)
typecheck(n, ctxStmt) -> TypecheckStmt(n)
typecheckslice(ns, ctxExpr) -> TypecheckExprs(ns)
typecheckslice(ns, ctxStmt) -> TypecheckStmts(ns)
typecheck(n, ctxExpr|ctxAssign) -> TypecheckAssignExpr(n)
typecheck(n, ctxExpr|ctxCallee) -> TypecheckCallee(n)
}
# Move some typechecking API to typecheck.
mv syslook LookupRuntime
mv substArgTypes SubstArgTypes
mv LookupRuntime SubstArgTypes syms.go
mv conv Conv
mv convnop ConvNop
mv Conv ConvNop typecheck.go
mv colasdefn AssignDefn
mv colasname assignableName
mv Target target.go
mv initname autoexport exportsym dcl.go
mv exportsym Export
# Export API to be called from outside typecheck.
# The ones with "Typecheck" prefixes will be renamed later to drop the prefix.
mv adddot AddImplicitDots
mv assignconv AssignConv
mv expandmeth CalcMethods
mv capturevarscomplete CaptureVarsComplete
mv checkMapKeys CheckMapKeys
mv checkreturn CheckReturn
mv dclcontext DeclContext
mv dclfunc DeclFunc
mv declare Declare
mv dotImportRefs DotImportRefs
mv declImporter DeclImporter
mv variter DeclVars
mv defaultlit DefaultLit
mv evalConst EvalConst
mv expandInline ImportBody
mv finishUniverse declareUniverse
mv funcbody FinishFuncBody
mv funchdr StartFuncBody
mv indexconst IndexConst
mv initTodo InitTodoFunc
mv lookup Lookup
mv resolve Resolve
mv lookupN LookupNum
mv nodAddr NodAddr
mv nodAddrAt NodAddrAt
mv nodnil NodNil
mv origBoolConst OrigBool
mv origConst OrigConst
mv origIntConst OrigInt
mv redeclare Redeclared
mv tostruct NewStructType
mv functype NewFuncType
mv methodfunc NewMethodType
mv structargs NewFuncParams
mv temp Temp
mv tempAt TempAt
mv typecheckok TypecheckAllowed
mv typecheck _typecheck # make room for typecheck pkg
mv typecheckinl TypecheckImportedBody
mv typecheckFunc TypecheckFunc
mv iimport ReadImports
mv iexport WriteExports
mv sysfunc LookupRuntimeFunc
mv sysvar LookupRuntimeVar
# Move function constructors to typecheck.
mv mkdotargslice MakeDotArgs
mv fixVariadicCall FixVariadicCall
mv closureType ClosureType
mv partialCallType PartialCallType
mv capturevars CaptureVars
mv MakeDotArgs FixVariadicCall ClosureType PartialCallType CaptureVars typecheckclosure func.go
mv autolabel AutoLabel
mv AutoLabel syms.go
mv Dlist dlist
mv Symlink symlink
mv \
AssignDefn assignableName \
AssignConv \
CaptureVarsComplete \
DeclContext \
DeclFunc \
DeclImporter \
DeclVars \
Declare \
DotImportRefs \
Export \
InitTodoFunc \
Lookup \
LookupNum \
LookupRuntimeFunc \
LookupRuntimeVar \
NewFuncParams \
NewName \
NodAddr \
NodAddrAt \
NodNil \
Redeclared \
StartFuncBody \
FinishFuncBody \
TypecheckImportedBody \
AddImplicitDots \
CalcMethods \
CheckFuncStack \
NewFuncType \
NewMethodType \
NewStructType \
TypecheckAllowed \
Temp \
TempAt \
adddot1 \
dotlist \
addmethod \
assignconvfn \
assignop \
autotmpname \
autoexport \
bexport.go \
checkdupfields \
checkembeddedtype \
closurename \
convertop \
declare_typegen \
decldepth \
dlist \
dotpath \
expand0 \
expand1 \
expandDecl \
fakeRecvField \
fnpkg \
funcStack \
funcStackEnt \
funcarg \
funcarg2 \
funcargs \
funcargs2 \
globClosgen \
ifacelookdot \
implements \
importalias \
importconst \
importfunc \
importobj \
importsym \
importtype \
importvar \
inimport \
initname \
isptrto \
loadsys \
lookdot0 \
lookdot1 \
makepartialcall \
okfor \
okforlen \
operandType \
slist \
symlink \
tointerface \
typeSet \
typeSet.add \
typeSetEntry \
typecheckExprSwitch \
typecheckTypeSwitch \
typecheckpartialcall \
typecheckrange \
typecheckrangeExpr \
typecheckselect \
typecheckswitch \
vargen \
builtin.go \
builtin_test.go \
const.go \
func.go \
iexport.go \
iimport.go \
mapfile_mmap.go \
syms.go \
target.go \
typecheck.go \
unsafe.go \
universe.go \
cmd/compile/internal/typecheck
'
rm gen.go types.go types_acc.go
sed -i '' 's/package gc/package typecheck/' mapfile_read.go mkbuiltin.go
mv mapfile_read.go ../typecheck # not part of default build
mv mkbuiltin.go ../typecheck # package main helper
mv builtin ../typecheck
cd ../typecheck
mv dcl.go dcl1.go
mv typecheck.go typecheck1.go
mv universe.go universe1.go
rf '
# Sweep some small files into larger ones.
# "mv sym... file1.go file.go" (after the mv file1.go file.go above)
# lets us insert sym... at the top of file.go.
mv okfor okforeq universe1.go universe.go
mv DeclContext vargen dcl1.go Temp TempAt autotmpname NewMethodType dcl.go
mv InitTodoFunc inimport decldepth TypecheckAllowed typecheck1.go typecheck.go
mv inl.go closure.go func.go
mv range.go select.go swt.go stmt.go
mv Lookup loadsys LookupRuntimeFunc LookupRuntimeVar syms.go
mv unsafe.go const.go
mv TypecheckAssignExpr AssignExpr
mv TypecheckExpr Expr
mv TypecheckStmt Stmt
mv TypecheckExprs Exprs
mv TypecheckStmts Stmts
mv TypecheckCall Call
mv TypecheckCallee Callee
mv _typecheck check
mv TypecheckFunc Func
mv TypecheckFuncBody FuncBody
mv TypecheckImports AllImportedBodies
mv TypecheckImportedBody ImportedBody
mv TypecheckInit Init
mv TypecheckPackage Package
'
rm gen.go go.go init.go main.go reflect.go
Change-Id: Iea6a7aaf6407d690670ec58aeb36cc0b280f80b0
Reviewed-on: https://go-review.googlesource.com/c/go/+/279236
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
|