Skip to content

Commit dd7a07a

Browse files
Merge pull request #13305 from dotty-staging/experimental-annotation
Change @experimental spec
2 parents 5eff3d0 + 366fa62 commit dd7a07a

29 files changed

+596
-79
lines changed

compiler/src/dotty/tools/dotc/config/Feature.scala

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,24 +97,20 @@ object Feature:
9797
else
9898
false
9999

100-
private val assumeExperimentalIn = Set("dotty.tools.vulpix.ParallelTesting")
101-
102100
def checkExperimentalFeature(which: String, srcPos: SrcPos)(using Context) =
103101
if !isExperimentalEnabled then
104102
report.error(i"Experimental $which may only be used with a nightly or snapshot version of the compiler", srcPos)
105103

106104
def checkExperimentalDef(sym: Symbol, srcPos: SrcPos)(using Context) =
107105
if !isExperimentalEnabled then
108106
val symMsg =
109-
if sym eq defn.ExperimentalAnnot then
110-
i"use of @experimental is experimental"
111-
else if sym.hasAnnotation(defn.ExperimentalAnnot) then
107+
if sym.hasAnnotation(defn.ExperimentalAnnot) then
112108
i"$sym is marked @experimental"
113109
else if sym.owner.hasAnnotation(defn.ExperimentalAnnot) then
114110
i"${sym.owner} is marked @experimental"
115111
else
116112
i"$sym inherits @experimental"
117-
report.error(s"$symMsg and therefore may only be used with a nightly or snapshot version of the compiler", srcPos)
113+
report.error(s"$symMsg and therefore may only be used in an experimental scope.", srcPos)
118114

119115
/** Check that experimental compiler options are only set for snapshot or nightly compiler versions. */
120116
def checkExperimentalSettings(using Context): Unit =
@@ -123,9 +119,6 @@ object Feature:
123119
do checkExperimentalFeature(s"feature $setting", NoSourcePosition)
124120

125121
def isExperimentalEnabled(using Context): Boolean =
126-
def hasSpecialPermission =
127-
Thread.currentThread.getStackTrace.exists(elem =>
128-
assumeExperimentalIn.exists(elem.getClassName().startsWith(_)))
129-
(Properties.experimental || hasSpecialPermission) && !ctx.settings.YnoExperimental.value
122+
Properties.experimental && !ctx.settings.YnoExperimental.value
130123

131124
end Feature

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,23 @@ object SymUtils:
267267

268268
/** Is symbol declared or inherits @experimental? */
269269
def isExperimental(using Context): Boolean =
270-
// TODO should be add `@experimental` to `class experimental` in PostTyper?
271-
self.eq(defn.ExperimentalAnnot)
272-
|| self.hasAnnotation(defn.ExperimentalAnnot)
270+
self.hasAnnotation(defn.ExperimentalAnnot)
273271
|| (self.maybeOwner.isClass && self.owner.hasAnnotation(defn.ExperimentalAnnot))
274272

273+
def isInExperimentalScope(using Context): Boolean =
274+
def isDefaultArgumentOfExperimentalMethod =
275+
self.name.is(DefaultGetterName)
276+
&& self.owner.isClass
277+
&& {
278+
val overloads = self.owner.asClass.membersNamed(self.name.firstPart)
279+
overloads.filterWithFlags(HasDefaultParams, EmptyFlags) match
280+
case denot: SymDenotation => denot.symbol.isExperimental
281+
case _ => false
282+
}
283+
self.hasAnnotation(defn.ExperimentalAnnot)
284+
|| isDefaultArgumentOfExperimentalMethod
285+
|| (!self.is(Package) && self.owner.isInExperimentalScope)
286+
275287
/** The declared self type of this class, as seen from `site`, stripping
276288
* all refinements for opaque types.
277289
*/

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

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -948,27 +948,23 @@ object RefChecks {
948948
report.deprecationWarning(s"${sym.showLocated} is deprecated${since}${msg}", pos)
949949

950950
private def checkExperimental(sym: Symbol, pos: SrcPos)(using Context): Unit =
951-
if sym.isExperimental
952-
&& !sym.isConstructor // already reported on the class
953-
&& !ctx.owner.isExperimental // already reported on the @experimental of the owner
954-
&& !sym.is(ModuleClass) // already reported on the module
955-
&& (sym.span.exists || sym != defn.ExperimentalAnnot) // already reported on inferred annotations
956-
then
951+
if sym.isExperimental && !ctx.owner.isInExperimentalScope then
957952
Feature.checkExperimentalDef(sym, pos)
958953

959954
private def checkExperimentalSignature(sym: Symbol, pos: SrcPos)(using Context): Unit =
960-
val checker = new TypeTraverser:
955+
class Checker extends TypeTraverser:
961956
def traverse(tp: Type): Unit =
962957
if tp.typeSymbol.isExperimental then
963958
Feature.checkExperimentalDef(tp.typeSymbol, pos)
964959
else
965960
traverseChildren(tp)
966-
if !sym.owner.isExperimental && !pos.span.isSynthetic then // avoid double errors
967-
checker.traverse(sym.info)
961+
if !sym.isInExperimentalScope then
962+
new Checker().traverse(sym.info)
968963

969964
private def checkExperimentalAnnots(sym: Symbol)(using Context): Unit =
970-
for annot <- sym.annotations if annot.symbol.isExperimental && annot.tree.span.exists do
971-
Feature.checkExperimentalDef(annot.symbol, annot.tree)
965+
if !sym.isInExperimentalScope then
966+
for annot <- sym.annotations if annot.symbol.isExperimental do
967+
Feature.checkExperimentalDef(annot.symbol, annot.tree)
972968

973969
/** If @migration is present (indicating that the symbol has changed semantics between versions),
974970
* emit a warning.
@@ -1344,7 +1340,6 @@ class RefChecks extends MiniPhase { thisPhase =>
13441340
}
13451341

13461342
override def transformTypeDef(tree: TypeDef)(using Context): TypeDef = {
1347-
checkExperimental(tree.symbol, tree.srcPos)
13481343
checkExperimentalAnnots(tree.symbol)
13491344
tree
13501345
}

0 commit comments

Comments
 (0)