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

x/tools/gopls: completing argument to %p verb adds unwanted & for some types #65609

Closed
dominikh opened this issue Feb 8, 2024 · 8 comments
Closed
Assignees
Labels
gopls Issues related to the Go language server, gopls. help wanted Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@dominikh
Copy link
Member

dominikh commented Feb 8, 2024

gopls version

f4fa7a7

go env

-

What did you do?

Trigger completion at the end of

package pkg

import "fmt"

func foo() {
	var longword any
	fmt.Printf("%p", lon

What did you see happen?

The line completes to

fmt.Printf("%p", &longword

What did you expect to see?

fmt.Printf("%p", longword

The variable has an interface type. I intended to print the pointer stored in the interface value, not the address of the local variable.

The same happens with maps, channels, unsafe.Pointer, and functions, all of which are accepted by %p. It does not happen with true pointers, or slices.

Editor and settings

No response

Logs

No response

@dominikh dominikh added gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository. labels Feb 8, 2024
@gopherbot gopherbot added this to the Unreleased milestone Feb 8, 2024
@findleyr
Copy link
Contributor

findleyr commented Feb 8, 2024

Thanks! I imagine this is straightforward to fix.

High level notes:

Adding to the next milestone.

@naeemaei
Copy link

naeemaei commented Feb 8, 2024

I will work on this issue

@findleyr
Copy link
Contributor

findleyr commented Feb 8, 2024

Thanks @naeemaei! Let us know if you need any additional guidance.

@dominikh
Copy link
Member Author

dominikh commented Feb 8, 2024

* Update `completion.candKind` to recognize interfaces

Maps, channels, unsafe.Pointer, and functions as well. Anything pointer-esque, really. Also, interfaces are probably a special case separate from that and not really limited to %p: if the static type is an interface, then the dynamic type might be valid for any verb.

@naeemaei
Copy link

I added the kindInterface to the parsePrintfVerb function and also handled the kindInterface in completion.candKind then the line completes without & when using local self-build gopls.

But when I print an interface variable, the print output is as below:

structInterface = person{FirstName: "name"}
fmt.Printf("structInterface: %p\n", structInterface) // structInterface: %!p(main.person={name})
fmt.Printf("structInterface pointer: %p\n", &structInterface) // structInterface pointer: 0xc000014070

When the interface underlying type is a pointer output is the underlying variable address:

strct := &person{FirstName: "name"}
structInterface = strct
fmt.Printf("struct pointer: %p\n", strict) // 0xc000014090
fmt.Printf("structInterface: %p\n", structInterface) // structInterface: 0xc000014090
fmt.Printf("structInterface pointer: %p\n", &structInterface) // structInterface pointer: 0xc000014070

if the static type is an interface, then the dynamic type might be valid for any verb.

This part is a bit vague, I need your guidance regarding the specific logic that should be handled after recognizing interfaces in completion.candKind
@findleyr
@dominikh

@findleyr
Copy link
Contributor

@naeemaei I think the point is that when the argument is an interface, we don't generally know whether or not it holds a pointer (or any other kind of type). In the absence of certainty, it is better not to apply the &. We should only apply type modifiers when they are strictly required to have a valid type.

So it sounds like gopls is working as intended in your example.

@muirdm
Copy link

muirdm commented Jun 15, 2024

Another way to fix this might be to make derivableTypes not try "deriving" a pointer from interface, chan, etc. types that already have pointer semantics. In the example, derivableTypes says you can derive a pointer type *interface{} from longword by doing &longword, which isn't useful in general.

As for what completion candidates the "%p" verb prefers, we should also include "chan", "map" and "func". I don't think we should make it prefer interfaces since those aren't necessarily printable with "%p".

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/593575 mentions this issue: gopls/completion: don't take address of interfaces for "%p" values

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gopls Issues related to the Go language server, gopls. help wanted Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

5 participants