mirror of
https://github.com/golang/go
synced 2024-11-26 05:27:57 -07:00
cmd/compile: fix devirtualization of promoted interface methods
A method selector expression can pick out a method or promoted method (represented by ODOTMETH), but it can also pick out an interface method from an embedded interface-typed field (represented by ODOTINTER). In the case that we're picking out an interface method, we're not able to fully devirtualize the method call. However, we're still able to improve escape analysis somewhat. E.g., the included test case demonstrates that we can optimize "i.M()" to "i.(T).I.M()", which means the T literal can be stack allocated instead of heap allocated. Fixes #42279. Change-Id: Ifa21d19011e2f008d84f9624b7055b4676b6d188 Reviewed-on: https://go-review.googlesource.com/c/go/+/266300 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
faa4426811
commit
e62adb1c0b
@ -1446,19 +1446,27 @@ func devirtualizeCall(call *Node) {
|
||||
x.Type = typ
|
||||
x = nodlSym(call.Left.Pos, OXDOT, x, call.Left.Sym)
|
||||
x = typecheck(x, ctxExpr|ctxCallee)
|
||||
if x.Op != ODOTMETH {
|
||||
// TODO(mdempsky): Figure out how to avoid this and
|
||||
// turn back into a Fatalf.
|
||||
if Debug.m != 0 {
|
||||
Warnl(call.Pos, "failed to devirtualize %v", x)
|
||||
}
|
||||
return
|
||||
}
|
||||
switch x.Op {
|
||||
case ODOTMETH:
|
||||
if Debug.m != 0 {
|
||||
Warnl(call.Pos, "devirtualizing %v to %v", call.Left, typ)
|
||||
}
|
||||
call.Op = OCALLMETH
|
||||
call.Left = x
|
||||
case ODOTINTER:
|
||||
// Promoted method from embedded interface-typed field (#42279).
|
||||
if Debug.m != 0 {
|
||||
Warnl(call.Pos, "partially devirtualizing %v to %v", call.Left, typ)
|
||||
}
|
||||
call.Op = OCALLINTER
|
||||
call.Left = x
|
||||
default:
|
||||
// TODO(mdempsky): Turn back into Fatalf after more testing.
|
||||
if Debug.m != 0 {
|
||||
Warnl(call.Pos, "failed to devirtualize %v (%v)", x, x.Op)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Duplicated logic from typecheck for function call return
|
||||
// value types.
|
||||
|
@ -255,3 +255,11 @@ func dotTypeEscape2() { // #13805, #15796
|
||||
sink, *(&ok) = y.(*int)
|
||||
}
|
||||
}
|
||||
|
||||
func issue42279() {
|
||||
type I interface{ M() }
|
||||
type T struct{ I }
|
||||
|
||||
var i I = T{} // ERROR "T\{\} does not escape"
|
||||
i.M() // ERROR "partially devirtualizing i.M to T"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user