Skip to content

Commit cb31976

Browse files
committed
Simplify and reuse using migration rewrites
1 parent 6efd2bc commit cb31976

File tree

9 files changed

+80
-63
lines changed

9 files changed

+80
-63
lines changed

compiler/src/dotty/tools/dotc/core/NamerOps.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ object NamerOps:
8888
case Nil =>
8989
resultType
9090
case TermSymbols(params) :: paramss1 =>
91-
val (isContextual, isImplicit, implicitToGiven) =
92-
if params.isEmpty then (false, false, false)
93-
else (params.head.is(Given), params.head.is(Implicit), params.head.isImplicitRewrittenToGiven)
94-
val make = MethodType.companion(isContextual = isContextual, isImplicit = isImplicit, implicitToGiven = implicitToGiven)
91+
val (isContextual, isImplicit) =
92+
if params.isEmpty then (false, false)
93+
else (params.head.is(Given), params.head.is(Implicit))
94+
val make = MethodType.companion(isContextual = isContextual, isImplicit = isImplicit)
9595
if isJava then
9696
for param <- params do
9797
if param.info.isDirectRef(defn.ObjectClass) then param.info = defn.AnyType

compiler/src/dotty/tools/dotc/core/Symbols.scala

-4
Original file line numberDiff line numberDiff line change
@@ -404,10 +404,6 @@ object Symbols extends SymUtils {
404404
def paramVariance(using Context): Variance = denot.variance
405405
def paramRef(using Context): TypeRef = denot.typeRef
406406

407-
/** Was it an implicit, currently rewritten into a given with `-Yimplicit-to-given` */
408-
def isImplicitRewrittenToGiven(using Context): Boolean =
409-
ctx.settings.YimplicitToGiven.value && denot.flags.is(Implicit) && this.isDefinedInSource
410-
411407
/** Copy a symbol, overriding selective fields.
412408
* Note that `coord` and `compilationUnitInfo` will be set from the fields in `owner`, not
413409
* the fields in `sym`. */

compiler/src/dotty/tools/dotc/core/Types.scala

+3-11
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,6 @@ object Types extends TypeUtils {
478478
/** Is this a Method or PolyType which has implicit or contextual parameters? */
479479
def isImplicitMethod: Boolean = false
480480

481-
/** Is this method parameter list implicit, currently rewritten into a given with `-Yimplicit-to-given`? */
482-
def isImplicitMethodRewrittenToContextual: Boolean = false
483-
484481
/** Is this a Method or PolyType which has contextual parameters as first value parameter list? */
485482
def isContextualMethod: Boolean = false
486483

@@ -4157,16 +4154,13 @@ object Types extends TypeUtils {
41574154
def companion: MethodTypeCompanion
41584155

41594156
final override def isImplicitMethod: Boolean =
4160-
companion.eq(ImplicitMethodType) || companion.eq(ImplicitRewrittenToContextualMethodType) || isContextualMethod
4157+
companion.eq(ImplicitMethodType) || isContextualMethod
41614158
final override def hasErasedParams(using Context): Boolean =
41624159
paramInfos.exists(p => p.hasAnnotation(defn.ErasedParamAnnot))
41634160

41644161
final override def isContextualMethod: Boolean =
41654162
companion.eq(ContextualMethodType)
41664163

4167-
final override def isImplicitMethodRewrittenToContextual: Boolean =
4168-
companion.eq(ImplicitRewrittenToContextualMethodType)
4169-
41704164
def erasedParams(using Context): List[Boolean] =
41714165
paramInfos.map(p => p.hasAnnotation(defn.ErasedParamAnnot))
41724166

@@ -4298,16 +4292,14 @@ object Types extends TypeUtils {
42984292
}
42994293

43004294
object MethodType extends MethodTypeCompanion("MethodType") {
4301-
def companion(isContextual: Boolean = false, isImplicit: Boolean = false, implicitToGiven: Boolean = false): MethodTypeCompanion =
4302-
if (implicitToGiven) ImplicitRewrittenToContextualMethodType
4303-
else if (isContextual) ContextualMethodType
4295+
def companion(isContextual: Boolean = false, isImplicit: Boolean = false): MethodTypeCompanion =
4296+
if (isContextual) ContextualMethodType
43044297
else if (isImplicit) ImplicitMethodType
43054298
else MethodType
43064299
}
43074300

43084301
object ContextualMethodType extends MethodTypeCompanion("ContextualMethodType")
43094302
object ImplicitMethodType extends MethodTypeCompanion("ImplicitMethodType")
4310-
object ImplicitRewrittenToContextualMethodType extends MethodTypeCompanion("ImplicitRewrittenToContextualMethodType")
43114303

43124304
/** A ternary extractor for MethodType */
43134305
object MethodTpe {

compiler/src/dotty/tools/dotc/typer/Migrations.scala

+63-5
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,7 @@ trait Migrations:
132132
if tp.companion == ImplicitMethodType && pt.applyKind != ApplyKind.Using && pt.args.nonEmpty then
133133
// The application can only be rewritten if it uses parentheses syntax.
134134
// See issue #22927 and related tests.
135-
val hasParentheses =
136-
ctx.source.content
137-
.slice(tree.span.end, pt.args.head.span.start)
138-
.exists(_ == '(')
135+
val hasParentheses = checkParentheses(tree, pt)
139136
val rewriteMsg =
140137
if hasParentheses then
141138
Message.rewriteNotice("This code", mversion.patchFrom)
@@ -148,7 +145,68 @@ trait Migrations:
148145
|""",
149146
pt.args.head.srcPos, mversion)
150147
if hasParentheses && mversion.needsPatch then
151-
patch(Span(pt.args.head.span.start), "using ")
148+
patchImplicitParams(tree, pt)
152149
end implicitParams
153150

151+
private def checkParentheses(tree: Tree, pt: FunProto)(using Context): Boolean =
152+
ctx.source.content
153+
.slice(tree.span.end, pt.args.head.span.start)
154+
.exists(_ == '(')
155+
156+
private def patchImplicitParams(tree: Tree, pt: FunProto)(using Context): Unit =
157+
patch(Span(pt.args.head.span.start), "using ")
158+
159+
object ImplicitToGiven:
160+
def valDef(vdef: ValDef)(using Context): Unit =
161+
if ctx.settings.YimplicitToGiven.value
162+
&& vdef.symbol.is(Implicit)
163+
&& !vdef.symbol.isParamOrAccessor
164+
then
165+
val implicitSpan =
166+
vdef.mods.mods.collectFirst {
167+
case mod: untpd.Mod.Implicit => mod.span
168+
}.get
169+
patch(
170+
Span(implicitSpan.start, implicitSpan.end + 1),
171+
""
172+
)
173+
patch(
174+
Span(vdef.mods.mods.last.span.end + 1, vdef.namePos.span.start), "given "
175+
)
176+
177+
def defDef(ddef: DefDef)(using Context): Unit =
178+
if
179+
ctx.settings.YimplicitToGiven.value
180+
&& ddef.symbol.is(Implicit)
181+
&& !ddef.symbol.isParamOrAccessor
182+
&& !ddef.symbol.isOldStyleImplicitConversion()
183+
then
184+
val implicitSpan =
185+
ddef.mods.mods.collectFirst {
186+
case mod: untpd.Mod.Implicit => mod.span
187+
}.get
188+
patch(
189+
Span(implicitSpan.start, implicitSpan.end + 1), ""
190+
)
191+
patch(
192+
Span(ddef.mods.mods.last.span.end + 1, ddef.namePos.span.start), "given "
193+
)
194+
ddef.tpt match
195+
case refinedType: untpd.RefinedTypeTree =>
196+
patch(refinedType.span.startPos, "(")
197+
patch(refinedType.span.endPos, ")")
198+
case _ =>
199+
200+
def implicitParams(tree: Tree, tp: MethodOrPoly, pt: FunProto)(using Context): Unit =
201+
if
202+
ctx.settings.YimplicitToGiven.value
203+
&& !mv.ExplicitContextBoundArgument.needsPatch // let's not needlessly repeat the patch
204+
&& tp.companion == ImplicitMethodType
205+
&& pt.applyKind != ApplyKind.Using
206+
&& pt.args.nonEmpty
207+
&& checkParentheses(tree, pt)
208+
then
209+
patchImplicitParams(tree, pt)
210+
211+
154212
end Migrations

compiler/src/dotty/tools/dotc/typer/Typer.scala

+3-37
Original file line numberDiff line numberDiff line change
@@ -2885,18 +2885,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
28852885
postProcessInfo(vdef1, sym)
28862886
vdef1.setDefTree
28872887

2888-
if ctx.isTyper && vdef1.symbol.isImplicitRewrittenToGiven && !vdef1.symbol.isParamOrAccessor then
2889-
val implicitSpan =
2890-
vdef1.mods.mods.collectFirst {
2891-
case mod: Mod.Implicit => mod.span
2892-
}.get
2893-
patch(
2894-
Span(implicitSpan.start, implicitSpan.end + 1),
2895-
""
2896-
)
2897-
patch(
2898-
Span(vdef1.mods.mods.last.span.end + 1, vdef1.namePos.span.start), "given "
2899-
)
2888+
migrate(ImplicitToGiven.valDef(vdef1))
29002889

29012890
val nnInfo = rhs1.notNullInfo
29022891
vdef1.withNotNullInfo(if sym.is(Lazy) then nnInfo.retractedInfo else nnInfo)
@@ -3010,27 +2999,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
30102999

30113000
val ddef2 = assignType(cpy.DefDef(ddef)(name, paramss1, tpt1, rhs1), sym)
30123001

3013-
if
3014-
ctx.isTyper
3015-
&& ddef2.symbol.isImplicitRewrittenToGiven
3016-
&& !ddef2.symbol.isParamOrAccessor
3017-
&& !ddef2.symbol.isOldStyleImplicitConversion()
3018-
then
3019-
val implicitSpan =
3020-
ddef2.mods.mods.collectFirst {
3021-
case mod: Mod.Implicit => mod.span
3022-
}.get
3023-
patch(
3024-
Span(implicitSpan.start, implicitSpan.end + 1), ""
3025-
)
3026-
patch(
3027-
Span(ddef2.mods.mods.last.span.end + 1, ddef2.namePos.span.start), "given "
3028-
)
3029-
ddef.tpt match
3030-
case refinedType: untpd.RefinedTypeTree =>
3031-
patch(refinedType.span.startPos, "(")
3032-
patch(refinedType.span.endPos, ")")
3033-
case _ =>
3002+
migrate(ImplicitToGiven.defDef(ddef2))
30343003

30353004
postProcessInfo(ddef2, sym)
30363005
//todo: make sure dependent method types do not depend on implicits or by-name params
@@ -4229,10 +4198,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
42294198
case wtp: MethodOrPoly =>
42304199
def methodStr = methPart(tree).symbol.showLocated
42314200
if matchingApply(wtp, pt) then
4232-
val isUsingApply = pt.applyKind == ApplyKind.Using
4233-
val notSynthetic = tree.span.exists && tree.span.start != tree.span.end
4234-
if ctx.isTyper && wtp.isImplicitMethodRewrittenToContextual && notSynthetic && !isUsingApply then
4235-
patch(Span(tree.span.end, tree.span.end + 1), "(using ")
4201+
migrate(ImplicitToGiven.implicitParams(tree, wtp, pt))
42364202
migrate(contextBoundParams(tree, wtp, pt))
42374203
migrate(implicitParams(tree, wtp, pt))
42384204
if needsTupledDual(wtp, pt) then adapt(tree, pt.tupledDual, locked)

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

-1
Original file line numberDiff line numberDiff line change
@@ -2284,7 +2284,6 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
22842284
self.companion match
22852285
case Types.ContextualMethodType => MethodTypeKind.Contextual
22862286
case Types.ImplicitMethodType => MethodTypeKind.Implicit
2287-
case Types.ImplicitRewrittenToContextualMethodType => MethodTypeKind.Implicit
22882287
case _ => MethodTypeKind.Plain
22892288
def param(idx: Int): TypeRepr = self.newParamRef(idx)
22902289

compiler/test/dotty/tools/dotc/CompilationTests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class CompilationTests {
8686
compileFile("tests/rewrites/i22440.scala", defaultOptions.and("-rewrite")),
8787
compileFile("tests/rewrites/i22731.scala", defaultOptions.and("-rewrite", "-source:3.7-migration")),
8888
compileFile("tests/rewrites/i22731b.scala", defaultOptions.and("-rewrite", "-source:3.7-migration")),
89-
compileFile("tests/rewrites/implicit-as-given.scala", defaultOptions.and("-rewrite", "-Yimplicit-to-given"))
89+
compileFile("tests/rewrites/implicit-to-given.scala", defaultOptions.and("-rewrite", "-Yimplicit-to-given"))
9090
).checkRewrites()
9191
}
9292

tests/rewrites/implicit-as-given.check renamed to tests/rewrites/implicit-to-given.check

+3
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ object Def:
1818
val implicitArg: Int => Unit = (implicit a => applicationTest) // should not change
1919

2020
given refined(): (A {type B = Int}) = ???
21+
22+
class EmptyParamListClass()(using a: Int)
23+
def emptyParamListTest() = new EmptyParamListClass()(using 0)

tests/rewrites/implicit-as-given.scala renamed to tests/rewrites/implicit-to-given.scala

+3
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ object Def:
1818
val implicitArg: Int => Unit = (implicit a => applicationTest) // should not change
1919

2020
implicit def refined(): A {type B = Int} = ???
21+
22+
class EmptyParamListClass(implicit a: Int)
23+
def emptyParamListTest() = new EmptyParamListClass()(0)

0 commit comments

Comments
 (0)