diff --git a/gopls/internal/golang/completion/completion.go b/gopls/internal/golang/completion/completion.go index 77c8b61615d..6aa371111ae 100644 --- a/gopls/internal/golang/completion/completion.go +++ b/gopls/internal/golang/completion/completion.go @@ -52,7 +52,6 @@ import ( // A CompletionItem represents a possible completion suggested by the algorithm. type CompletionItem struct { - // Invariant: CompletionItem does not refer to syntax or types. // Label is the primary text the user sees for this completion item. @@ -2965,6 +2964,13 @@ func (ci *candidateInference) candTypeMatches(cand *candidate) bool { // If candType doesn't otherwise match, consider if we can // convert candType directly to expType. if considerTypeConversion(candType, expType, cand.path) { + // special case: a string to a variadic []byte/[]rune + typ := deslice(expType) + isBytesOrRunes := typ != nil && (isBasicKind(typ, types.Byte) || isBasicKind(typ, types.Rune)) + if isBasicType(candType, types.IsString) && isBytesOrRunes && expType == variadicType { + cand.mods = append(cand.mods, takeDotDotDot) + } + cand.convertTo = expType // Give a major score penalty so we always prefer directly // assignable candidates, all else equal. @@ -3045,7 +3051,7 @@ func considerTypeConversion(from, to types.Type, path []types.Object) bool { // Don't offer to convert ints to strings since that probably // doesn't do what the user wants. - if isBasicKind(from, types.IsInteger) && isBasicKind(to, types.IsString) { + if isBasicType(from, types.IsInteger) && isBasicType(to, types.IsString) { return false } diff --git a/gopls/internal/golang/completion/format.go b/gopls/internal/golang/completion/format.go index dbc57c18082..1272ebcf9c8 100644 --- a/gopls/internal/golang/completion/format.go +++ b/gopls/internal/golang/completion/format.go @@ -182,7 +182,6 @@ Suffixes: // add the additional text edits needed. if cand.imp != nil { addlEdits, err := c.importEdits(cand.imp) - if err != nil { return CompletionItem{}, err } @@ -214,7 +213,7 @@ Suffixes: } prefix = typeName + "(" + prefix - suffix = ")" + suffix = ")" + suffix } if prefix != "" { diff --git a/gopls/internal/golang/completion/util.go b/gopls/internal/golang/completion/util.go index ad4ee5e09fc..898cddff8f2 100644 --- a/gopls/internal/golang/completion/util.go +++ b/gopls/internal/golang/completion/util.go @@ -300,10 +300,15 @@ func formatZeroValue(T types.Type, qf types.Qualifier) string { } } -// isBasicKind returns whether t is a basic type of kind k. -func isBasicKind(t types.Type, k types.BasicInfo) bool { +// isBasicType returns whether t has property information i. +func isBasicType(t types.Type, i types.BasicInfo) bool { b, _ := t.Underlying().(*types.Basic) - return b != nil && b.Info()&k > 0 + return b != nil && b.Info()&i > 0 +} + +func isBasicKind(t types.Type, k types.BasicKind) bool { + b, _ := t.Underlying().(*types.Basic) + return b != nil && b.Kind() == k } func (c *completer) editText(from, to token.Pos, newText string) ([]protocol.TextEdit, error) {