1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:04:46 -07:00

internal/lsp: improve completion support for type conversions

Now when completing in code like:

foo := int64(<>)

we prefer candidates whose type is convertible to int64.

Change-Id: Iadc6cdc7de097ac30d8807d6f5aa21d83f89d756
GitHub-Last-Rev: a86dd72496ba752a1f20877c0594ec6a0ed8160e
GitHub-Pull-Request: golang/tools#127
Reviewed-on: https://go-review.googlesource.com/c/tools/+/183941
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Muir Manders 2019-06-27 22:37:50 +00:00 committed by Rebecca Stambler
parent 970b2b065d
commit 30f1cf78d7
3 changed files with 53 additions and 4 deletions

View File

@ -727,6 +727,9 @@ type typeInference struct {
// assertableFrom is a type that must be assertable to our candidate type. // assertableFrom is a type that must be assertable to our candidate type.
assertableFrom types.Type assertableFrom types.Type
// convertibleTo is a type our candidate type must be convertible to.
convertibleTo types.Type
} }
// expectedType returns information about the expected type for an expression at // expectedType returns information about the expected type for an expression at
@ -741,8 +744,9 @@ func expectedType(c *completer) typeInference {
} }
var ( var (
modifiers []typeModifier modifiers []typeModifier
typ types.Type typ types.Type
convertibleTo types.Type
) )
Nodes: Nodes:
@ -774,6 +778,13 @@ Nodes:
case *ast.CallExpr: case *ast.CallExpr:
// Only consider CallExpr args if position falls between parens. // Only consider CallExpr args if position falls between parens.
if node.Lparen <= c.pos && c.pos <= node.Rparen { if node.Lparen <= c.pos && c.pos <= node.Rparen {
// For type conversions like "int64(foo)" we can only infer our
// desired type is convertible to int64.
if typ := typeConversion(node, c.info); typ != nil {
convertibleTo = typ
break Nodes
}
if tv, ok := c.info.Types[node.Fun]; ok { if tv, ok := c.info.Types[node.Fun]; ok {
if sig, ok := tv.Type.(*types.Signature); ok { if sig, ok := tv.Type.(*types.Signature); ok {
if sig.Params().Len() == 0 { if sig.Params().Len() == 0 {
@ -860,8 +871,9 @@ Nodes:
} }
return typeInference{ return typeInference{
objType: typ, objType: typ,
modifiers: modifiers, modifiers: modifiers,
convertibleTo: convertibleTo,
} }
} }
@ -1045,6 +1057,10 @@ func (c *completer) matchingType(cand *candidate) bool {
} }
} }
if c.expectedType.convertibleTo != nil {
return types.ConvertibleTo(objType, c.expectedType.convertibleTo)
}
return false return false
} }

View File

@ -139,6 +139,27 @@ func isFunc(obj types.Object) bool {
return ok return ok
} }
// typeConversion returns the type being converted to if call is a type
// conversion expression.
func typeConversion(call *ast.CallExpr, info *types.Info) types.Type {
var ident *ast.Ident
switch expr := call.Fun.(type) {
case *ast.Ident:
ident = expr
case *ast.SelectorExpr:
ident = expr.Sel
default:
return nil
}
// Type conversion (e.g. "float64(foo)").
if fun, _ := info.ObjectOf(ident).(*types.TypeName); fun != nil {
return fun.Type()
}
return nil
}
func formatParams(tup *types.Tuple, variadic bool, qf types.Qualifier) []string { func formatParams(tup *types.Tuple, variadic bool, qf types.Qualifier) []string {
params := make([]string, 0, tup.Len()) params := make([]string, 0, tup.Len())
for i := 0; i < tup.Len(); i++ { for i := 0; i < tup.Len(); i++ {

View File

@ -0,0 +1,12 @@
package rank
func _() {
type strList []string
wantsStrList := func(strList) {}
var (
convA string //@item(convertA, "convA", "string", "var")
convB []string //@item(convertB, "convB", "[]string", "var")
)
wantsStrList(strList(conv)) //@complete("))", convertB, convertA)
}