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: strange initialization loop error #43741

Closed
valyala opened this issue Jan 16, 2021 · 5 comments
Closed

cmd/compile: strange initialization loop error #43741

valyala opened this issue Jan 16, 2021 · 5 comments

Comments

@valyala
Copy link
Contributor

@valyala valyala commented Jan 16, 2021

What version of Go are you using (go version)?

go1.15

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

GOOS=linux
GOARCH=amd64

What did you do?

Tried to compile the following code:

var a = f

func f() {
	a()
}

What did you expect to see?

It should successfully compile, since f isn't called during a initialization.

What did you see instead?

Compiler returns the following error:

./prog.go:3:5: initialization loop:
	prog.go:3:5: a refers to
	prog.go:5:6: f refers to
	prog.go:3:5: a

Additional details

The following code with identical behavior successfully compiles:

var a func()

func init() {
	a = f
}

func f() {
	a()
}

This minimal code snipped has been reduced from real production code, which uses global function table for expression evaluation. Below is a pseudo-code:

type expr interface{}

type funcExpr struct {
	FuncName string
	Arg      expr
}

type F func(arg expr) float64

var funcTable = map[string]F{
	"abs": abs,
}

func abs(arg expr) float64 {
	var value float64
	switch t := arg.(type) {
	case *funcExpr:
		value = funcTable[t.FuncName](t.Arg)
	default:
		value = arg.(float64)
	}
	return math.Abs(value)
}
@seankhliao
Copy link
Contributor

@seankhliao seankhliao commented Jan 16, 2021

looks like it behaves according to spec, package initialization:

  • var a = f means a depends on f
  • func f() { a() } means f depends on a , from spec:

    A variable, function, or method x depends on a variable y if x's initialization expression or body (for functions and methods) contains a reference to y or to a function or method that depends on y.

Loading

@josharian josharian changed the title Strange initialization loop error cmd/compile: strange initialization loop error Jan 16, 2021
@go101
Copy link

@go101 go101 commented Jan 16, 2021

Here, how a depends on f is not very clear. a surely depends on f, but it doesn't depend on f's body.

[edit] In other words, f() depends on a, but f doesn't (though the spec think it does).

Loading

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jan 16, 2021

The spec is intended to be clear and straightforward to implement for all Go compilers. This is working as intended.

Loading

@go101
Copy link

@go101 go101 commented Jan 17, 2021

But it looks the rule is unnecessarily too strict.

Loading

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jan 17, 2021

The rule is stricter than it has to be, but not unnecessarily so. A less strict rule would have to distinguish between a reference to a function and a call of that function, and would have to work for code like

var a = func() int { x := f; return x() }()

Since the most important goal is a spec that is clear and straightforward to implement for all Go compilers, we did not try to write a spec that would handle cases like that in their full generality.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants