github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/types/identity.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types 6 7 // Identical reports whether t1 and t2 are identical types, following 8 // the spec rules. Receiver parameter types are ignored. 9 func Identical(t1, t2 *Type) bool { 10 return identical(t1, t2, true, nil) 11 } 12 13 // IdenticalIgnoreTags is like Identical, but it ignores struct tags 14 // for struct identity. 15 func IdenticalIgnoreTags(t1, t2 *Type) bool { 16 return identical(t1, t2, false, nil) 17 } 18 19 type typePair struct { 20 t1 *Type 21 t2 *Type 22 } 23 24 func identical(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) bool { 25 if t1 == t2 { 26 return true 27 } 28 if t1 == nil || t2 == nil || t1.Etype != t2.Etype || t1.Broke() || t2.Broke() { 29 return false 30 } 31 if t1.Sym != nil || t2.Sym != nil { 32 // Special case: we keep byte/uint8 and rune/int32 33 // separate for error messages. Treat them as equal. 34 switch t1.Etype { 35 case TUINT8: 36 return (t1 == Types[TUINT8] || t1 == Bytetype) && (t2 == Types[TUINT8] || t2 == Bytetype) 37 case TINT32: 38 return (t1 == Types[TINT32] || t1 == Runetype) && (t2 == Types[TINT32] || t2 == Runetype) 39 default: 40 return false 41 } 42 } 43 44 // Any cyclic type must go through a named type, and if one is 45 // named, it is only identical to the other if they are the 46 // same pointer (t1 == t2), so there's no chance of chasing 47 // cycles ad infinitum, so no need for a depth counter. 48 if assumedEqual == nil { 49 assumedEqual = make(map[typePair]struct{}) 50 } else if _, ok := assumedEqual[typePair{t1, t2}]; ok { 51 return true 52 } 53 assumedEqual[typePair{t1, t2}] = struct{}{} 54 55 switch t1.Etype { 56 case TIDEAL: 57 // Historically, cmd/compile used a single "untyped 58 // number" type, so all untyped number types were 59 // identical. Match this behavior. 60 // TODO(mdempsky): Revisit this. 61 return true 62 63 case TINTER: 64 if t1.NumFields() != t2.NumFields() { 65 return false 66 } 67 for i, f1 := range t1.FieldSlice() { 68 f2 := t2.Field(i) 69 if f1.Sym != f2.Sym || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) { 70 return false 71 } 72 } 73 return true 74 75 case TSTRUCT: 76 if t1.NumFields() != t2.NumFields() { 77 return false 78 } 79 for i, f1 := range t1.FieldSlice() { 80 f2 := t2.Field(i) 81 if f1.Sym != f2.Sym || f1.Embedded != f2.Embedded || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) { 82 return false 83 } 84 if cmpTags && f1.Note != f2.Note { 85 return false 86 } 87 } 88 return true 89 90 case TFUNC: 91 // Check parameters and result parameters for type equality. 92 // We intentionally ignore receiver parameters for type 93 // equality, because they're never relevant. 94 for _, f := range ParamsResults { 95 // Loop over fields in structs, ignoring argument names. 96 fs1, fs2 := f(t1).FieldSlice(), f(t2).FieldSlice() 97 if len(fs1) != len(fs2) { 98 return false 99 } 100 for i, f1 := range fs1 { 101 f2 := fs2[i] 102 if f1.IsDDD() != f2.IsDDD() || !identical(f1.Type, f2.Type, cmpTags, assumedEqual) { 103 return false 104 } 105 } 106 } 107 return true 108 109 case TARRAY: 110 if t1.NumElem() != t2.NumElem() { 111 return false 112 } 113 114 case TCHAN: 115 if t1.ChanDir() != t2.ChanDir() { 116 return false 117 } 118 119 case TMAP: 120 if !identical(t1.Key(), t2.Key(), cmpTags, assumedEqual) { 121 return false 122 } 123 } 124 125 return identical(t1.Elem(), t2.Elem(), cmpTags, assumedEqual) 126 }