Skip to content

Commit 284e7cc

Browse files
committed
fix: handle implicit params in extract method
1 parent d389999 commit 284e7cc

File tree

2 files changed

+108
-6
lines changed

2 files changed

+108
-6
lines changed

presentation-compiler/src/main/dotty/tools/pc/ExtractMethodProvider.scala

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import dotty.tools.dotc.ast.Trees.*
1313
import dotty.tools.dotc.ast.tpd
1414
import dotty.tools.dotc.ast.tpd.DeepFolder
1515
import dotty.tools.dotc.core.Contexts.*
16+
import dotty.tools.dotc.core.Flags
1617
import dotty.tools.dotc.core.Symbols.Symbol
1718
import dotty.tools.dotc.core.Types.MethodType
1819
import dotty.tools.dotc.core.Types.PolyType
@@ -116,9 +117,15 @@ final class ExtractMethodProvider(
116117
typeParams.toList.sortBy(_.decodedName),
117118
)
118119
end localRefs
120+
val optEnclosing =
121+
path.dropWhile(src => !src.sourcePos.encloses(range)) match
122+
case Nil => None
123+
case _ :: (app @ Apply(fun, args)) :: _ if args.exists(ImplicitParameters.isSyntheticArg(_)) => Some(app)
124+
case found :: _ => Some(found)
125+
119126
val edits =
120127
for
121-
enclosing <- path.find(src => src.sourcePos.encloses(range))
128+
enclosing <- optEnclosing
122129
extracted = extractFromBlock(enclosing)
123130
head <- extracted.headOption
124131
expr <- extracted.lastOption
@@ -131,11 +138,14 @@ final class ExtractMethodProvider(
131138
val exprType = prettyPrint(expr.typeOpt.widen)
132139
val name =
133140
genName(indexedCtx.scopeSymbols.map(_.decodedName).toSet, "newMethod")
134-
val (methodParams, typeParams) =
141+
val (allMethodParams, typeParams) =
135142
localRefs(extracted, stat.sourcePos, extractedPos)
136-
val methodParamsText = methodParams
137-
.map(sym => s"${sym.decodedName}: ${prettyPrint(sym.info)}")
138-
.mkString(", ")
143+
val (methodParams, implicitParams) = allMethodParams.partition(!_.isOneOf(Flags.GivenOrImplicit))
144+
def toParamText(params: List[Symbol]) =
145+
params.map(sym => s"${sym.decodedName}: ${prettyPrint(sym.info)}")
146+
.mkString(", ")
147+
val methodParamsText = toParamText(methodParams)
148+
val implicitParamsText = if implicitParams.nonEmpty then s"(given ${toParamText(implicitParams)})" else ""
139149
val typeParamsText = typeParams
140150
.map(_.decodedName) match
141151
case Nil => ""
@@ -155,7 +165,7 @@ final class ExtractMethodProvider(
155165
if noIndent && extracted.length > 1 then (" {", s"$newIndent}")
156166
else ("", "")
157167
val defText =
158-
s"def $name$typeParamsText($methodParamsText): $exprType =$obracket\n${toExtract}\n$cbracket\n$newIndent"
168+
s"def $name$typeParamsText($methodParamsText)$implicitParamsText: $exprType =$obracket\n${toExtract}\n$cbracket\n$newIndent"
159169
val replacedText = s"$name($exprParamsText)"
160170
List(
161171
new l.TextEdit(

presentation-compiler/test/dotty/tools/pc/tests/edit/ExtractMethodSuite.scala

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,3 +446,95 @@ class ExtractMethodSuite extends BaseExtractMethodSuite:
446446
| }
447447
|}""".stripMargin
448448
)
449+
450+
@Test def `i6476` =
451+
checkEdit(
452+
"""|object O {
453+
| class C
454+
| def foo(i: Int)(implicit o: C) = i
455+
|
456+
| @@val o = {
457+
| implicit val c = new C
458+
| <<foo(2)>>
459+
| ???
460+
| }
461+
|}
462+
|""".stripMargin,
463+
"""|object O {
464+
| class C
465+
| def foo(i: Int)(implicit o: C) = i
466+
|
467+
| def newMethod()(given c: C): Int =
468+
| foo(2)
469+
|
470+
| val o = {
471+
| implicit val c = new C
472+
| newMethod()
473+
| ???
474+
| }
475+
|}
476+
|""".stripMargin
477+
)
478+
479+
480+
@Test def `i6476-2` =
481+
checkEdit(
482+
"""|object O {
483+
| class C
484+
| def foo(i: Int)(implicit o: C) = i
485+
|
486+
| @@val o = {
487+
| <<foo(2)(new C)>>
488+
| ???
489+
| }
490+
|}
491+
|""".stripMargin,
492+
"""|object O {
493+
| class C
494+
| def foo(i: Int)(implicit o: C) = i
495+
|
496+
| def newMethod(): Int =
497+
| foo(2)(new C)
498+
|
499+
| val o = {
500+
| newMethod()
501+
| ???
502+
| }
503+
|}
504+
|""".stripMargin
505+
)
506+
507+
@Test def `i6476-3` =
508+
checkEdit(
509+
"""|object O {
510+
| class C
511+
| class D
512+
| def foo(i: Int)(using o: C)(x: Int)(using d: D) = i
513+
|
514+
| @@val o = {
515+
| given C = new C
516+
| given D = new D
517+
| val w = 2
518+
| <<foo(w)(w)>>
519+
| ???
520+
| }
521+
|}
522+
|""".stripMargin,
523+
"""|object O {
524+
| class C
525+
| class D
526+
| def foo(i: Int)(using o: C)(x: Int)(using d: D) = i
527+
|
528+
| def newMethod(w: Int)(given given_C: C, given_D: D): Int =
529+
| foo(w)(w)
530+
|
531+
| val o = {
532+
| given C = new C
533+
| given D = new D
534+
| val w = 2
535+
| newMethod(w)
536+
| ???
537+
| }
538+
|}
539+
|""".stripMargin
540+
)

0 commit comments

Comments
 (0)