Skip to content

Commit

Permalink
go/types: ignore struct tags when converting structs
Browse files Browse the repository at this point in the history
Implementation of spec change https://golang.org/cl/24190/.

For #16085.

Change-Id: I17bbbce38d98a169bc64e84983a7ebfe7142f6e9
Reviewed-on: https://go-review.googlesource.com/30190
Reviewed-by: Alan Donovan <adonovan@google.com>
  • Loading branch information
griesemer committed Oct 4, 2016
1 parent 3905570 commit f5b0012
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/go/types/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ var tests = [][]string{
{"testdata/shifts.src"},
{"testdata/builtins.src"},
{"testdata/conversions.src"},
{"testdata/conversions2.src"},
{"testdata/stmt0.src"},
{"testdata/stmt1.src"},
{"testdata/gotos.src"},
Expand Down
9 changes: 5 additions & 4 deletions src/go/types/conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,19 @@ func (x *operand) convertibleTo(conf *Config, T Type) bool {
return true
}

// "x's type and T have identical underlying types"
// "x's type and T have identical underlying types if tags are ignored"
V := x.typ
Vu := V.Underlying()
Tu := T.Underlying()
if Identical(Vu, Tu) {
if IdenticalIgnoreTags(Vu, Tu) {
return true
}

// "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
// "x's type and T are unnamed pointer types and their pointer base types
// have identical underlying types if tags are ignored"
if V, ok := V.(*Pointer); ok {
if T, ok := T.(*Pointer); ok {
if Identical(V.base.Underlying(), T.base.Underlying()) {
if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) {
return true
}
}
Expand Down
31 changes: 18 additions & 13 deletions src/go/types/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@ func hasNil(typ Type) bool {

// 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.
Expand All @@ -125,7 +130,7 @@ func (p *ifacePair) identical(q *ifacePair) bool {
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
}
Expand All @@ -143,13 +148,13 @@ func identical(x, y Type, p *ifacePair) bool {
// 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:
Expand All @@ -162,9 +167,9 @@ func identical(x, y Type, p *ifacePair) bool {
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
}
}
Expand All @@ -175,7 +180,7 @@ func identical(x, y Type, p *ifacePair) bool {
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:
Expand All @@ -186,7 +191,7 @@ func identical(x, y Type, p *ifacePair) bool {
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
}
}
Expand All @@ -202,8 +207,8 @@ func identical(x, y Type, p *ifacePair) bool {
// 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:
Expand Down Expand Up @@ -249,7 +254,7 @@ func identical(x, y Type, p *ifacePair) bool {
}
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
}
}
Expand All @@ -260,14 +265,14 @@ func identical(x, y Type, p *ifacePair) bool {
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:
Expand Down
Loading

0 comments on commit f5b0012

Please sign in to comment.