Skip to content

Commit c32f5a9

Browse files
committed
Add support for @deprecatedInheritance
[Cherry-picked 290094d][modified]
1 parent 8c29c1f commit c32f5a9

File tree

13 files changed

+108
-46
lines changed

13 files changed

+108
-46
lines changed

Diff for: compiler/src/dotty/tools/dotc/core/Definitions.scala

+1
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,7 @@ class Definitions {
998998
@tu lazy val ProvisionalSuperClassAnnot: ClassSymbol = requiredClass("scala.annotation.internal.ProvisionalSuperClass")
999999
@tu lazy val DeprecatedAnnot: ClassSymbol = requiredClass("scala.deprecated")
10001000
@tu lazy val DeprecatedOverridingAnnot: ClassSymbol = requiredClass("scala.deprecatedOverriding")
1001+
@tu lazy val DeprecatedInheritanceAnnot: ClassSymbol = requiredClass("scala.deprecatedInheritance")
10011002
@tu lazy val ImplicitAmbiguousAnnot: ClassSymbol = requiredClass("scala.annotation.implicitAmbiguous")
10021003
@tu lazy val ImplicitNotFoundAnnot: ClassSymbol = requiredClass("scala.annotation.implicitNotFound")
10031004
@tu lazy val InlineParamAnnot: ClassSymbol = requiredClass("scala.annotation.internal.InlineParam")

Diff for: compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala

+2-6
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,10 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
4747

4848
private val compiler: Compiler = new InteractiveCompiler
4949

50-
private val myOpenedFiles = new mutable.LinkedHashMap[URI, SourceFile] {
51-
override def default(key: URI) = NoSource
52-
}
50+
private val myOpenedFiles = new mutable.LinkedHashMap[URI, SourceFile].withDefaultValue(NoSource)
5351
def openedFiles: Map[URI, SourceFile] = myOpenedFiles
5452

55-
private val myOpenedTrees = new mutable.LinkedHashMap[URI, List[SourceTree]] {
56-
override def default(key: URI) = Nil
57-
}
53+
private val myOpenedTrees = new mutable.LinkedHashMap[URI, List[SourceTree]].withDefaultValue(Nil)
5854
def openedTrees: Map[URI, List[SourceTree]] = myOpenedTrees
5955

6056
private val myCompilationUnits = new mutable.LinkedHashMap[URI, CompilationUnit]

Diff for: compiler/src/dotty/tools/dotc/reporting/Message.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ object Message:
5050
*/
5151
private class Seen(disambiguate: Boolean):
5252

53-
val seen = new collection.mutable.HashMap[SeenKey, List[Recorded]]:
54-
override def default(key: SeenKey) = Nil
53+
val seen = new collection.mutable.HashMap[SeenKey, List[Recorded]].withDefaultValue(Nil)
5554

5655
var nonSensical = false
5756

Diff for: compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import dotty.tools.dotc.reporting.CodeAction
1515

1616
/** Handles rewriting of Scala2 files to Dotty */
1717
object Rewrites {
18-
private class PatchedFiles extends mutable.HashMap[SourceFile, Patches]
18+
private type PatchedFiles = mutable.HashMap[SourceFile, Patches]
1919

2020
private case class Patch(span: Span, replacement: String) {
2121
def delta = replacement.length - (span.end - span.start)

Diff for: compiler/src/dotty/tools/dotc/semanticdb/SemanticSymbolBuilder.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ class SemanticSymbolBuilder:
2020
private val locals = mutable.HashMap[Symbol, Int]()
2121

2222
/** The local symbol(s) starting at given offset */
23-
private val symsAtOffset = new mutable.HashMap[Int, Set[Symbol]]():
24-
override def default(key: Int) = Set[Symbol]()
23+
private val symsAtOffset = new mutable.HashMap[Int, Set[Symbol]]().withDefault(_ => Set[Symbol]())
2524

2625

2726
def symbolName(sym: Symbol)(using Context): String =

Diff for: compiler/src/dotty/tools/dotc/transform/CountOuterAccesses.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ class CountOuterAccesses extends MiniPhase:
4343
// LambdaLift can create outer paths. These need to be known in this phase.
4444

4545
/** The number of times an outer accessor that might be dropped is accessed */
46-
val outerAccessCount = new mutable.HashMap[Symbol, Int] {
47-
override def default(s: Symbol): Int = 0
48-
}
46+
val outerAccessCount = new mutable.HashMap[Symbol, Int].withDefaultValue(0)
4947

5048
private def markAccessed(tree: RefTree)(using Context): Tree =
5149
val sym = tree.symbol

Diff for: compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -511,9 +511,7 @@ object PatternMatcher {
511511
}
512512

513513
private class RefCounter extends PlanTransform {
514-
val count = new mutable.HashMap[Symbol, Int] {
515-
override def default(key: Symbol) = 0
516-
}
514+
val count = new mutable.HashMap[Symbol, Int].withDefaultValue(0)
517515
}
518516

519517
/** Reference counts for all labels */

Diff for: compiler/src/dotty/tools/dotc/typer/Checking.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -1116,9 +1116,7 @@ trait Checking {
11161116

11171117
/** Check that class does not declare same symbol twice */
11181118
def checkNoDoubleDeclaration(cls: Symbol)(using Context): Unit = {
1119-
val seen = new mutable.HashMap[Name, List[Symbol]] {
1120-
override def default(key: Name) = Nil
1121-
}
1119+
val seen = new mutable.HashMap[Name, List[Symbol]].withDefaultValue(Nil)
11221120
typr.println(i"check no double declarations $cls")
11231121

11241122
def checkDecl(decl: Symbol): Unit = {

Diff for: compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala

+38-20
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,16 @@ class CrossVersionChecks extends MiniPhase:
3232
checkMigration(sym, pos, xMigrationValue)
3333
end checkUndesiredProperties
3434

35-
/** If @deprecated is present, and the point of reference is not enclosed
36-
* in either a deprecated member or a scala bridge method, issue a warning.
37-
*/
38-
private def checkDeprecated(sym: Symbol, pos: SrcPos)(using Context): Unit =
35+
/**Skip warnings for synthetic members of case classes during declaration and
36+
* scan the chain of outer declaring scopes from the current context
37+
* a deprecation warning will be skipped if one the following holds
38+
* for a given declaring scope:
39+
* - the symbol associated with the scope is also deprecated.
40+
* - if and only if `sym` is an enum case, the scope is either
41+
* a module that declares `sym`, or the companion class of the
42+
* module that declares `sym`.
43+
*/
44+
def skipWarning(sym: Symbol)(using Context): Boolean =
3945

4046
/** is the owner an enum or its companion and also the owner of sym */
4147
def isEnumOwner(owner: Symbol)(using Context) =
@@ -46,26 +52,22 @@ class CrossVersionChecks extends MiniPhase:
4652

4753
def isDeprecatedOrEnum(owner: Symbol)(using Context) =
4854
// pre: sym is an enumcase
49-
owner.isDeprecated
50-
|| isEnumOwner(owner)
51-
52-
/**Skip warnings for synthetic members of case classes during declaration and
53-
* scan the chain of outer declaring scopes from the current context
54-
* a deprecation warning will be skipped if one the following holds
55-
* for a given declaring scope:
56-
* - the symbol associated with the scope is also deprecated.
57-
* - if and only if `sym` is an enum case, the scope is either
58-
* a module that declares `sym`, or the companion class of the
59-
* module that declares `sym`.
60-
*/
61-
def skipWarning(using Context): Boolean =
62-
(ctx.owner.is(Synthetic) && sym.is(CaseClass))
63-
|| ctx.owner.ownersIterator.exists(if sym.isEnumCase then isDeprecatedOrEnum else _.isDeprecated)
55+
owner.isDeprecated || isEnumOwner(owner)
56+
57+
(ctx.owner.is(Synthetic) && sym.is(CaseClass))
58+
|| ctx.owner.ownersIterator.exists(if sym.isEnumCase then isDeprecatedOrEnum else _.isDeprecated)
59+
end skipWarning
60+
61+
62+
/** If @deprecated is present, and the point of reference is not enclosed
63+
* in either a deprecated member or a scala bridge method, issue a warning.
64+
*/
65+
private def checkDeprecated(sym: Symbol, pos: SrcPos)(using Context): Unit =
6466

6567
// Also check for deprecation of the companion class for synthetic methods
6668
val toCheck = sym :: (if sym.isAllOf(SyntheticMethod) then sym.owner.companionClass :: Nil else Nil)
6769
for sym <- toCheck; annot <- sym.getAnnotation(defn.DeprecatedAnnot) do
68-
if !skipWarning then
70+
if !skipWarning(sym) then
6971
val msg = annot.argumentConstant(0).map(": " + _.stringValue).getOrElse("")
7072
val since = annot.argumentConstant(1).map(" since " + _.stringValue).getOrElse("")
7173
report.deprecationWarning(em"${sym.showLocated} is deprecated${since}${msg}", pos)
@@ -107,6 +109,18 @@ class CrossVersionChecks extends MiniPhase:
107109
}
108110
}
109111

112+
/** ??? */
113+
def checkDeprecatedInheritance(parents: List[Tree])(using Context): Unit = {
114+
for parent <- parents
115+
psym = parent.tpe.classSymbol
116+
annot <- psym.getAnnotation(defn.DeprecatedInheritanceAnnot)
117+
if !skipWarning(psym)
118+
do
119+
val msg = annot.argumentConstantString(0).map(msg => s": $msg").getOrElse("")
120+
val since = annot.argumentConstantString(1).map(version => s" (since: $version)").getOrElse("")
121+
report.deprecationWarning(em"inheritance from $psym is deprecated$since$msg", parent.srcPos)
122+
}
123+
110124
override def transformValDef(tree: ValDef)(using Context): ValDef =
111125
checkDeprecatedOvers(tree)
112126
checkExperimentalAnnots(tree.symbol)
@@ -122,6 +136,10 @@ class CrossVersionChecks extends MiniPhase:
122136
checkExperimentalAnnots(tree.symbol)
123137
tree
124138

139+
override def transformTemplate(tree: tpd.Template)(using Context): tpd.Tree =
140+
checkDeprecatedInheritance(tree.parents)
141+
tree
142+
125143
override def transformIdent(tree: Ident)(using Context): Ident = {
126144
checkUndesiredProperties(tree.symbol, tree.srcPos)
127145
tree

Diff for: compiler/src/dotty/tools/dotc/util/Stats.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import collection.mutable
1919

2020
@volatile private var stack: List[String] = Nil
2121

22-
val hits: mutable.HashMap[String, Int] = new mutable.HashMap[String, Int] {
23-
override def default(key: String): Int = 0
24-
}
22+
val hits: mutable.Map[String, Int] = new mutable.HashMap[String, Int].withDefaultValue(0)
2523

2624
inline def record(inline fn: String, inline n: Int = 1, inline skip: Boolean = timerOnly): Unit =
2725
if (enabled && !skip) doRecord(fn, n)

Diff for: tests/init/pos/patternMatcher.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import scala.collection.mutable
22

33
class Translater:
4-
val count = new mutable.HashMap[Int, Int] {
5-
override def default(key: Int) = 0
6-
}
4+
val count = new mutable.HashMap[Int, Int].withDefaultValue(0)
75
count.get(10)
86
val n = 10

Diff for: tests/warn/i19002.check

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-- Deprecation Warning: tests/warn/i19002.scala:5:20 -------------------------------------------------------------------
2+
5 |class TBar1 extends TFoo // warn
3+
| ^^^^
4+
| inheritance from trait TFoo is deprecated (since: FooLib 12.0): this class will be made final
5+
-- Deprecation Warning: tests/warn/i19002.scala:6:20 -------------------------------------------------------------------
6+
6 |trait TBar2 extends TFoo // warn
7+
| ^^^^
8+
| inheritance from trait TFoo is deprecated (since: FooLib 12.0): this class will be made final
9+
-- Deprecation Warning: tests/warn/i19002.scala:11:20 ------------------------------------------------------------------
10+
11 |class CBar1 extends CFoo // warn
11+
| ^^^^
12+
| inheritance from class CFoo is deprecated (since: FooLib 11.0)
13+
-- Deprecation Warning: tests/warn/i19002.scala:12:20 ------------------------------------------------------------------
14+
12 |trait CBar2 extends CFoo // warn
15+
| ^^^^
16+
| inheritance from class CFoo is deprecated (since: FooLib 11.0)
17+
-- Deprecation Warning: tests/warn/i19002.scala:17:20 ------------------------------------------------------------------
18+
17 |class ABar1 extends AFoo // warn
19+
| ^^^^
20+
| inheritance from class AFoo is deprecated: this class will be made final
21+
-- Deprecation Warning: tests/warn/i19002.scala:18:20 ------------------------------------------------------------------
22+
18 |trait ABar2 extends AFoo // warn
23+
| ^^^^
24+
| inheritance from class AFoo is deprecated: this class will be made final
25+
-- Deprecation Warning: tests/warn/i19002.scala:7:16 -------------------------------------------------------------------
26+
7 |def TBar3 = new TFoo {} // warn
27+
| ^^^^
28+
| inheritance from trait TFoo is deprecated (since: FooLib 12.0): this class will be made final
29+
-- Deprecation Warning: tests/warn/i19002.scala:13:16 ------------------------------------------------------------------
30+
13 |def CBar3 = new CFoo {} // warn
31+
| ^^^^
32+
| inheritance from class CFoo is deprecated (since: FooLib 11.0)
33+
-- Deprecation Warning: tests/warn/i19002.scala:19:16 ------------------------------------------------------------------
34+
19 |def ABar3 = new AFoo {} // warn
35+
| ^^^^
36+
| inheritance from class AFoo is deprecated: this class will be made final

Diff for: tests/warn/i19002.scala

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//> using options -deprecation
2+
3+
@deprecatedInheritance("this class will be made final", "FooLib 12.0")
4+
trait TFoo
5+
class TBar1 extends TFoo // warn
6+
trait TBar2 extends TFoo // warn
7+
def TBar3 = new TFoo {} // warn
8+
9+
@deprecatedInheritance(since = "FooLib 11.0")
10+
class CFoo
11+
class CBar1 extends CFoo // warn
12+
trait CBar2 extends CFoo // warn
13+
def CBar3 = new CFoo {} // warn
14+
15+
@deprecatedInheritance(message = "this class will be made final")
16+
abstract class AFoo
17+
class ABar1 extends AFoo // warn
18+
trait ABar2 extends AFoo // warn
19+
def ABar3 = new AFoo {} // warn
20+
21+
@deprecated
22+
class DeprecatedFoo:
23+
class Foo extends AFoo // it shoudln't warn here (in deprecated context)

0 commit comments

Comments
 (0)