1
0
mirror of https://github.com/golang/go synced 2024-07-03 00:40:45 +00:00

cmd/compile: fix identity case relating to 'any' and shape types

In identical(), we don't want any to match a shape empty-interface type
for the identStrict option, since IdenticalStrict() is specifically not
supposed to match a shape type with a non-shape type.

There is similar code in (*Type).cmp() (TINTER case), but I don't
believe that we want to disqualify shape types from matching any in this
case, since cmp() is used for back-end code, where we don't care about
shape types vs non-shape types.

The issue mainly comes about when 'any' is used as a type argument
(rather than 'interface{}'), but only with some complicated
circumstances, as shown by the test case. (Couldn't reproduce with
simpler test cases.)

Fixes #50109

Change-Id: I3f2f88be158f9ad09273237e1d346bc56aac099f
Reviewed-on: https://go-review.googlesource.com/c/go/+/371154
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-12-12 11:08:59 -08:00
parent 49b7c9caec
commit 9bfe09d78b
3 changed files with 111 additions and 1 deletions

View File

@ -59,7 +59,11 @@ func identical(t1, t2 *Type, flags int, assumedEqual map[typePair]struct{}) bool
case TINT32:
return (t1 == Types[TINT32] || t1 == RuneType) && (t2 == Types[TINT32] || t2 == RuneType)
case TINTER:
// Make sure named any type matches any empty interface.
// Make sure named any type matches any empty interface
// (but not a shape type, if identStrict).
if flags&identStrict != 0 {
return t1 == AnyType && t2.IsEmptyInterface() && !t2.HasShape() || t2 == AnyType && t1.IsEmptyInterface() && !t1.HasShape()
}
return t1 == AnyType && t2.IsEmptyInterface() || t2 == AnyType && t1.IsEmptyInterface()
default:
return false

View File

@ -0,0 +1,105 @@
// run -gcflags=-G=3
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
)
type AnyCacher[T any] interface {
// Get an item from the cache. Returns the item or nil, and a bool indicating
// whether the key was found.
Get(k string) (T, bool)
// Add an item to the cache, replacing any existing item.
Set(k string, x T)
}
// Item ...
type Item[T any] struct {
Object T
}
// AnyCache implements AnyCacher
type AnyCache[T any] struct {
*anyCache[T]
}
type anyCache[T any] struct {
items map[string]Item[T]
janitor *janitor[T] // Needed for the failure in the issue
}
// Set adds an item to the cache, replacing any existing item.
func (c *anyCache[T]) Set(k string, x T) {
c.items[k] = Item[T]{
Object: x,
}
}
// Get gets an item from the cache. Returns the item or nil, and a bool indicating
// whether the key was found.
func (c *anyCache[T]) Get(k string) (T, bool) {
// "Inlining" of get and Expired
item, found := c.items[k]
if !found {
var ret T
return ret, false
}
return item.Object, true
}
type janitor[T any] struct {
stop chan bool
}
func newAnyCache[T any](m map[string]Item[T]) *anyCache[T] {
c := &anyCache[T]{
items: m,
}
return c
}
// NewAny[T any](...) returns a new AnyCache[T].
func NewAny[T any]() *AnyCache[T] {
items := make(map[string]Item[T])
return &AnyCache[T]{newAnyCache(items)}
}
// NewAnyCacher[T any](...) returns an AnyCacher[T] interface.
func NewAnyCacher[T any]() AnyCacher[T] {
return NewAny[T]()
}
type MyStruct struct {
Name string
}
func main() {
// Create a generic cache.
// All items are cached as interface{} so they need to be cast back to their
// original type when retrieved.
// Failure in issue doesn't happen with 'any' replaced by 'interface{}'
c := NewAnyCacher[any]()
myStruct := &MyStruct{"MySuperStruct"}
c.Set("MySuperStruct", myStruct)
myRawCachedStruct, found := c.Get("MySuperStruct")
if found {
// Casting the retrieved object back to its original type
myCachedStruct := myRawCachedStruct.(*MyStruct)
fmt.Printf("%s", myCachedStruct.Name)
} else {
fmt.Printf("Error: MySuperStruct not found in cache")
}
// Output:
// MySuperStruct
}

View File

@ -0,0 +1 @@
MySuperStruct