// errorcheck -0 -m

// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package escape

type M interface{ M() }

type A interface{ A() }

type C interface{ C() }

type Impl struct{}

func (*Impl) M() {} // ERROR "can inline \(\*Impl\).M$"

func (*Impl) A() {} // ERROR "can inline \(\*Impl\).A$"

type Impl2 struct{}

func (*Impl2) M() {} // ERROR "can inline \(\*Impl2\).M$"

func (*Impl2) A() {} // ERROR "can inline \(\*Impl2\).A$"

type CImpl struct{}

func (CImpl) C() {} // ERROR "can inline CImpl.C$"

func typeAsserts() {
	var a M = &Impl{} // ERROR "&Impl{} does not escape$"

	a.(M).M()     // ERROR "devirtualizing a.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	a.(A).A()     // ERROR "devirtualizing a.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	a.(*Impl).M() // ERROR "inlining call to \(\*Impl\).M"
	a.(*Impl).A() // ERROR "inlining call to \(\*Impl\).A"

	v := a.(M)
	v.M()         // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
	v.(A).A()     // ERROR "devirtualizing v.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	v.(*Impl).A() // ERROR "inlining call to \(\*Impl\).A"
	v.(*Impl).M() // ERROR "inlining call to \(\*Impl\).M"

	v2 := a.(A)
	v2.A()         // ERROR "devirtualizing v2.A to \*Impl$" "inlining call to \(\*Impl\).A"
	v2.(M).M()     // ERROR "devirtualizing v2.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	v2.(*Impl).A() // ERROR "inlining call to \(\*Impl\).A"
	v2.(*Impl).M() // ERROR "inlining call to \(\*Impl\).M"

	a.(M).(A).A() // ERROR "devirtualizing a.\(M\).\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	a.(A).(M).M() // ERROR "devirtualizing a.\(A\).\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"

	a.(M).(A).(*Impl).A() // ERROR "inlining call to \(\*Impl\).A"
	a.(A).(M).(*Impl).M() // ERROR "inlining call to \(\*Impl\).M"

	any(a).(M).M()           // ERROR "devirtualizing any\(a\).\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	any(a).(A).A()           // ERROR "devirtualizing any\(a\).\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	any(a).(M).(any).(A).A() // ERROR "devirtualizing any\(a\).\(M\).\(any\).\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"

	c := any(a)
	c.(A).A() // ERROR "devirtualizing c.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	c.(M).M() // ERROR "devirtualizing c.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"

	M(a).M()    // ERROR "devirtualizing M\(a\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	M(M(a)).M() // ERROR "devirtualizing M\(M\(a\)\).M to \*Impl$" "inlining call to \(\*Impl\).M"

	a2 := a.(A)
	A(a2).A()    // ERROR "devirtualizing A\(a2\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	A(A(a2)).A() // ERROR "devirtualizing A\(A\(a2\)\).A to \*Impl$" "inlining call to \(\*Impl\).A"

	{
		var a C = &CImpl{}   // ERROR "&CImpl{} does not escape$"
		a.(any).(C).C()      // ERROR "devirtualizing a.\(any\).\(C\).C to \*CImpl$" "inlining call to CImpl.C"
		a.(any).(*CImpl).C() // ERROR "inlining call to CImpl.C"
	}
}

