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  }