Skip to content

Commit f5d2b9e

Browse files
committed
Align syntax with paper
1 parent 3cc0660 commit f5d2b9e

File tree

5 files changed

+50
-41
lines changed

5 files changed

+50
-41
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -995,9 +995,6 @@ class Definitions {
995995
@tu lazy val DeprecatedOverridingAnnot: ClassSymbol = requiredClass("scala.deprecatedOverriding")
996996
@tu lazy val ImplicitAmbiguousAnnot: ClassSymbol = requiredClass("scala.annotation.implicitAmbiguous")
997997
@tu lazy val ImplicitNotFoundAnnot: ClassSymbol = requiredClass("scala.annotation.implicitNotFound")
998-
@tu lazy val InitWidenAnnot: ClassSymbol = requiredClass("scala.annotation.init.widen")
999-
@tu lazy val InitExposeAnnot: ClassSymbol = requiredClass("scala.annotation.init.expose")
1000-
@tu lazy val InitRegionAnnot: ClassSymbol = requiredClass("scala.annotation.init.region")
1001998
@tu lazy val InlineParamAnnot: ClassSymbol = requiredClass("scala.annotation.internal.InlineParam")
1002999
@tu lazy val ErasedParamAnnot: ClassSymbol = requiredClass("scala.annotation.internal.ErasedParam")
10031000
@tu lazy val InvariantBetweenAnnot: ClassSymbol = requiredClass("scala.annotation.internal.InvariantBetween")
@@ -1048,6 +1045,11 @@ class Definitions {
10481045

10491046
@tu lazy val JavaRepeatableAnnot: ClassSymbol = requiredClass("java.lang.annotation.Repeatable")
10501047

1048+
// Initialization annotations
1049+
@tu lazy val InitModule: Symbol = requiredModule("scala.annotation.init")
1050+
@tu lazy val InitWidenAnnot: ClassSymbol = InitModule.requiredClass("widen")
1051+
@tu lazy val InitRegionMethod: Symbol = InitModule.requiredMethod("region")
1052+
10511053
// A list of meta-annotations that are relevant for fields and accessors
10521054
@tu lazy val NonBeanMetaAnnots: Set[Symbol] =
10531055
Set(FieldMetaAnnot, GetterMetaAnnot, ParamMetaAnnot, SetterMetaAnnot, CompanionClassMetaAnnot, CompanionMethodMetaAnnot)

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,15 @@ object Types {
376376
case _ => false
377377
}
378378

379+
/** Returns the annoation that is an instance of `cls` carried by the type. */
380+
@tailrec final def getAnnotation(cls: ClassSymbol)(using Context): Option[Annotation] = stripTypeVar match {
381+
case AnnotatedType(tp, annot) =>
382+
if annot.matches(cls) then Some(annot)
383+
else tp.getAnnotation(cls)
384+
case _ =>
385+
None
386+
}
387+
379388
/** Does this type have a supertype with an annotation satisfying given predicate `p`? */
380389
def derivesAnnotWith(p: Annotation => Boolean)(using Context): Boolean = this match {
381390
case tp: AnnotatedType => p(tp.annot) || tp.parent.derivesAnnotWith(p)

compiler/src/dotty/tools/dotc/transform/init/Objects.scala

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,15 @@ object Objects:
911911
instantiate(outer, cls, ctor, args)
912912
}
913913

914+
case Apply(ref, arg :: Nil) if ref.symbol == defn.InitRegionMethod =>
915+
val regions2 = Regions.extend(expr.sourcePos)
916+
if Regions.exists(expr.sourcePos) then
917+
report.warning("Cyclic region detected. Trace: " + Trace.show, expr)
918+
Bottom
919+
else
920+
given Regions.Data = regions2
921+
eval(arg, thisV, klass)
922+
914923
case Call(ref, argss) =>
915924
// check args
916925
val args = evalArgs(argss.flatten, thisV, klass)
@@ -963,14 +972,6 @@ object Objects:
963972
case Typed(expr, tpt) =>
964973
if tpt.tpe.hasAnnotation(defn.UncheckedAnnot) then
965974
Bottom
966-
else if tpt.tpe.hasAnnotation(defn.InitRegionAnnot) then
967-
val regions2 = Regions.extend(tpt.sourcePos)
968-
if Regions.exists(tpt.sourcePos) then
969-
report.warning("Cyclic region detected. Trace: " + Trace.show, tpt.sourcePos)
970-
Bottom
971-
else
972-
given Regions.Data = regions2
973-
eval(expr, thisV, klass)
974975
else
975976
eval(expr, thisV, klass)
976977

@@ -1144,11 +1145,21 @@ object Objects:
11441145
else
11451146
eval(arg.tree, thisV, klass)
11461147

1147-
// TODO: handle @widen(n)
11481148
val widened =
1149-
if arg.tree.tpe.hasAnnotation(defn.InitExposeAnnot) then
1150-
res.widen(1)
1151-
else
1149+
arg.tree.tpe.getAnnotation(defn.InitWidenAnnot) match
1150+
case Some(annot) =>
1151+
annot.argument(0).get match
1152+
case arg @ Literal(c: Constants.Constant) =>
1153+
val height = c.intValue
1154+
if height < 0 then
1155+
report.error("The argument should be positive", arg)
1156+
res.widen(1)
1157+
else
1158+
res.widen(c.intValue)
1159+
case arg =>
1160+
report.error("The argument should be a constant integer value", arg)
1161+
res.widen(1)
1162+
case _ =>
11521163
res.widen(1)
11531164

11541165
argInfos += TraceValue(widened, trace.add(arg.tree))

library/src/scala/annotation/init.scala

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,6 @@ package scala.annotation
88
object init:
99

1010
/** Widen the abstract value of the argument so that its height is below the specified height.
11-
*
12-
* This is an advanced version of `@init.expose`, where we tell the compiler the annotated method or
13-
* constructor argument are not cold aliases and its abstract value may have a maximum height of the
14-
* specified value.
15-
*/
16-
final class widen(hight: Int) extends StaticAnnotation
17-
18-
/** Expose the method argument or constructor argument so that it may be actively used during the
19-
* initialization of static objects.
2011
*
2112
* It can be used to mark method or constructor arguments, as the following example shows:
2213
*
@@ -28,19 +19,15 @@ object init:
2819
*
2920
* def build(o: A) = new A(o.square()) // calling methods on parameter
3021
*
31-
* By default, method and constructor arguments are cold aliases, which means they may not be actively
32-
* used --- calling methods or accessing fields on them are forbidden. By using `@expose` to the
33-
* method argument, we tell the compiler that the argument is not a cold alias. As a result, we may
34-
* call methods on the parameter.
35-
*
36-
* It is semantically equivalent to `@init.widen(1)`.
22+
* By default, method and constructor arguments are widened to height 1.
3723
*/
38-
final class expose extends StaticAnnotation
24+
final class widen(hight: Int) extends StaticAnnotation
3925

40-
/** Mark a region context.
26+
/** Introduce a region context.
27+
*
28+
* The same mutable field in the same region have the same abstract representation.
4129
*
42-
* The same mutable field of objects in the same region have the same shape. The concept of regions is an
43-
* attempt to make context-sensitivity explainable and customizable.
30+
* The concept of regions is intended to make context-sensitivity tuable for complex use cases.
4431
*
4532
* Example:
4633
*
@@ -50,13 +37,13 @@ object init:
5037
* class Box(var value: B)
5138
*
5239
* object A:
53-
* val box1: Box = new Box(new C(5)): @init.region
54-
* val box2: Box = new Box(new D(10)): @init.region
40+
* val box1: Box = region { new Box(new C(5)) }
41+
* val box2: Box = region { new Box(new D(10)) }
5542
* val m: Int = box1.value.foo()
5643
*
57-
* In the above, without the two region annotation, the two objects `box1` and `box2` are of the same region.
44+
* In the above, without the two region annotation, the two objects `box1` and `box2` are in the same region.
5845
* Therefore, the field `box1.value` and `box2.value` points to both instances of `C` and `D`. Consequently,
5946
* the method call `box1.value.foo()` will be invalid, because it reaches `A.m`, which is not yet initialized.
6047
* The explicit context annotation solves the problem.
6148
*/
62-
final class region extends StaticAnnotation
49+
def region[T](v: T): T = v
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import scala.annotation.init
1+
import scala.annotation.init.region
22

33
trait B { def foo(): Int }
44
class C(var x: Int) extends B { def foo(): Int = 20 }
55
class D(var y: Int) extends B { def foo(): Int = A.m }
66
class Box(var value: B)
77

88
object A:
9-
val box1: Box = new Box(new C(5)): @init.region
10-
val box2: Box = new Box(new D(10)): @init.region
9+
val box1: Box = region { new Box(new C(5)) }
10+
val box2: Box = region { new Box(new D(10)) }
1111
val m: Int = box1.value.foo() // ok

0 commit comments

Comments
 (0)