Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / go / types / typeutil / identical.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/go/types/typeutil/identical.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/go/types/typeutil/identical.go
new file mode 100644 (file)
index 0000000..c0ca441
--- /dev/null
@@ -0,0 +1,75 @@
+package typeutil
+
+import (
+       "go/types"
+)
+
+// Identical reports whether x and y are identical types.
+// Unlike types.Identical, receivers of Signature types are not ignored.
+// Unlike types.Identical, interfaces are compared via pointer equality (except for the empty interface, which gets deduplicated).
+// Unlike types.Identical, structs are compared via pointer equality.
+func Identical(x, y types.Type) (ret bool) {
+       if !types.Identical(x, y) {
+               return false
+       }
+
+       switch x := x.(type) {
+       case *types.Struct:
+               y, ok := y.(*types.Struct)
+               if !ok {
+                       // should be impossible
+                       return true
+               }
+               return x == y
+       case *types.Interface:
+               // The issue with interfaces, typeutil.Map and types.Identical
+               //
+               // types.Identical, when comparing two interfaces, only looks at the set
+               // of all methods, not differentiating between implicit (embedded) and
+               // explicit methods.
+               //
+               // When we see the following two types, in source order
+               //
+               // type I1 interface { foo() }
+               // type I2 interface { I1 }
+               //
+               // then we will first correctly process I1 and its underlying type. When
+               // we get to I2, we will see that its underlying type is identical to
+               // that of I1 and not process it again. This, however, means that we will
+               // not record the fact that I2 embeds I1. If only I2 is reachable via the
+               // graph root, then I1 will not be considered used.
+               //
+               // We choose to be lazy and compare interfaces by their
+               // pointers. This will obviously miss identical interfaces,
+               // but this only has a runtime cost, it doesn't affect
+               // correctness.
+               y, ok := y.(*types.Interface)
+               if !ok {
+                       // should be impossible
+                       return true
+               }
+               if x.NumEmbeddeds() == 0 &&
+                       y.NumEmbeddeds() == 0 &&
+                       x.NumMethods() == 0 &&
+                       y.NumMethods() == 0 {
+                       // all truly empty interfaces are the same
+                       return true
+               }
+               return x == y
+       case *types.Signature:
+               y, ok := y.(*types.Signature)
+               if !ok {
+                       // should be impossible
+                       return true
+               }
+               if x.Recv() == y.Recv() {
+                       return true
+               }
+               if x.Recv() == nil || y.Recv() == nil {
+                       return false
+               }
+               return Identical(x.Recv().Type(), y.Recv().Type())
+       default:
+               return true
+       }
+}