-
Notifications
You must be signed in to change notification settings - Fork 18.1k
gccgo: non-canonical reflect.Type #25284
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
Comments
Definitely a bug, but hard to fix. |
Would you care to elaborate why it's hard to fix? I naively thought that a canonicalizing map from reflect.Type to reflect.Type, analogous to what golang.org/x/tools/go/types/typeutil.Map does for go/types.Type, would suffice [Update] multiple calls to |
Yes, we already have a canonicaizing map in gccgo's version of the reflect package. What we don't have is a mechanism for efficiently entering the program defined types into that map. The gc toolchain builds a list of program defined types in the linker. But doing this efficiently without massive duplication requires linker support that gccgo doesn't have. What we need is some mechanism that only introduces a performance cost for the very rare programs that call |
Having examined gcc-20180425/libgo/go/reflect/type.go, I have an idea that only touches it's basically about returning canonicalize(ti.(Type)) instead of ti.(Type) as last statement in SliceOf() - I will describe more in detail in the next days, because there are some non-trivial interactions between the several maps: lookupCache, funcLookupCache, structLookupCache and canonicalType |
Here are the details: in my opinion there are at least three alternative fixes
Does it make sense to you? |
I don't understand why calling |
You're right in one point: at program startup they will not be in that map. But all other functions that return a reflect.Type (reflect.TypeOf(), reflect.Value.Type() and many others) already invoke canonicalize() indirectly through toType(), so the canonicalType map will be populated on-demand as a side effect of retrieving reflect.Types. If you want, I have a patch - and a test suite showing that the patch is effective at least in the tested cases |
Ah, of course, got it. Yes, clearly all the reflect functions should return via |
Good , thanks :) If you need just the patch and test suite, here they are: For the formal contribution procedure to gccgo I will need a bit more time |
Thanks. I'm not going to look at the patches to avoid any copyright issues. You should be able to contribute to gofrontend using a Github pull request if you like. |
Sent the patch using the official channel :) |
Sent new patch following Ian's recommendation: https://go-review.googlesource.com/115577 |
Change https://golang.org/cl/115635 mentions this issue: |
gccgo fails this test before CL 115577. Updates #25284 Change-Id: Id4550b7b3e268f3c294420ed31c57ad3f1002b5e Reviewed-on: https://go-review.googlesource.com/115635 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
Change https://golang.org/cl/115577 mentions this issue: |
Background: since gccgo does not currently merge identical types at link time, the reflect function canonicalize() exists to choose a canonical specimen for each set of identical types. In this way, user code has the guarantee that identical types will always compare as == Change: arrange reflect functions MapOf(), SliceOf(), StructOf() etc. to call canonicalize() on the types they create, before storing the types in internal lookup caches and returning them. This fixes known cases where canonicalize() is needed but was missing. Supersedes https://golang.org/cl/112575 and mostly fixes issue 25284. Updates golang/go#25284 Change-Id: I5a71bf5ff4bbb2585a5b84072cb59af9e9d16518 Reviewed-on: https://go-review.googlesource.com/115577 Reviewed-by: Ian Lance Taylor <[email protected]>
Background: since gccgo does not currently merge identical types at link time, the reflect function canonicalize() exists to choose a canonical specimen for each set of identical types. In this way, user code has the guarantee that identical types will always compare as == Change: arrange reflect functions MapOf(), SliceOf(), StructOf() etc. to call canonicalize() on the types they create, before storing the types in internal lookup caches and returning them. This fixes known cases where canonicalize() is needed but was missing. Supersedes https://golang.org/cl/112575 and mostly fixes issue 25284. Updates golang/go#25284 Reviewed-on: https://go-review.googlesource.com/115577 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@261216 138bc75d-0d04-0410-961f-82ee72b054a4
This test still passes with gc but fails with gccgo: package main
import (
"fmt"
"reflect"
)
func main() {
type Interface interface{}
t1 := reflect.StructOf([]reflect.StructField{
{
Name: "I",
Type: reflect.TypeOf((*Interface)(nil)).Elem(),
},
})
t2 := reflect.TypeOf(struct { I Interface }{nil})
fmt.Println(t1 == t2)
} |
Change https://golang.org/cl/116416 mentions this issue: |
Change https://golang.org/cl/116515 mentions this issue: |
Exactly. |
Updates #25284 Change-Id: I8ca382dd85b428ad6899d9277cf7f3ce34e35e9a Reviewed-on: https://go-review.googlesource.com/116416 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
@cosmos72 I sent a fix in https://golang.org/cl/116515. Thanks for uncovering the problem. |
Adjust the hash and string fields computed by StructOf to match the values that the compiler computes for a struct type with the same field names and types. This makes the reflect code match the compiler's Type::hash_for_method and Type::reflection methods. Fixes golang/go#25284 Reviewed-on: https://go-review.googlesource.com/116515 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@261235 138bc75d-0d04-0410-961f-82ee72b054a4
Adjust the hash and string fields computed by StructOf to match the values that the compiler computes for a struct type with the same field names and types. This makes the reflect code match the compiler's Type::hash_for_method and Type::reflection methods. Fixes golang/go#25284 Reviewed-on: https://go-review.googlesource.com/116515 From-SVN: r261235
Uh oh!
There was an error while loading. Please reload this page.
Please answer these questions before submitting your issue. Thanks!
What did you do?
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
Created a reflect.Type with
reflect.SliceOf()
and compared againstreflect.TypeOf([]int{})
.See https://play.golang.org/p/ua1-JdssJSF
What did you expect to see?
good: []int == []int
instances of
reflect.TypeOf([]int{})
should be canonical, i.e. == shoud return true, no matter how they are created: with reflection, or any other means - see https://golang.org/pkg/reflect/#TypeWhat did you see instead?
BAD: []int != []int
On gccgo, the reflect.Type created with
reflect.SliceOf()
compares as different thanreflect.TypeOf([]int{})
The same issue happens at least with
reflect.FuncOf()
, see https://play.golang.org/p/_t5enrDarXtso an educated guess is that instances of reflect.Type are not always canonicalized.
Does this issue reproduce with the latest release (go1.10.2)?
Only the gccgo compiler shows this issue. Tested on:
go version go1.10 gccgo (Debian 8.1.0-1) 8.1.0 linux/amd64
System details
The text was updated successfully, but these errors were encountered: