Skip to content

Commit 96ced02

Browse files
authored
Merge pull request #11588 from dotty-staging/add-symlit-import
Add language.deprecated.symbolLiterals import
2 parents 98e3839 + fe22b3b commit 96ced02

File tree

8 files changed

+59
-23
lines changed

8 files changed

+59
-23
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
@@ -450,6 +450,7 @@ object StdNames {
450450
val definitions: N = "definitions"
451451
val delayedInit: N = "delayedInit"
452452
val delayedInitArg: N = "delayedInit$body"
453+
val deprecated: N = "deprecated"
453454
val derived: N = "derived"
454455
val derives: N = "derives"
455456
val doubleHash: N = "doubleHash"

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

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@ import NameKinds.WildcardParamName
1717
import NameOps._
1818
import ast.{Positioned, Trees}
1919
import ast.Trees._
20+
import typer.ImportInfo
2021
import StdNames._
2122
import util.Spans._
2223
import Constants._
23-
import Symbols.defn
24+
import Symbols.{defn, NoSymbol}
2425
import ScriptParsers._
2526
import Decorators._
2627
import util.Chars
2728
import scala.annotation.{tailrec, switch}
2829
import rewrites.Rewrites.{patch, overlapsPatch}
2930
import reporting._
30-
import config.Feature.{sourceVersion, migrateTo3, dependentEnabled}
31+
import config.Feature.{sourceVersion, migrateTo3, dependentEnabled, symbolLiteralsEnabled}
3132
import config.SourceVersion._
3233
import config.SourceVersion
3334

@@ -496,20 +497,19 @@ object Parsers {
496497
* Parameters appear in reverse order.
497498
*/
498499
var placeholderParams: List[ValDef] = Nil
500+
var languageImportContext: Context = ctx
499501

500-
def checkNoEscapingPlaceholders[T](op: => T): T = {
502+
def checkNoEscapingPlaceholders[T](op: => T): T =
501503
val savedPlaceholderParams = placeholderParams
504+
val savedLanguageImportContext = languageImportContext
502505
placeholderParams = Nil
503-
504506
try op
505-
finally {
506-
placeholderParams match {
507+
finally
508+
placeholderParams match
507509
case vd :: _ => syntaxError(UnboundPlaceholderParameter(), vd.span)
508510
case _ =>
509-
}
510511
placeholderParams = savedPlaceholderParams
511-
}
512-
}
512+
languageImportContext = savedLanguageImportContext
513513

514514
def isWildcard(t: Tree): Boolean = t match {
515515
case Ident(name1) => placeholderParams.nonEmpty && name1 == placeholderParams.head.name
@@ -1197,17 +1197,19 @@ object Parsers {
11971197
in.nextToken()
11981198
Quote(t)
11991199
}
1200-
else {
1201-
report.errorOrMigrationWarning(
1202-
em"""symbol literal '${in.name} is no longer supported,
1203-
|use a string literal "${in.name}" or an application Symbol("${in.name}") instead,
1204-
|or enclose in braces '{${in.name}} if you want a quoted expression.""",
1205-
in.sourcePos())
1206-
if migrateTo3 then
1207-
patch(source, Span(in.offset, in.offset + 1), "Symbol(\"")
1208-
patch(source, Span(in.charOffset - 1), "\")")
1200+
else
1201+
if !symbolLiteralsEnabled(using languageImportContext) then
1202+
report.errorOrMigrationWarning(
1203+
em"""symbol literal '${in.name} is no longer supported,
1204+
|use a string literal "${in.name}" or an application Symbol("${in.name}") instead,
1205+
|or enclose in braces '{${in.name}} if you want a quoted expression.
1206+
|For now, you can also `import language.deprecated.symbolLiterals` to accept
1207+
|the idiom, but this possibility might no longer be available in the future.""",
1208+
in.sourcePos())
1209+
if migrateTo3 then
1210+
patch(source, Span(in.offset, in.offset + 1), "Symbol(\"")
1211+
patch(source, Span(in.charOffset - 1), "\")")
12091212
atSpan(in.skipToken()) { SymbolLit(in.strVal) }
1210-
}
12111213
else if (in.token == INTERPOLATIONID) interpolatedString(inPattern)
12121214
else {
12131215
val t = literalOf(in.token)
@@ -1629,7 +1631,7 @@ object Parsers {
16291631
typeIdent()
16301632
else
16311633
def singletonArgs(t: Tree): Tree =
1632-
if in.token == LPAREN && dependentEnabled
1634+
if in.token == LPAREN && dependentEnabled(using languageImportContext)
16331635
then singletonArgs(AppliedTypeTree(t, inParens(commaSeparated(singleton))))
16341636
else t
16351637
singletonArgs(simpleType1())
@@ -3094,7 +3096,9 @@ object Parsers {
30943096

30953097
/** Create an import node and handle source version imports */
30963098
def mkImport(outermost: Boolean = false): ImportConstr = (tree, selectors) =>
3099+
val imp = Import(tree, selectors)
30973100
if isLanguageImport(tree) then
3101+
languageImportContext = languageImportContext.importContext(imp, NoSymbol)
30983102
for
30993103
case ImportSelector(id @ Ident(imported), EmptyTree, _) <- selectors
31003104
if allSourceVersionNames.contains(imported)
@@ -3105,7 +3109,7 @@ object Parsers {
31053109
syntaxError(i"duplicate source version import", id.span)
31063110
else
31073111
ctx.compilationUnit.sourceVersion = Some(SourceVersion.valueOf(imported.toString))
3108-
Import(tree, selectors)
3112+
imp
31093113

31103114
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
31113115
* | SimpleRef ‘as’ id

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)