Skip to content

Commit ac4dbf0

Browse files
committed
Add language.deprecated.symbolLiterals import
Allow symbol literals if a language import import language.deprecated.symbolLiterals is given. This is useful for legacy software that uses symbol literals. A typical case are Spark notebooks, where column names are expressed with symbol literals.
1 parent 91f352d commit ac4dbf0

File tree

8 files changed

+45
-13
lines changed

8 files changed

+45
-13
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,16 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
251251
case TypeDefs(_) => true
252252
case _ => isUsingClause(params)
253253

254+
private val languageSubCategories = Set(nme.experimental, nme.deprecated)
255+
254256
/** If `path` looks like a language import, `Some(name)` where name
255257
* is `experimental` if that sub-module is imported, and the empty
256258
* term name otherwise.
257259
*/
258260
def languageImport(path: Tree): Option[TermName] = path match
259-
case Select(p1, nme.experimental) =>
261+
case Select(p1, name: TermName) if languageSubCategories.contains(name) =>
260262
languageImport(p1) match
261-
case Some(EmptyTermName) => Some(nme.experimental)
263+
case Some(EmptyTermName) => Some(name)
262264
case _ => None
263265
case p1: RefTree if p1.name == nme.language =>
264266
p1.qualifier match

compiler/src/dotty/tools/dotc/config/Feature.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@ object Feature:
1616
private def experimental(str: String): TermName =
1717
QualifiedName(nme.experimental, str.toTermName)
1818

19+
private def deprecated(str: String): TermName =
20+
QualifiedName(nme.deprecated, str.toTermName)
21+
1922
private val Xdependent = experimental("dependent")
2023
private val XnamedTypeArguments = experimental("namedTypeArguments")
2124
private val XgenericNumberLiterals = experimental("genericNumberLiterals")
2225
private val Xmacros = experimental("macros")
26+
private val symbolLiterals: TermName = deprecated("symbolLiterals")
2327

2428
/** Is `feature` enabled by by a command-line setting? The enabling setting is
2529
*
@@ -64,6 +68,8 @@ object Feature:
6468

6569
def genericNumberLiteralsEnabled(using Context) = enabled(XgenericNumberLiterals)
6670

71+
def symbolLiteralsEnabled(using Context) = enabled(symbolLiterals)
72+
6773
def scala2ExperimentalMacroEnabled(using Context) = enabled(Xmacros)
6874

6975
def sourceVersionSetting(using Context): SourceVersion =

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ class Definitions {
773773
@tu lazy val LanguageModule: Symbol = requiredModule("scala.language")
774774
@tu lazy val LanguageModuleClass: Symbol = LanguageModule.moduleClass.asClass
775775
@tu lazy val LanguageExperimentalModule: Symbol = requiredModule("scala.language.experimental")
776+
@tu lazy val LanguageDeprecatedModule: Symbol = requiredModule("scala.language.deprecated")
776777
@tu lazy val NonLocalReturnControlClass: ClassSymbol = requiredClass("scala.runtime.NonLocalReturnControl")
777778
@tu lazy val SelectableClass: ClassSymbol = requiredClass("scala.Selectable")
778779

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ object StdNames {
449449
val definitions: N = "definitions"
450450
val delayedInit: N = "delayedInit"
451451
val delayedInitArg: N = "delayedInit$body"
452+
val deprecated: N = "deprecated"
452453
val derived: N = "derived"
453454
val derives: N = "derives"
454455
val doubleHash: N = "doubleHash"

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import util.Chars
2828
import scala.annotation.{tailrec, switch}
2929
import rewrites.Rewrites.{patch, overlapsPatch}
3030
import reporting._
31-
import config.Feature.{sourceVersion, migrateTo3, dependentEnabled}
31+
import config.Feature.{sourceVersion, migrateTo3, dependentEnabled, symbolLiteralsEnabled}
3232
import config.SourceVersion._
3333
import config.SourceVersion
3434

@@ -1193,17 +1193,17 @@ object Parsers {
11931193
in.nextToken()
11941194
Quote(t)
11951195
}
1196-
else {
1197-
report.errorOrMigrationWarning(
1198-
em"""symbol literal '${in.name} is no longer supported,
1199-
|use a string literal "${in.name}" or an application Symbol("${in.name}") instead,
1200-
|or enclose in braces '{${in.name}} if you want a quoted expression.""",
1201-
in.sourcePos())
1202-
if migrateTo3 then
1203-
patch(source, Span(in.offset, in.offset + 1), "Symbol(\"")
1204-
patch(source, Span(in.charOffset - 1), "\")")
1196+
else
1197+
if !symbolLiteralsEnabled(using languageImportContext) then
1198+
report.errorOrMigrationWarning(
1199+
em"""symbol literal '${in.name} is no longer supported,
1200+
|use a string literal "${in.name}" or an application Symbol("${in.name}") instead,
1201+
|or enclose in braces '{${in.name}} if you want a quoted expression.""",
1202+
in.sourcePos())
1203+
if migrateTo3 then
1204+
patch(source, Span(in.offset, in.offset + 1), "Symbol(\"")
1205+
patch(source, Span(in.charOffset - 1), "\")")
12051206
atSpan(in.skipToken()) { SymbolLit(in.strVal) }
1206-
}
12071207
else if (in.token == INTERPOLATIONID) interpolatedString(inPattern)
12081208
else {
12091209
val t = literalOf(in.token)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,7 @@ trait Checking {
755755
case Some(prefix) =>
756756
val required =
757757
if prefix == nme.experimental then defn.LanguageExperimentalModule
758+
else if prefix == nme.deprecated then defn.LanguageDeprecatedModule
758759
else defn.LanguageModule
759760
if path.symbol != required then
760761
report.error(em"import looks like a language import, but refers to something else: ${path.symbol.showLocated}", path.srcPos)

library/src/scala/runtime/stdLibPatches/language.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ object language:
3838
object genericNumberLiterals
3939
end experimental
4040

41+
/** The deprecated object contains features that are no longer officially suypported in Scala.
42+
* Features in this object are slated for removal. New code should not use them and
43+
* old code should migrate away from them.
44+
*/
45+
object deprecated:
46+
47+
/** Symbol literals have been deprecated since 2.13. Since Scala 3.0 they
48+
* are no longer an official part of Scala. For compatibility with legacy software,
49+
* symbol literals are still supported with a language import, but new software
50+
* should not use them.
51+
*/
52+
object symbolLiterals
53+
end deprecated
54+
55+
object symbolLiterals
56+
4157
/** Where imported, auto-tupling is disabled.
4258
*
4359
* '''Why control the feature?''' Auto-tupling can lead to confusing and

tests/neg/symlits.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def f =
2+
import language.deprecated.symbolLiterals
3+
val x = 'Hello
4+
5+
val y = 'no // error

0 commit comments

Comments
 (0)