diff --git a/community-build/community-projects/stdLib213 b/community-build/community-projects/stdLib213 index d0dabde46af9..5b4406c7de9a 160000 --- a/community-build/community-projects/stdLib213 +++ b/community-build/community-projects/stdLib213 @@ -1 +1 @@ -Subproject commit d0dabde46af962d5d7c46aedd73064826920cf47 +Subproject commit 5b4406c7de9a7e671d8f533f7d4436a7a0586358 diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 9336bcc8e7bd..e13d5a4c3b2c 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -212,7 +212,9 @@ 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 Transparent()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Transparent) + + case class Infix()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Infix) } /** 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 65e4f01d44fe..51f1fe433e7a 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 mixin trait instances - * and others are not, replace as many mixin trait instances as possible with Any + /** If `tp` is an intersection such that some operands are transparent trait instances + * and others are not, replace as many transparent 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 mixin traits + * types (since in this case the type was not a true intersection of transparent traits * and other types to start with). */ - def dropMixinTraits(tp: Type, bound: Type)(using Context): Type = + def dropTransparentTraits(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 dropOneMixinTrait(tp: Type): Type = + def dropOneTransparentTrait(tp: Type): Type = val tpd = tp.dealias - if tpd.typeSymbol.isMixinTrait && !tpd.isLambdaSub && !kept.contains(tpd) then + if tpd.typeSymbol.isTransparentTrait && !tpd.isLambdaSub && !kept.contains(tpd) then dropped = tpd :: dropped defn.AnyType else tpd match case AndType(tp1, tp2) => - val tp1w = dropOneMixinTrait(tp1) + val tp1w = dropOneTransparentTrait(tp1) if tp1w ne tp1 then tp1w & tp2 else - val tp2w = dropOneMixinTrait(tp2) + val tp2w = dropOneTransparentTrait(tp2) if tp2w ne tp2 then tp1 & tp2w else tpd case _ => tp def recur(tp: Type): Type = - val tpw = dropOneMixinTrait(tp) + val tpw = dropOneTransparentTrait(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 dropMixinTraits + end dropTransparentTraits /** 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 mixin traits from intersections (see @dropMixinTraits) + * 3. drop transparent traits from intersections (see @dropTransparentTraits) * * 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 dropMixinTraits(widenOr(widenSingle(inst)), bound) + else dropTransparentTraits(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 5a7a27be15df..e18dd03908fb 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -912,7 +912,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 TransparentTraitAnnot: ClassSymbol = requiredClass("scala.annotation.transparentTrait") @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") @@ -940,7 +940,6 @@ class Definitions { @tu lazy val SetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.setter") @tu lazy val ShowAsInfixAnnot: ClassSymbol = requiredClass("scala.annotation.showAsInfix") @tu lazy val FunctionalInterfaceAnnot: ClassSymbol = requiredClass("java.lang.FunctionalInterface") - @tu lazy val InfixAnnot: ClassSymbol = requiredClass("scala.annotation.infix") @tu lazy val TargetNameAnnot: ClassSymbol = requiredClass("scala.annotation.targetName") @tu lazy val VarargsAnnot: ClassSymbol = requiredClass("scala.annotation.varargs") @@ -1507,8 +1506,8 @@ class Definitions { def isInfix(sym: Symbol)(using Context): Boolean = (sym eq Object_eq) || (sym eq Object_ne) - @tu lazy val assumedMixinTraits = - Set(ComparableClass, ProductClass, SerializableClass, + @tu lazy val assumedTransparentTraits = + Set[Symbol](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. requiredClass("scala.collection.SortedOps"), diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index b4f09856340d..e21a15a1b7b1 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -342,6 +342,9 @@ object Flags { /** Symbol is a Java default method */ val (_, DefaultMethod @ _, _) = newFlags(38, "") + /** Symbol is a transparent inline method or trait */ + val (Transparent @ _, _, _) = newFlags(39, "transparent") + /** Symbol is an enum class or enum case (if used with case) */ val (Enum @ _, EnumVal @ _, _) = newFlags(40, "enum") @@ -354,14 +357,16 @@ object Flags { /** An opaque type alias or a class containing one */ val (Opaque @ _, _, _) = newFlags(43, "opaque") + /** An infix method or type */ + val (Infix @ _, _, _) = newFlags(44, "infix") // ------------ Flags following this one are not pickled ---------------------------------- /** Symbol is not a member of its owner */ - val (NonMember @ _, _, _) = newFlags(45, "") + val (NonMember @ _, _, _) = newFlags(49, "") /** Denotation is in train of being loaded and completed, used to catch cyclic dependencies */ - val (Touched @ _, _, _) = newFlags(48, "") + val (Touched @ _, _, _) = newFlags(50, "") /** Class has been lifted out to package level, local value has been lifted out to class level */ val (Lifted @ _, _, _) = newFlags(51, "") @@ -419,7 +424,7 @@ object Flags { /** Flags representing source modifiers */ private val CommonSourceModifierFlags: FlagSet = - commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic) + commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent) val TypeSourceModifierFlags: FlagSet = CommonSourceModifierFlags.toTypeFlags | Abstract | Sealed | Opaque | Open @@ -449,7 +454,7 @@ object Flags { * is completed) */ val AfterLoadFlags: FlagSet = commonFlags( - FromStartFlags, AccessFlags, Final, AccessorOrSealed, LazyOrTrait, SelfName, JavaDefined) + FromStartFlags, AccessFlags, Final, AccessorOrSealed, LazyOrTrait, SelfName, JavaDefined, Transparent) /** A value that's unstable unless complemented with a Stable flag */ val UnstableValueFlags: FlagSet = Mutable | Method @@ -499,7 +504,7 @@ object Flags { /** Flags that can apply to a module val */ val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags | Override | Final | Method | Implicit | Given | Lazy | - Accessor | AbsOverride | StableRealizable | Captured | Synchronized | Erased + Accessor | AbsOverride | StableRealizable | Captured | Synchronized | Erased | Transparent /** Flags that can apply to a module class */ val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | Enum @@ -576,4 +581,5 @@ object Flags { val SyntheticParam: FlagSet = Synthetic | Param val SyntheticTermParam: FlagSet = Synthetic | TermParam val SyntheticTypeParam: FlagSet = Synthetic | TypeParam + val TransparentTrait: FlagSet = Trait | Transparent } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 48ff13852156..4fe98d77051f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1109,9 +1109,10 @@ object SymDenotations { final def isEffectivelySealed(using Context): Boolean = isOneOf(FinalOrSealed) || isClass && !isOneOf(EffectivelyOpenFlags) - final def isMixinTrait(using Context): Boolean = - isClass - && (hasAnnotation(defn.MixinAnnot) || defn.assumedMixinTraits.contains(symbol.asClass)) + final def isTransparentTrait(using Context): Boolean = + isAllOf(TransparentTrait) + || defn.assumedTransparentTraits.contains(symbol) + || isClass && hasAnnotation(defn.TransparentTraitAnnot) /** 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 1a95397f0b79..93d715ca38ed 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2674,8 +2674,8 @@ object TypeComparer { def widenInferred(inst: Type, bound: Type)(using Context): Type = comparing(_.widenInferred(inst, bound)) - def dropMixinTraits(tp: Type, bound: Type)(using Context): Type = - comparing(_.dropMixinTraits(tp, bound)) + def dropTransparentTraits(tp: Type, bound: Type)(using Context): Type = + comparing(_.dropTransparentTraits(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 1dbb3068720e..7187aff51340 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -712,6 +712,8 @@ class TreePickler(pickler: TastyPickler) { if (flags.is(Local)) writeModTag(LOCAL) if (flags.is(Synthetic)) writeModTag(SYNTHETIC) if (flags.is(Artifact)) writeModTag(ARTIFACT) + if flags.is(Transparent) then writeModTag(TRANSPARENT) + if flags.is(Infix) then writeModTag(INFIX) if (isTerm) { if (flags.is(Implicit)) writeModTag(IMPLICIT) if (flags.is(Given)) writeModTag(GIVEN) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a8b33bb1df1c..d9dac9222052 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -667,15 +667,14 @@ class TreeUnpickler(reader: TastyReader, case PARAMalias => addFlag(SuperParamAlias) case EXPORTED => addFlag(Exported) case OPEN => addFlag(Open) + case TRANSPARENT => addFlag(Transparent) + case INFIX => addFlag(Infix) case PRIVATEqualified => readByte() privateWithin = readWithin 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 34ac589c5971..eb9d0b2d0c37 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2732,6 +2732,7 @@ object Parsers { case nme.opaque => Mod.Opaque() case nme.open => Mod.Open() case nme.transparent => Mod.Transparent() + case nme.infix => Mod.Infix() } } @@ -2807,11 +2808,7 @@ object Parsers { } else mods - val result = normalize(loop(start)) - for case mod @ Mod.Transparent() <- result.mods do - if !result.is(Inline) then - syntaxError(em"`transparent` can only be used in conjunction with `inline`", mod.span) - result + normalize(loop(start)) } val funTypeArgMods: BitSet = BitSet(ERASED) diff --git a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala index 3bd14654260e..2e9a03ad771f 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Tokens.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Tokens.scala @@ -288,5 +288,5 @@ object Tokens extends TokensCommon { final val endMarkerTokens = identifierTokens | BitSet(IF, WHILE, FOR, MATCH, TRY, NEW, GIVEN, VAL, THIS) - final val softModifierNames = Set(nme.inline, nme.opaque, nme.open, nme.transparent) + final val softModifierNames = Set(nme.inline, nme.opaque, nme.open, nme.transparent, nme.infix) } diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index bcc40c5a57c0..9ec00ba3b642 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -897,8 +897,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (rawFlags.is(Param)) flagMask = flagMask &~ Given val flags = rawFlags & flagMask var flagsText = toTextFlags(sym, flags) - if mods.hasMod(classOf[untpd.Mod.Transparent]) then - flagsText = "transparent " ~ flagsText val annotations = if (sym.exists) sym.annotations.filterNot(ann => dropAnnotForModText(ann.symbol)).map(_.tree) else mods.annotations.filterNot(tree => dropAnnotForModText(tree.symbol)) diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 97c379384d37..5645e612e05b 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -241,7 +241,7 @@ object SymUtils: /** Is symbol assumed or declared as an infix symbol? */ def isDeclaredInfix(using Context): Boolean = - self.hasAnnotation(defn.InfixAnnot) + self.is(Infix) || defn.isInfix(self) || self.name.isUnapplyName && self.owner.is(Module) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 3960ac1a37bb..cf004a9134f8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1135,7 +1135,7 @@ trait Applications extends Compatibility { && tree.tpe.classSymbol.isEnumCase && tree.tpe.widen.isValueType then - val widened = TypeComparer.dropMixinTraits( + val widened = TypeComparer.dropTransparentTraits( tree.tpe.parents.reduceLeft(TypeComparer.andType(_, _)), pt) if widened <:< pt then Typed(tree, TypeTree(widened)) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 64b7b9af3a46..083f472d19b1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -449,6 +449,11 @@ object Checking { if (sym.isType) fail(TypesAndTraitsCantBeImplicit()) } + if sym.is(Transparent) then + if sym.isType then + if !sym.is(Trait) then fail(em"`transparent` can only be used for traits") + else + if !sym.isInlineMethod then fail(em"`transparent` can only be used for inline methods") if (!sym.isClass && sym.is(Abstract)) fail(OnlyClassesCanBeAbstract(sym)) // 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 { } /** Check that `tree` is a valid infix operation. That is, if the - * operator is alphanumeric, it must be declared `@infix`. + * operator is alphanumeric, it must be declared `infix`. */ def checkValidInfix(tree: untpd.InfixOp, meth: Symbol)(using Context): Unit = { tree.op match { @@ -802,7 +807,7 @@ trait Checking { else ("method", (n: Name) => s"method syntax .$n(...)") report.deprecationWarning( - i"""Alphanumeric $kind $name is not declared @infix; it should not be used as infix operator. + i"""Alphanumeric $kind $name is not declared `infix`; it should not be used as infix operator. |The operation can be rewritten automatically to `$name` under -deprecation -rewrite. |Or rewrite to ${alternative(name)} manually.""", tree.op.srcPos) diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index b09669b0625b..62a0e9ec793b 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -206,8 +206,7 @@ object PrepareInlineable { /** The type ascription `rhs: tpt`, unless `original` is `transparent`. */ def wrapRHS(original: untpd.DefDef, tpt: Tree, rhs: Tree)(using Context): Tree = - if original.mods.hasMod(classOf[untpd.Mod.Transparent]) then rhs - else Typed(rhs, tpt) + if original.mods.is(Transparent) then rhs else Typed(rhs, tpt) /** Return result of evaluating `op`, but drop `Inline` flag and `Body` annotation * of `sym` in case that leads to errors. diff --git a/docs/docs/reference/other-new-features/mixin-traits.md b/docs/docs/reference/other-new-features/transparent-traits.md similarity index 50% rename from docs/docs/reference/other-new-features/mixin-traits.md rename to docs/docs/reference/other-new-features/transparent-traits.md index f2a4f977ccad..787a29e2ffa9 100644 --- a/docs/docs/reference/other-new-features/mixin-traits.md +++ b/docs/docs/reference/other-new-features/transparent-traits.md @@ -1,6 +1,6 @@ --- layout: doc-page -title: Mixin Traits +title: Transparent Traits --- Traits are used in two roles: @@ -8,8 +8,7 @@ Traits are used in two roles: 1. As mixins for other classes and traits 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 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: +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 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 @@ -23,36 +22,36 @@ Here, the inferred type of `x` is `Set[Kind & Product & Serializable]` whereas o 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 `@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 3 allows one to mark a mixin trait as `transparent`, 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 transparent trait `S` instead of `Product`: ```scala -@mixin trait S +transparent 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 mixin trait `S` does not +Now `x` has inferred type `Set[Kind]`. The common transparent trait `S` does not appear in the inferred type. -### Mixin Traits +### Transparent Traits The traits `scala.Product`, `java.lang.Serializable` and `java.lang.Comparable` -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. +are treated automatically as transparent. Other traits are turned into transparent traits using the modifier `transparent`. Scala 2 traits can also be made transparent +by adding a `@transparentTrait` annotation. This annotation is defined in `scala.annotation`. It will be deprecated and phased out once Scala 2/3 interopability is no longer needed. -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: +Typically, transparent 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` - `StrictOptimizedSeqOps`, which optimises some of these implementations for sequences with efficient indexing. Generally, any trait that is extended recursively is a good candidate to be -declared a mixin trait. +declared transparent. ### Rules for Inference -Super traits can be given as explicit types as usual. But they are often elided when types are inferred. Roughly, the rules for type inference say that super traits are dropped from intersections where possible. +Transparent traits can be given as explicit types as usual. But they are often elided when types are inferred. Roughly, the rules for type inference say that transparent traits are dropped from intersections where possible. The precise rules are as follows: @@ -60,9 +59,9 @@ The precise rules are as follows: - where that type is not higher-kinded, - and where `B` is its known upper bound or `Any` if none exists: - If the type inferred so far is of the form `T1 & ... & Tn` where - `n >= 1`, replace the maximal number of `Ti`s by `Any`, while ensuring that + `n >= 1`, replace the maximal number of transparent `Ti`s by `Any`, while ensuring that 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. + - However, do not perform this widening if all transparent traits `Ti` can get replaced in that way. -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. +The last clause ensures that a single transparent trait instance such as `Product` is not widened to `Any`. Transparent trait instances are only dropped when they appear in conjunction with some other type. diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 91f53a23e3db..764a5d4266cb 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -89,8 +89,8 @@ sidebar: subsection: - title: Trait Parameters url: docs/reference/other-new-features/trait-parameters.html - - title: Mixin Traits - url: docs/reference/other-new-features/mixin-traits.html + - title: Transparent Traits + url: docs/reference/other-new-features/transparent-traits.html - title: Creator Applications url: docs/reference/other-new-features/creator-applications.html - title: Export Clauses diff --git a/library/src/scala/annotation/infix.scala b/library/src/scala/annotation/infix.scala deleted file mode 100644 index 3936af243d56..000000000000 --- a/library/src/scala/annotation/infix.scala +++ /dev/null @@ -1,7 +0,0 @@ -package scala.annotation - -/** A method annotation that suggests that the annotated method should - * be used as an infix operator. Infix operations with alphanumeric - * operator names require the operator to be annotated with `@infix`. - */ -final class infix extends StaticAnnotation \ No newline at end of file diff --git a/library/src/scala/annotation/mixin.scala b/library/src/scala/annotation/mixin.scala deleted file mode 100644 index e28f270a349e..000000000000 --- a/library/src/scala/annotation/mixin.scala +++ /dev/null @@ -1,7 +0,0 @@ -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/transparentTrait.scala b/library/src/scala/annotation/transparentTrait.scala new file mode 100644 index 000000000000..2583db74473c --- /dev/null +++ b/library/src/scala/annotation/transparentTrait.scala @@ -0,0 +1,8 @@ +package scala.annotation + +/** An annotation that can be used from Scala 2 to mark a trait as transparent. + * Scala 3 code would use the modifier `transparent` instead. Transparent traits + * are not inferred when combined with other types in an intersection. + * See reference/other-new-features/transparent-traits.html for details. + */ +final class transparentTrait extends StaticAnnotation diff --git a/library/src/scala/compiletime/ops/package.scala b/library/src/scala/compiletime/ops/package.scala index e272f6cb04e9..13a0123d5292 100644 --- a/library/src/scala/compiletime/ops/package.scala +++ b/library/src/scala/compiletime/ops/package.scala @@ -1,7 +1,5 @@ package scala.compiletime -import scala.annotation.infix - package object ops { object any { /** Equality comparison of two singleton types. @@ -11,7 +9,7 @@ package object ops { * val eq3: "1" == "1" = true * ``` */ - @infix type ==[X, Y] <: Boolean + type ==[X, Y] <: Boolean /** Inequality comparison of two singleton types. * ```scala @@ -20,7 +18,7 @@ package object ops { * val eq3: "1" != "1" = false * ``` */ - @infix type !=[X, Y] <: Boolean + type !=[X, Y] <: Boolean } object string { @@ -29,7 +27,7 @@ package object ops { * val hello: "hello " + "world" = "hello world" * ``` */ - @infix type +[X <: String, Y <: String] <: String + type +[X <: String, Y <: String] <: String } object int { @@ -38,63 +36,63 @@ package object ops { * val sum: 2 + 2 = 4 * ``` */ - @infix type +[X <: Int, Y <: Int] <: Int + type +[X <: Int, Y <: Int] <: Int /** Subtraction of two `Int` singleton types. * ```scala * val sub: 4 - 2 = 2 * ``` */ - @infix type -[X <: Int, Y <: Int] <: Int + type -[X <: Int, Y <: Int] <: Int /** Multiplication of two `Int` singleton types. * ```scala * val mul: 4 * 2 = 8 * ``` */ - @infix type *[X <: Int, Y <: Int] <: Int + type *[X <: Int, Y <: Int] <: Int /** Integer division of two `Int` singleton types. * ```scala * val div: 5 / 2 = 2 * ``` */ - @infix type /[X <: Int, Y <: Int] <: Int + type /[X <: Int, Y <: Int] <: Int /** Remainder of the division of `X` by `Y`. * ```scala * val mod: 5 % 2 = 1 * ``` */ - @infix type %[X <: Int, Y <: Int] <: Int + type %[X <: Int, Y <: Int] <: Int /** Binary left shift of `X` by `Y`. * ```scala * val lshift: 1 << 2 = 4 * ``` */ - @infix type <<[X <: Int, Y <: Int] <: Int + type <<[X <: Int, Y <: Int] <: Int /** Binary right shift of `X` by `Y`. * ```scala * val rshift: 10 >> 1 = 5 * ``` */ - @infix type >>[X <: Int, Y <: Int] <: Int + type >>[X <: Int, Y <: Int] <: Int /** Binary right shift of `X` by `Y`, filling the left with zeros. * ```scala * val rshiftzero: 10 >>> 1 = 5 * ``` */ - @infix type >>>[X <: Int, Y <: Int] <: Int + type >>>[X <: Int, Y <: Int] <: Int /** Bitwise xor of `X` and `Y`. * ```scala * val xor: 10 ^ 30 = 20 * ``` */ - @infix type ^[X <: Int, Y <: Int] <: Int + type ^[X <: Int, Y <: Int] <: Int /** Less-than comparison of two `Int` singleton types. * ```scala @@ -102,7 +100,7 @@ package object ops { * val lt2: 2 < 4 = true * ``` */ - @infix type <[X <: Int, Y <: Int] <: Boolean + type <[X <: Int, Y <: Int] <: Boolean /** Greater-than comparison of two `Int` singleton types. * ```scala @@ -110,7 +108,7 @@ package object ops { * val gt2: 2 > 2 = false * ``` */ - @infix type >[X <: Int, Y <: Int] <: Boolean + type >[X <: Int, Y <: Int] <: Boolean /** Greater-or-equal comparison of two `Int` singleton types. * ```scala @@ -118,7 +116,7 @@ package object ops { * val ge2: 2 >= 3 = false * ``` */ - @infix type >=[X <: Int, Y <: Int] <: Boolean + type >=[X <: Int, Y <: Int] <: Boolean /** Less-or-equal comparison of two `Int` singleton types. * ```scala @@ -126,7 +124,7 @@ package object ops { * val lt2: 2 <= 2 = true * ``` */ - @infix type <=[X <: Int, Y <: Int] <: Boolean + type <=[X <: Int, Y <: Int] <: Boolean /** Bitwise and of `X` and `Y`. * ```scala @@ -196,7 +194,7 @@ package object ops { * val b: false ^ true = true * ``` */ - @infix type ^[X <: Boolean, Y <: Boolean] <: Boolean + type ^[X <: Boolean, Y <: Boolean] <: Boolean /** Conjunction of two `Boolean` singleton types. * ```scala @@ -204,7 +202,7 @@ package object ops { * val b: false && true = false * ``` */ - @infix type &&[X <: Boolean, Y <: Boolean] <: Boolean + type &&[X <: Boolean, Y <: Boolean] <: Boolean /** Disjunction of two `Boolean` singleton types. * ```scala @@ -212,6 +210,6 @@ package object ops { * val b: false || false = false * ``` */ - @infix type ||[X <: Boolean, Y <: Boolean] <: Boolean + type ||[X <: Boolean, Y <: Boolean] <: Boolean } } diff --git a/library/src/scala/reflect/Enum.scala b/library/src/scala/reflect/Enum.scala index 39de5b4b3eb4..92efa34cf430 100644 --- a/library/src/scala/reflect/Enum.scala +++ b/library/src/scala/reflect/Enum.scala @@ -1,8 +1,7 @@ package scala.reflect -import annotation.mixin /** A base trait of all Scala enum definitions */ -@mixin trait Enum extends Any, Product, Serializable: +@annotation.transparentTrait 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 abe899ebe323..5eb078a8c34b 100644 --- a/library/src/scala/runtime/EnumValue.scala +++ b/library/src/scala/runtime/EnumValue.scala @@ -1,7 +1,6 @@ package scala.runtime -import annotation.mixin -@mixin trait EnumValue extends Product, Serializable: +@annotation.transparentTrait 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/scala3doc-testcases/src/tests/typesSignatures.scala b/scala3doc-testcases/src/tests/typesSignatures.scala index b62d9ee01f72..92c6f35394f6 100644 --- a/scala3doc-testcases/src/tests/typesSignatures.scala +++ b/scala3doc-testcases/src/tests/typesSignatures.scala @@ -43,7 +43,7 @@ class Operators // Infix annotation is not well supported in Dotty // import scala.annotation.infix - // @infix type op[A, B] = Int + // infix type op[A, B] = Int // type Binary2 = String op Int import scala.compiletime.ops.boolean._ diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 02ec1a207097..b99327393aa7 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -255,7 +255,7 @@ object TastyFormat { final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F) val MajorVersion: Int = 25 - val MinorVersion: Int = 0 + val MinorVersion: Int = 1 final val ASTsSection = "ASTs" final val PositionsSection = "Positions" @@ -370,7 +370,8 @@ object TastyFormat { final val OPEN = 40 final val PARAMEND = 41 final val PARAMalias = 42 - final val SUPERTRAIT = 43 // TODO: remove + final val TRANSPARENT = 43 + final val INFIX = 44 // Cat. 2: tag Nat @@ -485,7 +486,7 @@ object TastyFormat { /** Useful for debugging */ def isLegalTag(tag: Int): Boolean = - firstSimpleTreeTag <= tag && tag <= SUPERTRAIT || + firstSimpleTreeTag <= tag && tag <= INFIX || firstNatTreeTag <= tag && tag <= RENAMED || firstASTTreeTag <= tag && tag <= BOUNDED || firstNatASTTreeTag <= tag && tag <= NAMEDARG || @@ -514,7 +515,8 @@ object TastyFormat { | STATIC | OBJECT | TRAIT - | SUPERTRAIT + | TRANSPARENT + | INFIX | ENUM | LOCAL | SYNTHETIC @@ -575,7 +577,8 @@ object TastyFormat { case STATIC => "STATIC" case OBJECT => "OBJECT" case TRAIT => "TRAIT" - case SUPERTRAIT => "SUPERTRAIT" + case TRANSPARENT => "TRANSPARENT" + case INFIX => "INFIX" case ENUM => "ENUM" case LOCAL => "LOCAL" case SYNTHETIC => "SYNTHETIC" diff --git a/tests/neg-custom-args/fatal-warnings/supertraits.scala b/tests/neg-custom-args/fatal-warnings/supertraits.scala index 7680da8bc254..9337e2f925a3 100644 --- a/tests/neg-custom-args/fatal-warnings/supertraits.scala +++ b/tests/neg-custom-args/fatal-warnings/supertraits.scala @@ -1,6 +1,5 @@ -import annotation.mixin -@mixin sealed trait TA -@mixin sealed trait TB +transparent sealed trait TA +transparent sealed trait TB trait S case object a extends S, TA, TB case object b extends S, TA, TB diff --git a/tests/neg-custom-args/infix.scala b/tests/neg-custom-args/infix.scala index 48827fb89558..02c3be4e30ef 100644 --- a/tests/neg-custom-args/infix.scala +++ b/tests/neg-custom-args/infix.scala @@ -1,7 +1,6 @@ // Compile with -strict -Xfatal-warnings -deprecation -import scala.annotation.infix class C: - @infix def op(x: Int): Int = ??? + infix def op(x: Int): Int = ??? def meth(x: Int): Int = ??? def matching(x: Int => Int) = ??? def +(x: Int): Int = ??? @@ -9,7 +8,7 @@ class C: object C: given AnyRef: extension (x: C) - @infix def iop (y: Int) = ??? + infix def iop (y: Int) = ??? def mop (y: Int) = ??? def ++ (y: Int) = ??? @@ -34,25 +33,25 @@ def test() = { case x => x } - @infix class Or[X, Y] + infix class Or[X, Y] class AndC[X, Y] - @infix type And[X, Y] = AndC[X, Y] - @infix type &&[X, Y] = AndC[X, Y] + infix type And[X, Y] = AndC[X, Y] + infix type &&[X, Y] = AndC[X, Y] class Map[X, Y] val x1: Int Map String = ??? // error - val x2: Int Or String = ??? // OK since Or is declared `@infix` + val x2: Int Or String = ??? // OK since Or is declared `infix` val x3: Int AndC String = ??? // error val x4: Int `AndC` String = ??? // OK val x5: Int And String = ??? // OK val x6: Int && String = ??? case class Pair[T](x: T, y: T) - @infix case class Q[T](x: T, y: T) + infix case class Q[T](x: T, y: T) object PP { - @infix def unapply[T](x: Pair[T]): Option[(T, T)] = Some((x.x, x.y)) + infix def unapply[T](x: Pair[T]): Option[(T, T)] = Some((x.x, x.y)) } val p = Pair(1, 2) diff --git a/tests/neg/supertraits.scala b/tests/neg/supertraits.scala index b6d5d809619a..2fc79ca30f1d 100644 --- a/tests/neg/supertraits.scala +++ b/tests/neg/supertraits.scala @@ -1,5 +1,4 @@ -import annotation.mixin -@mixin trait S +transparent trait S trait A class B extends A, S class C extends A, S diff --git a/tests/neg/transparent.scala b/tests/neg/transparent.scala new file mode 100644 index 000000000000..fcd167799ba2 --- /dev/null +++ b/tests/neg/transparent.scala @@ -0,0 +1,9 @@ +transparent def foo = 1 // error +transparent inline def bar = 2 // ok +transparent inline val x = 2 // error +transparent class c // error +transparent object y // error +transparent trait t // ok +transparent type T = c // error +transparent given c // error + diff --git a/tests/pos/i8256.scala b/tests/pos/i8256.scala index ecccc21c639b..f2fc4c2c867e 100644 --- a/tests/pos/i8256.scala +++ b/tests/pos/i8256.scala @@ -7,4 +7,4 @@ val a = 1 val fetch = implicitly[Test[1]] -@main def main() : Unit = {} \ No newline at end of file +@main def tester() : Unit = {} \ No newline at end of file diff --git a/tests/pos/reference/extension-methods.scala b/tests/pos/reference/extension-methods.scala index 2f4f6d6ee195..5d063997f210 100644 --- a/tests/pos/reference/extension-methods.scala +++ b/tests/pos/reference/extension-methods.scala @@ -1,5 +1,3 @@ -import annotation.infix - object ExtMethods: case class Circle(x: Double, y: Double, radius: Double) @@ -13,7 +11,7 @@ object ExtMethods: extension (x: String) def < (y: String) = x.compareTo(y) < 0 extension [Elem](x: Elem) def #: (xs: Seq[Elem]) = x +: xs - extension (x: Number) @infix def min (y: Number) = x + extension (x: Number) infix def min (y: Number) = x assert("a" < "bb") val xs = 1 #: Vector(2, 3) diff --git a/tests/pos/singleton-ops-dispatch.scala b/tests/pos/singleton-ops-dispatch.scala index 724d00126ddd..71278a375cc6 100644 --- a/tests/pos/singleton-ops-dispatch.scala +++ b/tests/pos/singleton-ops-dispatch.scala @@ -1,8 +1,7 @@ import scala.compiletime.ops._ -import scala.annotation.infix object Test { - @infix type +[X <: Int | String, Y <: Int | String] = (X, Y) match { + infix type +[X <: Int | String, Y <: Int | String] = (X, Y) match { case (Int, Int) => int.+[X, Y] case (String, String) => string.+[X, Y] case (String, Int) => string.+[X, int.ToString[Y]] diff --git a/tests/pos/singleton-ops-test-issue-8287.scala b/tests/pos/singleton-ops-test-issue-8287.scala index ab92d43ec292..bc4595bf79a1 100644 --- a/tests/pos/singleton-ops-test-issue-8287.scala +++ b/tests/pos/singleton-ops-test-issue-8287.scala @@ -1,9 +1,8 @@ import scala.compiletime.ops.int._ -import scala.annotation.infix object Test { class Vec[S <: Int] { - @infix def concat [RS <: Int](that : Vec[RS]) : Vec[S + RS] = new Vec[S + RS] + infix def concat [RS <: Int](that : Vec[RS]) : Vec[S + RS] = new Vec[S + RS] } val v1 = new Vec[1] diff --git a/tests/run/infix.scala b/tests/run/infix.scala index 68dd960b337a..17bfc27a5490 100644 --- a/tests/run/infix.scala +++ b/tests/run/infix.scala @@ -1,10 +1,10 @@ -import annotation.{infix, targetName} +import annotation.targetName object Test extends App { case class Rational(n: Int, d: Int) { - @infix def + (that: Rational) = + infix def + (that: Rational) = Rational(this.n * that.d + that.n * this.d, this.d * that.d) - @infix @targetName("multiply") def * (that: Rational) = + @targetName("multiply") infix def * (that: Rational) = Rational(this.n * that.n, this.d * that.d) }