From 3313880bdcb29d24dc5068b3a0f1bdd102c12b13 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 2 Feb 2023 14:16:23 -0800 Subject: [PATCH] go/types, types2: use a comparer struct to control the identical predicate This makes it easier to configure the behavior of identical: we can simply add fields to the comparer instead of adding more parameters to identical. Change-Id: I9a6f5451b3ee5c37e71486060653c5a6e8f24304 Reviewed-on: https://go-review.googlesource.com/c/go/+/464937 Auto-Submit: Robert Griesemer Reviewed-by: Robert Findley Run-TryBot: Robert Griesemer TryBot-Result: Gopher Robot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/api.go | 7 +++-- src/cmd/compile/internal/types2/predicates.go | 31 +++++++++++-------- src/go/types/api.go | 7 +++-- src/go/types/predicates.go | 31 +++++++++++-------- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index d9e6d5ad40..eebecce037 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -494,11 +494,14 @@ func Satisfies(V Type, T *Interface) bool { // Identical reports whether x and y are identical types. // Receivers of Signature types are ignored. func Identical(x, y Type) bool { - return identical(x, y, true, nil) + var c comparer + return c.identical(x, y, nil) } // IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. // Receivers of Signature types are ignored. func IdenticalIgnoreTags(x, y Type) bool { - return identical(x, y, false, nil) + var c comparer + c.ignoreTags = true + return c.identical(x, y, nil) } diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index acc1549084..c30badfe17 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -199,8 +199,13 @@ func (p *ifacePair) identical(q *ifacePair) bool { return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x } +// A comparer is used to compare types. +type comparer struct { + ignoreTags bool // if set, identical ignores struct tags +} + // For changes to this code the corresponding changes should be made to unifier.nify. -func identical(x, y Type, cmpTags bool, p *ifacePair) bool { +func (c *comparer) identical(x, y Type, p *ifacePair) bool { if x == y { return true } @@ -220,13 +225,13 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { if y, ok := y.(*Array); ok { // If one or both array lengths are unknown (< 0) due to some error, // assume they are the same to avoid spurious follow-on errors. - return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p) + return (x.len < 0 || y.len < 0 || x.len == y.len) && c.identical(x.elem, y.elem, 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, cmpTags, p) + return c.identical(x.elem, y.elem, p) } case *Struct: @@ -239,9 +244,9 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { for i, f := range x.fields { g := y.fields[i] if f.embedded != g.embedded || - cmpTags && x.Tag(i) != y.Tag(i) || + !c.ignoreTags && x.Tag(i) != y.Tag(i) || !f.sameId(g.pkg, g.name) || - !identical(f.typ, g.typ, cmpTags, p) { + !c.identical(f.typ, g.typ, p) { return false } } @@ -252,7 +257,7 @@ func identical(x, y Type, cmpTags bool, 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, cmpTags, p) + return c.identical(x.base, y.base, p) } case *Tuple: @@ -263,7 +268,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { if x != nil { for i, v := range x.vars { w := y.vars[i] - if !identical(v.typ, w.typ, cmpTags, p) { + if !c.identical(v.typ, w.typ, p) { return false } } @@ -311,7 +316,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // Constraints must be pair-wise identical, after substitution. for i, xtparam := range xtparams { ybound := check.subst(nopos, ytparams[i].bound, smap, nil, ctxt) - if !identical(xtparam.bound, ybound, cmpTags, p) { + if !c.identical(xtparam.bound, ybound, p) { return false } } @@ -321,8 +326,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { } return x.variadic == y.variadic && - identical(x.params, yparams, cmpTags, p) && - identical(x.results, yresults, cmpTags, p) + c.identical(x.params, yparams, p) && + c.identical(x.results, yresults, p) case *Union: if y, _ := y.(*Union); y != nil { @@ -389,7 +394,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { } for i, f := range a { g := b[i] - if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) { + if f.Id() != g.Id() || !c.identical(f.typ, g.typ, q) { return false } } @@ -400,14 +405,14 @@ func identical(x, y Type, cmpTags bool, 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, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p) + return c.identical(x.key, y.key, p) && c.identical(x.elem, y.elem, 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, cmpTags, p) + return x.dir == y.dir && c.identical(x.elem, y.elem, p) } case *Named: diff --git a/src/go/types/api.go b/src/go/types/api.go index d59e6d9b49..ae46ccaabb 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -480,11 +480,14 @@ func Satisfies(V Type, T *Interface) bool { // Identical reports whether x and y are identical types. // Receivers of Signature types are ignored. func Identical(x, y Type) bool { - return identical(x, y, true, nil) + var c comparer + return c.identical(x, y, nil) } // IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored. // Receivers of Signature types are ignored. func IdenticalIgnoreTags(x, y Type) bool { - return identical(x, y, false, nil) + var c comparer + c.ignoreTags = true + return c.identical(x, y, nil) } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 1927844732..9a156a040c 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -201,8 +201,13 @@ func (p *ifacePair) identical(q *ifacePair) bool { return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x } +// A comparer is used to compare types. +type comparer struct { + ignoreTags bool // if set, identical ignores struct tags +} + // For changes to this code the corresponding changes should be made to unifier.nify. -func identical(x, y Type, cmpTags bool, p *ifacePair) bool { +func (c *comparer) identical(x, y Type, p *ifacePair) bool { if x == y { return true } @@ -222,13 +227,13 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { if y, ok := y.(*Array); ok { // If one or both array lengths are unknown (< 0) due to some error, // assume they are the same to avoid spurious follow-on errors. - return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p) + return (x.len < 0 || y.len < 0 || x.len == y.len) && c.identical(x.elem, y.elem, 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, cmpTags, p) + return c.identical(x.elem, y.elem, p) } case *Struct: @@ -241,9 +246,9 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { for i, f := range x.fields { g := y.fields[i] if f.embedded != g.embedded || - cmpTags && x.Tag(i) != y.Tag(i) || + !c.ignoreTags && x.Tag(i) != y.Tag(i) || !f.sameId(g.pkg, g.name) || - !identical(f.typ, g.typ, cmpTags, p) { + !c.identical(f.typ, g.typ, p) { return false } } @@ -254,7 +259,7 @@ func identical(x, y Type, cmpTags bool, 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, cmpTags, p) + return c.identical(x.base, y.base, p) } case *Tuple: @@ -265,7 +270,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { if x != nil { for i, v := range x.vars { w := y.vars[i] - if !identical(v.typ, w.typ, cmpTags, p) { + if !c.identical(v.typ, w.typ, p) { return false } } @@ -313,7 +318,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { // Constraints must be pair-wise identical, after substitution. for i, xtparam := range xtparams { ybound := check.subst(nopos, ytparams[i].bound, smap, nil, ctxt) - if !identical(xtparam.bound, ybound, cmpTags, p) { + if !c.identical(xtparam.bound, ybound, p) { return false } } @@ -323,8 +328,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { } return x.variadic == y.variadic && - identical(x.params, yparams, cmpTags, p) && - identical(x.results, yresults, cmpTags, p) + c.identical(x.params, yparams, p) && + c.identical(x.results, yresults, p) case *Union: if y, _ := y.(*Union); y != nil { @@ -391,7 +396,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool { } for i, f := range a { g := b[i] - if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) { + if f.Id() != g.Id() || !c.identical(f.typ, g.typ, q) { return false } } @@ -402,14 +407,14 @@ func identical(x, y Type, cmpTags bool, 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, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p) + return c.identical(x.key, y.key, p) && c.identical(x.elem, y.elem, 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, cmpTags, p) + return x.dir == y.dir && c.identical(x.elem, y.elem, p) } case *Named: -- 2.48.1