Source file test/devirtualization_with_type_assertions_interleaved.go
1 // errorcheck -0 -m 2 3 // Copyright 2025 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package escape 8 9 type hashIface interface { 10 Sum() []byte 11 } 12 13 type cloneableHashIface interface { 14 hashIface 15 Clone() hashIface 16 } 17 18 type hash struct{ state [32]byte } 19 20 func (h *hash) Sum() []byte { // ERROR "can inline \(\*hash\).Sum$" "h does not escape$" 21 return make([]byte, 32) // ERROR "make\(\[\]byte, 32\) escapes to heap$" 22 } 23 24 func (h *hash) Clone() hashIface { // ERROR "can inline \(\*hash\).Clone$" "h does not escape$" 25 c := *h // ERROR "moved to heap: c$" 26 return &c 27 } 28 29 type hash2 struct{ state [32]byte } 30 31 func (h *hash2) Sum() []byte { // ERROR "can inline \(\*hash2\).Sum$" "h does not escape$" 32 return make([]byte, 32) // ERROR "make\(\[\]byte, 32\) escapes to heap$" 33 } 34 35 func (h *hash2) Clone() hashIface { // ERROR "can inline \(\*hash2\).Clone$" "h does not escape$" 36 c := *h // ERROR "moved to heap: c$" 37 return &c 38 } 39 40 func newHash() hashIface { // ERROR "can inline newHash$" 41 return &hash{} // ERROR "&hash{} escapes to heap$" 42 } 43 44 func cloneHash1(h hashIface) hashIface { // ERROR "can inline cloneHash1$" "leaking param: h$" 45 if h, ok := h.(cloneableHashIface); ok { 46 return h.Clone() 47 } 48 return &hash{} // ERROR "&hash{} escapes to heap$" 49 } 50 51 func cloneHash2(h hashIface) hashIface { // ERROR "can inline cloneHash2$" "leaking param: h$" 52 if h, ok := h.(cloneableHashIface); ok { 53 return h.Clone() 54 } 55 return nil 56 } 57 58 func cloneHash3(h hashIface) hashIface { // ERROR "can inline cloneHash3$" "leaking param: h$" 59 if h, ok := h.(cloneableHashIface); ok { 60 return h.Clone() 61 } 62 return &hash2{} // ERROR "&hash2{} escapes to heap$" 63 } 64 65 func cloneHashWithBool1(h hashIface) (hashIface, bool) { // ERROR "can inline cloneHashWithBool1$" "leaking param: h$" 66 if h, ok := h.(cloneableHashIface); ok { 67 return h.Clone(), true 68 } 69 return &hash{}, false // ERROR "&hash{} escapes to heap$" 70 } 71 72 func cloneHashWithBool2(h hashIface) (hashIface, bool) { // ERROR "can inline cloneHashWithBool2$" "leaking param: h$" 73 if h, ok := h.(cloneableHashIface); ok { 74 return h.Clone(), true 75 } 76 return nil, false 77 } 78 79 func cloneHashWithBool3(h hashIface) (hashIface, bool) { // ERROR "can inline cloneHashWithBool3$" "leaking param: h$" 80 if h, ok := h.(cloneableHashIface); ok { 81 return h.Clone(), true 82 } 83 return &hash2{}, false // ERROR "&hash2{} escapes to heap$" 84 } 85 86 func interleavedWithTypeAssertions() { 87 h1 := newHash() // ERROR "&hash{} does not escape$" "inlining call to newHash" 88 _ = h1.Sum() // ERROR "devirtualizing h1.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$" 89 90 h2 := cloneHash1(h1) // ERROR "&hash{} does not escape$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHash1" 91 _ = h2.Sum() // ERROR "devirtualizing h2.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$" 92 93 h3 := cloneHash2(h1) // ERROR "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHash2" 94 _ = h3.Sum() // ERROR "devirtualizing h3.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$" 95 96 h4 := cloneHash3(h1) // ERROR "&hash2{} escapes to heap$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHash3" "moved to heap: c$" 97 _ = h4.Sum() 98 99 h5, _ := cloneHashWithBool1(h1) // ERROR "&hash{} does not escape$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHashWithBool1" 100 _ = h5.Sum() // ERROR "devirtualizing h5.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$" 101 102 h6, _ := cloneHashWithBool2(h1) // ERROR "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHashWithBool2" 103 _ = h6.Sum() // ERROR "devirtualizing h6.Sum to \*hash$" "inlining call to \(\*hash\).Sum" "make\(\[\]byte, 32\) does not escape$" 104 105 h7, _ := cloneHashWithBool3(h1) // ERROR "&hash2{} escapes to heap$" "devirtualizing h.Clone to \*hash$" "inlining call to \(\*hash\).Clone" "inlining call to cloneHashWithBool3" "moved to heap: c$" 106 _ = h7.Sum() 107 } 108 109 type cloneableHashError interface { 110 hashIface 111 Clone() (hashIface, error) 112 } 113 114 type hash3 struct{ state [32]byte } 115 116 func newHash3() hashIface { // ERROR "can inline newHash3$" 117 return &hash3{} // ERROR "&hash3{} escapes to heap$" 118 } 119 120 func (h *hash3) Sum() []byte { // ERROR "can inline \(\*hash3\).Sum$" "h does not escape$" 121 return make([]byte, 32) // ERROR "make\(\[\]byte, 32\) escapes to heap$" 122 } 123 124 func (h *hash3) Clone() (hashIface, error) { // ERROR "can inline \(\*hash3\).Clone$" "h does not escape$" 125 c := *h // ERROR "moved to heap: c$" 126 return &c, nil 127 } 128 129 func interleavedCloneableHashError() { 130 h1 := newHash3() // ERROR "&hash3{} does not escape$" "inlining call to newHash3" 131 _ = h1.Sum() // ERROR "devirtualizing h1.Sum to \*hash3$" "inlining call to \(\*hash3\).Sum" "make\(\[\]byte, 32\) does not escape$" 132 133 if h1, ok := h1.(cloneableHashError); ok { 134 h2, err := h1.Clone() // ERROR "devirtualizing h1.Clone to \*hash3$" "inlining call to \(\*hash3\).Clone" 135 if err == nil { 136 _ = h2.Sum() // ERROR "devirtualizing h2.Sum to \*hash3$" "inlining call to \(\*hash3\).Sum" "make\(\[\]byte, 32\) does not escape$" 137 } 138 } 139 } 140