Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum MigrationVersion(val warnFrom: SourceVersion, val errorFrom: SourceVersion)
case GivenSyntax extends MigrationVersion(future, future)
case ImplicitParamsWithoutUsing extends MigrationVersion(`3.7`, future)
case Scala2Implicits extends MigrationVersion(future, future)
case IdentifierDollars extends MigrationVersion(`3.8`, `3.9`)

require(warnFrom.ordinal <= errorFrom.ordinal)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,6 @@ class ClassfileTastyUUIDParser(classfile: AbstractFile)(ictx: Context) {
class ConstantPool(using in: DataReader) extends ClassfileParser.AbstractConstantPool {
def getClassOrArrayType(index: Int)(using ctx: Context, in: DataReader): Type = throw new UnsupportedOperationException
def getClassSymbol(index: Int)(using ctx: Context, in: DataReader): Symbol = throw new UnsupportedOperationException
def getType(index: Int, isVarargs: Boolean)(using x$3: Context, x$4: DataReader): Type = throw new UnsupportedOperationException
def getType(index: Int, isVarargs: Boolean)(using Context, DataReader): Type = throw new UnsupportedOperationException
}
}
41 changes: 28 additions & 13 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1286,9 +1286,7 @@ object Parsers {
if (isIdent) {
val name = in.name
if name == nme.CONSTRUCTOR || name == nme.STATIC_CONSTRUCTOR then
report.error(
em"""Illegal backquoted identifier: `<init>` and `<clinit>` are forbidden""",
in.sourcePos())
report.error(IllegalIdentifier(name), in.sourcePos())
in.nextToken()
name
}
Expand All @@ -1297,6 +1295,19 @@ object Parsers {
nme.ERROR
}

/** An ident that is checked to be clean for a definition. */
def defName(): TermName =
val checkable = in.token != BACKQUOTED_IDENT
val start = in.sourcePos()
ident().tap: name =>
if checkable && name.toSimpleName.contains('$') then
report.errorOrMigrationWarning(IllegalIdentifier(name), start, MigrationVersion.IdentifierDollars)

extension (nameTree: NameTree) def checkName: nameTree.type =
if !isBackquoted(nameTree) && nameTree.name.toSimpleName.contains('$') then
report.errorOrMigrationWarning(IllegalIdentifier(nameTree.name), nameTree.srcPos, MigrationVersion.IdentifierDollars)
nameTree

/** Accept identifier and return Ident with its name as a term name. */
def termIdent(): Ident =
makeIdent(in.token, in.offset, ident())
Expand All @@ -1309,7 +1320,7 @@ object Parsers {
val tree = Ident(name)
if (tok == BACKQUOTED_IDENT) tree.pushAttachment(Backquoted, ())

// Make sure that even trees with parsing errors have a offset that is within the offset
// Make sure that even trees with parsing errors have an offset that is within the offset
val errorOffset = offset min (in.lastOffset - 1)
if (tree.name == nme.ERROR && tree.span == NoSpan) tree.withSpan(Span(errorOffset, errorOffset))
else atSpan(offset)(tree)
Expand Down Expand Up @@ -1379,7 +1390,7 @@ object Parsers {

/** QualId ::= id {`.' id}
*/
def qualId(): Tree = dotSelectors(termIdent())
def qualId(): Tree = dotSelectors(termIdent().checkName)

/** SimpleLiteral ::= [‘-’] integerLiteral
* | [‘-’] floatingPointLiteral
Expand Down Expand Up @@ -3414,6 +3425,9 @@ object Parsers {
p = atSpan(startOffset(t), in.offset) { TypeApply(p, typeArgs(namedOK = false, wildOK = false)) }
if (in.token == LPAREN)
p = atSpan(startOffset(t), in.offset) { Apply(p, argumentPatterns()) }
p match
case nt: NameTree if isVarPattern(nt) => checkName(nt)
case _ =>
p

/** Patterns ::= Pattern [`,' Pattern]
Expand Down Expand Up @@ -3773,7 +3787,7 @@ object Parsers {
mods |= Param
}
atSpan(start, nameStart) {
val name = ident()
val name = defName()
acceptColon()
if (in.token == ARROW && paramOwner.isClass && !mods.is(Local))
syntaxError(VarValParametersMayNotBeCallByName(name, mods.is(Mutable)))
Expand Down Expand Up @@ -4103,6 +4117,7 @@ object Parsers {
case IdPattern(id, t) :: Nil if t.isEmpty =>
val vdef = ValDef(id.name.asTermName, tpt, rhs)
if (isBackquoted(id)) vdef.pushAttachment(Backquoted, ())
else checkName(id)
finalizeDef(vdef, mods, start)
case _ =>
def isAllIds = lhs.forall {
Expand Down Expand Up @@ -4158,7 +4173,7 @@ object Parsers {
}
else {
val mods1 = addFlag(mods, Method)
val ident = termIdent()
val ident = termIdent().checkName
var name = ident.name.asTermName
val paramss =
if sourceVersion.enablesClauseInterleaving then
Expand Down Expand Up @@ -4229,7 +4244,7 @@ object Parsers {

newLinesOpt()
atSpan(start, nameStart) {
val nameIdent = typeIdent()
val nameIdent = typeIdent().checkName
val isCapDef = gobbleHat()
val tname = nameIdent.name.asTypeName
val tparams = typeParamClauseOpt(ParamOwner.Hk)
Expand Down Expand Up @@ -4321,7 +4336,7 @@ object Parsers {
/** ClassDef ::= id ClassConstr TemplateOpt
*/
def classDef(start: Offset, mods: Modifiers): TypeDef = atSpan(start, nameStart) {
classDefRest(start, mods, ident().toTypeName)
classDefRest(start, mods, defName().toTypeName)
}

def classDefRest(start: Offset, mods: Modifiers, name: TypeName): TypeDef =
Expand All @@ -4346,7 +4361,7 @@ object Parsers {
/** ObjectDef ::= id TemplateOpt
*/
def objectDef(start: Offset, mods: Modifiers): ModuleDef = atSpan(start, nameStart) {
val name = ident()
val name = defName()
val templ = templateOpt(emptyConstructor)
finalizeDef(ModuleDef(name, templ), mods, start)
}
Expand All @@ -4366,7 +4381,7 @@ object Parsers {
*/
def enumDef(start: Offset, mods: Modifiers): TypeDef = atSpan(start, nameStart) {
val mods1 = checkAccessOnly(mods, "")
val modulName = ident()
val modulName = defName()
val clsName = modulName.toTypeName
val constr = classConstr(ParamOwner.Class)
val templ = template(constr, isEnum = true)
Expand All @@ -4380,10 +4395,10 @@ object Parsers {
accept(CASE)

atSpan(start, nameStart) {
val id = termIdent()
val id = termIdent().checkName
if (in.token == COMMA) {
in.nextToken()
val ids = commaSeparated(() => termIdent())
val ids = commaSeparated(() => termIdent().checkName)
if ctx.settings.Whas.enumCommentDiscard then
in.getDocComment(start).foreach: comm =>
warning(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case DefaultShadowsGivenID // errorNumber: 220
case RecurseWithDefaultID // errorNumber: 221
case EncodedPackageNameID // errorNumber: 222
case IllegalIdentifierID // errorNumber: 223

def errorNumber = ordinal - 1

Expand Down
18 changes: 18 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3749,3 +3749,21 @@ final class EncodedPackageName(name: Name)(using Context) extends SyntaxMsg(Enco
|or `myfile-test.scala` can produce encoded names for the generated package objects.
|
|In this case, the name `$name` is encoded as `${name.encode}`."""

final class IllegalIdentifier(name: Name)(using Context) extends SyntaxMsg(IllegalIdentifierID):
override protected def msg(using Context): String =
name match
case nme.CONSTRUCTOR | nme.STATIC_CONSTRUCTOR =>
"Illegal backquoted identifier: `<init>` and `<clinit>` are forbidden"
case _ =>
i"The identifier `$name` should not contain `$$`, which is reserved for internal compiler use."
override protected def explain(using Context): String =
name match
case nme.CONSTRUCTOR | nme.STATIC_CONSTRUCTOR =>
"Names can include unusual characters when enclosed in backquotes, but `<init>` and `<clinit>` are reserved."
case _ =>
i"""User identifiers may be encoded with embedded `$$`, and other compiler artifacts
|may rely on using `$$` with specific meanings.
|
|The prohibition against explicit `$$` may be ignored by enclosing the identifier in backquotes
|at the definition site."""
2 changes: 1 addition & 1 deletion library/src/scala/collection/immutable/List.scala
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ final case class :: [+A](override val head: A, private[scala] var next: List[A @
override def tail: List[A] = next

@publicInBinary
private[::] def next$access$1 = next
private[::] def `next$access$1` = next

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CompilerCachingSuite extends BasePCSuite:
case pc: ScalaPresentationCompiler =>
val compilations = pc.compilerAccess.withNonInterruptableCompiler(-1, EmptyCancelToken) { driver =>
driver.compiler().currentCtx.runId
}(emptyQueryContext).get(timeout.length, timeout.unit)
}(using emptyQueryContext).get(timeout.length, timeout.unit)
assertEquals(expected, compilations, s"Expected $expected compilations but got $compilations")
case _ => throw IllegalStateException("Presentation compiler should always be of type of ScalaPresentationCompiler")

Expand All @@ -39,7 +39,7 @@ class CompilerCachingSuite extends BasePCSuite:
case pc: ScalaPresentationCompiler =>
pc.compilerAccess.withNonInterruptableCompiler(null, EmptyCancelToken) { driver =>
driver.compiler().currentCtx
}(emptyQueryContext).get(timeout.length, timeout.unit)
}(using emptyQueryContext).get(timeout.length, timeout.unit)
case _ => throw IllegalStateException("Presentation compiler should always be of type of ScalaPresentationCompiler")

private def emptyQueryContext = PcQueryContext(None, () => "")(using EmptyReportContext())
Expand Down Expand Up @@ -133,7 +133,7 @@ class CompilerCachingSuite extends BasePCSuite:
checkCompilationCount(6)


private val testFunctions: List[OffsetParams => CompletableFuture[_]] = List(
private val testFunctions: List[OffsetParams => CompletableFuture[?]] = List(
presentationCompiler.complete(_),
presentationCompiler.convertToNamedArguments(_, Collections.emptyList()),
presentationCompiler.autoImports("a", _, false),
Expand Down
2 changes: 1 addition & 1 deletion repl/test-resources/type-printer/source-compatible
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ val m:
def i_=(x$1: Int): Unit; type N = Int; val l: List[Int];
def p[T](t: T): String
} = Bag()
scala> type t = Bag { val f: Int; def g: Int; def h(i: Int): Int; val i: Int; def i_=(x$1: Int): Unit; type N = Int; val l: List[Int]; val s: String @unchecked }
scala> type t = Bag { val f: Int; def g: Int; def h(i: Int): Int; val i: Int; def i_=(`x$1`: Int): Unit; type N = Int; val l: List[Int]; val s: String @unchecked }
// defined alias type t
=
Bag{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import scala.jdk.CollectionConverters._

case class LazyEntry(getKey: String, value: () => String) extends JMapEntry[String, Object]:
lazy val getValue: Object = value()
def setValue(x$0: Object): Object = ???
def setValue(`x$0`: Object): Object = ???

case class LoadedTemplate(
templateFile: TemplateFile,
Expand Down
2 changes: 1 addition & 1 deletion tests/init/pos/i10549a.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ class Wrap {
class E
object E {
final val A = new E {}
val $values = Array(A)
val `$values` = Array(A)
}
}
2 changes: 1 addition & 1 deletion tests/init/pos/i9664.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ object Wrap1 {
class E
object E {
final val A = E()
val $values = Array(A)
val `$values` = Array(A)
}
}
object Wrap2 {
Expand Down
2 changes: 1 addition & 1 deletion tests/init/warn/java1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class A extends Spliterator.OfDouble:
def characteristics() = 10
def estimateSize() = 10
def trySplit() = ???
def tryAdvance(x$0: java.util.function.DoubleConsumer): Boolean = false
def tryAdvance(`x$0`: java.util.function.DoubleConsumer): Boolean = false

val m = n + 1
val n = 10 // warn
2 changes: 1 addition & 1 deletion tests/neg/i15381.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//> using options -Vprint:parser

case class $[A](value: A)
case class `$`[A](value: A)

def g: Int = $ // error

Expand Down
Loading
Loading