gopls version
f4fa7a75e44868caa1b37947e8b811b1bdb144e6
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
Comment From: findleyr
Thanks! I imagine this is straightforward to fix.
High level notes:
- Add a new kindInterface here: https://cs.opensource.google/go/x/tools/+/master:gopls/internal/golang/completion/printf.go;l=155;drc=6823da4bc3f39c895ac7f0a46d3994d146397193
- Update completion.candKind
to recognize interfaces
- Write tests, e.g. at https://cs.opensource.google/go/x/tools/+/master:gopls/internal/test/marker/testdata/completion/type_mods.txt
Adding to the next milestone.
Comment From: naeemaei
I will work on this issue
Comment From: findleyr
Thanks @naeemaei! Let us know if you need any additional guidance.
Comment From: dominikh
* 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.
Comment From: naeemaei
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
Comment From: findleyr
@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.
Comment From: muirdm
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".
Comment From: gopherbot
Change https://go.dev/cl/593575 mentions this issue: gopls/completion: don't take address of interfaces for "%p" values