// Identical reports whether x and y are identical.
func Identical(x, y Type) bool {
- return identical(x, y, nil)
+ return identical(x, y, true, nil)
+}
+
+// IdenticalIgnoreTags reports whether x and y are identical if tags are ignored.
+func IdenticalIgnoreTags(x, y Type) bool {
+ return identical(x, y, false, nil)
}
// An ifacePair is a node in a stack of interface type pairs compared for identity.
return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
}
-func identical(x, y Type, p *ifacePair) bool {
+func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
if x == y {
return true
}
// Two array types are identical if they have identical element types
// and the same array length.
if y, ok := y.(*Array); ok {
- return x.len == y.len && identical(x.elem, y.elem, p)
+ return x.len == y.len && identical(x.elem, y.elem, cmpTags, p)
}
case *Slice:
// Two slice types are identical if they have identical element types.
if y, ok := y.(*Slice); ok {
- return identical(x.elem, y.elem, p)
+ return identical(x.elem, y.elem, cmpTags, p)
}
case *Struct:
for i, f := range x.fields {
g := y.fields[i]
if f.anonymous != g.anonymous ||
- x.Tag(i) != y.Tag(i) ||
+ cmpTags && x.Tag(i) != y.Tag(i) ||
!f.sameId(g.pkg, g.name) ||
- !identical(f.typ, g.typ, p) {
+ !identical(f.typ, g.typ, cmpTags, p) {
return false
}
}
case *Pointer:
// Two pointer types are identical if they have identical base types.
if y, ok := y.(*Pointer); ok {
- return identical(x.base, y.base, p)
+ return identical(x.base, y.base, cmpTags, p)
}
case *Tuple:
if x != nil {
for i, v := range x.vars {
w := y.vars[i]
- if !identical(v.typ, w.typ, p) {
+ if !identical(v.typ, w.typ, cmpTags, p) {
return false
}
}
// names are not required to match.
if y, ok := y.(*Signature); ok {
return x.variadic == y.variadic &&
- identical(x.params, y.params, p) &&
- identical(x.results, y.results, p)
+ identical(x.params, y.params, cmpTags, p) &&
+ identical(x.results, y.results, cmpTags, p)
}
case *Interface:
}
for i, f := range a {
g := b[i]
- if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
+ if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) {
return false
}
}
case *Map:
// Two map types are identical if they have identical key and value types.
if y, ok := y.(*Map); ok {
- return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
+ return identical(x.key, y.key, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p)
}
case *Chan:
// Two channel types are identical if they have identical value types
// and the same direction.
if y, ok := y.(*Chan); ok {
- return x.dir == y.dir && identical(x.elem, y.elem, p)
+ return x.dir == y.dir && identical(x.elem, y.elem, cmpTags, p)
}
case *Named:
--- /dev/null
+// Copyright 2016 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.
+
+// Test various valid and invalid struct assignments and conversions.
+// Does not compile.
+
+package conversions2
+
+type I interface {
+ m()
+}
+
+// conversions between structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s S
+ var t T
+ var u struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u
+ t = T(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t /* ERROR "cannot convert" */ )
+ s = S(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s S
+ var t T
+ var u struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u /* ERROR "cannot convert" */ )
+}
+
+// conversions between pointers to structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s *S
+ var t *T
+ var u *struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t /* ERROR "cannot convert" */ )
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u /* ERROR "cannot convert" */ )
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(*struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(*struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u /* ERROR "cannot convert" */ )
+}