@@ -24,6 +24,10 @@ import dotty.tools.dotc.util.SourcePosition
24
24
25
25
import scala .collection .mutable
26
26
import scala .util .control .NonFatal
27
+ import dotty .tools .dotc .core .ContextOps .localContext
28
+ import dotty .tools .dotc .core .Names
29
+ import dotty .tools .dotc .core .Types
30
+ import dotty .tools .dotc .core .Symbols
27
31
28
32
/**
29
33
* One of the results of a completion query.
@@ -130,8 +134,8 @@ object Completion:
130
134
case _ => 0
131
135
}
132
136
133
- /** Some information about the trees is lost after Typer such as Extension method definitions
134
- * are expanded into methods. In order to support completions in those cases
137
+ /** Some information about the trees is lost after Typer such as Extension method construct
138
+ * is expanded into methods. In order to support completions in those cases
135
139
* we have to rely on untyped trees and only when types are necessary use typed trees.
136
140
*/
137
141
def resolveTypedOrUntypedPath (tpdPath : List [Tree ], pos : SourcePosition )(using Context ): List [untpd.Tree ] =
@@ -144,6 +148,28 @@ object Completion:
144
148
case (_ : untpd.TypTree ) :: _ => tpdPath
145
149
case _ => untpdPath
146
150
151
+ /** Handle case when cursor position is inside extension method construct.
152
+ * The extension method construct is then desugared into methods, and consturct parameters
153
+ * are no longer a part of a typed tree, but instead are prepended to method parameters.
154
+ *
155
+ * @param untpdPath The typed or untyped path to the tree that is being completed
156
+ * @param tpdPath The typed path that will be returned if no extension method construct is found
157
+ * @param pos The cursor position
158
+ *
159
+ * @return Typed path to the parameter of the extension construct if found or tpdPath
160
+ */
161
+ private def typeCheckExtensionConstructPath (
162
+ untpdPath : List [untpd.Tree ], tpdPath : List [Tree ], pos : SourcePosition
163
+ )(using Context ): List [Tree ] =
164
+ untpdPath.collectFirst:
165
+ case untpd.ExtMethods (paramss, _) =>
166
+ val enclosingParam = paramss.flatten.find(_.span.contains(pos.span))
167
+ enclosingParam.map: param =>
168
+ ctx.typer.index(paramss.flatten)
169
+ val typedEnclosingParam = ctx.typer.typed(param)
170
+ Interactive .pathTo(typedEnclosingParam, pos.span)
171
+ .flatten.getOrElse(tpdPath)
172
+
147
173
private def computeCompletions (pos : SourcePosition , tpdPath : List [Tree ])(using Context ): (Int , List [Completion ]) =
148
174
val path0 = resolveTypedOrUntypedPath(tpdPath, pos)
149
175
val mode = completionMode(path0, pos)
@@ -154,10 +180,7 @@ object Completion:
154
180
155
181
val completer = new Completer (mode, prefix, pos)
156
182
157
- val adjustedPath : List [Tree ] = path0 match
158
- case (sel : untpd.Select ) :: _ :: untpd.ExtMethods (_, _) :: _ => List (ctx.typer.typedExpr(sel))
159
- case _ => tpdPath
160
-
183
+ val adjustedPath = typeCheckExtensionConstructPath(path0, tpdPath, pos)
161
184
val completions = adjustedPath match
162
185
// Ignore synthetic select from `This` because in code it was `Ident`
163
186
// See example in dotty.tools.languageserver.CompletionTest.syntheticThis
0 commit comments