From 662d54ec4c3823616a41c8f20cef93cc69ad2819 Mon Sep 17 00:00:00 2001 From: Fernando Perez Diaz Date: Sun, 17 Sep 2023 03:57:36 +0200 Subject: [PATCH 1/3] Fix #18234: Warn of identifiers with $ in their name --- compiler/src/dotty/tools/dotc/Compiler.scala | 3 +- .../tools/dotc/config/ScalaSettings.scala | 1 + .../transform/CheckDollarInIdentifier.scala | 88 +++++++ tests/neg/i18234.check | 244 ++++++++++++++++++ tests/neg/i18234.scala | 162 ++++++++++++ tests/pos/i18234.scala | 38 +++ 6 files changed, 535 insertions(+), 1 deletion(-) create mode 100644 compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala create mode 100644 tests/neg/i18234.check create mode 100644 tests/neg/i18234.scala create mode 100644 tests/pos/i18234.scala diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index d34fa247b155..075e9e6c3b63 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -35,7 +35,8 @@ class Compiler { protected def frontendPhases: List[List[Phase]] = List(new Parser) :: // Compiler frontend: scanner, parser List(new TyperPhase) :: // Compiler frontend: namer, typer - List(new CheckUnused.PostTyper) :: // Check for unused elements + List(new CheckUnused.PostTyper) :: // Check for unused elements + List(new CheckDollarInIdentifier) :: // Warn if identifier contains a dollar sign $ List(new CheckShadowing) :: // Check shadowing elements List(new YCheckPositions) :: // YCheck positions List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 43c2cd5a2ff9..ae7ca5d3516a 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -195,6 +195,7 @@ private sealed trait WarningSettings: ), default = Nil ) + val WdollarCheck: Setting[Boolean] = BooleanSetting("-Wdollar-check", "Warn if identifier contains a dollar sign") object WunusedHas: def isChoiceSet(s: String)(using Context) = Wunused.value.pipe(us => us.contains(s)) def allOr(s: String)(using Context) = Wunused.value.pipe(us => us.contains("all") || us.contains(s)) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala b/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala new file mode 100644 index 000000000000..813d6527c974 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala @@ -0,0 +1,88 @@ +package dotty.tools.dotc.transform + +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.ast.tpd.Tree +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.transform.MegaPhase.MiniPhase +import dotty.tools.dotc.core.Contexts.* +import dotty.tools.dotc.core.StdNames.nme +import dotty.tools.dotc.report +import dotty.tools.dotc.reporting.* +import dotty.tools.dotc.util.SourcePosition + + +class CheckDollarInIdentifier extends MiniPhase: + import CheckDollarInIdentifier.ShouldNotContainDollarSignError + + override def phaseName: String = CheckUnused.phaseNamePrefix + + override def description: String = CheckUnused.description + + override def isRunnable(using Context): Boolean = + super.isRunnable && ctx.settings.WdollarCheck.value + + override def transformValDef(tree: tpd.ValDef)(using Context): tpd.Tree = + reportDollarInIdentifier(tree) + + override def transformDefDef(tree: tpd.DefDef)(using Context): tpd.Tree = + reportDollarInIdentifier(tree) + + override def transformTypeDef(tree: tpd.TypeDef)(using Context): tpd.Tree = + reportDollarInIdentifier(tree) + + override def transformTemplate(tree: tpd.Template)(using Context): tpd.Tree = + reportDollarInIdentifier(tree) + + override def transformCaseDef(tree: tpd.CaseDef)(using Context): tpd.Tree = + reportDollarInIdentifier(tree) + + override def transformPackageDef(tree: tpd.PackageDef)(using Context): tpd.Tree = + reportDollarInIdentifier(tree) + + + private val allowedValTermNames = List( + nme.DOLLAR_VALUES, + nme.ordinalDollar_, + ).map(_.toString) + + private val allowedDefTermNames = List( + nme.DOLLAR_NEW, + ).map(_.toString) + + private def allowedTerms[T <: Tree](tree: T): List[String] = + tree match + case _: tpd.ValDef => allowedValTermNames + case _: tpd.DefDef => allowedDefTermNames + case _ => Nil + + private def containsAllowedTerms[T <: Tree](tree: T, name: String): Boolean = + allowedTerms(tree).contains(name) + + private def symbolName[T <: Tree](tree: T)(using Context): String = + tree match + case typeDef: tpd.TypeDef => + typeDef.symbol.toString match { + case s"module class $className$$" => className // to catch the compiled singleton class which includes a $ at the end + case _ => tree.symbol.name.toString + } + case _ => tree.symbol.name.toString + + private def reportDollarInIdentifier[T <: Tree](tree: T)(using Context): T = + val name = symbolName(tree) + val originalSrcPos = tree.srcPos.sourcePos + val originalSpan = originalSrcPos.span + + // only report source-derived (non-synthetic) spans + if name.contains("$") && !containsAllowedTerms(tree, name) && !originalSpan.isSynthetic then + val srcPos = originalSrcPos.withSpan(originalSrcPos.span.focus) // focus span to place a single `^` at identifier position + report.warning(ShouldNotContainDollarSignError, srcPos) + + tree + + +object CheckDollarInIdentifier: + val name: String = "dollarWarn" + val description: String = "warns if identifiers contain dollar sign, $" + + private val ShouldNotContainDollarSignError = s"identifiers should not include dollar sign" + diff --git a/tests/neg/i18234.check b/tests/neg/i18234.check new file mode 100644 index 000000000000..42c134dd3e6b --- /dev/null +++ b/tests/neg/i18234.check @@ -0,0 +1,244 @@ +-- Error: tests/neg/i18234.scala:40:7 ---------------------------------------------------------------------------------- +40 | case $BadCaseStart // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:41:7 ---------------------------------------------------------------------------------- +41 | case BadCase$Middle // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:42:7 ---------------------------------------------------------------------------------- +42 | case BadCaseEnd$ // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:44:5 ---------------------------------------------------------------------------------- +44 |enum $BadEnumStart: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:46:7 ---------------------------------------------------------------------------------- +46 | case $BadCase // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:48:5 ---------------------------------------------------------------------------------- +48 |enum BadEnum$Middle: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:50:7 ---------------------------------------------------------------------------------- +50 | case Bad$Case // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:52:5 ---------------------------------------------------------------------------------- +52 |enum BadEnumEnd$: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:54:7 ---------------------------------------------------------------------------------- +54 | case BadCase$ // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:56:5 ---------------------------------------------------------------------------------- +56 |enum E$numWithEndKeyword: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:68:6 ---------------------------------------------------------------------------------- +68 | val $badVal = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:66:7 ---------------------------------------------------------------------------------- +66 |object $ObjectStart: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:72:6 ---------------------------------------------------------------------------------- +72 | val bad$Val = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:70:7 ---------------------------------------------------------------------------------- +70 |object Object$Middle: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:76:6 ---------------------------------------------------------------------------------- +76 | val badVal$ = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:74:7 ---------------------------------------------------------------------------------- +74 |object ObjectEnd$: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:80:6 ---------------------------------------------------------------------------------- +80 | val b$adVal = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:82:7 ---------------------------------------------------------------------------------- +82 |object Ob$jectWithEndKeyword: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:89:11 --------------------------------------------------------------------------------- +89 |case class $InlineCaseClassStart(someField: Int) // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:90:11 --------------------------------------------------------------------------------- +90 |case class InlineCaseClass$Middle(someField: Int) // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:91:11 --------------------------------------------------------------------------------- +91 |case class InlineCaseClassEnd$(someField: Int) // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:93:43 --------------------------------------------------------------------------------- +93 |case class InlineCaseClass(goodField: Int, badFiel$d: Int) // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:97:2 ---------------------------------------------------------------------------------- +97 | b$adfield: Int // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:95:11 --------------------------------------------------------------------------------- +95 |case class $CaseClassStart( // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:102:2 --------------------------------------------------------------------------------- +102 | bad$Field: Int // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:100:11 -------------------------------------------------------------------------------- +100 |case class CaseClass$Middle( // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:107:2 --------------------------------------------------------------------------------- +107 | badField$: Int // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:105:11 -------------------------------------------------------------------------------- +105 |case class CaseClassEnd$( // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:111:7 --------------------------------------------------------------------------------- +111 |object CaseClassEnd$: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:118:6 --------------------------------------------------------------------------------- +118 |class $StartClass // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:119:6 --------------------------------------------------------------------------------- +119 |class Middle$Class // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:120:6 --------------------------------------------------------------------------------- +120 |class EndClass$ // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:124:7 --------------------------------------------------------------------------------- +124 | var badM$ember: Int // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:127:6 --------------------------------------------------------------------------------- +127 | def bad$Method(y: Int) = goodMember // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:128:28 -------------------------------------------------------------------------------- +128 | def methodWithBadArgNames(b$ad$arg: Int) = goodMember // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:129:6 --------------------------------------------------------------------------------- +129 | def method$WithEndKeyword() = // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:122:6 --------------------------------------------------------------------------------- +122 |class Cla$$( // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:142:6 --------------------------------------------------------------------------------- +142 |trait $BadTraitStart // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:143:6 --------------------------------------------------------------------------------- +143 |trait BadTrait$Middle // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:144:6 --------------------------------------------------------------------------------- +144 |trait BadTraitEnd$ // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:150:6 --------------------------------------------------------------------------------- +150 | val b$adVal = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:154:6 --------------------------------------------------------------------------------- +154 | val $badVal = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:152:8 --------------------------------------------------------------------------------- +152 |package $BadPackageStart: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:158:6 --------------------------------------------------------------------------------- +158 | val bad$Val = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:156:8 --------------------------------------------------------------------------------- +156 |package BadPackage$Middle: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:162:6 --------------------------------------------------------------------------------- +162 | val badVal$ = 2 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:160:8 --------------------------------------------------------------------------------- +160 |package BadPackageEnd$: // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:5:4 ----------------------------------------------------------------------------------- +5 |val $startVal = 1 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:6:4 ----------------------------------------------------------------------------------- +6 |val mid$dleVal = 1 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:7:4 ----------------------------------------------------------------------------------- +7 |val endVal$ = 1 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:13:4 ---------------------------------------------------------------------------------- +13 |def $funcStart() = 3 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:14:4 ---------------------------------------------------------------------------------- +14 |def func$Middle() = 3 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:15:4 ---------------------------------------------------------------------------------- +15 |def funcEnd$() = 3 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:17:30 --------------------------------------------------------------------------------- +17 |def func1badArg(goodArg: Int, bad$Arg: Int) = 5 // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:18:57 --------------------------------------------------------------------------------- +18 |def func1badArgAndUsageDoesNotThrowWarning(goodArg: Int, bad$Arg: Int) = bad$Arg // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:19:31 --------------------------------------------------------------------------------- +19 |def func2badArgs(goodArg: Int, bad$Arg: Int, bad$arg2: String) = 5 // error // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:19:45 --------------------------------------------------------------------------------- +19 |def func2badArgs(goodArg: Int, bad$Arg: Int, bad$arg2: String) = 5 // error // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:22:2 ---------------------------------------------------------------------------------- +22 | badAr$g: Int // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:30:5 ---------------------------------------------------------------------------------- +30 |type $StartType = Int // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:31:5 ---------------------------------------------------------------------------------- +31 |type Middle$Type = Int // error + | ^ + | identifiers should not include dollar sign +-- Error: tests/neg/i18234.scala:32:5 ---------------------------------------------------------------------------------- +32 |type EndType$ = Int // error + | ^ + | identifiers should not include dollar sign diff --git a/tests/neg/i18234.scala b/tests/neg/i18234.scala new file mode 100644 index 000000000000..207d01fd6a6b --- /dev/null +++ b/tests/neg/i18234.scala @@ -0,0 +1,162 @@ +//> using options -Xfatal-warnings -Wdollar-check + +/* vals */ +val goodVal = 1 +val $startVal = 1 // error +val mid$dleVal = 1 // error +val endVal$ = 1 // error + +def testValUsage = + $startVal + endVal$ // ok, should only warn on declaration not on usage + +/* functions */ +def $funcStart() = 3 // error +def func$Middle() = 3 // error +def funcEnd$() = 3 // error + +def func1badArg(goodArg: Int, bad$Arg: Int) = 5 // error +def func1badArgAndUsageDoesNotThrowWarning(goodArg: Int, bad$Arg: Int) = bad$Arg // error +def func2badArgs(goodArg: Int, bad$Arg: Int, bad$arg2: String) = 5 // error // error +def multilineFunc( + goodArg: Int, + badAr$g: Int // error +) = 1 + +def testFuncUsaage = + $funcStart() + func1badArg(1, 2) // ok, should only warn on declaration not on usage + +/* types */ +type GoodType = Int +type $StartType = Int // error +type Middle$Type = Int // error +type EndType$ = Int // error + +val typedVal: Middle$Type = 2 // ok, should only warn on declaration not on usage +def funcWithDollarTypes(foo: $StartType): Middle$Type = 2 // ok, should only warn on declaration not on usage + +/* enums */ +enum GoodEnum: + case GoodCase + case $BadCaseStart // error + case BadCase$Middle // error + case BadCaseEnd$ // error + +enum $BadEnumStart: // error + case GoodCase + case $BadCase // error + +enum BadEnum$Middle: // error + case GoodCase + case Bad$Case // error + +enum BadEnumEnd$: // error + case GoodCase + case BadCase$ // error + +enum E$numWithEndKeyword: // error + case SomeCase +end E$numWithEndKeyword // ok + +def TestEnumUsage(a: $BadEnumStart): Int = // ok, should only warn on declaration not on usage + a match + case $BadEnumStart.GoodCase => 1 + case $BadEnumStart.$BadCase => 2 // ok, should only warn on declaration not on usage + +/* objects */ +object $ObjectStart: // error + val goodVal = 1 + val $badVal = 2 // error + +object Object$Middle: // error + val goodVal = 1 + val bad$Val = 2 // error + +object ObjectEnd$: // error + val goodVal = 1 + val badVal$ = 2 // error + +object GoodObject: + val goodVal = 1 + val b$adVal = 2 // error + +object Ob$jectWithEndKeyword: // error + val someVal = 1 +end Ob$jectWithEndKeyword // ok + +val testObjectUsage = ObjectEnd$.badVal$ // ok, should only warn on declaration not on usage + +/* case classes */ +case class $InlineCaseClassStart(someField: Int) // error +case class InlineCaseClass$Middle(someField: Int) // error +case class InlineCaseClassEnd$(someField: Int) // error + +case class InlineCaseClass(goodField: Int, badFiel$d: Int) // error + +case class $CaseClassStart( // error + somefield: Int, + b$adfield: Int // error +) + +case class CaseClass$Middle( // error + somefield: Int, + bad$Field: Int // error +) + +case class CaseClassEnd$( // error + somefield: Int, + badField$: Int // error +) + +// companion oject +object CaseClassEnd$: // error + val food = 1 + +val testCaseClassUsage = CaseClass$Middle(somefield = 1, bad$Field = 2) // ok, should only warn on declaration not on usage + +/* classes */ +class GoodClass +class $StartClass // error +class Middle$Class // error +class EndClass$ // error + +class Cla$$( // error + var goodMember: Int, + var badM$ember: Int // error +): + def goodMethod(x: Int) = badM$ember // ok, only checking if the method name does not contain a dollar sign + def bad$Method(y: Int) = goodMember // error + def methodWithBadArgNames(b$ad$arg: Int) = goodMember // error + def method$WithEndKeyword() = // error + 3 + end method$WithEndKeyword +end Cla$$ // ok + +def testUsage = + val instatiation = new Cla$$(goodMember = 1, badM$ember = 2) // ok, should only warn on declaration not on usage + instatiation.bad$Method(1) // ok, should only warn on declaration not on usage + instatiation.methodWithBadArgNames(2) // ok, should only warn on declaration not on usage + + +/* traits */ +trait GoodTrait +trait $BadTraitStart // error +trait BadTrait$Middle // error +trait BadTraitEnd$ // error + +class TestTraitUsage extends $BadTraitStart // ok, should only warn on declaration not on usage + +package GoodPackage: + val goodVal = 1 + val b$adVal = 2 // error + +package $BadPackageStart: // error + val goodVal = 1 + val $badVal = 2 // error + +package BadPackage$Middle: // error + val goodVal = 1 + val bad$Val = 2 // error + +package BadPackageEnd$: // error + val goodVal = 1 + val badVal$ = 2 // error \ No newline at end of file diff --git a/tests/pos/i18234.scala b/tests/pos/i18234.scala new file mode 100644 index 000000000000..ff4f7664e17d --- /dev/null +++ b/tests/pos/i18234.scala @@ -0,0 +1,38 @@ +//> using options -Xfatal-warnings -Wdollar-check + +val goodVal = 1 +def func() = 1 +def func1(a: Int) = a +def func2( + a: Int, + b: Int +) = a + b + +type GoodType = Int + +val typedVal: GoodType = 2 + +enum GoodEnum: + case GoodCase + +case class CaseClass(someField: Int) // error + +class GoodClass + +class Class( + var goodMember: Int, +): + def goodMethod(x: Int) = goodMember +end Class + +def testUsage = + val instatiation = new Class(goodMember = 1) + instatiation.goodMethod(1) + + +trait GoodTrait + +class TestTraitUsage extends GoodTrait + +package GoodPackage: + val goodVal = 1 \ No newline at end of file From ad3630772abbef66cb669bb4f525b7a5e0ee65ef Mon Sep 17 00:00:00 2001 From: Fernando Perez Diaz Date: Sun, 8 Oct 2023 22:37:05 +0200 Subject: [PATCH 2/3] Fix phase name & description. Add to same megaphase as CheckUnused --- compiler/src/dotty/tools/dotc/Compiler.scala | 4 ++-- .../dotc/transform/CheckDollarInIdentifier.scala | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 075e9e6c3b63..35fee8e66025 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -35,8 +35,8 @@ class Compiler { protected def frontendPhases: List[List[Phase]] = List(new Parser) :: // Compiler frontend: scanner, parser List(new TyperPhase) :: // Compiler frontend: namer, typer - List(new CheckUnused.PostTyper) :: // Check for unused elements - List(new CheckDollarInIdentifier) :: // Warn if identifier contains a dollar sign $ + List(new CheckUnused.PostTyper, // Check for unused elements + new CheckDollarInIdentifier) :: // Warn if identifier contains a dollar sign $ List(new CheckShadowing) :: // Check shadowing elements List(new YCheckPositions) :: // YCheck positions List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks diff --git a/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala b/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala index 813d6527c974..cccee9a2dd57 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala @@ -7,19 +7,19 @@ import dotty.tools.dotc.transform.MegaPhase.MiniPhase import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.StdNames.nme import dotty.tools.dotc.report -import dotty.tools.dotc.reporting.* -import dotty.tools.dotc.util.SourcePosition class CheckDollarInIdentifier extends MiniPhase: import CheckDollarInIdentifier.ShouldNotContainDollarSignError - override def phaseName: String = CheckUnused.phaseNamePrefix + override def phaseName: String = CheckDollarInIdentifier.phaseName - override def description: String = CheckUnused.description + override def description: String = CheckDollarInIdentifier.description override def isRunnable(using Context): Boolean = - super.isRunnable && ctx.settings.WdollarCheck.value + super.isRunnable && + ctx.settings.WdollarCheck.value && + !ctx.isJava override def transformValDef(tree: tpd.ValDef)(using Context): tpd.Tree = reportDollarInIdentifier(tree) @@ -81,7 +81,7 @@ class CheckDollarInIdentifier extends MiniPhase: object CheckDollarInIdentifier: - val name: String = "dollarWarn" + val phaseName: String = "checkDollarInIdentifier" val description: String = "warns if identifiers contain dollar sign, $" private val ShouldNotContainDollarSignError = s"identifiers should not include dollar sign" From 2727c77205b87bea2151060d7ed176a432beaff3 Mon Sep 17 00:00:00 2001 From: Fernando Perez Diaz Date: Mon, 9 Oct 2023 00:11:42 +0200 Subject: [PATCH 3/3] Add more pos tests --- .../transform/CheckDollarInIdentifier.scala | 1 + tests/pos/i18234.scala | 64 ++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala b/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala index cccee9a2dd57..7fae289ced1e 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckDollarInIdentifier.scala @@ -47,6 +47,7 @@ class CheckDollarInIdentifier extends MiniPhase: private val allowedDefTermNames = List( nme.DOLLAR_NEW, + nme.ANON_FUN, ).map(_.toString) private def allowedTerms[T <: Tree](tree: T): List[String] = diff --git a/tests/pos/i18234.scala b/tests/pos/i18234.scala index ff4f7664e17d..be3a1899c6cd 100644 --- a/tests/pos/i18234.scala +++ b/tests/pos/i18234.scala @@ -19,6 +19,10 @@ case class CaseClass(someField: Int) // error class GoodClass +object GoodClass: + val companionObjectValue = 5 +end GoodClass + class Class( var goodMember: Int, ): @@ -35,4 +39,62 @@ trait GoodTrait class TestTraitUsage extends GoodTrait package GoodPackage: - val goodVal = 1 \ No newline at end of file + val goodVal = 1 + + +lazy val lazyVal = 23 + +val listWithAnonymousFunc = List(1, 2, 3).map(_ * 2).map((num) => num + 1) + +object TestAnonymousClass: + trait SomeTrait: + def somefunc(): String + + val anObject = new SomeTrait: + override def somefunc(): String = "hello" +end TestAnonymousClass + +val partialFunc: PartialFunction[Int, Int] = + case x if x <= 0 => Math.abs(x) + +val anotherPartialFunc: PartialFunction[String, String] = { case x @ "abc" => x } + +object TestInline: + import scala.quoted.* // imports Quotes, Expr + + inline val pi = 3.141592653589793 + + inline def power(inline x: Double, inline n: Int) = + ${ powerCode('x, 'n) } + + + def pow(x: Double, n: Int): Double = + if n == 0 then 1 else x * pow(x, n - 1) + + def powerCode( + x: Expr[Double], + n: Expr[Int] + )(using Quotes): Expr[Double] = + val value: Double = pow(x.valueOrAbort, n.valueOrAbort) + Expr(value) + +end TestInline + +object TestGivens: + trait Showable[A]: + extension (a: A) def show: String + case class Person(firstName: String, lastName: String) + // anonymous given + given Showable[Person] with + extension (p: Person) def show: String = + s"${p.firstName} ${p.lastName}" + // named given + given caseClassShowable: Showable[CaseClass] with + extension (c: CaseClass) def show: String = s"number ${c.someField}" + def showMe[T: Showable](t: T) = t.show + showMe(Person("John", "Doe")) + showMe(CaseClass(42)) + + given Int = 42 + def showUsing(using someNumber: Int) = CaseClass(someNumber) +end TestGivens \ No newline at end of file