From 67017d72719a4b780caf4ad4e27e9a24aaab89a0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 9 Nov 2020 13:57:48 +0100 Subject: [PATCH 1/2] Fix #10239: `@mixin trait` instead of `super trait` --- compiler/src/dotty/tools/dotc/ast/untpd.scala | 2 - .../tools/dotc/core/ConstraintHandling.scala | 24 +++++------ .../dotty/tools/dotc/core/Definitions.scala | 4 +- .../src/dotty/tools/dotc/core/Flags.scala | 5 +-- .../tools/dotc/core/SymDenotations.scala | 6 +-- .../dotty/tools/dotc/core/TypeComparer.scala | 4 +- .../tools/dotc/core/tasty/TreePickler.scala | 1 - .../tools/dotc/core/tasty/TreeUnpickler.scala | 4 +- .../dotty/tools/dotc/parsing/Parsers.scala | 4 +- .../dotty/tools/dotc/parsing/Scanners.scala | 6 +-- .../src/dotty/tools/dotc/parsing/Tokens.scala | 3 +- .../tools/dotc/printing/RefinedPrinter.scala | 8 +--- .../dotty/tools/dotc/typer/Applications.scala | 2 +- docs/docs/internals/syntax.md | 2 +- .../{super-traits.md => mixin-traits.md} | 42 ++++++------------- docs/sidebar.yml | 4 +- library/src/scala/annotation/mixin.scala | 7 ++++ library/src/scala/annotation/superTrait.scala | 8 ---- library/src/scala/reflect/Enum.scala | 3 +- library/src/scala/runtime/EnumValue.scala | 3 +- tasty/src/dotty/tools/tasty/TastyFormat.scala | 3 +- .../fatal-warnings/supertraits.scala | 5 ++- tests/neg/supertraits.scala | 3 +- 23 files changed, 61 insertions(+), 92 deletions(-) rename docs/docs/reference/other-new-features/{super-traits.md => mixin-traits.md} (62%) create mode 100644 library/src/scala/annotation/mixin.scala delete mode 100644 library/src/scala/annotation/superTrait.scala diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 1cba0631bcc9..9336bcc8e7bd 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -213,8 +213,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case class Inline()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Inline) case class Transparent()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.EmptyFlags) - - case class Super()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.SuperTrait) } /** Modifiers and annotations for definitions diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 5d73475f4e0b..65e4f01d44fe 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -286,35 +286,35 @@ trait ConstraintHandling { } } - /** If `tp` is an intersection such that some operands are super trait instances - * and others are not, replace as many super trait instances as possible with Any + /** If `tp` is an intersection such that some operands are mixin trait instances + * and others are not, replace as many mixin trait instances as possible with Any * as long as the result is still a subtype of `bound`. But fall back to the * original type if the resulting widened type is a supertype of all dropped - * types (since in this case the type was not a true intersection of super traits + * types (since in this case the type was not a true intersection of mixin traits * and other types to start with). */ - def dropSuperTraits(tp: Type, bound: Type)(using Context): Type = + def dropMixinTraits(tp: Type, bound: Type)(using Context): Type = var kept: Set[Type] = Set() // types to keep since otherwise bound would not fit var dropped: List[Type] = List() // the types dropped so far, last one on top - def dropOneSuperTrait(tp: Type): Type = + def dropOneMixinTrait(tp: Type): Type = val tpd = tp.dealias - if tpd.typeSymbol.isSuperTrait && !tpd.isLambdaSub && !kept.contains(tpd) then + if tpd.typeSymbol.isMixinTrait && !tpd.isLambdaSub && !kept.contains(tpd) then dropped = tpd :: dropped defn.AnyType else tpd match case AndType(tp1, tp2) => - val tp1w = dropOneSuperTrait(tp1) + val tp1w = dropOneMixinTrait(tp1) if tp1w ne tp1 then tp1w & tp2 else - val tp2w = dropOneSuperTrait(tp2) + val tp2w = dropOneMixinTrait(tp2) if tp2w ne tp2 then tp1 & tp2w else tpd case _ => tp def recur(tp: Type): Type = - val tpw = dropOneSuperTrait(tp) + val tpw = dropOneMixinTrait(tp) if tpw eq tp then tp else if tpw <:< bound then recur(tpw) else @@ -324,7 +324,7 @@ trait ConstraintHandling { val tpw = recur(tp) if (tpw eq tp) || dropped.forall(_ frozen_<:< tpw) then tp else tpw - end dropSuperTraits + end dropMixinTraits /** Widen inferred type `inst` with upper `bound`, according to the following rules: * 1. If `inst` is a singleton type, or a union containing some singleton types, @@ -332,7 +332,7 @@ trait ConstraintHandling { * (i.e. `inst.widenSingletons <:< bound` succeeds with satisfiable constraint) * 2. If `inst` is a union type, approximate the union type from above by an intersection * of all common base types, provided the result is a subtype of `bound`. - * 3. drop super traits from intersections (see @dropSuperTraits) + * 3. drop mixin traits from intersections (see @dropMixinTraits) * * Don't do these widenings if `bound` is a subtype of `scala.Singleton`. * Also, if the result of these widenings is a TypeRef to a module class, @@ -357,7 +357,7 @@ trait ConstraintHandling { val wideInst = if isSingleton(bound) then inst - else dropSuperTraits(widenOr(widenSingle(inst)), bound) + else dropMixinTraits(widenOr(widenSingle(inst)), bound) wideInst match case wideInst: TypeRef if wideInst.symbol.is(Module) => TermRef(wideInst.prefix, wideInst.symbol.sourceModule) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 70d7c6106ea0..81e70258223f 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -916,6 +916,7 @@ class Definitions { @tu lazy val InvariantBetweenAnnot: ClassSymbol = requiredClass("scala.annotation.internal.InvariantBetween") @tu lazy val MainAnnot: ClassSymbol = requiredClass("scala.main") @tu lazy val MigrationAnnot: ClassSymbol = requiredClass("scala.annotation.migration") + @tu lazy val MixinAnnot: ClassSymbol = requiredClass("scala.annotation.mixin") @tu lazy val NativeAnnot: ClassSymbol = requiredClass("scala.native") @tu lazy val RepeatedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Repeated") @tu lazy val SourceFileAnnot: ClassSymbol = requiredClass("scala.annotation.internal.SourceFile") @@ -924,7 +925,6 @@ class Definitions { @tu lazy val ScalaStrictFPAnnot: ClassSymbol = requiredClass("scala.annotation.strictfp") @tu lazy val ScalaStaticAnnot: ClassSymbol = requiredClass("scala.annotation.static") @tu lazy val SerialVersionUIDAnnot: ClassSymbol = requiredClass("scala.SerialVersionUID") - @tu lazy val SuperTraitAnnot: ClassSymbol = requiredClass("scala.annotation.superTrait") @tu lazy val TASTYSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYSignature") @tu lazy val TASTYLongSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYLongSignature") @tu lazy val TailrecAnnot: ClassSymbol = requiredClass("scala.annotation.tailrec") @@ -1513,7 +1513,7 @@ class Definitions { def isInfix(sym: Symbol)(using Context): Boolean = (sym eq Object_eq) || (sym eq Object_ne) - @tu lazy val assumedSuperTraits = + @tu lazy val assumedMixinTraits = Set(ComparableClass, ProductClass, SerializableClass, // add these for now, until we had a chance to retrofit 2.13 stdlib // we should do a more through sweep through it then. diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index adf8a7681149..b4f09856340d 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -227,7 +227,7 @@ object Flags { val (Final @ _, _, _) = newFlags(6, "final") /** A method symbol / a super trait */ - val (_, Method @ _, SuperTrait @ _) = newFlags(7, "", "super") + val (_, Method @ _, _) = newFlags(7, "") /** A (term or type) parameter to a class or method */ val (Param @ _, TermParam @ _, TypeParam @ _) = newFlags(8, "") @@ -437,8 +437,7 @@ object Flags { * TODO: Should check that FromStartFlags do not change in completion */ val FromStartFlags: FlagSet = commonFlags( - Module, Package, Deferred, Method, Case, Enum, - SuperTrait, Param, ParamAccessor, + Module, Package, Deferred, Method, Case, Enum, Param, ParamAccessor, Scala2SpecialFlags, MutableOrOpen, Opaque, Touched, JavaStatic, OuterOrCovariant, LabelOrContravariant, CaseAccessor, Extension, NonMember, Implicit, Given, Permanent, Synthetic, diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 8f29eedd2990..6f10d7aa2d87 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1095,11 +1095,9 @@ object SymDenotations { final def isEffectivelySealed(using Context): Boolean = isOneOf(FinalOrSealed) || isClass && !isOneOf(EffectivelyOpenFlags) - final def isSuperTrait(using Context): Boolean = + final def isMixinTrait(using Context): Boolean = isClass - && (is(SuperTrait) - || defn.assumedSuperTraits.contains(symbol.asClass) - || hasAnnotation(defn.SuperTraitAnnot)) + && (hasAnnotation(defn.MixinAnnot) || defn.assumedMixinTraits.contains(symbol.asClass)) /** The class containing this denotation which has the given effective name. */ final def enclosingClassNamed(name: Name)(using Context): Symbol = { diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index b14a0066760a..baaa1fb58afa 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2638,8 +2638,8 @@ object TypeComparer { def widenInferred(inst: Type, bound: Type)(using Context): Type = comparing(_.widenInferred(inst, bound)) - def dropSuperTraits(tp: Type, bound: Type)(using Context): Type = - comparing(_.dropSuperTraits(tp, bound)) + def dropMixinTraits(tp: Type, bound: Type)(using Context): Type = + comparing(_.dropMixinTraits(tp, bound)) def constrainPatternType(pat: Type, scrut: Type)(using Context): Boolean = comparing(_.constrainPatternType(pat, scrut)) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index b7613c67b706..534a01ab8edb 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -729,7 +729,6 @@ class TreePickler(pickler: TastyPickler) { if (flags.is(Sealed)) writeModTag(SEALED) if (flags.is(Abstract)) writeModTag(ABSTRACT) if (flags.is(Trait)) writeModTag(TRAIT) - if flags.is(SuperTrait) then writeModTag(SUPERTRAIT) if (flags.is(Covariant)) writeModTag(COVARIANT) if (flags.is(Contravariant)) writeModTag(CONTRAVARIANT) if (flags.is(Opaque)) writeModTag(OPAQUE) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 18f3f15fd5d2..647d38b157ac 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -648,7 +648,6 @@ class TreeUnpickler(reader: TastyReader, case STATIC => addFlag(JavaStatic) case OBJECT => addFlag(Module) case TRAIT => addFlag(Trait) - case SUPERTRAIT => addFlag(SuperTrait) case ENUM => addFlag(Enum) case LOCAL => addFlag(Local) case SYNTHETIC => addFlag(Synthetic) @@ -672,6 +671,9 @@ class TreeUnpickler(reader: TastyReader, case PROTECTEDqualified => addFlag(Protected) privateWithin = readWithin + case SUPERTRAIT => + readByte() + annotFns = (_ => Annotation(defn.MixinAnnot)) :: annotFns case ANNOTATION => annotFns = readAnnot :: annotFns case tag => diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 8cbda78a474a..39eda0800c44 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3378,7 +3378,7 @@ object Parsers { } } - /** TmplDef ::= ([‘case’] ‘class’ | [‘super’] ‘trait’) ClassDef + /** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef * | [‘case’] ‘object’ ObjectDef * | ‘enum’ EnumDef * | ‘given’ GivenDef @@ -3388,8 +3388,6 @@ object Parsers { in.token match { case TRAIT => classDef(start, in.skipToken(addFlag(mods, Trait))) - case SUPERTRAIT => - classDef(start, in.skipToken(addFlag(mods, Trait | SuperTrait))) case CLASS => classDef(start, in.skipToken(mods)) case CASECLASS => diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 07e925b6bf15..489ee4522453 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -554,7 +554,7 @@ object Scanners { currentRegion = r.outer case _ => - /** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SUPER + TRAIT => SUPERTRAIT + /** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT * SEMI + ELSE => ELSE, COLON + => COLONEOL * - Insert missing OUTDENTs at EOF */ @@ -571,10 +571,6 @@ object Scanners { if (token == CLASS) fuse(CASECLASS) else if (token == OBJECT) fuse(CASEOBJECT) else reset() - case SUPER => - lookAhead() - if token == TRAIT then fuse(SUPERTRAIT) - else reset() case SEMI => lookAhead() if (token != ELSE) reset() diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 70dce5b85e13..7f5944c871ce 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -184,7 +184,6 @@ object Tokens extends TokensCommon { final val ERASED = 63; enter(ERASED, "erased") final val GIVEN = 64; enter(GIVEN, "given") final val EXPORT = 65; enter(EXPORT, "export") - final val SUPERTRAIT = 66; enter(SUPERTRAIT, "super trait") final val MACRO = 67; enter(MACRO, "macro") // TODO: remove /** special symbols */ @@ -234,7 +233,7 @@ object Tokens extends TokensCommon { final val canStartTypeTokens: TokenSet = literalTokens | identifierTokens | BitSet( THIS, SUPER, USCORE, LPAREN, AT) - final val templateIntroTokens: TokenSet = BitSet(CLASS, TRAIT, OBJECT, ENUM, CASECLASS, CASEOBJECT, SUPERTRAIT) + final val templateIntroTokens: TokenSet = BitSet(CLASS, TRAIT, OBJECT, ENUM, CASECLASS, CASEOBJECT) final val dclIntroTokens: TokenSet = BitSet(DEF, VAL, VAR, TYPE, GIVEN) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 34d2693f0320..c2cc0f52214c 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -738,7 +738,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if mdef.hasType then Modifiers(mdef.symbol) else mdef.rawMods private def Modifiers(sym: Symbol): Modifiers = untpd.Modifiers( - sym.flags & (if (sym.isType) ModifierFlags | VarianceFlags | SuperTrait else ModifierFlags), + sym.flags & (if (sym.isType) ModifierFlags | VarianceFlags else ModifierFlags), if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY, sym.annotations.filterNot(ann => dropAnnotForModText(ann.symbol)).map(_.tree)) @@ -856,10 +856,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } protected def templateText(tree: TypeDef, impl: Template): Text = { - val kw = - if tree.mods.is(SuperTrait) then "super trait" - else if tree.mods.is(Trait) then "trait" - else "class" + val kw = if tree.mods.is(Trait) then "trait" else "class" val decl = modText(tree.mods, tree.symbol, keywordStr(kw), isType = true) ( decl ~~ typeText(nameIdText(tree)) ~ withEnclosingDef(tree) { toTextTemplate(impl) } // ~ (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) { else if (sym.isPackageObject) "package object" else if (flags.is(Module) && flags.is(Case)) "case object" else if (sym.isClass && flags.is(Case)) "case class" - else if sym.isClass && flags.is(SuperTrait) then "super trait" else super.keyString(sym) } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index fb7d69d0b86b..3bed63185c6c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1133,7 +1133,7 @@ trait Applications extends Compatibility { && tree.tpe.classSymbol.isEnumCase && tree.tpe.widen.isValueType then - val widened = TypeComparer.dropSuperTraits( + val widened = TypeComparer.dropMixinTraits( tree.tpe.parents.reduceLeft(TypeComparer.andType(_, _)), pt) if widened <:< pt then Typed(tree, TypeTree(widened)) diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index 78a3e65161c7..aa1d5b182b29 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -387,7 +387,7 @@ VarDef ::= PatDef DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr) | ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr DefDef(_, , Nil, vparamss, EmptyTree, expr | Block) -TmplDef ::= ([‘case’] ‘class’ | [‘super’] ‘trait’) ClassDef +TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef | [‘case’] ‘object’ ObjectDef | ‘enum’ EnumDef | ‘given’ GivenDef diff --git a/docs/docs/reference/other-new-features/super-traits.md b/docs/docs/reference/other-new-features/mixin-traits.md similarity index 62% rename from docs/docs/reference/other-new-features/super-traits.md rename to docs/docs/reference/other-new-features/mixin-traits.md index f7ca5d688ea1..f2a4f977ccad 100644 --- a/docs/docs/reference/other-new-features/super-traits.md +++ b/docs/docs/reference/other-new-features/mixin-traits.md @@ -1,6 +1,6 @@ --- layout: doc-page -title: super traits +title: Mixin Traits --- Traits are used in two roles: @@ -9,7 +9,7 @@ Traits are used in two roles: 2. As types of vals, defs, or parameters 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 -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: +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: ```scala trait Kind case object Var extends Kind @@ -20,27 +20,27 @@ Here, the inferred type of `x` is `Set[Kind & Product & Serializable]` whereas o - The type of the conditional above is the union type `Val | Var`. - A union type is widened in type inference to the least supertype that is - not a union type. In the example, this type is `Kind & Product & Serializable` since all three traits are supertraits of both `Val` and `Var`. + not a union type. In the example, this type is `Kind & Product & Serializable` since all three traits are traits of both `Val` and `Var`. So that type becomes the inferred element type of the set. -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 -code above, but now with a new super trait `S` instead of `Product`: +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 +code above, but now with a new mixin trait `S` instead of `Product`: ```scala -super trait S +@mixin trait S trait Kind object Var extends Kind, S object Val extends Kind, S val x = Set(if condition then Val else Var) ``` -Now `x` has inferred type `Set[Kind]`. The common super trait `S` does not +Now `x` has inferred type `Set[Kind]`. The common mixin trait `S` does not appear in the inferred type. -### Super Traits +### Mixin Traits The traits `scala.Product`, `java.lang.Serializable` and `java.lang.Comparable` -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. +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. -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 +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 standard collection library: - `IterableOps`, which provides method implementations for an `Iterable` @@ -48,18 +48,7 @@ standard collection library: sequences with efficient indexing. Generally, any trait that is extended recursively is a good candidate to be -declared a super trait. - -### Retro-Fitting Scala 2 Libraries - -To allow cross-building between Scala 2 and 3, super traits can also be -introduced by adding the `@superTrait` annotation, which is defined in package `scala.annotation`. Example: -```scala -import scala.annotation.superTrait - -@superTrait trait StrictOptimizedSeqOps[+A, +CC[_], +C] ... -``` -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. +declared a mixin trait. ### Rules for Inference @@ -75,12 +64,5 @@ The precise rules are as follows: the resulting type is still a subtype of the bound `B`. - However, do not perform this widening if all types `Ti` can get replaced in that way. -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. - -### Syntax +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. -Only the production `TmplDef` for class and trait definitions has to be changed. -The new version is: -``` -TmplDef ::= ([‘case’] ‘class’ | [‘super’] ‘trait’) ClassDef -``` diff --git a/docs/sidebar.yml b/docs/sidebar.yml index b8f627760c8c..93683709a745 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -87,8 +87,8 @@ sidebar: subsection: - title: Trait Parameters url: docs/reference/other-new-features/trait-parameters.html - - title: Super Traits - url: docs/reference/other-new-features/super-traits.html + - title: Mixin Traits + url: docs/reference/other-new-features/mixin-traits.html - title: Creator Applications url: docs/reference/other-new-features/creator-applications.html - title: Export Clauses diff --git a/library/src/scala/annotation/mixin.scala b/library/src/scala/annotation/mixin.scala new file mode 100644 index 000000000000..e28f270a349e --- /dev/null +++ b/library/src/scala/annotation/mixin.scala @@ -0,0 +1,7 @@ +package scala.annotation + +/** An annotation that marks a trait as a mixin trait. Mixin traits + * are not inferred when combined with other types in an intersection. + * See reference/other-new-features/mixin-traits.html for details. + */ +final class mixin extends StaticAnnotation diff --git a/library/src/scala/annotation/superTrait.scala b/library/src/scala/annotation/superTrait.scala deleted file mode 100644 index d9dc7e27a4d5..000000000000 --- a/library/src/scala/annotation/superTrait.scala +++ /dev/null @@ -1,8 +0,0 @@ -package scala.annotation - -/** Equivalent to declaring a super trait in Scala 3. This annotation - * should be used only for files that need to cross-compile between - * Scala 2 and 3. - */ -final class superTrait extends StaticAnnotation - diff --git a/library/src/scala/reflect/Enum.scala b/library/src/scala/reflect/Enum.scala index 7296ca8becd2..39de5b4b3eb4 100644 --- a/library/src/scala/reflect/Enum.scala +++ b/library/src/scala/reflect/Enum.scala @@ -1,7 +1,8 @@ package scala.reflect +import annotation.mixin /** A base trait of all Scala enum definitions */ -super trait Enum extends Any, Product, Serializable: +@mixin trait Enum extends Any, Product, Serializable: /** A number uniquely identifying a case of an enum */ def ordinal: Int diff --git a/library/src/scala/runtime/EnumValue.scala b/library/src/scala/runtime/EnumValue.scala index 55eaf7d48d1a..abe899ebe323 100644 --- a/library/src/scala/runtime/EnumValue.scala +++ b/library/src/scala/runtime/EnumValue.scala @@ -1,6 +1,7 @@ package scala.runtime +import annotation.mixin -super trait EnumValue extends Product, Serializable: +@mixin trait EnumValue extends Product, Serializable: override def canEqual(that: Any) = this eq that.asInstanceOf[AnyRef] override def productArity: Int = 0 override def productElement(n: Int): Any = diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index a857d21ca101..6b84cddf31e9 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -188,7 +188,6 @@ Standard-Section: "ASTs" TopLevelStat* STATIC -- Mapped to static Java member OBJECT -- An object or its class TRAIT -- A trait - SUPERTRAIT -- A super trait ENUM -- A enum class or enum case LOCAL -- private[this] or protected[this], used in conjunction with PRIVATE or PROTECTED SYNTHETIC -- Generated by Scala compiler @@ -359,7 +358,7 @@ object TastyFormat { final val OPEN = 40 final val PARAMEND = 41 final val PARAMalias = 42 - final val SUPERTRAIT = 43 + final val SUPERTRAIT = 43 // TODO: remove // Cat. 2: tag Nat diff --git a/tests/neg-custom-args/fatal-warnings/supertraits.scala b/tests/neg-custom-args/fatal-warnings/supertraits.scala index abadeb07d4f9..7680da8bc254 100644 --- a/tests/neg-custom-args/fatal-warnings/supertraits.scala +++ b/tests/neg-custom-args/fatal-warnings/supertraits.scala @@ -1,5 +1,6 @@ -sealed super trait TA -sealed super trait TB +import annotation.mixin +@mixin sealed trait TA +@mixin sealed trait TB trait S case object a extends S, TA, TB case object b extends S, TA, TB diff --git a/tests/neg/supertraits.scala b/tests/neg/supertraits.scala index 61a837ff47d1..b6d5d809619a 100644 --- a/tests/neg/supertraits.scala +++ b/tests/neg/supertraits.scala @@ -1,4 +1,5 @@ -super trait S +import annotation.mixin +@mixin trait S trait A class B extends A, S class C extends A, S From 5245ff27f469618feb813486fce5827eddb3324d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 9 Nov 2020 18:06:41 +0100 Subject: [PATCH 2/2] Rename superTrait -> mixin in stdlib213 --- community-build/community-projects/stdLib213 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/community-build/community-projects/stdLib213 b/community-build/community-projects/stdLib213 index 47aa43534da7..d0dabde46af9 160000 --- a/community-build/community-projects/stdLib213 +++ b/community-build/community-projects/stdLib213 @@ -1 +1 @@ -Subproject commit 47aa43534da7a59127fb8a93f8e7364e3d0eed8a +Subproject commit d0dabde46af962d5d7c46aedd73064826920cf47