// type changes old
const ( C1 = 1 C2 int = 2 C3 = 3 C4 u1 = 4 )
new
const ( // i C1: changed from untyped int to untyped string C1 = "1" // i C2: changed from int to untyped int C2 = -1 // i C3: changed from untyped int to int C3 int = 3 // i V8: changed from var to const V8 int = 1 C4 u2 = 4 // OK: u1 corresponds to u2 )
value change old
const ( Cr1 = 1 Cr2 = "2" Cr3 = 3.5 Cr4 = complex(0, 4.1) )
new
const ( // i Cr1: value changed from 1 to -1 Cr1 = -1 // i Cr2: value changed from "2" to "3" Cr2 = "3" // i Cr3: value changed from 3.5 to 3.8 Cr3 = 3.8 // i Cr4: value changed from (0 + 4.1i) to (4.1 + 0i) Cr4 = complex(4.1, 0) )
old
const C5 = 3
new i C5: value changed from 3 to 4
const C5 = 4
// simple type changes old
var ( V1 string V3 A V7 <-chan int )
new
var ( // i V1: changed from string to []string V1 []string V3 A // OK: same // i V7: changed from <-chan int to chan int V7 chan int )
// interface type changes old
var ( V9 interface{ M() } V10 interface{ M() } V11 interface{ M() } )
new
var ( // i V9: changed from interface{M()} to interface{} V9 interface{} // i V10: changed from interface{M()} to interface{M(); M2()} V10 interface { M2() M() } // i V11: changed from interface{M()} to interface{M(int)} V11 interface{ M(int) } )
// struct type changes old
var ( VS1 struct{ A, B int } VS2 struct{ A, B int } VS3 struct{ A, B int } VS4 struct { A int // contains filtered or unexported fields } )
new
var ( // i VS1: changed from struct{A int; B int} to struct{B int; A int} VS1 struct{ B, A int } // i VS2: changed from struct{A int; B int} to struct{A int} VS2 struct{ A int } // i VS3: changed from struct{A int; B int} to struct{A int; B int; C int} VS3 struct{ A, B, C int } VS4 struct { A int // contains filtered or unexported fields } )
new c F8: changed from func to var
var F8 func(bool)
old
var F9 func(int)
// ...unless it is exposed. both
var V2 u
var V5 u1
new
var V5 u2 // OK: V5 has changed type, but old u1 corresponds to new u2
var V8 int
var VK4 k4 // expose k4
new i VT1: changed from T1 to int This fails because old T1 corresponds to both int and new T1.
var VT1 int
var VT2 t2
new OK: t2 corresponds to int. It's fine that old t2 doesn't exist in new.
var VT2 int
old
var VT3 t3
new i t3.M: removed Here the change from t3 to int is incompatible because old t3 has an exported method.
var VT3 int
old
var VT4 int
i VT4: changed from int to t4 This is incompatible because of code like
VT4 + int(1)
which works in old but fails in new. The difference from the above cases is that in those, we were merging two types into one; here, we are splitting int into t4 and int.
var VT4 t4
var Vj3 j3 // expose j3
var Vj4 j4 // expose j4
old
var Z w
new
var Z w
func F1(a int, b string) map[u1]A
old
func F10(S1)
both OK, even though new S1 is incompatible with old S1 (see below)
func F2(int) bool
i F2: changed from func(int) to func(int) bool
func F3(int, int)
i F3: changed from func(int) to func(int, int)
func F4(bool) int
i F4: changed from func(int) int to func(bool) int
func F5(int) string
i F5: changed from func(int) int to func(int) string
func F6(...int)
i F6: changed from func(int) to func(...int)
func F7(a interface{ x() })
i F7: changed from func(interface{}) to func(interface{x()})
func F8(bool)
old
func F9(int)
new i F9: changed from var to func
// Same type in both: OK. both
type A int
type A1 [1]int
i A2: changed from [2]int to [2]bool
type A2 [2]bool
i A3: changed from [3]int to [4]int
type A3 [C5]int
// Adding a new type, whether alias or not, is a compatible change. new c AA: added
type AA = A
new i B: changed from int to string
type B string
c B1: added
type B1 bool
new
type BadMerge1 = u3
i u4.M: removed What's really happening here is that old u4 corresponds to new u3, and new u3's method set is not a superset of old u4's.
type BadMerge2 = u3
new c Bc1: changed from int32 to int
type Bc1 int
c Bc2: changed from uint to uint64
type Bc2 uint64
c Bc3: changed from float32 to float64
type Bc3 float64
c Bc4: changed from complex64 to complex128
type Bc4 complex128
new i Bi1: changed from int32 to int16
type Bi1 int16
i Bi2: changed from uint to uint32
type Bi2 uint32
i Bi3: changed from float64 to float32
type Bi3 float32
i Bi4: changed from complex128 to complex64
type Bi4 complex64
i Ch1, element type: changed from int to bool
type Ch1 chan bool
i Ch2: changed direction
type Ch2 chan<- int
i Ch3: changed direction
type Ch3 <-chan int
c Ch4: removed direction
type Ch4 chan int
type Embedm struct { // i Embedm.A: changed from int to bool A bool }
func (*Embedm) FP()
func (Embedm) FV(int)
i Embedm.FV: changed from func() to func(int)
both
type F int
new
type GoodMerge1 = u3
new
type GoodMerge2 = u3
new i H: changed from struct{} to interface{M()}
type H interface { M() }
func (H) M()
new
type I1 interface { // M1() // i I1.M1: removed M2(int) // i I1.M2: changed from func() to func(int) M3() // contains filtered or unexported methods }
new
type I2 interface { M1() // c I2.M2: added M2() // contains filtered or unexported methods }
new OK: what matters is the method set; the name of the embedded interface isn't important.
type I3 interface { M() Read([]byte) (int, error) }
new OK: in both, I4 is a distinct type from io.Writer, and the old and new I4s have the same method set.
type I4 interface { Write([]byte) (int, error) }
new i I5: changed from io.Writer to I5 In old, I5 and io.Writer are the same type; in new, they are different. That can break something like:
var _ func(io.Writer) = func(pkg.I6) {}
type I5 io.Writer
new i I6: changed from I6 to io.Writer Similar to the above.
type I6 = io.Writer
new
type J1 = K1
new i K2: changed from K2 to K2
type J2 K2 // old K2 corresponds with new J2
new
type K1 int
// Old has one type, K2; new has J2 and K2. both
type K2 int
new
type L1 = J1
new
type M1 map[string]int
i M2: changed from map[string]int to map[int]int
type M2 map[int]int
i M3: changed from map[string]int to map[string]string
type M3 map[string]string
i P1: changed from *int to **bool
type P1 **bool
new
type P2 *u2 // OK: u1 corresponds to u2
old
type Rem int
type RepeatEmbedm struct { // i RepeatEmbedm.A: changed from int to bool Embedm }
new
type S1 = s1
type S2 struct { A int // contains filtered or unexported fields }
type S3 struct { // c S3.F: added A int // contains filtered or unexported fields }
new
type S4 struct { // OK: removed unexported fields // D and F marked as added because they are now part of the immediate fields D bool // c S4.D: added E int // OK: same as in old F F // c S4.F: added A1 // OK: same *S4 // OK: same (recursive embedding) }
// Difference between exported selectable fields and exported immediate fields. both
type S5 struct{ A int }
i S6.A: removed
type S6 struct { S5 }
new
type S7 struct { // c S7.E: added E string // contains filtered or unexported fields }
new
type SM struct { Embedm // contains filtered or unexported fields }
func (*SM) EP2()
func (SM) EV2()
func (*SM) P1()
func (*SM) P2()
func (*SM) P3()
func (SM) P4()
c SM.P4: added P4 is not removed from (*SM) because value methods are in the pointer method set.
func (*SM) P5()
c (*SM).P5: added
func (SM) V1()
func (SM) V2()
func (SM) V3(int)
i SM.V3: changed from func() to func(int)
func (*SM) V4(int)
i SM.V4: removed i (*SM).V4: changed from func() to func(int)
func (SM) V5()
c SM.V5: added
c SMa: added
type SMa = SM
func (*SMa) P3(int)
i (*SM).P3: changed from func() to func(int)
i Sl: changed from []int to []string
type Sl []string
new
type Split1 = u2 // OK, since old u1 corresponds to new u2
This tries to make u1 correspond to u3 i Split2: changed from u1 to u3
type Split2 = u3
both
type T1 int
old
var VT1 T1
new
type WI1 interface {
M1()
// contains filtered or unexported methods
}
type WI2 interface {
M2()
// contains filtered or unexported methods
}
type WS1 int
func (WS1) M1()
type WS2 int
func (WS2) M2()