github.com/99designs/gqlgen@v0.17.45/internal/code/compare.go (about) 1 package code 2 3 import ( 4 "fmt" 5 "go/types" 6 ) 7 8 // CompatibleTypes isnt a strict comparison, it allows for pointer differences 9 func CompatibleTypes(expected, actual types.Type) error { 10 // Special case to deal with pointer mismatches 11 { 12 expectedPtr, expectedIsPtr := expected.(*types.Pointer) 13 actualPtr, actualIsPtr := actual.(*types.Pointer) 14 15 if expectedIsPtr && actualIsPtr { 16 return CompatibleTypes(expectedPtr.Elem(), actualPtr.Elem()) 17 } 18 if expectedIsPtr && !actualIsPtr { 19 return CompatibleTypes(expectedPtr.Elem(), actual) 20 } 21 if !expectedIsPtr && actualIsPtr { 22 return CompatibleTypes(expected, actualPtr.Elem()) 23 } 24 } 25 26 switch expected := expected.(type) { 27 case *types.Slice: 28 if actual, ok := actual.(*types.Slice); ok { 29 return CompatibleTypes(expected.Elem(), actual.Elem()) 30 } 31 32 case *types.Array: 33 if actual, ok := actual.(*types.Array); ok { 34 if expected.Len() != actual.Len() { 35 return fmt.Errorf("array length differs") 36 } 37 38 return CompatibleTypes(expected.Elem(), actual.Elem()) 39 } 40 41 case *types.Basic: 42 if actual, ok := actual.(*types.Basic); ok { 43 if actual.Kind() != expected.Kind() { 44 return fmt.Errorf("basic kind differs, %s != %s", expected.Name(), actual.Name()) 45 } 46 47 return nil 48 } 49 50 case *types.Struct: 51 if actual, ok := actual.(*types.Struct); ok { 52 if expected.NumFields() != actual.NumFields() { 53 return fmt.Errorf("number of struct fields differ") 54 } 55 56 for i := 0; i < expected.NumFields(); i++ { 57 if expected.Field(i).Name() != actual.Field(i).Name() { 58 return fmt.Errorf("struct field %d name differs, %s != %s", i, expected.Field(i).Name(), actual.Field(i).Name()) 59 } 60 if err := CompatibleTypes(expected.Field(i).Type(), actual.Field(i).Type()); err != nil { 61 return err 62 } 63 } 64 return nil 65 } 66 67 case *types.Tuple: 68 if actual, ok := actual.(*types.Tuple); ok { 69 if expected.Len() != actual.Len() { 70 return fmt.Errorf("tuple length differs, %d != %d", expected.Len(), actual.Len()) 71 } 72 73 for i := 0; i < expected.Len(); i++ { 74 if err := CompatibleTypes(expected.At(i).Type(), actual.At(i).Type()); err != nil { 75 return err 76 } 77 } 78 79 return nil 80 } 81 82 case *types.Signature: 83 if actual, ok := actual.(*types.Signature); ok { 84 if err := CompatibleTypes(expected.Params(), actual.Params()); err != nil { 85 return err 86 } 87 err := CompatibleTypes(expected.Results(), actual.Results()) 88 return err 89 } 90 case *types.Interface: 91 if actual, ok := actual.(*types.Interface); ok { 92 if expected.NumMethods() != actual.NumMethods() { 93 return fmt.Errorf("interface method count differs, %d != %d", expected.NumMethods(), actual.NumMethods()) 94 } 95 96 for i := 0; i < expected.NumMethods(); i++ { 97 if expected.Method(i).Name() != actual.Method(i).Name() { 98 return fmt.Errorf("interface method %d name differs, %s != %s", i, expected.Method(i).Name(), actual.Method(i).Name()) 99 } 100 if err := CompatibleTypes(expected.Method(i).Type(), actual.Method(i).Type()); err != nil { 101 return err 102 } 103 } 104 105 return nil 106 } 107 108 case *types.Map: 109 if actual, ok := actual.(*types.Map); ok { 110 if err := CompatibleTypes(expected.Key(), actual.Key()); err != nil { 111 return err 112 } 113 114 err := CompatibleTypes(expected.Elem(), actual.Elem()) 115 return err 116 } 117 118 case *types.Chan: 119 if actual, ok := actual.(*types.Chan); ok { 120 return CompatibleTypes(expected.Elem(), actual.Elem()) 121 } 122 123 case *types.Named: 124 if actual, ok := actual.(*types.Named); ok { 125 if NormalizeVendor(expected.Obj().Pkg().Path()) != NormalizeVendor(actual.Obj().Pkg().Path()) { 126 return fmt.Errorf( 127 "package name of named type differs, %s != %s", 128 NormalizeVendor(expected.Obj().Pkg().Path()), 129 NormalizeVendor(actual.Obj().Pkg().Path()), 130 ) 131 } 132 133 if expected.Obj().Name() != actual.Obj().Name() { 134 return fmt.Errorf( 135 "named type name differs, %s != %s", 136 NormalizeVendor(expected.Obj().Name()), 137 NormalizeVendor(actual.Obj().Name()), 138 ) 139 } 140 141 return nil 142 } 143 144 // Before models are generated all missing references will be Invalid Basic references. 145 // lets assume these are valid too. 146 if actual, ok := actual.(*types.Basic); ok && actual.Kind() == types.Invalid { 147 return nil 148 } 149 150 default: 151 return fmt.Errorf("missing support for %T", expected) 152 } 153 154 return fmt.Errorf("type mismatch %T != %T", expected, actual) 155 }