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: cannot use struct fields in short variable declaration i.e. f.field, err := fn() #37134

Closed
saritseal opened this issue Feb 8, 2020 · 7 comments

Comments

@saritseal
Copy link

@saritseal saritseal commented Feb 8, 2020

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

go 1.12.6

$ go version

Does this issue reproduce with the latest release?

Yes

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

"darwin"

go env Output
$ go env

What did you do?

Option1:
if I have two variables one defined and other undefined then the := does not identify the defined variable and results in compile error "non-name fs.err on left side of :=" The line of code is as follows

d, fs.err := fs.client.Collection(fs.CollectionName).Doc(fs.ID).Get(fs.ctx)
In order to make it work d needs to be defined
var d *firestore.DocumentSnapshot

Option 2:
while the following fragment works and go infer the type for d
var err error
d, err := fs.client.Collection(fs.CollectionName).Doc(fs.ID).Get(fs.ctx)

In the line above fs is a struct and has been defined. In this case I am receiving it as an argument

What did you expect to see?

I expect go to infer types for non defined parameters, as it does in the second scenario above

What did you see instead?

Option 1 does not work while Option 2 works

@saritseal saritseal changed the title Wierd behaviour Cannot infer types if one argument is defined Feb 8, 2020
@ALTree
Copy link
Member

@ALTree ALTree commented Feb 8, 2020

Yeah you can't do this. := will always create new variables. For example, in

	var a int = 1
	{
		a, b := 99, 2
		fmt.Println(a, b)
	}
	fmt.Println(a)

The a outside the block and the a inside the block are two different variables. Even if you used := for the second assignment, it won't overwrite the outer a, it'll create a new one.

The workaround is writing var d ... and then using = ....

Closing here (see #377).

@ALTree ALTree closed this Feb 8, 2020
@saritseal saritseal changed the title Cannot infer types if one argument is defined Cannot infer types if one argument (Struct field) is defined Feb 8, 2020
@saritseal
Copy link
Author

@saritseal saritseal commented Feb 8, 2020

Yeah you can't do this. := will always create new variables. For example, in

	var a int = 1
	{
		a, b := 99, 2
		fmt.Println(a, b)
	}
	fmt.Println(a)

The a outside the block and the a inside the block are two different variables. Even if you used := for the second assignment, it won't overwrite the outer a, it'll create a new one.

The workaround is writing var d ... and then using = ....

Closing here (see #377).

I do not think it is scope is the reason. Probably i did not explain better

@ALTree ALTree reopened this Feb 8, 2020
@ALTree
Copy link
Member

@ALTree ALTree commented Feb 8, 2020

Okay, can you explain better?

@ALTree
Copy link
Member

@ALTree ALTree commented Feb 8, 2020

Because what you wrote here:

if I have two variables one defined and other undefined then the := does not identify the defined variable

looks like the example I wrote above. Ignore the scoping stuff, as I said := will ignore the already defined variable, that's the issue here.

@odeke-em
Copy link
Member

@odeke-em odeke-em commented Feb 8, 2020

Thank you for the report @saritseal, @ALTree thanks for the response.

For clarity and others looking at this issue in the future, here is a full example https://play.golang.org/p/PSUFXGSVTWQ or inlined below

package main

type Foo struct {
	err  error
}

func f1() (string, error) {
	return "here", nil
}

func main() {
	n1, err := f1()
	if err != nil {
		panic("Expected an error")
	}
	_ = n1
	
	f := new(Foo)
	n2, f.err  := f1()
	_ = n2
}

which won't compile as per

./prog.go:19:7: non-name f.err on left side of :=

Yes indeed, this is forbidden by the language's specification under the section "Short variable declarations" https://golang.org/ref/spec#Short_variable_declarations; a struct field being used is not an IDENTIFIER -- which must be composed only of free standing variables from letters and unicode digits. The language's grammar expects only identifiers for these short variable declarations to be redefined using := provided it was previously declared.

I don't think that we can change this for Go1 at least, but perhaps @griesemer might want to take a look.

@odeke-em odeke-em changed the title Cannot infer types if one argument (Struct field) is defined cmd/compile: cannot use struct fields in short variable declaration i.e. f.field, err := fn() Feb 8, 2020
@griesemer
Copy link
Contributor

@griesemer griesemer commented Feb 8, 2020

There's been various discussions in the past regarding relaxing the rules for := assignments (see #377 as the tracking issue for several proposals).

But as has been said before by @odeke-em, this is working as intended.

@griesemer griesemer closed this Feb 8, 2020
@TapirLiu
Copy link
Contributor

@TapirLiu TapirLiu commented Feb 9, 2020

more related: #30318

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

Successfully merging a pull request may close this issue.

None yet
5 participants
You can’t perform that action at this time.