diff --git a/community-build/community-projects/Lucre b/community-build/community-projects/Lucre index 21a27a294ac7..5f2ca01f44ce 160000 --- a/community-build/community-projects/Lucre +++ b/community-build/community-projects/Lucre @@ -1 +1 @@ -Subproject commit 21a27a294ac7c413f80839d96a02942b2c6d021c +Subproject commit 5f2ca01f44ce0784ebce0d5455d996fb05a81fdb diff --git a/community-build/community-projects/scala-parallel-collections b/community-build/community-projects/scala-parallel-collections index 7d0e41ae4d09..3b978f915181 160000 --- a/community-build/community-projects/scala-parallel-collections +++ b/community-build/community-projects/scala-parallel-collections @@ -1 +1 @@ -Subproject commit 7d0e41ae4d09e1ddf063651e377921ec493fc5bf +Subproject commit 3b978f9151817716ccced61edb1640ae750718ba diff --git a/community-build/community-projects/specs2 b/community-build/community-projects/specs2 index 06c992d17048..b0652c36f995 160000 --- a/community-build/community-projects/specs2 +++ b/community-build/community-projects/specs2 @@ -1 +1 @@ -Subproject commit 06c992d1704846840a0ea3cab4780ea7305e2980 +Subproject commit b0652c36f99570f31673beb8fb3d480e8e7f6102 diff --git a/community-build/community-projects/zio b/community-build/community-projects/zio index a7f6e1a3b2e6..fee051a48f82 160000 --- a/community-build/community-projects/zio +++ b/community-build/community-projects/zio @@ -1 +1 @@ -Subproject commit a7f6e1a3b2e6bc35bed188739120da6cff105dbb +Subproject commit fee051a48f82802c397df6b181a602d5929012ce diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index a81f4be9068a..5d94c019eba5 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -460,7 +460,7 @@ class Definitions { @tu lazy val CBCompanion: TypeSymbol = // type ``[-Refs] enterPermanentSymbol(tpnme.CBCompanion, TypeBounds(NothingType, - HKTypeLambda(tpnme.syntheticTypeParamName(0) :: Nil, Contravariant :: Nil)( + HKTypeLambda(tpnme.syntheticTypeParamName(0) :: Nil)( tl => TypeBounds.empty :: Nil, tl => AnyType))).asType diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index b44942d4e7ff..53e2112ead95 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -307,7 +307,7 @@ object NamerOps: * The context-bound companion has as name the name of `tsym` translated to * a term name. We create a synthetic val of the form * - * val A: ``[witnessRef1 | ... | witnessRefN] + * val A: ``[witnessRef1] & ... & ``[witnessRefN] * * where * @@ -325,8 +325,7 @@ object NamerOps: prefix.select(params.find(_.name == witnessName).get) else witnessNames.map(TermRef(prefix, _)) - val cbtype = defn.CBCompanion.typeRef.appliedTo: - witnessRefs.reduce[Type](OrType(_, _, soft = false)) + val cbtype = witnessRefs.map(defn.CBCompanion.typeRef.appliedTo).reduce(AndType.apply) val cbc = newSymbol( ctx.owner, companionName, (tsym.flagsUNSAFE & (AccessFlags)).toTermFlags | Synthetic, diff --git a/compiler/src/dotty/tools/dotc/core/SymUtils.scala b/compiler/src/dotty/tools/dotc/core/SymUtils.scala index 34908a2df6d6..e9a73d25cc0b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/core/SymUtils.scala @@ -88,7 +88,7 @@ class SymUtils: } def isContextBoundCompanion(using Context): Boolean = - self.is(Synthetic) && self.infoOrCompleter.typeSymbol == defn.CBCompanion + self.is(Synthetic) && self.infoOrCompleter.isContextBoundCompanion def isDummyCaptureParam(using Context): Boolean = self.isAllOf(CaptureParam) && !(self.isClass || self.is(Method)) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 136384413810..30a9abaaefce 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -475,13 +475,19 @@ class TypeApplications(val self: Type) extends AnyVal { self.derivedExprType(tp.translateParameterized(from, to)) case _ => if (self.derivesFrom(from)) { + // NOTE: we assume the `To` class is covariant s.t. + // `To[T] X To[U] <:< To[T | U]` where X ::= `&` | `|` def elemType(tp: Type): Type = tp.widenDealias match case tp: OrType => if tp.tp1.isBottomType then elemType(tp.tp2) else if tp.tp2.isBottomType then elemType(tp.tp1) else tp.derivedOrType(elemType(tp.tp1), elemType(tp.tp2)) - case tp: AndType => tp.derivedAndType(elemType(tp.tp1), elemType(tp.tp2)) - case _ => tp.baseType(from).argInfos.headOption.getOrElse(defn.NothingType) + case AndType(tp1, tp2) => + // see #23435 for why this is not `tp.derivedAndType(elemType(tp1), ...)` + OrType(elemType(tp1), elemType(tp2), soft = false) + case _ => + tp.baseType(from).argInfos.headOption.getOrElse(defn.NothingType) + end elemType val arg = elemType(self) val arg1 = if (wildcardArg) TypeBounds.upper(arg) else arg to.typeRef.appliedTo(arg1) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index d675bda73eed..9c659194f26c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2458,26 +2458,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling isSubRef(tp1, tp2) && isSubRef(tp2, tp1) } - /** If the range `tp1..tp2` consist of a single type, that type, otherwise NoType`. - * This is the case if `tp1 =:= tp2`, but also if `tp1 <:< tp2`, `tp1` is a singleton type, - * and `tp2` derives from `scala.Singleton` (or vice-versa). Examples of the latter case: - * - * "name".type .. Singleton - * "name".type .. String & Singleton - * Singleton .. "name".type - * String & Singleton .. "name".type - * - * All consist of the single type `"name".type`. - */ - def singletonInterval(tp1: Type, tp2: Type): Type = { - def isSingletonBounds(lo: Type, hi: Type) = - lo.isSingleton && hi.derivesFrom(defn.SingletonClass) && isSubTypeWhenFrozen(lo, hi) - if (isSameTypeWhenFrozen(tp1, tp2)) tp1 - else if (isSingletonBounds(tp1, tp2)) tp1 - else if (isSingletonBounds(tp2, tp1)) tp2 - else NoType - } - /** The greatest lower bound of two types */ def glb(tp1: Type, tp2: Type): Type = // trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true): if tp1 eq tp2 then tp1 @@ -2583,7 +2563,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case tparam :: tparamsRest => val arg1 :: args1Rest = args1: @unchecked val arg2 :: args2Rest = args2: @unchecked - val common = singletonInterval(arg1, arg2) + val common = if isSameTypeWhenFrozen(arg1, arg2) then arg1 else NoType val v = tparam.paramVarianceSign val lubArg = if (common.exists) common @@ -2615,7 +2595,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case tparam :: tparamsRest => val arg1 :: args1Rest = args1: @unchecked val arg2 :: args2Rest = args2: @unchecked - val common = singletonInterval(arg1, arg2) + val common = if isSameTypeWhenFrozen(arg1, arg2) then arg1 else NoType val v = tparam.paramVarianceSign val glbArg = if (common.exists) common @@ -2768,19 +2748,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling } /** Try to distribute `&` inside type, detect and handle conflicts + * Note that an intersection cannot be pushed into an applied type, see tests/neg/i23435-min. * @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before */ private def distributeAnd(tp1: Type, tp2: Type): Type = tp1 match { - case tp1 @ AppliedType(tycon1, args1) => - tp2 match { - case AppliedType(tycon2, args2) - if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 => - val jointArgs = glbArgs(args1, args2, tycon1.typeParams) - if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs) - else NoType - case _ => - NoType - } case tp1: RefinedType => // opportunistically merge same-named refinements // this does not change anything semantically (i.e. merging or not merging @@ -2819,8 +2790,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling } /** Try to distribute `|` inside type, detect and handle conflicts - * Note that, unlike for `&`, a disjunction cannot be pushed into - * a refined or applied type. Example: + * Note that a disjunction cannot be pushed into a refined or applied type. Example: * * List[T] | List[U] is not the same as List[T | U]. * diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8cbf309206bb..cb43b4d36354 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -466,6 +466,14 @@ object Types extends TypeUtils { case AppliedType(tycon: TypeRef, arg :: Nil) => defn.isInto(tycon.symbol) case _ => false + /** Is this type of the form `[Ref1] & ... & [RefN]`? + * Where the intersection may be introduced by `NamerOps.addContextBoundCompanionFor` + * or by inheriting multiple context bound companions for the same name. + */ + def isContextBoundCompanion(using Context): Boolean = this.widen match + case AndType(tp1, tp2) => tp1.isContextBoundCompanion.ensuring(_ == tp2.isContextBoundCompanion) + case tp => tp.typeSymbol == defn.CBCompanion + /** Is this type a legal target type for an implicit conversion, so that * no `implicitConversions` language import is necessary? */ diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b0156883261a..9f0bc600974d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -928,7 +928,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // Otherwise, if the qualifier is a context bound companion, handle // by selecting a witness in typedCBSelect def tryCBCompanion() = - if qual.tpe.typeSymbol == defn.CBCompanion then + if qual.tpe.isContextBoundCompanion then typedCBSelect(tree0, pt, qual) else EmptyTree @@ -997,13 +997,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer * alternatives referred to by `witnesses`. * @param prevs a list of (ref tree, typer state, term ref) tripls that * represents previously identified alternatives - * @param witnesses a type of the form ref_1 | ... | ref_n containing references + * @param witnesses a type of the form `isContextBoundCompanion` containing references * still to be considered. */ - def tryAlts(prevs: Alts, witnesses: Type): Alts = witnesses match - case OrType(wit1, wit2) => + def tryAlts(prevs: Alts, witnesses: Type): Alts = witnesses.widen match + case AndType(wit1, wit2) => tryAlts(tryAlts(prevs, wit1), wit2) - case witness: TermRef => + case AppliedType(_, List(witness: TermRef)) => val altQual = tpd.ref(witness).withSpan(qual.span) val altCtx = ctx.fresh.setNewTyperState() val alt = typedSelectWithAdapt(tree, pt, altQual)(using altCtx) @@ -1015,19 +1015,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer if comparisons.exists(_ == 1) then prevs else current :: prevs.zip(comparisons).collect{ case (prev, cmp) if cmp != -1 => prev } - qual.tpe.widen match - case AppliedType(_, arg :: Nil) => - tryAlts(Nil, arg) match - case Nil => EmptyTree - case (best @ (bestTree, bestState, _)) :: Nil => - bestState.commit() - bestTree - case multiAlts => - report.error( - em"""Ambiguous witness reference. None of the following alternatives is more specific than the other: - |${multiAlts.map((alt, _, witness) => i"\n $witness.${tree.name}: ${alt.tpe.widen}")}""", - tree.srcPos) - EmptyTree + tryAlts(Nil, qual.tpe) match + case Nil => EmptyTree + case (best @ (bestTree, bestState, _)) :: Nil => + bestState.commit() + bestTree + case multiAlts => + report.error( + em"""Ambiguous witness reference. None of the following alternatives is more specific than the other: + |${multiAlts.map((alt, _, witness) => i"\n $witness.${tree.name}: ${alt.tpe.widen}")}""", + tree.srcPos) + EmptyTree end typedCBSelect def typedSelect(tree: untpd.Select, pt: Type)(using Context): Tree = { diff --git a/docs/_docs/reference/new-types/intersection-types-spec.md b/docs/_docs/reference/new-types/intersection-types-spec.md index 723720fdef89..f7d84e624cdc 100644 --- a/docs/_docs/reference/new-types/intersection-types-spec.md +++ b/docs/_docs/reference/new-types/intersection-types-spec.md @@ -46,11 +46,6 @@ A & B <: B A & B <: A In another word, `A & B` is the same type as `B & A`, in the sense that the two types have the same values and are subtypes of each other. -If `C` is a co- or contravariant type constructor, then `C[A] & C[B]` can be simplified using the following rules: - -- If `C` is covariant, `C[A] & C[B] ~> C[A & B]` -- If `C` is contravariant, `C[A] & C[B] ~> C[A | B]` - When `C` is covariant, `C[A & B] <: C[A] & C[B]` can be derived: ``` diff --git a/docs/_docs/reference/new-types/union-types-spec.md b/docs/_docs/reference/new-types/union-types-spec.md index 1093631e7c63..1bd27ebb674c 100644 --- a/docs/_docs/reference/new-types/union-types-spec.md +++ b/docs/_docs/reference/new-types/union-types-spec.md @@ -46,6 +46,30 @@ case _: (A | B) => ... A & (B | C) =:= A & B | A & C ``` +When `C` is covariant, `C[A] | C[B] <: C[A | B]` can be derived: + +``` + A <: A B <: B + ---------- --------- + A <: A | B B <: A | B +---------------- ---------------- +C[A] <: C[A | B] C[B] <: C[A | B] +----------------------------------------- + C[A] | C[B] <: C[A | B] +``` + +When `C` is contravariant, `C[A] | C[B] <: C[A & B]` can be derived: + +``` + A <: A B <: B + ---------- ---------- + A & B <: A A & B <: B +---------------- ---------------- +C[A] <: C[A & B] C[B] <: C[A & B] +----------------------------------------- + C[A] | C[B] <: C[A & B] +``` + From these rules it follows that the _least upper bound_ (LUB) of a set of types is the union of these types. This replaces the [definition of least upper bound in the Scala 2 specification](https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#least-upper-bounds-and-greatest-lower-bounds). diff --git a/scala2-library-cc/src/scala/collection/Iterable.scala b/scala2-library-cc/src/scala/collection/Iterable.scala index c5d10211e3ab..9cc97b416a1a 100644 --- a/scala2-library-cc/src/scala/collection/Iterable.scala +++ b/scala2-library-cc/src/scala/collection/Iterable.scala @@ -992,7 +992,7 @@ trait EvidenceIterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]], E trait SortedSetFactoryDefaults[+A, +CC[X] <: SortedSet[X] with SortedSetOps[X, CC, CC[X]], +WithFilterCC[x] <: IterableOps[x, WithFilterCC, WithFilterCC[x]] with Set[x]] extends SortedSetOps[A @uncheckedVariance, CC, CC[A @uncheckedVariance]] { - self: IterableOps[A, WithFilterCC, _] => + self: IterableOps[A, WithFilterCC, CC[A @uncheckedVariance]] => override protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]^): CC[A @uncheckedVariance] = sortedIterableFactory.from(coll)(using ordering) override protected def newSpecificBuilder: mutable.Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = sortedIterableFactory.newBuilder[A](using ordering) @@ -1047,7 +1047,7 @@ trait SortedMapFactoryDefaults[K, +V, +CC[x, y] <: Map[x, y] with SortedMapOps[x, y, CC, CC[x, y]] with UnsortedCC[x, y], +WithFilterCC[x] <: IterableOps[x, WithFilterCC, WithFilterCC[x]] with Iterable[x], +UnsortedCC[x, y] <: Map[x, y]] extends SortedMapOps[K, V, CC, CC[K, V @uncheckedVariance]] with MapOps[K, V, UnsortedCC, CC[K, V @uncheckedVariance]] { - self: IterableOps[(K, V), WithFilterCC, _] => + self: IterableOps[(K, V), WithFilterCC, CC[K, V @uncheckedVariance]] => override def empty: CC[K, V @uncheckedVariance] = sortedMapFactory.empty(using ordering) override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]^): CC[K, V @uncheckedVariance] = sortedMapFactory.from(coll)(using ordering) diff --git a/tests/neg-deep-subtype/i11064.scala b/tests/neg-deep-subtype/i11064.scala deleted file mode 100644 index 7cfab64d0e04..000000000000 --- a/tests/neg-deep-subtype/i11064.scala +++ /dev/null @@ -1,9 +0,0 @@ -trait TypedArray[T, Repr] - -trait Ops[T <: TypedArray[_, T]] { - def typedArray(): T -} - -object Test { - def test(ops: Ops[_ <: TypedArray[_ <: AnyRef, _]]) = ops.typedArray() // error: Recursion limit exceeded. -} \ No newline at end of file diff --git a/tests/neg/conflicting-inst-basetypes.scala b/tests/neg/conflicting-inst-basetypes.scala new file mode 100644 index 000000000000..a6ff3cf1e53e --- /dev/null +++ b/tests/neg/conflicting-inst-basetypes.scala @@ -0,0 +1,7 @@ + +object Test: + trait A[T] + trait B1 extends A[Int] + trait B2 extends A[String] + class D extends B1, B2 // error: cannot be instantiated since it has conflicting base types Test.A[Int] and Test.A[String] + // NOTE this is not accepted in Scala 2 either diff --git a/tests/neg/i11103.scala b/tests/neg/i11103.scala index 6892f9ad30b2..261a1416494e 100644 --- a/tests/neg/i11103.scala +++ b/tests/neg/i11103.scala @@ -9,8 +9,4 @@ case p: P => new Foo // error } - - class UpBndAndB extends UpBnd[Bar] with P - // ClassCastException: Foo cannot be cast to Bar - val x = pmatch(new UpBndAndB) } diff --git a/tests/neg/i23435-min.scala b/tests/neg/i23435-min.scala new file mode 100644 index 000000000000..962cca357fe5 --- /dev/null +++ b/tests/neg/i23435-min.scala @@ -0,0 +1,6 @@ + +type Or[+A, +B] = A | B + +val x: Or[Int, String] & Or[String, Int] = 3 +val y: Or[Int & String, String & Int] = x // error +val z: String = y diff --git a/tests/neg/i23435.scala b/tests/neg/i23435.scala new file mode 100644 index 000000000000..a7c47b350e17 --- /dev/null +++ b/tests/neg/i23435.scala @@ -0,0 +1,16 @@ + +trait L[+A]{val a:A} +trait R[+B]{val b: B} + +class LR(val a: Int, val b: String) extends L[Int] with R[String] + +type E[+A] = L[A] | R[A] + +val x: E[Int] & E[String] = LR(4, "hi") +val y: E[Int&String] = x // error + +val z = y match + case l : L[Int&String] => l.a + case r : R[Int&String] => r.b + +val _ = z:String // was: java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String diff --git a/tests/neg/i3989e.scala b/tests/neg/i3989e.scala index 33b5ee665815..4942d3d71270 100644 --- a/tests/neg/i3989e.scala +++ b/tests/neg/i3989e.scala @@ -1,6 +1,6 @@ object Test extends App { trait A[+X](val x: X) - class B extends A(5) with A("hello") // error: A is extended twice + class B extends A(5) with A("hello") // error: A is extended twice // error: class B cannot be instantiated since it has conflicting base types Test.A[Int] and Test.A[String] def f(a: A[Int]): Int = a match { case b: B => b.x diff --git a/tests/neg/lucre-23441-min.scala b/tests/neg/lucre-23441-min.scala new file mode 100644 index 000000000000..ec54184c4ca1 --- /dev/null +++ b/tests/neg/lucre-23441-min.scala @@ -0,0 +1,15 @@ + +trait Txn[T] +trait Expr[X <: Txn[X], +Y] +trait BinOp[T, Repr[X <: Txn[X]] <: Expr[X, T]] + +trait IntObj[T] extends Expr[T, Int] +trait IntBinOp extends BinOp[Int, IntObj] +object IntEq extends IntBinOp + +object Test: + val r: BinOp[?, ?] = IntEq : BinOp[Int, IntObj] // error: Required: BinOp[?, ?[X] <: Expr[X, BinOp[?, ?]#T]] + // We would need the second wildcard to "depend" on the 1st one, + // e.g. have SomeBinop[?] where `type SomeBinop[X] = BinOp[X, ? <: [Y] =>> Expr[Y, X]]`, + // but this is an instance of an unreducible application of higher-kinded type to a wildcard argument. + // Also note there would be no error if we made BinOp covariant in T. diff --git a/tests/neg/singletonInterval.scala b/tests/neg/singletonInterval.scala new file mode 100644 index 000000000000..61b6198196d1 --- /dev/null +++ b/tests/neg/singletonInterval.scala @@ -0,0 +1,16 @@ + +/** Why the singletonInterval logic cannot be applied for lubArgs and glbArgs in TypeComparer. */ + +type Or[+A, +B] = A | B + +object TestGlb: + val x: Or["3", Singleton] & Or[Singleton, "3"] = 3 + val y: Or["3", "3"] = x // error + val z: String = y + +object TestLub: + def f[P[_, _]](x1: P["3", Singleton], x2: P[Singleton, "3"]): P["3", "3"] = + val x = if true then x1 else x2 + x // error, was accepted because inferred type of x was `P["3", "3"]` + // by going through Types.join, TypeOps.mergeRefinedOrApplied, TypeComparer#lubArgs, TypeComparer#singletonInterval + val z: String = f[Or](3, 3) diff --git a/tests/pos-macros/quoted-pattern-type.scala b/tests/pos-macros/quoted-pattern-type.scala index 0a3e0f279df1..c58deb287384 100644 --- a/tests/pos-macros/quoted-pattern-type.scala +++ b/tests/pos-macros/quoted-pattern-type.scala @@ -20,7 +20,7 @@ object Lib { e case e @ '{ Some($x: Int) } => - e: Expr[T & Some[Int]] + e: Expr[T] & Expr[Some[Int]] x: Expr[Int] e diff --git a/tests/pos/cb-companion-joins.scala b/tests/pos/cb-companion-joins.scala index 91df784bb2ce..de039cbb63ff 100644 --- a/tests/pos/cb-companion-joins.scala +++ b/tests/pos/cb-companion-joins.scala @@ -7,14 +7,39 @@ trait M[Self]: trait Num[Self]: def zero: Self -trait A extends M[A] -trait B extends M[A] - -trait AA: - type X: M -trait BB: - type X: Num -class CC[X1: {M, Num}] extends AA, BB: - type X = X1 - X.zero - X.unit +object Test1: + trait X extends M[X] + trait Y extends M[Y] + +object Test2: + trait A[X: Num]: + X.zero + trait B[X: {M, Num}]: + X.unit + X.zero + +object Test3: + + trait A: + type X: M + X.unit + + trait B: + type X: Num + X.zero + + trait C extends A, B: + X.zero + X.unit + + class AA[Y: M] extends A: + type X = Y + X.unit + Y.unit + + class CC[Y: {M, Num}] extends C: + type X = Y + X.zero + X.unit + Y.zero + Y.unit diff --git a/tests/neg/i10256.scala b/tests/pos/i10256.scala similarity index 50% rename from tests/neg/i10256.scala rename to tests/pos/i10256.scala index a2581867d5cd..da0d836b74ad 100644 --- a/tests/neg/i10256.scala +++ b/tests/pos/i10256.scala @@ -2,6 +2,6 @@ trait Foo[T <: Foo[T]] { type I <: Foo[I] } -trait Bar[T <: Foo[T]] extends Foo[T] { // error: cyclic +trait Bar[T <: Foo[T]] extends Foo[T] { // was error: cyclic self: T => } diff --git a/tests/pos/i11064.scala b/tests/pos/i11064.scala index 286b3d8dcc07..14df98f08621 100644 --- a/tests/pos/i11064.scala +++ b/tests/pos/i11064.scala @@ -5,5 +5,6 @@ trait Ops[T <: TypedArray[_, T]] { } object Test { - def test(ops: Ops[_ <: TypedArray[_, _]]) = ops.typedArray() + def test1(ops: Ops[_ <: TypedArray[_, _]]) = ops.typedArray() + def test2(ops: Ops[_ <: TypedArray[_ <: AnyRef, _]]) = ops.typedArray() // ok, was error: Recursion limit exceeded. } \ No newline at end of file diff --git a/tests/pos/i5980.scala b/tests/pos/i5980.scala index 60e744bbbfca..59e33faa17e9 100644 --- a/tests/pos/i5980.scala +++ b/tests/pos/i5980.scala @@ -4,20 +4,20 @@ trait B trait Covariant[F[+_]] { trait G[+X] - def fx: F[A & B] = fy + def fx: F[A & B] = ??? def fy: F[A] & F[B] = fx - def gx: G[A & B] = gy + def gx: G[A & B] = ??? def gy: G[A] & G[B] = gx } trait Contravariant[F[-_]] { trait G[-X] - def fx: F[A | B] = fy + def fx: F[A | B] = ??? def fy: F[A] & F[B] = fx - def gx: G[A | B] = gy + def gx: G[A | B] = ??? def gy: G[A] & G[B] = gx } @@ -28,7 +28,5 @@ trait LiskovViolation[F[+_]] { def fc1: C = new C {} def fc2: A & B = fc1 - - def fy1: F[A & B] = fc1.children - def fy2: F[A & B] = fc2.children + def fy2: F[A] & F[B] = fc2.children } diff --git a/tests/pos/i7965.scala b/tests/pos/i7965.scala index ee9a9e64a01b..4841aebd3daa 100644 --- a/tests/pos/i7965.scala +++ b/tests/pos/i7965.scala @@ -5,8 +5,6 @@ trait Z abstract class Test { def x: Has[X] | (Has[Y] & Has[Z]) - val y: Has[? >: (X & Y) | (X & Z) <: (X | Y) & (X | Z)] = x - def foo[T <: Has[_]](has: T): T = has foo(x) } diff --git a/tests/pos/i8056.scala b/tests/pos/i8056.scala index cf38633b5402..35cee739930b 100644 --- a/tests/pos/i8056.scala +++ b/tests/pos/i8056.scala @@ -1,5 +1,8 @@ -object O{ +object O { def m(x: Any*) = () - def n(l: List[Int] | List[String]): Unit = m(l*) - def n2(l: List[Int] & List[String]): Unit = m(l*) + + def n2(l: List[Int] | List[String]): Unit = m(l) + def n1(l: List[Int] | List[String]): Unit = m(l*) + def m2(l: List[Int] & List[String]): Unit = m(l) + def m1(l: List[Int] & List[String]): Unit = m(l*) } \ No newline at end of file diff --git a/tests/pos/intersection.scala b/tests/pos/intersection.scala index 9b7e15b317e3..6a41b2884252 100644 --- a/tests/pos/intersection.scala +++ b/tests/pos/intersection.scala @@ -18,8 +18,7 @@ object intersection { class C[-T] - def f: C[A] & C[B] = ??? - def g: C[A | B] = f + def g: C[A | B] = ??? def h: C[A] & C[B] = g } object Test { @@ -41,14 +40,3 @@ object Test { def fooBA = (??? : B with A).f def fooBA1: Int = fooBA } - -object Test2: - class Row[+X] - class A - class B - class C extends Row[A] - class D extends Row[B] - val x: C & D = ??? - val y: Row[A & B] = x - - diff --git a/tests/pos/reference/intersection-types.scala b/tests/pos/reference/intersection-types.scala index b36f52028739..6a7e9a6947cd 100644 --- a/tests/pos/reference/intersection-types.scala +++ b/tests/pos/reference/intersection-types.scala @@ -26,7 +26,7 @@ object t2 { } val x: A & B = new C - val ys: List[A & B] = x.children + val ys: List[A] & List[B] = x.children class C extends A with B { def children: List[A & B] = ??? diff --git a/tests/pos/templateParents.scala b/tests/pos/templateParents.scala index 1bc07b57174b..423fd0aeba1a 100644 --- a/tests/pos/templateParents.scala +++ b/tests/pos/templateParents.scala @@ -14,8 +14,8 @@ object templateParents1 { trait D extends C[String] trait E extends C[Int] - val x = new D with E + trait P[T] - val y: C[Int & String] = x + val x = new D with P[Int] }