Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: bad order of evaluation for multi-value f(g()) calls #50672

Closed
mdempsky opened this issue Jan 18, 2022 · 8 comments
Closed

cmd/compile: bad order of evaluation for multi-value f(g()) calls #50672

mdempsky opened this issue Jan 18, 2022 · 8 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@mdempsky
Copy link
Member

This program panics when compiled with cmd/compile, but should succeed:

package main

func main() {
	ok := false

	f := func() func(int, int) {
		ok = true
		return func(int, int) {}
	}
	g := func() (int, int) {
		if !ok {
			panic("FAIL")
		}
		return 0, 0
	}

	f()(g())
}

This is because we rewrite f()(g()) into t1, t2 := g(); f()(t1, t2) during type checking.

gccgo compiles it correctly.

@mdempsky mdempsky added the NeedsFix The path to resolution is known, but the work has not been done. label Jan 18, 2022
@mdempsky mdempsky added this to the Go1.19 milestone Jan 18, 2022
@cuonglm
Copy link
Member

cuonglm commented Jan 18, 2022

It seems to me that we should evaluate f() before t1, t2 = g().

@mdempsky
Copy link
Member Author

@cuonglm Yeah, rewriting as t0 := f(); t1, t2 := g(); t0(t1, t2) instead seems like a reasonable quick fix to me. I think direct function calls and method calls are probably the most common case though, so we should make sure those are still handled efficiently.

Longer term, I think we should probably incorporate order.go directly into unified IR.

@bcmills
Copy link
Contributor

bcmills commented Jan 18, 2022

Is the order of evaluation actually specified here, or is this another case like #27804?

https://go.dev/ref/spec#Order_of_evaluation says:

[W]hen evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.

I guess in this case f() is considered an “operand” of the call-expression?

@mdempsky
Copy link
Member Author

mdempsky commented Jan 18, 2022

Yeah, f() is an operand. But also it's simply to the left of the g() call in f()(g()), so it needs to be evaluated first per the "..., all function calls, ... are evaluated in lexical left-to-right order" rule.

/cc @griesemer @ianlancetaylor in case they interpret the spec differently here

@ianlancetaylor
Copy link
Contributor

Yes, I think the call to f has to happen before the call to g in this test case.

I think this differs from #27804 which hinges on when we evaluate a variable in a tuple assignment.

The gc compiler got this right up to version 1.12. In version 1.13 it started failing. Possibly due to CL 114797; CC @josharian .

@mdempsky
Copy link
Member Author

I suspect CL 166983 (c0cfe96) is a more likely culprit.

@cuonglm
Copy link
Member

cuonglm commented Mar 15, 2022

@cuonglm Yeah, rewriting as t0 := f(); t1, t2 := g(); t0(t1, t2) instead seems like a reasonable quick fix to me. I think direct function calls and method calls are probably the most common case though, so we should make sure those are still handled efficiently.

Longer term, I think we should probably incorporate order.go directly into unified IR.

Note that the rewriting of f(g()) happens during old typecheck phase, not during order phase. Though, it's also reasonable to me for incorporating order.go directly into unified IR.

@gopherbot
Copy link

Change https://go.dev/cl/392834 mentions this issue: cmd/compile: fix bad order of evaluation for multi-value f()(g()) calls

@golang golang locked and limited conversation to collaborators May 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants