Skip to content

Commit 1eb466c

Browse files
Check deprecation of inline methods (#19914)
We must check these constraint just before inlining as later on there on the call might completely disappear. We do the same as we did for experimental definition checks. Fixes #19913 ### Changes - Define `CrossVersionChecks.checkRef` that checks both deprecation and experimental. - Used in `Inlines` and `PostTyper` to check the deprecation of inlined calls. - Rename `checkDeprecated` to `checkDeprecatedRef` - Move `checkDeprecatedRef` and `skipWarning` to `object CrossVersionChecks`
2 parents 65972b4 + f2ba6f4 commit 1eb466c

File tree

6 files changed

+75
-48
lines changed

6 files changed

+75
-48
lines changed

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ object Inlines:
100100
if ctx.isAfterTyper then
101101
// During typer we wait with cross version checks until PostTyper, in order
102102
// not to provoke cyclic references. See i16116 for a test case.
103-
CrossVersionChecks.checkExperimentalRef(tree.symbol, tree.srcPos)
103+
CrossVersionChecks.checkRef(tree.symbol, tree.srcPos)
104104

105105
if tree.symbol.isConstructor then return tree // error already reported for the inline constructor definition
106106

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
369369
}
370370
case tree @ Inlined(call, bindings, expansion) if !tree.inlinedFromOuterScope =>
371371
val pos = call.sourcePos
372-
CrossVersionChecks.checkExperimentalRef(call.symbol, pos)
372+
CrossVersionChecks.checkRef(call.symbol, pos)
373373
withMode(Mode.NoInline)(transform(call))
374374
val callTrace = Inlines.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source))
375375
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(tree)))

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

+50-45
Original file line numberDiff line numberDiff line change
@@ -24,54 +24,13 @@ class CrossVersionChecks extends MiniPhase:
2424
// warnings after the first, but I think it'd be better if we didn't have to
2525
// arbitrarily choose one as more important than the other.
2626
private def checkUndesiredProperties(sym: Symbol, pos: SrcPos)(using Context): Unit =
27-
checkDeprecated(sym, pos)
28-
checkExperimentalRef(sym, pos)
27+
checkRef(sym, pos)
2928

3029
val xMigrationValue = ctx.settings.Xmigration.value
3130
if xMigrationValue != NoScalaVersion then
3231
checkMigration(sym, pos, xMigrationValue)
3332
end checkUndesiredProperties
3433

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 =
45-
46-
/** is the owner an enum or its companion and also the owner of sym */
47-
def isEnumOwner(owner: Symbol)(using Context) =
48-
// pre: sym is an enumcase
49-
if owner.isEnumClass then owner.companionClass eq sym.owner
50-
else if owner.is(ModuleClass) && owner.companionClass.isEnumClass then owner eq sym.owner
51-
else false
52-
53-
def isDeprecatedOrEnum(owner: Symbol)(using Context) =
54-
// pre: sym is an enumcase
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 =
66-
67-
// Also check for deprecation of the companion class for synthetic methods
68-
val toCheck = sym :: (if sym.isAllOf(SyntheticMethod) then sym.owner.companionClass :: Nil else Nil)
69-
for sym <- toCheck; annot <- sym.getAnnotation(defn.DeprecatedAnnot) do
70-
if !skipWarning(sym) then
71-
val msg = annot.argumentConstant(0).map(": " + _.stringValue).getOrElse("")
72-
val since = annot.argumentConstant(1).map(" since " + _.stringValue).getOrElse("")
73-
report.deprecationWarning(em"${sym.showLocated} is deprecated${since}${msg}", pos)
74-
7534
private def checkExperimentalAnnots(sym: Symbol)(using Context): Unit =
7635
if sym.exists && !sym.isInExperimentalScope then
7736
for annot <- sym.annotations if annot.symbol.isExperimental do
@@ -160,11 +119,11 @@ class CrossVersionChecks extends MiniPhase:
160119
tpe.foreachPart {
161120
case TypeRef(_, sym: Symbol) =>
162121
if tree.span.isSourceDerived then
163-
checkDeprecated(sym, tree.srcPos)
122+
checkDeprecatedRef(sym, tree.srcPos)
164123
checkExperimentalRef(sym, tree.srcPos)
165124
case TermRef(_, sym: Symbol) =>
166125
if tree.span.isSourceDerived then
167-
checkDeprecated(sym, tree.srcPos)
126+
checkDeprecatedRef(sym, tree.srcPos)
168127
checkExperimentalRef(sym, tree.srcPos)
169128
case _ =>
170129
}
@@ -186,9 +145,55 @@ object CrossVersionChecks:
186145
val name: String = "crossVersionChecks"
187146
val description: String = "check issues related to deprecated and experimental"
188147

148+
/** Check that a reference to an experimental definition with symbol `sym` meets cross-version constraints
149+
* for `@deprecated` and `@experimental`.
150+
*/
151+
def checkRef(sym: Symbol, pos: SrcPos)(using Context): Unit =
152+
checkDeprecatedRef(sym, pos)
153+
checkExperimentalRef(sym, pos)
154+
189155
/** Check that a reference to an experimental definition with symbol `sym` is only
190156
* used in an experimental scope
191157
*/
192-
def checkExperimentalRef(sym: Symbol, pos: SrcPos)(using Context): Unit =
158+
private[CrossVersionChecks] def checkExperimentalRef(sym: Symbol, pos: SrcPos)(using Context): Unit =
193159
if sym.isExperimental && !ctx.owner.isInExperimentalScope then
194160
Feature.checkExperimentalDef(sym, pos)
161+
162+
/** If @deprecated is present, and the point of reference is not enclosed
163+
* in either a deprecated member or a scala bridge method, issue a warning.
164+
*/
165+
private[CrossVersionChecks] def checkDeprecatedRef(sym: Symbol, pos: SrcPos)(using Context): Unit =
166+
167+
// Also check for deprecation of the companion class for synthetic methods
168+
val toCheck = sym :: (if sym.isAllOf(SyntheticMethod) then sym.owner.companionClass :: Nil else Nil)
169+
for sym <- toCheck; annot <- sym.getAnnotation(defn.DeprecatedAnnot) do
170+
if !skipWarning(sym) then
171+
val msg = annot.argumentConstant(0).map(": " + _.stringValue).getOrElse("")
172+
val since = annot.argumentConstant(1).map(" since " + _.stringValue).getOrElse("")
173+
report.deprecationWarning(em"${sym.showLocated} is deprecated${since}${msg}", pos)
174+
175+
/** Skip warnings for synthetic members of case classes during declaration and
176+
* scan the chain of outer declaring scopes from the current context
177+
* a deprecation warning will be skipped if one the following holds
178+
* for a given declaring scope:
179+
* - the symbol associated with the scope is also deprecated.
180+
* - if and only if `sym` is an enum case, the scope is either
181+
* a module that declares `sym`, or the companion class of the
182+
* module that declares `sym`.
183+
*/
184+
private def skipWarning(sym: Symbol)(using Context): Boolean =
185+
186+
/** is the owner an enum or its companion and also the owner of sym */
187+
def isEnumOwner(owner: Symbol)(using Context) =
188+
// pre: sym is an enumcase
189+
if owner.isEnumClass then owner.companionClass eq sym.owner
190+
else if owner.is(ModuleClass) && owner.companionClass.isEnumClass then owner eq sym.owner
191+
else false
192+
193+
def isDeprecatedOrEnum(owner: Symbol)(using Context) =
194+
// pre: sym is an enumcase
195+
owner.isDeprecated || isEnumOwner(owner)
196+
197+
(ctx.owner.is(Synthetic) && sym.is(CaseClass))
198+
|| ctx.owner.ownersIterator.exists(if sym.isEnumCase then isDeprecatedOrEnum else _.isDeprecated)
199+
end skipWarning

scaladoc-testcases/src/tests/hugetype.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package tests.hugetype
33
import compiletime._
44
import compiletime.ops.int._
55
import scala.annotation.experimental
6+
import scala.annotation.nowarn
67

78
/**
89
* a particular group of people or things that share similar characteristics and form a smaller division of a larger set:
@@ -39,7 +40,7 @@ trait XD extends E:
3940
*/
4041
@experimental
4142
@deprecated
42-
protected override final implicit transparent inline abstract infix def same[A](a: A): A = a
43+
protected override final implicit transparent inline abstract infix def same[A](a: A): A = a: @nowarn
4344

4445
trait Parent[X, A[_], B[_, _]]
4546

tests/warn/i19913.check

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Deprecation Warning: tests/warn/i19913.scala:13:25 ------------------------------------------------------------------
2+
13 | Deprecated.inlineMethod() // warn
3+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
4+
| method inlineMethod in object Deprecated is deprecated: test
5+
-- Deprecation Warning: tests/warn/i19913.scala:12:13 ------------------------------------------------------------------
6+
12 | Deprecated.method() // warn
7+
| ^^^^^^^^^^^^^^^^^
8+
| method method in object Deprecated is deprecated: test

tests/warn/i19913.scala

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//> using options -deprecation
2+
3+
object Deprecated:
4+
5+
@deprecated("test")
6+
def method() = ???
7+
8+
@deprecated("test")
9+
inline def inlineMethod() = ???
10+
11+
object Test:
12+
Deprecated.method() // warn
13+
Deprecated.inlineMethod() // warn

0 commit comments

Comments
 (0)