Skip to content

Commit e13089f

Browse files
authored
Merge pull request #10458 from dotty-staging/change-mixin
Introduce `Transparent` flag
2 parents da9afab + f08f00c commit e13089f

35 files changed

+135
-133
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
212212

213213
case class Inline()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Inline)
214214

215-
case class Transparent()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.EmptyFlags)
215+
case class Transparent()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Transparent)
216+
217+
case class Infix()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Infix)
216218
}
217219

218220
/** Modifiers and annotations for definitions

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

+12-12
Original file line numberDiff line numberDiff line change
@@ -286,35 +286,35 @@ trait ConstraintHandling {
286286
}
287287
}
288288

289-
/** If `tp` is an intersection such that some operands are mixin trait instances
290-
* and others are not, replace as many mixin trait instances as possible with Any
289+
/** If `tp` is an intersection such that some operands are transparent trait instances
290+
* and others are not, replace as many transparent trait instances as possible with Any
291291
* as long as the result is still a subtype of `bound`. But fall back to the
292292
* original type if the resulting widened type is a supertype of all dropped
293-
* types (since in this case the type was not a true intersection of mixin traits
293+
* types (since in this case the type was not a true intersection of transparent traits
294294
* and other types to start with).
295295
*/
296-
def dropMixinTraits(tp: Type, bound: Type)(using Context): Type =
296+
def dropTransparentTraits(tp: Type, bound: Type)(using Context): Type =
297297
var kept: Set[Type] = Set() // types to keep since otherwise bound would not fit
298298
var dropped: List[Type] = List() // the types dropped so far, last one on top
299299

300-
def dropOneMixinTrait(tp: Type): Type =
300+
def dropOneTransparentTrait(tp: Type): Type =
301301
val tpd = tp.dealias
302-
if tpd.typeSymbol.isMixinTrait && !tpd.isLambdaSub && !kept.contains(tpd) then
302+
if tpd.typeSymbol.isTransparentTrait && !tpd.isLambdaSub && !kept.contains(tpd) then
303303
dropped = tpd :: dropped
304304
defn.AnyType
305305
else tpd match
306306
case AndType(tp1, tp2) =>
307-
val tp1w = dropOneMixinTrait(tp1)
307+
val tp1w = dropOneTransparentTrait(tp1)
308308
if tp1w ne tp1 then tp1w & tp2
309309
else
310-
val tp2w = dropOneMixinTrait(tp2)
310+
val tp2w = dropOneTransparentTrait(tp2)
311311
if tp2w ne tp2 then tp1 & tp2w
312312
else tpd
313313
case _ =>
314314
tp
315315

316316
def recur(tp: Type): Type =
317-
val tpw = dropOneMixinTrait(tp)
317+
val tpw = dropOneTransparentTrait(tp)
318318
if tpw eq tp then tp
319319
else if tpw <:< bound then recur(tpw)
320320
else
@@ -324,15 +324,15 @@ trait ConstraintHandling {
324324

325325
val tpw = recur(tp)
326326
if (tpw eq tp) || dropped.forall(_ frozen_<:< tpw) then tp else tpw
327-
end dropMixinTraits
327+
end dropTransparentTraits
328328

329329
/** Widen inferred type `inst` with upper `bound`, according to the following rules:
330330
* 1. If `inst` is a singleton type, or a union containing some singleton types,
331331
* widen (all) the singleton type(s), provided the result is a subtype of `bound`
332332
* (i.e. `inst.widenSingletons <:< bound` succeeds with satisfiable constraint)
333333
* 2. If `inst` is a union type, approximate the union type from above by an intersection
334334
* of all common base types, provided the result is a subtype of `bound`.
335-
* 3. drop mixin traits from intersections (see @dropMixinTraits)
335+
* 3. drop transparent traits from intersections (see @dropTransparentTraits)
336336
*
337337
* Don't do these widenings if `bound` is a subtype of `scala.Singleton`.
338338
* Also, if the result of these widenings is a TypeRef to a module class,
@@ -357,7 +357,7 @@ trait ConstraintHandling {
357357

358358
val wideInst =
359359
if isSingleton(bound) then inst
360-
else dropMixinTraits(widenOr(widenSingle(inst)), bound)
360+
else dropTransparentTraits(widenOr(widenSingle(inst)), bound)
361361
wideInst match
362362
case wideInst: TypeRef if wideInst.symbol.is(Module) =>
363363
TermRef(wideInst.prefix, wideInst.symbol.sourceModule)

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ class Definitions {
914914
@tu lazy val InvariantBetweenAnnot: ClassSymbol = requiredClass("scala.annotation.internal.InvariantBetween")
915915
@tu lazy val MainAnnot: ClassSymbol = requiredClass("scala.main")
916916
@tu lazy val MigrationAnnot: ClassSymbol = requiredClass("scala.annotation.migration")
917-
@tu lazy val MixinAnnot: ClassSymbol = requiredClass("scala.annotation.mixin")
917+
@tu lazy val TransparentTraitAnnot: ClassSymbol = requiredClass("scala.annotation.transparentTrait")
918918
@tu lazy val NativeAnnot: ClassSymbol = requiredClass("scala.native")
919919
@tu lazy val RepeatedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Repeated")
920920
@tu lazy val SourceFileAnnot: ClassSymbol = requiredClass("scala.annotation.internal.SourceFile")
@@ -942,7 +942,6 @@ class Definitions {
942942
@tu lazy val SetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.setter")
943943
@tu lazy val ShowAsInfixAnnot: ClassSymbol = requiredClass("scala.annotation.showAsInfix")
944944
@tu lazy val FunctionalInterfaceAnnot: ClassSymbol = requiredClass("java.lang.FunctionalInterface")
945-
@tu lazy val InfixAnnot: ClassSymbol = requiredClass("scala.annotation.infix")
946945
@tu lazy val TargetNameAnnot: ClassSymbol = requiredClass("scala.annotation.targetName")
947946
@tu lazy val VarargsAnnot: ClassSymbol = requiredClass("scala.annotation.varargs")
948947

@@ -1568,8 +1567,8 @@ class Definitions {
15681567
def isInfix(sym: Symbol)(using Context): Boolean =
15691568
(sym eq Object_eq) || (sym eq Object_ne)
15701569

1571-
@tu lazy val assumedMixinTraits =
1572-
Set(ComparableClass, ProductClass, SerializableClass,
1570+
@tu lazy val assumedTransparentTraits =
1571+
Set[Symbol](ComparableClass, ProductClass, SerializableClass,
15731572
// add these for now, until we had a chance to retrofit 2.13 stdlib
15741573
// we should do a more through sweep through it then.
15751574
requiredClass("scala.collection.SortedOps"),

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

+11-5
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ object Flags {
342342
/** Symbol is a Java default method */
343343
val (_, DefaultMethod @ _, _) = newFlags(38, "<defaultmethod>")
344344

345+
/** Symbol is a transparent inline method or trait */
346+
val (Transparent @ _, _, _) = newFlags(39, "transparent")
347+
345348
/** Symbol is an enum class or enum case (if used with case) */
346349
val (Enum @ _, EnumVal @ _, _) = newFlags(40, "enum")
347350

@@ -354,14 +357,16 @@ object Flags {
354357
/** An opaque type alias or a class containing one */
355358
val (Opaque @ _, _, _) = newFlags(43, "opaque")
356359

360+
/** An infix method or type */
361+
val (Infix @ _, _, _) = newFlags(44, "infix")
357362

358363
// ------------ Flags following this one are not pickled ----------------------------------
359364

360365
/** Symbol is not a member of its owner */
361-
val (NonMember @ _, _, _) = newFlags(45, "<non-member>")
366+
val (NonMember @ _, _, _) = newFlags(49, "<non-member>")
362367

363368
/** Denotation is in train of being loaded and completed, used to catch cyclic dependencies */
364-
val (Touched @ _, _, _) = newFlags(48, "<touched>")
369+
val (Touched @ _, _, _) = newFlags(50, "<touched>")
365370

366371
/** Class has been lifted out to package level, local value has been lifted out to class level */
367372
val (Lifted @ _, _, _) = newFlags(51, "<lifted>")
@@ -419,7 +424,7 @@ object Flags {
419424

420425
/** Flags representing source modifiers */
421426
private val CommonSourceModifierFlags: FlagSet =
422-
commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic)
427+
commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent)
423428

424429
val TypeSourceModifierFlags: FlagSet =
425430
CommonSourceModifierFlags.toTypeFlags | Abstract | Sealed | Opaque | Open
@@ -449,7 +454,7 @@ object Flags {
449454
* is completed)
450455
*/
451456
val AfterLoadFlags: FlagSet = commonFlags(
452-
FromStartFlags, AccessFlags, Final, AccessorOrSealed, LazyOrTrait, SelfName, JavaDefined)
457+
FromStartFlags, AccessFlags, Final, AccessorOrSealed, LazyOrTrait, SelfName, JavaDefined, Transparent)
453458

