Skip to content

Commit 6443cba

Browse files
authored
Merge pull request #10243 from dotty-staging/fix-#10239
Fix #10239: `@mixin trait` instead of `super trait`
2 parents 819e0b1 + 5245ff2 commit 6443cba

File tree

24 files changed

+62
-93
lines changed

24 files changed

+62
-93
lines changed

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

-2
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
213213
case class Inline()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Inline)
214214

215215
case class Transparent()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.EmptyFlags)
216-
217-
case class Super()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.SuperTrait)
218216
}
219217

220218
/** 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 super trait instances
290-
* and others are not, replace as many super trait instances as possible with Any
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
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 super traits
293+
* types (since in this case the type was not a true intersection of mixin traits
294294
* and other types to start with).
295295
*/
296-
def dropSuperTraits(tp: Type, bound: Type)(using Context): Type =
296+
def dropMixinTraits(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 dropOneSuperTrait(tp: Type): Type =
300+
def dropOneMixinTrait(tp: Type): Type =
301301
val tpd = tp.dealias
302-
if tpd.typeSymbol.isSuperTrait && !tpd.isLambdaSub && !kept.contains(tpd) then
302+
if tpd.typeSymbol.isMixinTrait && !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 = dropOneSuperTrait(tp1)
307+
val tp1w = dropOneMixinTrait(tp1)
308308
if tp1w ne tp1 then tp1w & tp2
309309
else
310-
val tp2w = dropOneSuperTrait(tp2)
310+
val tp2w = dropOneMixinTrait(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 = dropOneSuperTrait(tp)
317+
val tpw = dropOneMixinTrait(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 dropSuperTraits
327+
end dropMixinTraits
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 super traits from intersections (see @dropSuperTraits)
335+
* 3. drop mixin traits from intersections (see @dropMixinTraits)
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 dropSuperTraits(widenOr(widenSingle(inst)), bound)
360+
else dropMixinTraits(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

+2-2
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ class Definitions {
909909
@tu lazy val InvariantBetweenAnnot: ClassSymbol = requiredClass("scala.annotation.internal.InvariantBetween")
910910
@tu lazy val MainAnnot: ClassSymbol = requiredClass("scala.main")
911911
@tu lazy val MigrationAnnot: ClassSymbol = requiredClass("scala.annotation.migration")
912+
@tu lazy val MixinAnnot: ClassSymbol = requiredClass("scala.annotation.mixin")
912913
@tu lazy val NativeAnnot: ClassSymbol = requiredClass("scala.native")
913914
@tu lazy val RepeatedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Repeated")
914915
@tu lazy val SourceFileAnnot: ClassSymbol = requiredClass("scala.annotation.internal.SourceFile")
@@ -917,7 +918,6 @@ class Definitions {
917918
@tu lazy val ScalaStrictFPAnnot: ClassSymbol = requiredClass("scala.annotation.strictfp")
918919
@tu lazy val ScalaStaticAnnot: ClassSymbol = requiredClass("scala.annotation.static")
919920
@tu lazy val SerialVersionUIDAnnot: ClassSymbol = requiredClass("scala.SerialVersionUID")
920-
@tu lazy val SuperTraitAnnot: ClassSymbol = requiredClass("scala.annotation.superTrait")
921921
@tu lazy val TASTYSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYSignature")
922922
@tu lazy val TASTYLongSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYLongSignature")
923923
@tu lazy val TailrecAnnot: ClassSymbol = requiredClass("scala.annotation.tailrec")
@@ -1506,7 +1506,7 @@ class Definitions {
15061506
def isInfix(sym: Symbol)(using Context): Boolean =
15071507
(sym eq Object_eq) || (sym eq Object_ne)
15081508

1509-
@tu lazy val assumedSuperTraits =
1509+
@tu lazy val assumedMixinTraits =
15101510
Set(ComparableClass, ProductClass, SerializableClass,
15111511
// add these for now, until we had a chance to retrofit 2.13 stdlib
15121512
// we should do a more through sweep through it then.

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ object Flags {
227227
val (Final @ _, _, _) = newFlags(6, "final")
228228

229229
/** A method symbol / a super trait */
230-
val (_, Method @ _, SuperTrait @ _) = newFlags(7, "<method>", "super")
230+
val (_, Method @ _, _) = newFlags(7, "<method>")
231231

232232
/** A (term or type) parameter to a class or method */
233233
val (Param @ _, TermParam @ _, TypeParam @ _) = newFlags(8, "<param>")
@@ -437,8 +437,7 @@ object Flags {
437437
* TODO: Should check that FromStartFlags do not change in completion
438438
*/
439439
val FromStartFlags: FlagSet = commonFlags(
440-
Module, Package, Deferred, Method, Case, Enum,
441-
SuperTrait, Param, ParamAccessor,
440+
Module, Package, Deferred, Method, Case, Enum, Param, ParamAccessor,
442441
Scala2SpecialFlags, MutableOrOpen, Opaque, Touched, JavaStatic,
443442
OuterOrCovariant, LabelOrContravariant, CaseAccessor,
444443
Extension, NonMember, Implicit, Given, Permanent, Synthetic,

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

+2-4
Original file line numberDiff line numberDiff line change
@@ -1095,11 +1095,9 @@ object SymDenotations {
10951095
final def isEffectivelySealed(using Context): Boolean =
10961096
isOneOf(FinalOrSealed) || isClass && !isOneOf(EffectivelyOpenFlags)
10971097

1098-
final def isSuperTrait(using Context): Boolean =
1098+
final def isMixinTrait(using Context): Boolean =
10991099
isClass
1100-
&& (is(SuperTrait)
1101-
|| defn.assumedSuperTraits.contains(symbol.asClass)
1102-
|| hasAnnotation(defn.SuperTraitAnnot))
1100+
&& (hasAnnotation(defn.MixinAnnot) || defn.assumedMixinTraits.contains(symbol.asClass))
11031101

11041102
/** The class containing this denotation which has the given effective name. */
11051103
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
@@ -2638,8 +2638,8 @@ object TypeComparer {
26382638
def widenInferred(inst: Type, bound: Type)(using Context): Type =
26392639
comparing(_.widenInferred(inst, bound))
26402640

2641-
def dropSuperTraits(tp: Type, bound: Type)(using Context): Type =
2642-
comparing(_.dropSuperTraits(tp, bound))
2641+
def dropMixinTraits(tp: Type, bound: Type)(using Context): Type =
2642+
comparing(_.dropMixinTraits(tp, bound))
26432643

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

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

-1
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,6 @@ class TreePickler(pickler: TastyPickler) {
729729
if (flags.is(Sealed)) writeModTag(SEALED)
730730
if (flags.is(Abstract)) writeModTag(ABSTRACT)
731731
if (flags.is(Trait)) writeModTag(TRAIT)
732-
if flags.is(SuperTrait) then writeModTag(SUPERTRAIT)
733732
if (flags.is(Covariant)) writeModTag(COVARIANT)
734733
if (flags.is(Contravariant)) writeModTag(CONTRAVARIANT)
735734
if (flags.is(Opaque)) writeModTag(OPAQUE)

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,6 @@ class TreeUnpickler(reader: TastyReader,
648648
case STATIC => addFlag(JavaStatic)
649649
case OBJECT => addFlag(Module)
650650
case TRAIT => addFlag(Trait)
651-
case SUPERTRAIT => addFlag(SuperTrait)
652651
case ENUM => addFlag(Enum)
653652
case LOCAL => addFlag(Local)
654653
case SYNTHETIC => addFlag(Synthetic)
@@ -672,6 +671,9 @@ class TreeUnpickler(reader: TastyReader,
672671
case PROTECTEDqualified =>
673672
addFlag(Protected)
674673
privateWithin = readWithin
674+
case SUPERTRAIT =>
675+
readByte()
676+
annotFns = (_ => Annotation(defn.MixinAnnot)) :: annotFns
675677
case ANNOTATION =>
676678
annotFns = readAnnot :: annotFns
677679
case tag =>

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -3378,7 +3378,7 @@ object Parsers {
33783378
}
33793379
}
33803380

3381-
/** TmplDef ::= ([‘case’] ‘class’ | [‘super’] ‘trait’) ClassDef
3381+
/** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
33823382
* | [‘case’] ‘object’ ObjectDef
33833383
* | ‘enum’ EnumDef
33843384
* | ‘given’ GivenDef
@@ -3388,8 +3388,6 @@ object Parsers {
33883388
in.token match {
33893389
case TRAIT =>
33903390
classDef(start, in.skipToken(addFlag(mods, Trait)))
3391-
case SUPERTRAIT =>
3392-
classDef(start, in.skipToken(addFlag(mods, Trait | SuperTrait)))
33933391
case CLASS =>
33943392
classDef(start, in.skipToken(mods))
33953393
case CASECLASS =>

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ object Scanners {
554554
currentRegion = r.outer
555555
case _ =>
556556

557-
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SUPER + TRAIT => SUPERTRAIT
557+
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT
558558
* SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
559559
* - Insert missing OUTDENTs at EOF
560560
*/
@@ -571,10 +571,6 @@ object Scanners {
571571
if (token == CLASS) fuse(CASECLASS)
572572
else if (token == OBJECT) fuse(CASEOBJECT)
573573
else reset()
574-
case SUPER =>
575-
lookAhead()
576-
if token == TRAIT then fuse(SUPERTRAIT)
577-
else reset()
578574
case SEMI =>
579575
lookAhead()
580576
if (token != ELSE) reset()

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ object Tokens extends TokensCommon {
184184
final val ERASED = 63; enter(ERASED, "erased")
185185
final val GIVEN = 64; enter(GIVEN, "given")
186186
final val EXPORT = 65; enter(EXPORT, "export")
187-
final val SUPERTRAIT = 66; enter(SUPERTRAIT, "super trait")
188187
final val MACRO = 67; enter(MACRO, "macro") // TODO: remove
189188

190189
/** special symbols */
@@ -234,7 +233,7 @@ object Tokens extends TokensCommon {
234233
final val canStartTypeTokens: TokenSet = literalTokens | identifierTokens | BitSet(
235234
THIS, SUPER, USCORE, LPAREN, AT)
236235

237-
final val templateIntroTokens: TokenSet = BitSet(CLASS, TRAIT, OBJECT, ENUM, CASECLASS, CASEOBJECT, SUPERTRAIT)
236+
final val templateIntroTokens: TokenSet = BitSet(CLASS, TRAIT, OBJECT, ENUM, CASECLASS, CASEOBJECT)
238237

239238
final val dclIntroTokens: TokenSet = BitSet(DEF, VAL, VAR, TYPE, GIVEN)
240239

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

+2-6
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
738738
if mdef.hasType then Modifiers(mdef.symbol) else mdef.rawMods
739739

740740
private def Modifiers(sym: Symbol): Modifiers = untpd.Modifiers(
741-
sym.flags & (if (sym.isType) ModifierFlags | VarianceFlags | SuperTrait else ModifierFlags),
741+
sym.flags & (if (sym.isType) ModifierFlags | VarianceFlags else ModifierFlags),
742742
if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY,
743743
sym.annotations.filterNot(ann => dropAnnotForModText(ann.symbol)).map(_.tree))
744744

@@ -856,10 +856,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
856856
}
857857

858858
protected def templateText(tree: TypeDef, impl: Template): Text = {
859-
val kw =
860-
if tree.mods.is(SuperTrait) then "super trait"
861-
else if tree.mods.is(Trait) then "trait"
862-
else "class"
859+
val kw = if tree.mods.is(Trait) then "trait" else "class"
863860
val decl = modText(tree.mods, tree.symbol, keywordStr(kw), isType = true)
864861
( decl ~~ typeText(nameIdText(tree)) ~ withEnclosingDef(tree) { toTextTemplate(impl) }
865862
// ~ (if (tree.hasType && printDebug) i"[decls = ${tree.symbol.info.decls}]" else "") // uncomment to enable
@@ -966,7 +963,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
966963
else if (sym.isPackageObject) "package object"
967964
else if (flags.is(Module) && flags.is(Case)) "case object"
968965
else if (sym.isClass && flags.is(Case)) "case class"
969-
else if sym.isClass && flags.is(SuperTrait) then "super trait"
970966
else super.keyString(sym)
971967
}
972968

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ trait Applications extends Compatibility {
11331133
&& tree.tpe.classSymbol.isEnumCase
11341134
&& tree.tpe.widen.isValueType
11351135
then
1136-
val widened = TypeComparer.dropSuperTraits(
1136+
val widened = TypeComparer.dropMixinTraits(
11371137
tree.tpe.parents.reduceLeft(TypeComparer.andType(_, _)),
11381138
pt)
11391139
if widened <:< pt then Typed(tree, TypeTree(widened))

docs/docs/internals/syntax.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ VarDef ::= PatDef
387387
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
388388
| ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)
389389
390-
TmplDef ::= ([‘case’] ‘class’ | [‘super’] ‘trait’) ClassDef
390+
TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
391391
| [‘case’] ‘object’ ObjectDef
392392
| ‘enum’ EnumDef
393393
| ‘given’ GivenDef
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
layout: doc-page
3-
title: super traits
3+
title: Mixin Traits
44
---
55

66
Traits are used in two roles:
@@ -9,7 +9,7 @@ Traits are used in two roles:
99
2. As types of vals, defs, or parameters
1010

1111
Some traits are used primarily in the first role, and we usually do not want to see them in inferred types. An example is the `Product` trait that the compiler
12-
adds as a super trait to every case class or case object. In Scala 2, this parent trait sometimes makes inferred types more complicated than they should be. Example:
12+
adds as a mixin trait to every case class or case object. In Scala 2, this parent trait sometimes makes inferred types more complicated than they should be. Example:
1313
```scala
1414
trait Kind
1515
case object Var extends Kind
@@ -20,46 +20,35 @@ Here, the inferred type of `x` is `Set[Kind & Product & Serializable]` whereas o
2020

2121
- The type of the conditional above is the union type `Val | Var`.
2222
- A union type is widened in type inference to the least supertype that is
23-
not a union type. In the example, this type is `Kind & Product & Serializable` since all three traits are supertraits of both `Val` and `Var`.
23+
not a union type. In the example, this type is `Kind & Product & Serializable` since all three traits are traits of both `Val` and `Var`.
2424
So that type becomes the inferred element type of the set.
2525

26-
Scala 3 allows one to mark a trait as a `super` trait, which means that it can be suppressed in type inference. Here's an example that follows the lines of the
27-
code above, but now with a new super trait `S` instead of `Product`:
26+
Scala 3 allows one to mark a trait as a `@mixin` trait, which means that it can be suppressed in type inference. Here's an example that follows the lines of the
27+
code above, but now with a new mixin trait `S` instead of `Product`:
2828
```scala
29-
super trait S
29+
@mixin trait S
3030
trait Kind
3131
object Var extends Kind, S
3232
object Val extends Kind, S
3333
val x = Set(if condition then Val else Var)
3434
```
35-
Now `x` has inferred type `Set[Kind]`. The common super trait `S` does not
35+
Now `x` has inferred type `Set[Kind]`. The common mixin trait `S` does not
3636
appear in the inferred type.
3737

38-
### Super Traits
38+
### Mixin Traits
3939

4040
The traits `scala.Product`, `java.lang.Serializable` and `java.lang.Comparable`
41-
are treated automatically as super traits. Other traits can be turned into super traits, by adding the keyword `super` in front of `trait`, as shown above.
41+
are treated automatically as mixin traits. Other traits can be turned into mixin traits, by adding the annotation `@mixin` in front of `trait`, as shown above.
4242

43-
Every trait can be declared as a super trait. Typically super traits are traits that influence the implementation of inheriting classes and traits and that are not usually used as types by themselves. Two examples from the
43+
Every trait can be declared as a mixin trait. Typically mixin traits are traits that influence the implementation of inheriting classes and traits and that are not usually used as types by themselves. Two examples from the
4444
standard collection library:
4545

4646
- `IterableOps`, which provides method implementations for an `Iterable`
4747
- `StrictOptimizedSeqOps`, which optimises some of these implementations for
4848
sequences with efficient indexing.
4949

5050
Generally, any trait that is extended recursively is a good candidate to be
51-
declared a super trait.
52-
53-
### Retro-Fitting Scala 2 Libraries
54-
55-
To allow cross-building between Scala 2 and 3, super traits can also be
56-
introduced by adding the `@superTrait` annotation, which is defined in package `scala.annotation`. Example:
57-
```scala
58-
import scala.annotation.superTrait
59-
60-
@superTrait trait StrictOptimizedSeqOps[+A, +CC[_], +C] ...
61-
```
62-
The `@superTrait` annotation will be deprecated and removed in some later version of Scala when cross-building with Scala 2 will no longer be a concern.
51+
declared a mixin trait.
6352

6453
### Rules for Inference
6554

@@ -75,12 +64,5 @@ The precise rules are as follows:
7564
the resulting type is still a subtype of the bound `B`.
7665
- However, do not perform this widening if all types `Ti` can get replaced in that way.
7766

78-
The last clause ensures that a single super trait instance such as `Product` is not widened to `Any`. Super trait instances are only dropped when they appear in conjunction with some other type.
79-
80-
### Syntax
67+
The last clause ensures that a single mixin trait instance such as `Product` is not widened to `Any`. Mixin trait instances are only dropped when they appear in conjunction with some other type.
8168

82-
Only the production `TmplDef` for class and trait definitions has to be changed.
83-
The new version is:
84-
```
85-
TmplDef ::= ([‘case’] ‘class’ | [‘super’] ‘trait’) ClassDef
86-
```

docs/sidebar.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ sidebar:
8787
subsection:
8888
- title: Trait Parameters
8989
url: docs/reference/other-new-features/trait-parameters.html
90-
- title: Super Traits
91-
url: docs/reference/other-new-features/super-traits.html
90+
- title: Mixin Traits
91+
url: docs/reference/other-new-features/mixin-traits.html
9292
- title: Creator Applications
9393
url: docs/reference/other-new-features/creator-applications.html
9494
- title: Export Clauses
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package scala.annotation
2+
3+
/** An annotation that marks a trait as a mixin trait. Mixin traits
4+
* are not inferred when combined with other types in an intersection.
5+
* See reference/other-new-features/mixin-traits.html for details.
6+
*/
7+
final class mixin extends StaticAnnotation

library/src/scala/annotation/superTrait.scala

-8
This file was deleted.

0 commit comments

Comments
 (0)