Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 09559f3

Browse files
committed
Remove by-name restriction for case copy
1 parent 11af0ed commit 09559f3

File tree

11 files changed

+86
-19
lines changed

11 files changed

+86
-19
lines changed

src/compiler/scala/tools/nsc/Global.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,7 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
11881188
import s.XsourceFeatures.contains
11891189
def caseApplyCopyAccess = isScala3 && contains(o.caseApplyCopyAccess)
11901190
def caseCompanionFunction = isScala3 && contains(o.caseCompanionFunction)
1191+
def caseCopyByName = isScala3 && contains(o.caseCopyByName)
11911192
def inferOverride = isScala3 && contains(o.inferOverride)
11921193
def any2StringAdd = isScala3 && contains(o.any2StringAdd)
11931194
def unicodeEscapesRaw = isScala3 && contains(o.unicodeEscapesRaw)

src/compiler/scala/tools/nsc/settings/ScalaSettings.scala

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
125125
val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "")
126126
val reporter = StringSetting ("-Xreporter", "classname", "Specify a custom subclass of FilteringReporter for compiler messages.", "scala.tools.nsc.reporters.ConsoleReporter")
127127
private val XsourceHelp =
128-
sm"""|-Xsource:3 is for migrating a codebase, -Xsource-features can be added for
129-
|cross-building to adopt certain Scala 3 behavior.
128+
sm"""|-Xsource:3 is for migrating a codebase. -Xsource-features can be added for
129+
|cross-building to adopt certain Scala 3 behaviors.
130130
|
131131
|See also "Scala 2 with -Xsource:3" on docs.scala-lang.org.
132132
|
@@ -169,9 +169,10 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
169169
// buffet of features available under -Xsource:3
170170
object sourceFeatures extends MultiChoiceEnumeration {
171171
// Changes affecting binary encoding
172-
val caseApplyCopyAccess = Choice("case-apply-copy-access", "Constructor modifiers are used for apply / copy methods of case classes. [bin]")
172+
val caseApplyCopyAccess = Choice("case-apply-copy-access", "Constructor modifiers are used for apply / copy methods of case classes. [bin]")
173173
val caseCompanionFunction = Choice("case-companion-function", "Synthetic case companion objects no longer extend FunctionN. [bin]")
174-
val inferOverride = Choice("infer-override", "Inferred type of member uses type of overridden member. [bin]")
174+
val caseCopyByName = Choice("case-copy-by-name", "Synthesize case copy method with by-name parameters. [bin]")
175+
val inferOverride = Choice("infer-override", "Inferred type of member uses type of overridden member. [bin]")
175176

176177
// Other semantic changes
177178
val any2StringAdd = Choice("any2stringadd", "Implicit `any2stringadd` is never inferred.")
@@ -203,10 +204,11 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett
203204
helpText = Some(
204205
sm"""Enable Scala 3 features under -Xsource:3.
205206
|
206-
|Instead of `-Xsource-features:_`, it is recommended to enable specific features, for
207-
|example `-Xsource-features:v2.13.14,-case-companion-function` (-x to exclude x).
208-
|This way, new semantic changes in future Scala versions are not silently adopted;
209-
|new features can be enabled after auditing the corresponding migration warnings.
207+
|Instead of `-Xsource-features:_`, it is recommended to enable individual features.
208+
|Features can also be removed from a feature group by prefixing with `-`;
209+
|for example, `-Xsource-features:v2.13.14,-case-companion-function`.
210+
|Listing features explicitly ensures new semantic changes in future Scala versions are
211+
|not silently adopted; new features can be enabled after auditing migration warnings.
210212
|
211213
|`-Xsource:3-cross` is a shorthand for `-Xsource:3 -Xsource-features:_`.
212214
|

src/compiler/scala/tools/nsc/typechecker/Unapplies.scala

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ trait Unapplies extends ast.TreeDSL {
2727

2828
import global._
2929
import definitions._
30-
import CODE.{ CASE => _, _ }
31-
import treeInfo.{ isRepeatedParamType, isByNameParamType }
30+
import CODE.{CASE => _, _}
31+
import treeInfo.{isByNameParamType, isRepeatedParamType}
3232

3333
private def unapplyParamName = nme.x_0
3434
private def caseMods = Modifiers(SYNTHETIC | CASE)
@@ -265,26 +265,29 @@ trait Unapplies extends ast.TreeDSL {
265265
* ClassDef of the case class.
266266
*/
267267
def caseClassCopyMeth(cdef: ClassDef): Option[DefDef] = {
268-
def isDisallowed(vd: ValDef) = isRepeatedParamType(vd.tpt) || isByNameParamType(vd.tpt)
269-
val classParamss = constrParamss(cdef)
270-
271-
if (cdef.symbol.hasAbstractFlag || mexists(classParamss)(isDisallowed)) None
272-
else {
268+
val classParamss = constrParamss(cdef)
269+
def copyOK = {
270+
def warn() = if (currentRun.isScala3) runReporting.warning(cdef.namePos, "case `copy` method is allowed to have by-name parameters under Scala 3 (or with -Xsource-features:case-copy-by-name)", Scala3Migration, cdef.symbol)
271+
def isAllowed(vd: ValDef) = {
272+
def checkByName = currentRun.sourceFeatures.caseCopyByName || !isByNameParamType(vd.tpt).tap(if (_) warn())
273+
!isRepeatedParamType(vd.tpt) && checkByName
274+
}
275+
!cdef.symbol.hasAbstractFlag && mforall(classParamss)(isAllowed)
276+
}
277+
def synthesizeCopy = {
273278
def makeCopyParam(vd: ValDef, putDefault: Boolean) = {
274279
val rhs = if (putDefault) toIdent(vd) else EmptyTree
275280
val flags = PARAM | (vd.mods.flags & IMPLICIT) | (if (putDefault) DEFAULTPARAM else 0)
276281
// empty tpt: see comment above
277282
val tpt = atPos(vd.pos.focus)(TypeTree() setOriginal vd.tpt)
278283
treeCopy.ValDef(vd, Modifiers(flags), vd.name, tpt, rhs)
279284
}
280-
281285
val tparams = constrTparamsInvariant(cdef)
282286
val paramss = classParamss match {
283287
case Nil => Nil
284288
case ps :: pss =>
285289
ps.map(makeCopyParam(_, putDefault = true)) :: mmap(pss)(makeCopyParam(_, putDefault = false))
286290
}
287-
288291
val classTpe = classType(cdef, tparams)
289292
val argss = mmap(paramss)(toIdent)
290293
val body: Tree = New(classTpe, argss)
@@ -301,10 +304,10 @@ trait Unapplies extends ast.TreeDSL {
301304
}
302305
}
303306
else synth
304-
val copyDefDef = atPos(cdef.pos.focus)(
307+
atPos(cdef.pos.focus)(
305308
DefDef(copyMods, nme.copy, tparams, paramss, TypeTree(), body)
306309
)
307-
Some(copyDefDef)
308310
}
311+
if (copyOK) Some(synthesizeCopy) else None
309312
}
310313
}

test/files/neg/t7879.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
t7879.scala:2: error: case `copy` method is allowed to have by-name parameters under Scala 3 (or with -Xsource-features:case-copy-by-name)
2+
Scala 3 migration messages are issued as errors under -Xsource:3. Use -Wconf or @nowarn to demote them to warnings or suppress.
3+
Applicable -Wconf / @nowarn filters for this fatal warning: msg=<part of the message>, cat=scala3-migration, site=C
4+
case class C(i: Int)(j: => Int)(k: => Int) { def sum = i + j + k }
5+
^
6+
1 error

test/files/neg/t7879.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
//> using options -Xsource:3
2+
case class C(i: Int)(j: => Int)(k: => Int) { def sum = i + j + k }

test/files/neg/t7879b.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
t7879b.scala:5: error: value copy is not a member of C
2+
def f(c: C): C = c.copy(42)(Seq(9, 9, 9): _*)
3+
^
4+
1 error

test/files/neg/t7879b.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//> using options -Xsource:3 -Xsource-features:case-copy-by-name
2+
case class C(i: Int)(js: Int*) { def sum = i + js.sum }
3+
4+
class Usage {
5+
def f(c: C): C = c.copy(42)(Seq(9, 9, 9): _*)
6+
}

test/files/neg/t7879c.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
t7879c.scala:6: error: value copy is not a member of C
2+
C(42)(27)(1).copy()
3+
^
4+
1 error

test/files/neg/t7879c.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//> using options -Werror -Xlint
2+
case class C(i: Int)(j: => Int)(k: => Int) { def sum = i + j + k }
3+
4+
object Test extends App {
5+
println {
6+
C(42)(27)(1).copy()
7+
}
8+
}

test/files/run/t7879.check

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
scala> case class C(i: Int)(j: => Int) { def sum = i + j }
3+
class C
4+
5+
scala> def z = 27.tap(println)
6+
def z: Int
7+
8+
scala> val c = C(42)(z)
9+
val c: C = C(42)
10+
11+
scala> c.sum
12+
27
13+
val res0: Int = 69
14+
15+
scala> def y = 28.tap(println)
16+
def y: Int
17+
18+
scala> c.copy()(y)
19+
val res1: C = C(42)
20+
21+
scala> c.copy()(y).sum
22+
28
23+
val res2: Int = 70
24+
25+
scala> :quit

0 commit comments

Comments
 (0)