mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
internal/lsp: apply type modifiers to completion candidate
In situations like: var buf bytes.Buffer var w io.Writer = &b<> if we want to complete to "buf" properly we need to apply the "&" type modifier to buf's type of bytes.Buffer to see that it is assignable to type io.Writer. Previously we applied type modifiers in reverse to the "expected" type (io.Writer in this case), but that is obviously incorrect in this situation since it is nonsensical to dereference (the reverse of "&") io.Writer. Change-Id: Ib7ab5761f625217e023286384c23b8c60e677aac GitHub-Last-Rev: 4be528f2572c9c987334552e3f8a31d4eddce81a GitHub-Pull-Request: golang/tools#121 Reviewed-on: https://go-review.googlesource.com/c/tools/+/182598 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
b76e30ffa0
commit
22e91af008
@ -664,6 +664,10 @@ type typeInference struct {
|
||||
|
||||
// wantTypeName is true if we expect the name of a type.
|
||||
wantTypeName bool
|
||||
|
||||
// modifiers are prefixes such as "*", "&" or "<-" that influence how
|
||||
// a candidate type relates to the expected type.
|
||||
modifiers []typeModifier
|
||||
}
|
||||
|
||||
// expectedType returns information about the expected type for an expression at
|
||||
@ -796,25 +800,30 @@ Nodes:
|
||||
}
|
||||
}
|
||||
|
||||
if typ != nil {
|
||||
for _, mod := range modifiers {
|
||||
switch mod {
|
||||
case dereference:
|
||||
// For every "*" deref operator, add another pointer layer to expected type.
|
||||
typ = types.NewPointer(typ)
|
||||
case reference:
|
||||
// For every "&" ref operator, remove a pointer layer from expected type.
|
||||
typ = deref(typ)
|
||||
case chanRead:
|
||||
// For every "<-" operator, add another layer of channelness.
|
||||
typ = types.NewChan(types.SendRecv, typ)
|
||||
return typeInference{
|
||||
objType: typ,
|
||||
modifiers: modifiers,
|
||||
}
|
||||
}
|
||||
|
||||
// applyTypeModifiers applies the list of type modifiers to a type.
|
||||
func (ti typeInference) applyTypeModifiers(typ types.Type) types.Type {
|
||||
for _, mod := range ti.modifiers {
|
||||
switch mod {
|
||||
case dereference:
|
||||
// For every "*" deref operator, remove a pointer layer from candidate type.
|
||||
typ = deref(typ)
|
||||
case reference:
|
||||
// For every "&" ref operator, add another pointer layer to candidate type.
|
||||
typ = types.NewPointer(typ)
|
||||
case chanRead:
|
||||
// For every "<-" operator, remove a layer of channelness.
|
||||
if ch, ok := typ.(*types.Chan); ok {
|
||||
typ = ch.Elem()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return typeInference{
|
||||
objType: typ,
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// findSwitchStmt returns an *ast.CaseClause's corresponding *ast.SwitchStmt or
|
||||
@ -916,6 +925,9 @@ func (c *completer) matchingType(obj types.Object) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Take into account any type modifiers on the expected type.
|
||||
actual = c.expectedType.applyTypeModifiers(actual)
|
||||
|
||||
if c.expectedType.objType != nil {
|
||||
// AssignableTo covers the case where the types are equal, but also handles
|
||||
// cases like assigning a concrete type to an interface type.
|
||||
|
2
internal/lsp/testdata/channel/channel.go
vendored
2
internal/lsp/testdata/channel/channel.go
vendored
@ -20,6 +20,6 @@ func _() {
|
||||
{
|
||||
var foo chan int //@item(channelFoo, "foo", "chan int", "var")
|
||||
wantsInt := func(int) {} //@item(channelWantsInt, "wantsInt", "func(int)", "var")
|
||||
wantsInt(<-) //@complete(")", channelFoo, channelWantsInt, channelAA, channelAB)
|
||||
wantsInt(<-) //@complete(")", channelFoo, channelAB, channelWantsInt, channelAA)
|
||||
}
|
||||
}
|
||||
|
@ -17,4 +17,7 @@ func _() {
|
||||
)
|
||||
|
||||
wantsFoo(a) //@complete(")", irAB, irAA)
|
||||
|
||||
var ac fooImpl //@item(irAC, "ac", "fooImpl", "var")
|
||||
wantsFoo(&a) //@complete(")", irAC, irAA, irAB)
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
// We hardcode the expected number of test cases to ensure that all tests
|
||||
// are being executed. If a test is added, this number must be changed.
|
||||
const (
|
||||
ExpectedCompletionsCount = 124
|
||||
ExpectedCompletionsCount = 125
|
||||
ExpectedCompletionSnippetCount = 14
|
||||
ExpectedDiagnosticsCount = 17
|
||||
ExpectedFormatCount = 5
|
||||
|
Loading…
x
Reference in New Issue
Block a user