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)
old
var V io.Writer
new i V: changed from io.Writer to text/tabwriter.Writer
var V tabwriter.Writer
...unless it is exposed. both
var V2 u
var V5 u1
new
var V5 u2 // OK: V5 has changed type, but old u1 corresopnds to new u2
var V8 int
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 Vg g // expose g
var Vh h // expose h
var Vj j // expose j
old
var Z w
new
var Z w
func F1(a int, b string) map[u1]A
old
func F10(S)
both OK, even though new S is incompatible with old S (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
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
new c AA: added
type AA = A
new
type B int
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
new
type C = A
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
Old has one type, D; new has E and D. both
type D int
new i E: changed from D to E
type E D // old D corresponds with new E
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 OK: param name change
type G[A any] []A
new i GM: changed from map[A]B to map[B]A
type GM[A, B comparable] map[B]A
new OK
type GT[V any] struct { }
func (GT[V]) M(*GT[V])
new i GT2: changed from GT2[V any] to GT2[V comparable]
type GT2[V comparable] struct { }
func (GT2[V]) M(*GT2[V])
type GT3[E custom] map[E]int
new
type GoodMerge1 = u3
new
type GoodMerge2 = u3
new i H: changed from struct{} to interface{M()}
type H interface { M() }
old
var V1 H[int]
new i V1: changed from H[int] to H[bool]
var V1 H[bool]
var V2 H[T]
OK: we reported on T, so we don't need to here.
var V2 H[T]
both
var V3 H[t]
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 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 S struct { // i S.A: changed from int to bool A bool }
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 T int
both
type T1 int
old
var VT1 T1
new i U: changed from T to U
type U T
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()