Skip to content

Commit 9d2cec0

Browse files
committed
Add transparent modifier
1 parent e8c96cb commit 9d2cec0

15 files changed

+92
-55
lines changed

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
130130

131131
case class Inline() extends Mod(Flags.Inline)
132132

133+
case class Transparent() extends Mod(Flags.Transparent)
134+
133135
case class Enum() extends Mod(Flags.Enum)
134136
}
135137

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,10 @@ object Flags {
363363
/** Symbol is a Java default method */
364364
final val DefaultMethod = termFlag(38, "<defaultmethod>")
365365

366-
/** Symbol is a Java enum */
366+
/** Labelled with `transparent` modifier */
367+
final val Transparent = termFlag(39, "transparent")
368+
369+
/** Symbol is an enum class or enum case (if used with case) */
367370
final val Enum = commonFlag(40, "<enum>")
368371

369372
/** Labeled with `erased` modifier (erased value) */
@@ -436,7 +439,7 @@ object Flags {
436439

437440
/** Flags representing source modifiers */
438441
final val SourceModifierFlags =
439-
commonFlags(Private, Protected, Abstract, Final, Inline,
442+
commonFlags(Private, Protected, Abstract, Final, Inline, Transparent,
440443
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic, Erased)
441444

442445
/** Flags representing modifiers that can appear in trees */
@@ -457,7 +460,7 @@ object Flags {
457460
Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic |
458461
CovariantOrOuter | ContravariantOrLabel | CaseAccessor.toCommonFlags |
459462
NonMember | ImplicitCommon | Permanent | Synthetic |
460-
SuperAccessorOrScala2x | Inline
463+
SuperAccessorOrScala2x | Inline | Transparent.toCommonFlags
461464

462465
/** Flags that are not (re)set when completing the denotation, or, if symbol is
463466
* a top-level class or object, when completing the denotation once the class
@@ -513,7 +516,7 @@ object Flags {
513516
/** Flags that can apply to a module val */
514517
final val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
515518
Override | Final | Method | Implicit | Lazy |
516-
Accessor | AbsOverride | Stable | Captured | Synchronized | Inline | Erased
519+
Accessor | AbsOverride | Stable | Captured | Synchronized | Erased
517520

518521
/** Flags that can apply to a module class */
519522
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | ImplClass | Enum
@@ -548,8 +551,8 @@ object Flags {
548551
/** Either method or lazy or deferred */
549552
final val MethodOrLazyOrDeferred = Method | Lazy | Deferred
550553

551-
/** Labeled `private`, `final`, or `inline` */
552-
final val PrivateOrFinalOrInline = Private | Final | Inline
554+
/** Labeled `private`, `final`, `inline`, or `transparent` */
555+
final val EffectivelyFinal = Private | Final | Inline | Transparent.toCommonFlags
553556

554557
/** A private method */
555558
final val PrivateMethod = allOf(Private, Method)
@@ -560,6 +563,9 @@ object Flags {
560563
/** An inline method */
561564
final val InlineMethod = allOf(Inline, Method)
562565

566+
/** An transparent method */
567+
final val TransparentMethod = allOf(Transparent, Method)
568+
563569
/** An inline parameter */
564570
final val InlineParam = allOf(Inline, Param)
565571

@@ -575,6 +581,9 @@ object Flags {
575581
/** An accessor or label */
576582
final val AccessorOrLabel = Accessor | Label
577583

584+
/** An accessor or a synthetic symbol */
585+
final val AccessorOrSynthetic = Accessor | Synthetic
586+
578587
/** A synthetic or private definition */
579588
final val SyntheticOrPrivate = Synthetic | Private
580589

@@ -584,8 +593,8 @@ object Flags {
584593
/** A deferred type member or parameter (these don't have right hand sides) */
585594
final val DeferredOrTypeParam = Deferred | TypeParam
586595

587-
/** value that's final or inline */
588-
final val FinalOrInline = Final | Inline
596+
/** value that's final, inline, or transparent */
597+
final val FinalOrInlineOrTransparent = Final | Inline | Transparent.toCommonFlags
589598

590599
/** A covariant type parameter instance */
591600
final val LocalCovariant = allOf(Local, Covariant)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,6 @@ object Mode {
9494
/** We are in the IDE */
9595
val Interactive = newMode(20, "Interactive")
9696

97+
/** We are typing the body of a transparent method */
98+
val TransparentBody = newMode(21, "TransparentBody")
9799
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,13 @@ object SymDenotations {
783783

784784
def isSkolem: Boolean = name == nme.SKOLEM
785785

786-
def isInlineMethod(implicit ctx: Context): Boolean = is(InlineMethod, butNot = Accessor)
786+
def isInlinedMethod(implicit ctx: Context): Boolean =
787+
is(InlineMethod, butNot = Accessor)
788+
789+
def isTransparentMethod(implicit ctx: Context): Boolean =
790+
is(TransparentMethod, butNot = AccessorOrSynthetic)
791+
792+
def isInlineableMethod(implicit ctx: Context) = isInlinedMethod || isTransparentMethod
787793

788794
/** ()T and => T types should be treated as equivalent for this symbol.
789795
* Note: For the moment, we treat Scala-2 compiled symbols as loose matching,
@@ -909,7 +915,7 @@ object SymDenotations {
909915

910916
/** A symbol is effectively final if it cannot be overridden in a subclass */
911917
final def isEffectivelyFinal(implicit ctx: Context): Boolean =
912-
is(PrivateOrFinalOrInline) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass
918+
is(EffectivelyFinal) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass
913919

914920
/** The class containing this denotation which has the given effective name. */
915921
final def enclosingClassNamed(name: Name)(implicit ctx: Context): Symbol = {

compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ Standard-Section: "ASTs" TopLevelStat*
181181
ERASED
182182
LAZY
183183
OVERRIDE
184-
INLINE // inline method
184+
INLINE
185+
TRANSPARENT
185186
MACRO // inline method containing toplevel splices
186187
STATIC // mapped to static Java member
187188
OBJECT // an object or its class
@@ -290,25 +291,26 @@ object TastyFormat {
290291
final val LAZY = 14
291292
final val OVERRIDE = 15
292293
final val INLINE = 16
293-
final val STATIC = 17
294-
final val OBJECT = 18
295-
final val TRAIT = 19
296-
final val ENUM = 20
297-
final val LOCAL = 21
298-
final val SYNTHETIC = 22
299-
final val ARTIFACT = 23
300-
final val MUTABLE = 24
301-
final val LABEL = 25
302-
final val FIELDaccessor = 26
303-
final val CASEaccessor = 27
304-
final val COVARIANT = 28
305-
final val CONTRAVARIANT = 29
306-
final val SCALA2X = 30
307-
final val DEFAULTparameterized = 31
308-
final val STABLE = 32
309-
final val MACRO = 33
310-
final val ERASED = 34
311-
final val PARAMsetter = 35
294+
final val TRANSPARENT = 17
295+
final val STATIC = 18
296+
final val OBJECT = 19
297+
final val TRAIT = 20
298+
final val ENUM = 21
299+
final val LOCAL = 22
300+
final val SYNTHETIC = 23
301+
final val ARTIFACT = 24
302+
final val MUTABLE = 25
303+
final val LABEL = 26
304+
final val FIELDaccessor = 27
305+
final val CASEaccessor = 28
306+
final val COVARIANT = 29
307+
final val CONTRAVARIANT = 30
308+
final val SCALA2X = 31
309+
final val DEFAULTparameterized = 32
310+
final val STABLE = 33
311+
final val MACRO = 34
312+
final val ERASED = 35
313+
final val PARAMsetter = 36
312314

313315
// Cat. 2: tag Nat
314316

@@ -466,6 +468,7 @@ object TastyFormat {
466468
| LAZY
467469
| OVERRIDE
468470
| INLINE
471+
| TRANSPARENT
469472
| MACRO
470473
| STATIC
471474
| OBJECT
@@ -522,6 +525,7 @@ object TastyFormat {
522525
case LAZY => "LAZY"
523526
case OVERRIDE => "OVERRIDE"
524527
case INLINE => "INLINE"
528+
case TRANSPARENT => "TRANSPARENT"
525529
case MACRO => "MACRO"
526530
case STATIC => "STATIC"
527531
case OBJECT => "OBJECT"

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ class TreePickler(pickler: TastyPickler) {
601601
if (flags is Case) writeByte(CASE)
602602
if (flags is Override) writeByte(OVERRIDE)
603603
if (flags is Inline) writeByte(INLINE)
604+
if (flags is Transparent) writeByte(TRANSPARENT)
604605
if (flags is Macro) writeByte(MACRO)
605606
if (flags is JavaStatic) writeByte(STATIC)
606607
if (flags is Module) writeByte(OBJECT)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ class TreeUnpickler(reader: TastyReader,
548548
sym.completer.withDecls(newScope)
549549
forkAt(templateStart).indexTemplateParams()(localContext(sym))
550550
}
551-
else if (sym.isInlineMethod)
551+
else if (sym.isInlinedMethod)
552552
sym.addAnnotation(LazyBodyAnnotation { ctx0 =>
553553
implicit val ctx: Context = localContext(sym)(ctx0).addMode(Mode.ReadPositions)
554554
// avoids space leaks by not capturing the current context
@@ -590,6 +590,7 @@ class TreeUnpickler(reader: TastyReader,
590590
case LAZY => addFlag(Lazy)
591591
case OVERRIDE => addFlag(Override)
592592
case INLINE => addFlag(Inline)
593+
case TRANSPARENT => addFlag(Transparent)
593594
case MACRO => addFlag(Macro)
594595
case STATIC => addFlag(JavaStatic)
595596
case OBJECT => addFlag(Module)

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,16 +1675,17 @@ object Parsers {
16751675
/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
16761676

16771677
private def modOfToken(tok: Int): Mod = tok match {
1678-
case ABSTRACT => Mod.Abstract()
1679-
case FINAL => Mod.Final()
1680-
case IMPLICIT => Mod.Implicit()
1681-
case ERASED => Mod.Erased()
1682-
case INLINE => Mod.Inline()
1683-
case LAZY => Mod.Lazy()
1684-
case OVERRIDE => Mod.Override()
1685-
case PRIVATE => Mod.Private()
1686-
case PROTECTED => Mod.Protected()
1687-
case SEALED => Mod.Sealed()
1678+
case ABSTRACT => Mod.Abstract()
1679+
case FINAL => Mod.Final()
1680+
case IMPLICIT => Mod.Implicit()
1681+
case ERASED => Mod.Erased()
1682+
case INLINE => Mod.Inline()
1683+
case TRANSPARENT => Mod.Transparent()
1684+
case LAZY => Mod.Lazy()
1685+
case OVERRIDE => Mod.Override()
1686+
case PRIVATE => Mod.Private()
1687+
case PROTECTED => Mod.Protected()
1688+
case SEALED => Mod.Sealed()
16881689
}
16891690

16901691
/** Drop `private' modifier when followed by a qualifier.

compiler/src/dotty/tools/dotc/parsing/Tokens.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,9 @@ object Tokens extends TokensCommon {
176176
final val THEN = 60; enter(THEN, "then")
177177
final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
178178
final val INLINE = 62; enter(INLINE, "inline")
179-
final val ENUM = 63; enter(ENUM, "enum")
180-
final val ERASED = 64; enter(ERASED, "erased")
179+
final val TRANSPARENT = 63; enter(TRANSPARENT, "transparent")
180+
final val ENUM = 64; enter(ENUM, "enum")
181+
final val ERASED = 65; enter(ERASED, "erased")
181182

182183
/** special symbols */
183184
final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
@@ -226,7 +227,7 @@ object Tokens extends TokensCommon {
226227
final val defIntroTokens = templateIntroTokens | dclIntroTokens
227228

228229
final val localModifierTokens = BitSet(
229-
ABSTRACT, FINAL, SEALED, IMPLICIT, INLINE, LAZY, ERASED)
230+
ABSTRACT, FINAL, SEALED, IMPLICIT, INLINE, TRANSPARENT, LAZY, ERASED)
230231

231232
final val accessModifierTokens = BitSet(
232233
PRIVATE, PROTECTED)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
165165

166166
def markAsMacro(c: Context): Unit =
167167
if (c.owner eq c.outer.owner) markAsMacro(c.outer)
168-
else if (c.owner.isInlineMethod) c.owner.setFlag(Macro)
168+
else if (c.owner.isInlineableMethod) c.owner.setFlag(Macro)
169169
else if (!c.outer.owner.is(Package)) markAsMacro(c.outer)
170170

171171
if (sym.isSplice || sym.isQuote) {
@@ -193,7 +193,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
193193
else
194194
transformSelect(tree, Nil)
195195
case tree: Super =>
196-
if (ctx.owner.enclosingMethod.isInlineMethod)
196+
if (ctx.owner.enclosingMethod.isInlinedMethod)
197197
ctx.error(SuperCallsNotAllowedInline(ctx.owner), tree.pos)
198198
super.transform(tree)
199199
case tree: Apply =>

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ object Checking {
371371
checkCombination(Private, Protected)
372372
checkCombination(Abstract, Override)
373373
checkCombination(Lazy, Inline)
374+
checkCombination(Module, Inline)
375+
checkCombination(Transparent, Inline)
374376
checkNoConflict(Lazy, ParamAccessor, s"parameter may not be `lazy`")
375377
if (sym.is(Inline)) checkApplicable(Inline, sym.isTerm && !sym.is(Mutable | Module))
376378
if (sym.is(Lazy)) checkApplicable(Lazy, !sym.is(Method | Mutable))
@@ -646,7 +648,8 @@ trait Checking {
646648
case tp => tp.widenTermRefExpr match {
647649
case tp: ConstantType if exprPurity(tree) >= purityLevel => // ok
648650
case _ =>
649-
if (!ctx.erasedTypes) ctx.error(em"$what must be a constant expression", tree.pos)
651+
val allow = ctx.erasedTypes || ctx.owner.ownersIterator.exists(_.isInlineableMethod)
652+
if (!allow) ctx.error(em"$what must be a constant expression", tree.pos)
650653
}
651654
}
652655
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ object Inliner {
9090
}
9191
}
9292

93+
def isLocal(sym: Symbol, inlineMethod: Symbol)(implicit ctx: Context) =
94+
sym.isContainedIn(inlineMethod) &&
95+
sym != inlineMethod &&
96+
(!sym.is(Param) || sym.owner != inlineMethod)
97+
9398
/** Register inline info for given inline method `sym`.
9499
*
95100
* @param sym The symbol denotatioon of the inline method for which info is registered
@@ -119,7 +124,7 @@ object Inliner {
119124
* from Scala2x class files might be `@inline`, but still lack that body.
120125
*/
121126
def hasBodyToInline(sym: SymDenotation)(implicit ctx: Context): Boolean =
122-
sym.isInlineMethod && sym.hasAnnotation(defn.BodyAnnot)
127+
sym.isInlineableMethod && sym.hasAnnotation(defn.BodyAnnot)
123128

124129
/** The body to inline for method `sym`.
125130
* @pre hasBodyToInline(sym)

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ class Namer { typer: Typer =>
822822
}
823823

824824
private def addInlineInfo(denot: SymDenotation) = original match {
825-
case original: untpd.DefDef if denot.isInlineMethod =>
825+
case original: untpd.DefDef if denot.isInlineableMethod =>
826826
Inliner.registerInlineInfo(
827827
denot,
828828
implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs
@@ -1113,7 +1113,7 @@ class Namer { typer: Typer =>
11131113

11141114
// println(s"final inherited for $sym: ${inherited.toString}") !!!
11151115
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
1116-
def isInline = sym.is(FinalOrInline, butNot = Method | Mutable)
1116+
def isInline = sym.is(FinalOrInlineOrTransparent, butNot = Method | Mutable)
11171117

11181118
// Widen rhs type and eliminate `|' but keep ConstantTypes if
11191119
// definition is inline (i.e. final in Scala2) and keep module singleton types
@@ -1128,7 +1128,8 @@ class Namer { typer: Typer =>
11281128
// it would be erased to BoxedUnit.
11291129
def dealiasIfUnit(tp: Type) = if (tp.isRef(defn.UnitClass)) defn.UnitType else tp
11301130

1131-
val rhsCtx = ctx.addMode(Mode.InferringReturnType)
1131+
var rhsCtx = ctx.addMode(Mode.InferringReturnType)
1132+
if (sym.isTransparentMethod) rhsCtx = rhsCtx.addMode(Mode.TransparentBody)
11321133
def rhsType = typedAheadExpr(mdef.rhs, inherited orElse rhsProto)(rhsCtx).tpe
11331134

11341135
// Approximate a type `tp` with a type that does not contain skolem types.

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ class Typer extends Namer
10561056
(EmptyTree, WildcardType)
10571057
}
10581058
else if (owner != cx.outer.owner && owner.isRealMethod) {
1059-
if (owner.isInlineMethod)
1059+
if (owner.isInlineableMethod)
10601060
(EmptyTree, errorType(NoReturnFromInline(owner), tree.pos))
10611061
else if (!owner.isCompleted)
10621062
(EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.pos))
@@ -1413,10 +1413,11 @@ class Typer extends Namer
14131413
(tparams1, sym.owner.typeParams).zipped.foreach ((tdef, tparam) =>
14141414
rhsCtx.gadt.setBounds(tdef.symbol, TypeAlias(tparam.typeRef)))
14151415
}
1416+
if (sym.isTransparentMethod) rhsCtx = rhsCtx.addMode(Mode.TransparentBody)
14161417
val rhs1 = normalizeErasedRhs(typedExpr(ddef.rhs, tpt1.tpe)(rhsCtx), sym)
14171418

14181419
// Overwrite inline body to make sure it is not evaluated twice
1419-
if (sym.isInlineMethod) Inliner.registerInlineInfo(sym, _ => rhs1)
1420+
if (sym.isInlineableMethod) Inliner.registerInlineInfo(sym, _ => rhs1)
14201421

14211422
if (sym.isConstructor && !sym.isPrimaryConstructor)
14221423
for (param <- tparams1 ::: vparamss1.flatten)
@@ -2325,7 +2326,7 @@ class Typer extends Namer
23252326
if (pt.hasAnnotation(defn.InlineParamAnnot))
23262327
checkInlineConformant(tree, isFinal = false, "argument to inline parameter")
23272328
if (Inliner.hasBodyToInline(tree.symbol) &&
2328-
!ctx.owner.ownersIterator.exists(_.isInlineMethod) &&
2329+
!ctx.owner.ownersIterator.exists(_.isInlineableMethod) &&
23292330
!ctx.settings.YnoInline.value &&
23302331
!ctx.isAfterTyper &&
23312332
!ctx.reporter.hasErrors)

tests/neg/i2421.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
inline object Foo // error: modifier(s) `inline' incompatible with type definition
1+
inline object Foo // OK (error would be detected later, in PostTyper)
22
inline class Bar // error: modifier(s) `inline' incompatible with type definition
33
inline abstract class Baz // error: modifier(s) `inline' incompatible with type definition
44
inline trait Qux // error: modifier(s) `inline' incompatible with type definition

0 commit comments

Comments
 (0)