func typeAssertsWithOkReturn() {
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		if v, ok := a.(M); ok {
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		}
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		if v, ok := a.(A); ok {
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		v, ok := a.(M)
		if ok {
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		}
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		v, ok := a.(A)
		if ok {
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		v, ok := a.(*Impl)
		if ok {
			v.A() // ERROR "inlining call to \(\*Impl\).A"
			v.M() // ERROR "inlining call to \(\*Impl\).M"
		}
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		v, _ := a.(M)
		v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		v, _ := a.(A)
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		v, _ := a.(*Impl)
		v.A() // ERROR "inlining call to \(\*Impl\).A"
		v.M() // ERROR "inlining call to \(\*Impl\).M"
	}
	{
		a := newM() // ERROR "&Impl{} does not escape$" "inlining call to newM"
		callA(a)    // ERROR "devirtualizing m.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callA"
		callIfA(a)  // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callIfA"
	}
	{
		_, a := newM2ret() // ERROR "&Impl{} does not escape$" "inlining call to newM2ret"
		callA(a)           // ERROR "devirtualizing m.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callA"
		callIfA(a)         // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A" "inlining call to callIfA"
	}
	{
		var a M = &Impl{} // ERROR "&Impl{} does not escape$"
		// Note the !ok condition, devirtualizing here is fine.
		if v, ok := a.(M); !ok {
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		}
	}
	{
		var a A = newImplNoInline()
		if v, ok := a.(M); ok {
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		}
	}
	{
		var impl2InA A = &Impl2{} // ERROR "&Impl2{} does not escape$"
		var a A
		a, _ = impl2InA.(*Impl)
		// a now contains the zero value of *Impl
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		a := newANoInline()
		a.A()
	}
	{
		_, a := newANoInlineRet2()
		a.A()
	}
}

func newM() M { // ERROR "can inline newM$"
	return &Impl{} // ERROR "&Impl{} escapes to heap$"
}

func newM2ret() (int, M) { // ERROR "can inline newM2ret$"
	return -1, &Impl{} // ERROR "&Impl{} escapes to heap$"
}

func callA(m M) { // ERROR "can inline callA$" "leaking param: m$"
	m.(A).A()
}

func callIfA(m M) { // ERROR "can inline callIfA$" "leaking param: m$"
	if v, ok := m.(A); ok {
		v.A()
	}
}

//go:noinline
func newImplNoInline() *Impl {
	return &Impl{} // ERROR "&Impl{} escapes to heap$"
}

//go:noinline
func newImpl2ret2() (string, *Impl2) {
	return "str", &Impl2{} // ERROR "&Impl2{} escapes to heap$"
}

//go:noinline
func newImpl2() *Impl2 {
	return &Impl2{} // ERROR "&Impl2{} escapes to heap$"
}

//go:noinline
func newANoInline() A {
	return &Impl{} // ERROR "&Impl{} escapes to heap$"
}

//go:noinline
func newANoInlineRet2() (string, A) {
	return "", &Impl{} // ERROR "&Impl{} escapes to heap$"
}

func testTypeSwitch() {
	{
		var v A = &Impl{} // ERROR "&Impl{} does not escape$"
		switch v := v.(type) {
		case A:
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		case M:
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		}
	}
	{
		var v A = &Impl{} // ERROR "&Impl{} does not escape$"
		switch v := v.(type) {
		case A:
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		case M:
			v.M()       // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
			v = &Impl{} // ERROR "&Impl{} does not escape$"
			v.M()       // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		}
		v.(M).M() // ERROR "devirtualizing v.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		switch v1 := v.(type) {
		case A:
			v1.A()
		case M:
			v1.M()
			v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		}
	}
	{
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		switch v := v.(type) {
		case A:
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		case M:
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		case C:
			v.C()
		}
	}
	{
		var v A = &Impl{} // ERROR "&Impl{} does not escape$"
		switch v := v.(type) {
		case M:
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		default:
			panic("does not implement M") // ERROR ".does not implement M. escapes to heap$"
		}
	}
}

func differentTypeAssign() {
	{
		var a A
		a = &Impl{}  // ERROR "&Impl{} escapes to heap$"
		a = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		a.A()
	}
	{
		a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$"
		a = &Impl2{}    // ERROR "&Impl2{} escapes to heap$"
		a.A()
	}
	{
		a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$"
		a.A()
		a = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
	}
	{
		a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$"
		a = &Impl2{}    // ERROR "&Impl2{} escapes to heap$"
		var asAny any = a
		asAny.(A).A()
	}
	{
		a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$"
		var asAny any = a
		asAny = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		asAny.(A).A()
	}
	{
		a := A(&Impl{}) // ERROR "&Impl{} escapes to heap$"
		var asAny any = a
		asAny.(A).A()
		asAny = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		a.A()            // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A
		a = &Impl{} // ERROR "&Impl{} escapes to heap$"
		a = newImpl2()
		a.A()
	}
	{
		var a A
		a = &Impl{} // ERROR "&Impl{} escapes to heap$"
		_, a = newImpl2ret2()
		a.A()
	}
}

func assignWithTypeAssert() {
	{
		var i1 A = &Impl{}  // ERROR "&Impl{} does not escape$"
		var i2 A = &Impl2{} // ERROR "&Impl2{} does not escape$"
		i1 = i2.(*Impl)     // this will panic
		i1.A()              // ERROR "devirtualizing i1.A to \*Impl$" "inlining call to \(\*Impl\).A"
		i2.A()              // ERROR "devirtualizing i2.A to \*Impl2$" "inlining call to \(\*Impl2\).A"
	}
	{
		var i1 A = &Impl{}  // ERROR "&Impl{} does not escape$"
		var i2 A = &Impl2{} // ERROR "&Impl2{} does not escape$"
		i1, _ = i2.(*Impl)  // i1 is going to be nil
		i1.A()              // ERROR "devirtualizing i1.A to \*Impl$" "inlining call to \(\*Impl\).A"
		i2.A()              // ERROR "devirtualizing i2.A to \*Impl2$" "inlining call to \(\*Impl2\).A"
	}
}

func nilIface() {
	{
		var v A = &Impl{} // ERROR "&Impl{} does not escape$"
		v = nil
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A = &Impl{} // ERROR "&Impl{} does not escape$"
		v.A()             // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		v = nil
	}
	{
		var nilIface A
		var v A = &Impl{} // ERROR "&Impl{} does not escape$"
		v.A()             // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		v = nilIface
	}
	{
		var nilIface A
		var v A = &Impl{} // ERROR "&Impl{} does not escape$"
		v = nilIface
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		v.A()       // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		v = &Impl{} // ERROR "&Impl{} does not escape$"
	}
	{
		var v A
		var v2 A = v
		v2.A()       // ERROR "devirtualizing v2.A to \*Impl$" "inlining call to \(\*Impl\).A"
		v2 = &Impl{} // ERROR "&Impl{} does not escape$"
	}
	{
		var v A
		v.A()
	}
	{
		var v A
		var v2 A = v
		v2.A()
	}
	{
		var v A
		var v2 A
		v2 = v
		v2.A()
	}
}

func longDevirtTest() {
	var a interface {
		M
		A
	} = &Impl{} // ERROR "&Impl{} does not escape$"

	{
		var b A = a
		b.A()     // ERROR "devirtualizing b.A to \*Impl$" "inlining call to \(\*Impl\).A"
		b.(M).M() // ERROR "devirtualizing b.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		var b M = a
		b.M()     // ERROR "devirtualizing b.M to \*Impl$" "inlining call to \(\*Impl\).M"
		b.(A).A() // ERROR "devirtualizing b.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var b A = a.(M).(A)
		b.A()     // ERROR "devirtualizing b.A to \*Impl$" "inlining call to \(\*Impl\).A"
		b.(M).M() // ERROR "devirtualizing b.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		var b M = a.(A).(M)
		b.M()     // ERROR "devirtualizing b.M to \*Impl$" "inlining call to \(\*Impl\).M"
		b.(A).A() // ERROR "devirtualizing b.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	}

	if v, ok := a.(A); ok {
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}

	if v, ok := a.(M); ok {
		v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
	}

	{
		var c A = a

		if v, ok := c.(A); ok {
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}

		c = &Impl{} // ERROR "&Impl{} does not escape$"

		if v, ok := c.(M); ok {
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
		}

		if v, ok := c.(interface {
			A
			M
		}); ok {
			v.M() // ERROR "devirtualizing v.M to \*Impl$" "inlining call to \(\*Impl\).M"
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
	}
}

func deferDevirt() {
	var a A
	defer func() { // ERROR "can inline deferDevirt.func1$" "func literal does not escape$"
		a = &Impl{} // ERROR "&Impl{} escapes to heap$"
	}()
	a = &Impl{} // ERROR "&Impl{} does not escape$"
	a.A()       // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
}

func deferNoDevirt() {
	var a A
	defer func() { // ERROR "can inline deferNoDevirt.func1$" "func literal does not escape$"
		a = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
	}()
	a = &Impl{} // ERROR "&Impl{} escapes to heap$"
	a.A()
}

//go:noinline
func closureDevirt() {
	var a A
	func() { // ERROR "func literal does not escape$"
		// defer so that it does not lnline.
		defer func() {}() // ERROR "can inline closureDevirt.func1.1$" "func literal does not escape$"
		a = &Impl{}       // ERROR "&Impl{} escapes to heap$"
	}()
	a = &Impl{} // ERROR "&Impl{} does not escape$"
	a.A()       // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
}

//go:noinline
func closureNoDevirt() {
	var a A
	func() { // ERROR "func literal does not escape$"
		// defer so that it does not lnline.
		defer func() {}() // ERROR "can inline closureNoDevirt.func1.1$" "func literal does not escape$"
		a = &Impl2{}      // ERROR "&Impl2{} escapes to heap$"
	}()
	a = &Impl{} // ERROR "&Impl{} escapes to heap$"
	a.A()
}

var global = "1"

func closureDevirt2() {
	var a A
	a = &Impl{}   // ERROR "&Impl{} does not escape$"
	c := func() { // ERROR "can inline closureDevirt2.func1$" "func literal does not escape$"
		a = &Impl{} // ERROR "&Impl{} escapes to heap$"
	}
	if global == "1" {
		c = func() { // ERROR "can inline closureDevirt2.func2$" "func literal does not escape$"
			a = &Impl{} // ERROR "&Impl{} escapes to heap$"
		}
	}
	a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	c()
}

func closureNoDevirt2() {
	var a A
	a = &Impl{}   // ERROR "&Impl{} escapes to heap$"
	c := func() { // ERROR "can inline closureNoDevirt2.func1$" "func literal does not escape$"
		a = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
	}
	if global == "1" {
		c = func() { // ERROR "can inline closureNoDevirt2.func2$" "func literal does not escape$"
			a = &Impl{} // ERROR "&Impl{} escapes to heap$"
		}
	}
	a.A()
	c()
}

//go:noinline
func closureDevirt3() {
	var a A = &Impl{} // ERROR "&Impl{} does not escape$"
	func() {          // ERROR "func literal does not escape$"
		// defer so that it does not lnline.
		defer func() {}() // ERROR "can inline closureDevirt3.func1.1$" "func literal does not escape$"
		a.A()             // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}()
	func() { // ERROR "can inline closureDevirt3.func2$"
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}() // ERROR "inlining call to closureDevirt3.func2" "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
}

//go:noinline
func closureNoDevirt3() {
	var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
	func() {          // ERROR "func literal does not escape$"
		// defer so that it does not lnline.
		defer func() {}() // ERROR "can inline closureNoDevirt3.func1.1$" "func literal does not escape$"
		a.A()
	}()
	func() { // ERROR "can inline closureNoDevirt3.func2$"
		a.A()
	}() // ERROR "inlining call to closureNoDevirt3.func2"
	a = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
}

//go:noinline
func varDeclaredInClosureReferencesOuter() {
	var a A = &Impl{} // ERROR "&Impl{} does not escape$"
	func() {          // ERROR "func literal does not escape$"
		// defer for noinline
		defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func1.1$" "func literal does not escape$"
		var v A = a
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}()
	func() { // ERROR "func literal does not escape$"
		// defer for noinline
		defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func2.1$" "func literal does not escape$"
		var v A = a
		v = &Impl{} // ERROR "&Impl{} does not escape$"
		v.A()       // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}()

	var b A = &Impl{} // ERROR "&Impl{} escapes to heap$"
	func() {          // ERROR "func literal does not escape$"
		// defer for noinline
		defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func3.1$" "func literal does not escape$"
		var v A = b
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.A()
	}()
	func() { // ERROR "func literal does not escape$"
		// defer for noinline
		defer func() {}() // ERROR "can inline varDeclaredInClosureReferencesOuter.func4.1$" "func literal does not escape$"
		var v A = b
		v.A()
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
	}()
}

//go:noinline
func testNamedReturn0() (v A) {
	v = &Impl{} // ERROR "&Impl{} escapes to heap$"
	v.A()
	return
}

//go:noinline
func testNamedReturn1() (v A) {
	v = &Impl{} // ERROR "&Impl{} escapes to heap$"
	v.A()
	return &Impl{} // ERROR "&Impl{} escapes to heap$"
}

func testNamedReturns3() (v A) {
	v = &Impl{}    // ERROR "&Impl{} escapes to heap$"
	defer func() { // ERROR "can inline testNamedReturns3.func1$" "func literal does not escape$"
		v.A()
	}()
	v.A()
	return &Impl2{} // ERROR "&Impl2{} escapes to heap$"
}

var (
	globalImpl    = &Impl{}
	globalImpl2   = &Impl2{}
	globalA     A = &Impl{}
	globalM     M = &Impl{}
)

func globals() {
	{
		globalA.A()
		globalA.(M).M()
		globalM.M()
		globalM.(A).A()

		a := globalA
		a.A()
		a.(M).M()

		m := globalM
		m.M()
		m.(A).A()
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape$"
		a = globalImpl
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape$"
		a = A(globalImpl)
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape$"
		a = M(globalImpl).(A)
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape$"
		a = globalA.(*Impl)
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
		a = globalM.(*Impl)
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		a = globalImpl2
		a.A()
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		a = globalA
		a.A()
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		a = globalM.(A)
		a.A()
	}
}

func mapsDevirt() {
	{
		m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$"
		var v A = m[0]
		v.A()     // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		v.(M).M() // ERROR "devirtualizing v.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$"
		var v A
		var ok bool
		if v, ok = m[0]; ok {
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$"
		var v A
		v, _ = m[0]
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
}

func mapsNoDevirt() {
	{
		m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$"
		var v A = m[0]
		v.A()
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.(M).M()
	}
	{
		m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$"
		var v A
		var ok bool
		if v, ok = m[0]; ok {
			v.A()
		}
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.A()
	}
	{
		m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$"
		var v A = &Impl{}        // ERROR "&Impl{} escapes to heap$"
		v, _ = m[0]
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.A()
	}

	{
		m := make(map[int]A) // ERROR "make\(map\[int\]A\) does not escape$"
		var v A = &Impl{}    // ERROR "&Impl{} escapes to heap$"
		v = m[0]
		v.A()
	}
	{
		m := make(map[int]A) // ERROR "make\(map\[int\]A\) does not escape$"
		var v A = &Impl{}    // ERROR "&Impl{} escapes to heap$"
		var ok bool
		if v, ok = m[0]; ok {
			v.A()
		}
		v.A()
	}
	{
		m := make(map[int]A) // ERROR "make\(map\[int\]A\) does not escape$"
		var v A = &Impl{}    // ERROR "&Impl{} escapes to heap$"
		v, _ = m[0]
		v.A()
	}
}

func chanDevirt() {
	{
		m := make(chan *Impl)
		var v A = <-m
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		m := make(chan *Impl)
		var v A
		v = <-m
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		m := make(chan *Impl)
		var v A
		v, _ = <-m
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		m := make(chan *Impl)
		var v A
		var ok bool
		if v, ok = <-m; ok {
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		m := make(chan *Impl)
		var v A
		var ok bool
		if v, ok = <-m; ok {
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
		select {
		case <-m:
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		case v = <-m:
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		case v, ok = <-m:
			v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
	}
}

func chanNoDevirt() {
	{
		m := make(chan *Impl)
		var v A = <-m
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.A()
	}
	{
		m := make(chan *Impl)
		var v A
		v = <-m
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.A()
	}
	{
		m := make(chan *Impl)
		var v A
		v, _ = <-m
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.A()
	}
	{
		m := make(chan *Impl)
		var v A
		var ok bool
		if v, ok = <-m; ok {
			v.A()
		}
		v = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		v.A()
	}
	{
		m := make(chan *Impl)
		var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		var ok bool
		if v, ok = <-m; ok {
			v.A()
		}
	}
	{
		m := make(chan *Impl)
		var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		select {
		case v = <-m:
			v.A()
		}
		v.A()
	}
	{
		m := make(chan *Impl)
		var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		select {
		case v, _ = <-m:
			v.A()
		}
		v.A()
	}

	{
		m := make(chan A)
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		v = <-m
		v.A()
	}
	{
		m := make(chan A)
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		v, _ = <-m
		v.A()
	}
	{
		m := make(chan A)
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		var ok bool
		if v, ok = <-m; ok {
			v.A()
		}
	}
	{
		m := make(chan A)
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		select {
		case v = <-m:
			v.A()
		}
		v.A()
	}
	{
		m := make(chan A)
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		select {
		case v, _ = <-m:
			v.A()
		}
		v.A()
	}
}

func rangeDevirt() {
	{
		var v A
		m := make(map[*Impl]struct{}) // ERROR "make\(map\[\*Impl\]struct {}\) does not escape$"
		v = &Impl{}                   // ERROR "&Impl{} does not escape$"
		for v = range m {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$"
		v = &Impl{}                // ERROR "&Impl{} does not escape$"
		for v = range m {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$"
		v = &Impl{}                // ERROR "&Impl{} does not escape$"
		for _, v = range m {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		m := make(chan *Impl)
		v = &Impl{} // ERROR "&Impl{} does not escape$"
		for v = range m {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		m := []*Impl{} // ERROR "\[\]\*Impl{} does not escape$"
		v = &Impl{}    // ERROR "&Impl{} does not escape$"
		for _, v = range m {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		v = &Impl{}     // ERROR "&Impl{} does not escape$"
		impl := &Impl{} // ERROR "&Impl{} does not escape$"
		i := 0
		for v = impl; i < 10; i++ {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		v = &Impl{}     // ERROR "&Impl{} does not escape$"
		impl := &Impl{} // ERROR "&Impl{} does not escape$"
		i := 0
		for v = impl; i < 10; i++ {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		m := [1]*Impl{&Impl{}} // ERROR "&Impl{} does not escape$"
		v = &Impl{}            // ERROR "&Impl{} does not escape$"
		for _, v = range m {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var v A
		m := [1]*Impl{&Impl{}} // ERROR "&Impl{} does not escape$"
		v = &Impl{}            // ERROR "&Impl{} does not escape$"
		for _, v = range &m {
		}
		v.A() // ERROR "devirtualizing v.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
}

func rangeNoDevirt() {
	{
		var v A = &Impl2{}            // ERROR "&Impl2{} escapes to heap$"
		m := make(map[*Impl]struct{}) // ERROR "make\(map\[\*Impl\]struct {}\) does not escape$"
		for v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl2{}         // ERROR "&Impl2{} escapes to heap$"
		m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$"
		for v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl2{}         // ERROR "&Impl2{} escapes to heap$"
		m := make(map[*Impl]*Impl) // ERROR "make\(map\[\*Impl\]\*Impl\) does not escape$"
		for _, v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		m := make(chan *Impl)
		for v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		m := []*Impl{}     // ERROR "\[\]\*Impl{} does not escape$"
		for _, v = range m {
		}
		v.A()
	}
	{
		var v A
		v = &Impl2{}    // ERROR "&Impl2{} escapes to heap$"
		impl := &Impl{} // ERROR "&Impl{} escapes to heap$"
		i := 0
		for v = impl; i < 10; i++ {
		}
		v.A()
	}
	{
		var v A
		v = &Impl2{}    // ERROR "&Impl2{} escapes to heap$"
		impl := &Impl{} // ERROR "&Impl{} escapes to heap$"
		i := 0
		for v = impl; i < 10; i++ {
		}
		v.A()
	}
	{
		var v A
		m := [1]*Impl{&Impl{}} // ERROR "&Impl{} escapes to heap$"
		v = &Impl2{}           // ERROR "&Impl2{} escapes to heap$"
		for _, v = range m {
		}
		v.A()
	}
	{
		var v A
		m := [1]*Impl{&Impl{}} // ERROR "&Impl{} escapes to heap$"
		v = &Impl2{}           // ERROR "&Impl2{} escapes to heap$"
		for _, v = range &m {
		}
		v.A()
	}

	{
		var v A = &Impl{}         // ERROR "&Impl{} escapes to heap$"
		m := make(map[A]struct{}) // ERROR "make\(map\[A\]struct {}\) does not escape$"
		for v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl{}  // ERROR "&Impl{} escapes to heap$"
		m := make(map[A]A) // ERROR "make\(map\[A\]A\) does not escape$"
		for v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl{}  // ERROR "&Impl{} escapes to heap$"
		m := make(map[A]A) // ERROR "make\(map\[A\]A\) does not escape$"
		for _, v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		m := make(chan A)
		for v = range m {
		}
		v.A()
	}
	{
		var v A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		m := []A{}        // ERROR "\[\]A{} does not escape$"
		for _, v = range m {
		}
		v.A()
	}

	{
		var v A
		m := [1]A{&Impl{}} // ERROR "&Impl{} escapes to heap$"
		v = &Impl{}        // ERROR "&Impl{} escapes to heap$"
		for _, v = range m {
		}
		v.A()
	}
	{
		var v A
		m := [1]A{&Impl{}} // ERROR "&Impl{} escapes to heap$"
		v = &Impl{}        // ERROR "&Impl{} escapes to heap$"
		for _, v = range &m {
		}
		v.A()
	}
}

var globalInt = 1

func testIfInit() {
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape$"
		var i = &Impl{}   // ERROR "&Impl{} does not escape$"
		if a = i; globalInt == 1 {
			a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
		a.A()     // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
		a.(M).M() // ERROR "devirtualizing a.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		var i2 = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		if a = i2; globalInt == 1 {
			a.A()
		}
		a.A()
	}
}

func testSwitchInit() {
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape$"
		var i = &Impl{}   // ERROR "&Impl{} does not escape$"
		switch a = i; globalInt {
		case 12:
			a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
		}
		a.A()     // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
		a.(M).M() // ERROR "devirtualizing a.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		var i2 = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		switch a = i2; globalInt {
		case 12:
			a.A()
		}
		a.A()
	}
}

type implWrapper Impl

func (implWrapper) A() {} // ERROR "can inline implWrapper.A$"

//go:noinline
func devirtWrapperType() {
	{
		i := &Impl{} // ERROR "&Impl{} does not escape$"
		// This is an OCONVNOP, so we have to be careful, not to devirtualize it to Impl.A.
		var a A = (*implWrapper)(i)
		a.A() // ERROR "devirtualizing a.A to \*implWrapper$" "inlining call to implWrapper.A"
	}
	{
		i := Impl{}
		// This is an OCONVNOP, so we have to be careful, not to devirtualize it to Impl.A.
		var a A = (implWrapper)(i) // ERROR "implWrapper\(i\) does not escape$"
		a.A()                      // ERROR "devirtualizing a.A to implWrapper$" "inlining call to implWrapper.A"
	}
	{
		type anyWrapper any
		var foo any = &Impl{} // ERROR "&Impl\{\} does not escape"
		var bar anyWrapper = foo
		bar.(M).M() // ERROR "devirtualizing bar\.\(M\).M to \*Impl" "inlining call to \(\*Impl\)\.M"
	}
}

func selfAssigns() {
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape$"
		a = a
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape"
		var asAny any = a
		asAny = asAny
		asAny.(A).A() // ERROR "devirtualizing asAny.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape"
		var asAny any = a
		a = asAny.(A)
		asAny.(A).A() // ERROR "devirtualizing asAny.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
		a.(A).A()     // ERROR "devirtualizing a.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
		b := a
		b.(A).A() // ERROR "devirtualizing b.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape"
		var asAny any = a
		asAny = asAny
		a = asAny.(A)
		asAny = a
		asAny.(A).A() // ERROR "devirtualizing asAny.\(A\).A to \*Impl$" "inlining call to \(\*Impl\).A"
		asAny.(M).M() // ERROR "devirtualizing asAny.\(M\).M to \*Impl$" "inlining call to \(\*Impl\).M"
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} does not escape"
		var asAny A = a
		a = asAny.(A)
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
	{
		var a, b, c A
		c = &Impl{} // ERROR "&Impl{} does not escape$"
		a = c
		c = b
		b = c
		a = b
		b = a
		c = a
		a.A() // ERROR "devirtualizing a.A to \*Impl$" "inlining call to \(\*Impl\).A"
	}
}

func boolNoDevirt() {
	{
		m := make(map[int]*Impl) // ERROR "make\(map\[int\]\*Impl\) does not escape$"
		var v any = &Impl{}      // ERROR "&Impl{} escapes to heap$"
		_, v = m[0]              // ERROR ".autotmp_[0-9]+ escapes to heap$"
		v.(A).A()
	}
	{
		m := make(chan *Impl)
		var v any = &Impl{} // ERROR "&Impl{} escapes to heap$"
		select {
		case _, v = <-m: // ERROR ".autotmp_[0-9]+ escapes to heap$"
		}
		v.(A).A()
	}
	{
		m := make(chan *Impl)
		var v any = &Impl{} // ERROR "&Impl{} escapes to heap$"
		_, v = <-m          // ERROR ".autotmp_[0-9]+ escapes to heap$"
		v.(A).A()
	}
	{
		var a any = 4       // ERROR "4 does not escape$"
		var v any = &Impl{} // ERROR "&Impl{} escapes to heap$"
		_, v = a.(int)      // ERROR ".autotmp_[0-9]+ escapes to heap$"
		v.(A).A()
	}
}

func addrTaken() {
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		var ptrA = &a
		a.A()
		_ = ptrA
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		var ptrA = &a
		*ptrA = &Impl{} // ERROR "&Impl{} escapes to heap$"
		a.A()
	}
	{
		var a A = &Impl{} // ERROR "&Impl{} escapes to heap$"
		var ptrA = &a
		*ptrA = &Impl2{} // ERROR "&Impl2{} escapes to heap$"
		a.A()
	}
}

func testInvalidAsserts() {
	any(0).(interface{ A() }).A() // ERROR "any\(0\) escapes to heap$"
	{
		var a M = &Impl{} // ERROR "&Impl{} escapes to heap$"
		a.(C).C()         // this will panic
		a.(any).(C).C()   // this will panic
	}
	{
		var a C = &CImpl{} // ERROR "&CImpl{} escapes to heap$"
		a.(M).M()          // this will panic
		a.(any).(M).M()    // this will panic
	}
	{
		var a C = &CImpl{} // ERROR "&CImpl{} does not escape$"

		// this will panic
		a.(M).(*Impl).M() // ERROR "inlining call to \(\*Impl\).M"

		// this will panic
		a.(any).(M).(*Impl).M() // ERROR "inlining call to \(\*Impl\).M"
	}
}

type namedBool bool

func (namedBool) M() {} // ERROR "can inline namedBool.M$"

//go:noinline
func namedBoolTest() {
	m := map[int]int{} // ERROR "map\[int\]int{} does not escape"
	var ok namedBool
	_, ok = m[5]
	var i M = ok // ERROR "ok does not escape"
	i.M()        // ERROR "devirtualizing i.M to namedBool$" "inlining call to namedBool.M"
}

//go:noinline
func identicalType() {
	var i C = struct {
		CImpl
	}{} // ERROR "struct \{ CImpl \}\{\} escapes to heap"

	i = struct {
		CImpl
	}{} // ERROR "struct \{ CImpl \}\{\} escapes to heap"

	i.C()
}

type GenericAImpl[T any] struct{ _ T }

//go:noinline
func (GenericAImpl[T]) A() {}

//go:noinline
func generics() {
	{
		var i A = GenericAImpl[int]{} // ERROR "GenericAImpl\[int\]\{\} does not escape"
		i.A()                         // ERROR "devirtualizing i.A to GenericAImpl\[int\]"
	}
	{
		var i A = GenericAImpl[int]{} // ERROR "GenericAImpl\[int\]\{\} does not escape"
		i = GenericAImpl[int]{}       // ERROR "GenericAImpl\[int\]\{\} does not escape"
		i.A()                         // ERROR "devirtualizing i.A to GenericAImpl\[int\]"
	}
	{
		var i A = GenericAImpl[int]{} // ERROR "GenericAImpl\[int\]\{\} escapes to heap"
		i = GenericAImpl[byte]{}      // ERROR "GenericAImpl\[uint8\]\{\} escapes to heap"
		i.A()
	}
}