454459
/** A value that's unstable unless complemented with a Stable flag */
455460
val UnstableValueFlags: FlagSet = Mutable | Method
@@ -499,7 +504,7 @@ object Flags {
499504
/** Flags that can apply to a module val */
500505
val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
501506
Override | Final | Method | Implicit | Given | Lazy |
502-
Accessor | AbsOverride | StableRealizable | Captured | Synchronized | Erased
507+
Accessor | AbsOverride | StableRealizable | Captured | Synchronized | Erased | Transparent
503508

504509
/** Flags that can apply to a module class */
505510
val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | Enum
@@ -576,4 +581,5 @@ object Flags {
576581
val SyntheticParam: FlagSet = Synthetic | Param
577582
val SyntheticTermParam: FlagSet = Synthetic | TermParam
578583
val SyntheticTypeParam: FlagSet = Synthetic | TypeParam
584+
val TransparentTrait: FlagSet = Trait | Transparent
579585
}

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -1109,9 +1109,10 @@ object SymDenotations {
11091109
final def isEffectivelySealed(using Context): Boolean =
11101110
isOneOf(FinalOrSealed) || isClass && !isOneOf(EffectivelyOpenFlags)
11111111

1112-
final def isMixinTrait(using Context): Boolean =
1113-
isClass
1114-
&& (hasAnnotation(defn.MixinAnnot) || defn.assumedMixinTraits.contains(symbol.asClass))
1112+
final def isTransparentTrait(using Context): Boolean =
1113+
isAllOf(TransparentTrait)
1114+
|| defn.assumedTransparentTraits.contains(symbol)
1115+
|| isClass && hasAnnotation(defn.TransparentTraitAnnot)
11151116

11161117
/** The class containing this denotation which has the given effective name. */
11171118
final def enclosingClassNamed(name: Name)(using Context): Symbol = {

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -2674,8 +2674,8 @@ object TypeComparer {
26742674
def widenInferred(inst: Type, bound: Type)(using Context): Type =
26752675
comparing(_.widenInferred(inst, bound))
26762676

2677-
def dropMixinTraits(tp: Type, bound: Type)(using Context): Type =
2678-
comparing(_.dropMixinTraits(tp, bound))
2677+
def dropTransparentTraits(tp: Type, bound: Type)(using Context): Type =
2678+
comparing(_.dropTransparentTraits(tp, bound))
26792679

26802680
def constrainPatternType(pat: Type, scrut: Type)(using Context): Boolean =
26812681
comparing(_.constrainPatternType(pat, scrut))

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

+2
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,8 @@ class TreePickler(pickler: TastyPickler) {
712712
if (flags.is(Local)) writeModTag(LOCAL)
713713
if (flags.is(Synthetic)) writeModTag(SYNTHETIC)
714714
if (flags.is(Artifact)) writeModTag(ARTIFACT)
715+
if flags.is(Transparent) then writeModTag(TRANSPARENT)
716+
if flags.is(Infix) then writeModTag(INFIX)
715717
if (isTerm) {
716718
if (flags.is(Implicit)) writeModTag(IMPLICIT)
717719
if (flags.is(Given)) writeModTag(GIVEN)

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -667,15 +667,14 @@ class TreeUnpickler(reader: TastyReader,
667667
case PARAMalias => addFlag(SuperParamAlias)
668668
case EXPORTED => addFlag(Exported)
669669
case OPEN => addFlag(Open)
670+
case TRANSPARENT => addFlag(Transparent)
671+
case INFIX => addFlag(Infix)
670672
case PRIVATEqualified =>
671673
readByte()
672674
privateWithin = readWithin
673675
case PROTECTEDqualified =>
674676
addFlag(Protected)
675677
privateWithin = readWithin
676-
case SUPERTRAIT =>
677-
readByte()
678-
annotFns = (_ => Annotation(defn.MixinAnnot)) :: annotFns
679678
case ANNOTATION =>
680679
annotFns = readAnnot :: annotFns
681680
case tag =>

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

+2-5
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,7 @@ object Parsers {
27322732
case nme.opaque => Mod.Opaque()
27332733
case nme.open => Mod.Open()
27342734
case nme.transparent => Mod.Transparent()
2735+
case nme.infix => Mod.Infix()
27352736
}
27362737
}
27372738

@@ -2807,11 +2808,7 @@ object Parsers {
28072808
}
28082809
else
28092810
mods
2810-
val result = normalize(loop(start))
2811-
for case mod @ Mod.Transparent() <- result.mods do
2812-
if !result.is(Inline) then
2813-
syntaxError(em"`transparent` can only be used in conjunction with `inline`", mod.span)
2814-
result
2811+
normalize(loop(start))
28152812
}
28162813

28172814
val funTypeArgMods: BitSet = BitSet(ERASED)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -288,5 +288,5 @@ object Tokens extends TokensCommon {
288288

289289
final val endMarkerTokens = identifierTokens | BitSet(IF, WHILE, FOR, MATCH, TRY, NEW, GIVEN, VAL, THIS)
290290

291-
final val softModifierNames = Set(nme.inline, nme.opaque, nme.open, nme.transparent)
291+
final val softModifierNames = Set(nme.inline, nme.opaque, nme.open, nme.transparent, nme.infix)
292292
}

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

-2
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
897897
if (rawFlags.is(Param)) flagMask = flagMask &~ Given
898898
val flags = rawFlags & flagMask
899899
var flagsText = toTextFlags(sym, flags)
900-
if mods.hasMod(classOf[untpd.Mod.Transparent]) then
901-
flagsText = "transparent " ~ flagsText
902900
val annotations =
903901
if (sym.exists) sym.annotations.filterNot(ann => dropAnnotForModText(ann.symbol)).map(_.tree)
904902
else mods.annotations.filterNot(tree => dropAnnotForModText(tree.symbol))

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ object SymUtils:
241241

242242
/** Is symbol assumed or declared as an infix symbol? */
243243
def isDeclaredInfix(using Context): Boolean =
244-
self.hasAnnotation(defn.InfixAnnot)
244+
self.is(Infix)
245245
|| defn.isInfix(self)
246246
|| self.name.isUnapplyName
247247
&& self.owner.is(Module)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ trait Applications extends Compatibility {
11351135
&& tree.tpe.classSymbol.isEnumCase
11361136
&& tree.tpe.widen.isValueType
11371137
then
1138-
val widened = TypeComparer.dropMixinTraits(
1138+
val widened = TypeComparer.dropTransparentTraits(
11391139
tree.tpe.parents.reduceLeft(TypeComparer.andType(_, _)),
11401140
pt)
11411141
if widened <:< pt then Typed(tree, TypeTree(widened))

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

+7-2
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,11 @@ object Checking {
449449
if (sym.isType)
450450
fail(TypesAndTraitsCantBeImplicit())
451451
}
452+
if sym.is(Transparent) then
453+
if sym.isType then
454+
if !sym.is(Trait) then fail(em"`transparent` can only be used for traits")
455+
else
456+
if !sym.isInlineMethod then fail(em"`transparent` can only be used for inline methods")
452457
if (!sym.isClass && sym.is(Abstract))
453458
fail(OnlyClassesCanBeAbstract(sym))
454459
// note: this is not covered by the next test since terms can be abstract (which is a dual-mode flag)
@@ -781,7 +786,7 @@ trait Checking {
781786
}
782787

783788
/** Check that `tree` is a valid infix operation. That is, if the
784-
* operator is alphanumeric, it must be declared `@infix`.
789+
* operator is alphanumeric, it must be declared `infix`.
785790
*/
786791
def checkValidInfix(tree: untpd.InfixOp, meth: Symbol)(using Context): Unit = {
787792
tree.op match {
@@ -802,7 +807,7 @@ trait Checking {
802807
else
803808
("method", (n: Name) => s"method syntax .$n(...)")
804809
report.deprecationWarning(
805-
i"""Alphanumeric $kind $name is not declared @infix; it should not be used as infix operator.
810+
i"""Alphanumeric $kind $name is not declared `infix`; it should not be used as infix operator.
806811
|The operation can be rewritten automatically to `$name` under -deprecation -rewrite.
807812
|Or rewrite to ${alternative(name)} manually.""",
808813
tree.op.srcPos)

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,7 @@ object PrepareInlineable {
206206

207207
/** The type ascription `rhs: tpt`, unless `original` is `transparent`. */
208208
def wrapRHS(original: untpd.DefDef, tpt: Tree, rhs: Tree)(using Context): Tree =
209-
if original.mods.hasMod(classOf[untpd.Mod.Transparent]) then rhs
210-
else Typed(rhs, tpt)
209+
if original.mods.is(Transparent) then rhs else Typed(rhs, tpt)
211210

212211
/** Return result of evaluating `op`, but drop `Inline` flag and `Body` annotation
213212
* of `sym` in case that leads to errors.

0 commit comments

Comments
 (0)