diff --git a/community-build/community-projects/onnx-scala b/community-build/community-projects/onnx-scala index 87600b3d4234..3a5a45016d1a 160000 --- a/community-build/community-projects/onnx-scala +++ b/community-build/community-projects/onnx-scala @@ -1 +1 @@ -Subproject commit 87600b3d4234517d44e1549de5d8015afc8801fb +Subproject commit 3a5a45016d1a48d2a84dc3159d3e08c1ad5ac587 diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index df2c195b9e74..3e72f224cab0 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -407,7 +407,7 @@ object SymDenotations { * @param tparams The type parameters with which the right-hand side bounds should be abstracted * */ - def opaqueToBounds(info: Type, rhs: tpd.Tree, tparams: List[TypeParamInfo])(using Context): Type = + def opaqueToBounds(info: Type, rhs: tpd.Tree, tparams: List[TypeSymbol])(using Context): Type = def setAlias(tp: Type) = def recur(self: Type): Unit = self match diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 41db7d88ffdd..0b13fe0dbb3a 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4039,7 +4039,7 @@ object Types { // ----- Type application: LambdaParam, AppliedType --------------------- /** The parameter of a type lambda */ - case class LambdaParam(tl: TypeLambda, n: Int) extends ParamInfo { + case class LambdaParam(tl: TypeLambda, n: Int) extends ParamInfo, printing.Showable { type ThisName = TypeName def isTypeParam(using Context): Boolean = tl.paramNames.head.isTypeName @@ -4084,6 +4084,8 @@ object Types { case _ => myVariance = Invariant myVariance + + def toText(printer: Printer): Text = printer.toText(this) } /** A type application `C[T_1, ..., T_n]` */ diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f7b56c246b8c..2853052eb0b7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -860,14 +860,24 @@ class TreeUnpickler(reader: TastyReader, sym.info = TypeBounds.empty // needed to avoid cyclic references when unpickling rhs, see i3816.scala sym.setFlag(Provisional) val rhs = readTpt()(using localCtx) - sym.info = new NoCompleter { + + sym.info = new NoCompleter: override def completerTypeParams(sym: Symbol)(using Context) = rhs.tpe.typeParams - } - sym.info = sym.opaqueToBounds( - checkNonCyclic(sym, rhs.tpe.toBounds, reportErrors = false), - rhs, rhs.tpe.typeParams) - if sym.isOpaqueAlias then sym.typeRef.recomputeDenot() // make sure we see the new bounds from now on + + def opaqueToBounds(info: Type): Type = + val tparamSyms = rhs match + case LambdaTypeTree(tparams, body) => tparams.map(_.symbol.asType) + case _ => Nil + sym.opaqueToBounds(info, rhs, tparamSyms) + + val info = checkNonCyclic(sym, rhs.tpe.toBounds, reportErrors = false) + if sym.isOpaqueAlias then + sym.info = opaqueToBounds(info) + sym.typeRef.recomputeDenot() // make sure we see the new bounds from now on + else + sym.info = info + sym.resetFlag(Provisional) TypeDef(rhs) } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 69df16da08c3..7009a55d3aeb 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -540,6 +540,12 @@ class PlainPrinter(_ctx: Context) extends Printer { def toText(annot: Annotation): Text = s"@${annot.symbol.name}" // for now + def toText(param: LambdaParam): Text = + varianceSign(param.paramVariance) + ~ toText(param.paramName) + ~ (if param.isTypeParam then "" else ": ") + ~ toText(param.paramInfo) + protected def escapedString(str: String): String = str flatMap escapedChar def dclsText(syms: List[Symbol], sep: String): Text = Text(syms map dclText, sep) diff --git a/compiler/src/dotty/tools/dotc/printing/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala index 8584c889eeda..2079bc7cc1cd 100644 --- a/compiler/src/dotty/tools/dotc/printing/Printer.scala +++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala @@ -4,7 +4,8 @@ package printing import core._ import Texts._, ast.Trees._ -import Types.{Type, SingletonType}, Symbols.Symbol, Scopes.Scope, Constants.Constant, +import Types.{Type, SingletonType, LambdaParam}, + Symbols.Symbol, Scopes.Scope, Constants.Constant, Names.Name, Denotations._, Annotations.Annotation import typer.Implicits.SearchResult import util.SourcePosition @@ -130,6 +131,9 @@ abstract class Printer { /** Textual representation of type */ def toText(tp: Type): Text + /** Textual representation of lambda param */ + def toText(tree: LambdaParam): Text + /** Textual representation of all symbols in given list, * using `dclText` for displaying each. */ diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index d2264e367f36..b4bc79cd1f60 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -425,7 +425,7 @@ class Namer { typer: Typer => * is still missing its parents. Parents are set to Nil when completion starts and are * set to the actual parents later. If a superclass completes a subclass in one * of its parents, the parents of the superclass or some intervening class might - * not yet be set. This situation can be detected by asking for the baseType of Any - + * not yet be set. This situation can be detected by asking for the baseType of Any - * if that type does not exist, one of the base classes of this class misses its parents. * If this situation arises, the computation of the superclass might be imprecise. * For instance, in i12722.scala, the superclass of `IPersonalCoinOps` is computed @@ -988,9 +988,12 @@ class Namer { typer: Typer => val unsafeInfo = if (isDerived) rhsBodyType else abstracted(rhsBodyType) def opaqueToBounds(info: Type): Type = - if sym.isOpaqueAlias && info.typeParams.nonEmpty && info.hkResult.typeParams.nonEmpty then - report.error(em"opaque type alias cannot have multiple type parameter lists", rhs.srcPos) - sym.opaqueToBounds(info, rhs1, tparamSyms) + if sym.isOpaqueAlias then + if info.typeParams.nonEmpty && info.hkResult.typeParams.nonEmpty then + report.error(em"opaque type alias cannot have multiple type parameter lists", rhs.srcPos) + sym.opaqueToBounds(info, rhs1, tparamSyms) + else + info if (isDerived) sym.info = unsafeInfo else { diff --git a/sbt-test/opaques/i12927/build.sbt b/sbt-test/opaques/i12927/build.sbt new file mode 100644 index 000000000000..63e314982c41 --- /dev/null +++ b/sbt-test/opaques/i12927/build.sbt @@ -0,0 +1 @@ +scalaVersion := sys.props("plugin.scalaVersion") diff --git a/sbt-test/opaques/i12927/changes/Foo.scala b/sbt-test/opaques/i12927/changes/Foo.scala new file mode 100644 index 000000000000..5c4cbfafede5 --- /dev/null +++ b/sbt-test/opaques/i12927/changes/Foo.scala @@ -0,0 +1,7 @@ +object Foo: + opaque type BlaBla[+T, D] = Int + extension [T, D](token: BlaBla[T, D]) def data: D = ??? + +//To cause the crash, after initial clean compilation +//replace `???` with `value.data` to cause the compiler crash +def foo[W <: Int](value: Bar.BlaBla[W]): Unit = value.data diff --git a/sbt-test/opaques/i12927/src/main/scala/Bar.scala b/sbt-test/opaques/i12927/src/main/scala/Bar.scala new file mode 100644 index 000000000000..5688944e6e3e --- /dev/null +++ b/sbt-test/opaques/i12927/src/main/scala/Bar.scala @@ -0,0 +1,4 @@ +object Bar: + type Fuzzy[W <: Int] = Int + opaque type BlaBla[W <: Int] <: Foo.BlaBla[Fuzzy[W], Int] = + Foo.BlaBla[Fuzzy[W], Int] diff --git a/sbt-test/opaques/i12927/src/main/scala/Foo.scala b/sbt-test/opaques/i12927/src/main/scala/Foo.scala new file mode 100644 index 000000000000..24ab85caa49a --- /dev/null +++ b/sbt-test/opaques/i12927/src/main/scala/Foo.scala @@ -0,0 +1,7 @@ +object Foo: + opaque type BlaBla[+T, D] = Int + extension [T, D](token: BlaBla[T, D]) def data: D = ??? + +//To cause the crash, after initial clean compilation +//replace `???` with `value.data` to cause the compiler crash +def foo[W <: Int](value: Bar.BlaBla[W]): Unit = ??? //value.data diff --git a/sbt-test/opaques/i12927/test b/sbt-test/opaques/i12927/test new file mode 100644 index 000000000000..c0ed101b5606 --- /dev/null +++ b/sbt-test/opaques/i12927/test @@ -0,0 +1,3 @@ +> compile +$ copy-file changes/Foo.scala src/main/scala/Foo.scala +> compile diff --git a/tests/pos/i12945/A_1.scala b/tests/pos/i12945/A_1.scala new file mode 100644 index 000000000000..890171a63051 --- /dev/null +++ b/tests/pos/i12945/A_1.scala @@ -0,0 +1,10 @@ +opaque type Lie[W <: Int] = Int +object Lie: + trait TC[-T]: + type Out + object TC: + given [W <: Int]: TC[Lie[W]] with + type Out = W + +val x = summon[Lie.TC[Lie[7]]] +val works = summon[x.Out =:= 7] diff --git a/tests/pos/i12945/B_2.scala b/tests/pos/i12945/B_2.scala new file mode 100644 index 000000000000..371754a87ff5 --- /dev/null +++ b/tests/pos/i12945/B_2.scala @@ -0,0 +1,3 @@ +object Test: + val x = summon[Lie.TC[Lie[7]]] + val fails = summon[x.Out =:= 7] diff --git a/tests/pos/i12950/repro_1.scala b/tests/pos/i12950/repro_1.scala new file mode 100644 index 000000000000..4c4a12de8cd6 --- /dev/null +++ b/tests/pos/i12950/repro_1.scala @@ -0,0 +1,27 @@ +package repro +object repro: + object opq: + opaque type Lift[T] = Int + extension(v: Int) + def lift[T]: Lift[T] = v + extension[T](l: Lift[T]) + def value: Int = l + + export opq.Lift as Lift + export opq.lift as lift + + final type Two + + extension[TL](l: Lift[TL]) + def repro[TR](using m: Mul[TL, TR]): Int = l.value + m.value + + abstract class Mul[TL, TR]: + val value: Int + + transparent inline given mulGivenInt[TL <: Int & Singleton, TR <: Int & Singleton]: Mul[TL, TR] = + val m: Int = scala.compiletime.constValue[TL] * scala.compiletime.constValue[TR] + new Mul[TL, TR] { val value: Int = m } + + transparent inline given mulGivenTwo[TR <: Int & Singleton]: Mul[Two, TR] = + val m: Int = 2 * scala.compiletime.constValue[TR] + new Mul[Two, TR] { val value: Int = m } \ No newline at end of file diff --git a/tests/pos/i12950/test_2.scala b/tests/pos/i12950/test_2.scala new file mode 100644 index 000000000000..2640501f4388 --- /dev/null +++ b/tests/pos/i12950/test_2.scala @@ -0,0 +1,6 @@ +import repro.repro.{*, given} + +val x = 1.lift[Two] +val _ = x.repro[2] +val y = 1.lift[2] +val _ = y.repro[2] diff --git a/tests/pos/i13001/Main_1.scala b/tests/pos/i13001/Main_1.scala new file mode 100644 index 000000000000..ad46df9f2fe1 --- /dev/null +++ b/tests/pos/i13001/Main_1.scala @@ -0,0 +1,31 @@ +case class Foo(a: String) + +trait Arbitrary[T] +trait Gen[+T] + +object ArbitraryDerivation: + given deriveArb[A](using gen: DerivedGen[A]): Arbitrary[A] = ??? + +opaque type DerivedGen[A] = Gen[A] +object DerivedGen extends DerivedGenInstances + +sealed abstract class DerivedGenInstances: + inline given derived[A](using gen: K0.Generic[A]): DerivedGen[A] = + val dummy: DerivedGen[A] = ??? + gen.derive(dummy, dummy) + +// from shapeless3-deriving +import scala.deriving.* +object K0 { + type Kind[C, O] = C { type Kind = K0.type ; type MirroredType = O ; type MirroredElemTypes <: Tuple } + type Generic[O] = Kind[Mirror, O] + type ProductGeneric[O] = Kind[Mirror.Product, O] + type CoproductGeneric[O] = Kind[Mirror.Sum, O] + + extension [F[_], T](gen: Generic[T]) + inline def derive(f: => (ProductGeneric[T] & gen.type) ?=> F[T], g: => (CoproductGeneric[T] & gen.type) ?=> F[T]): F[T] = + inline gen match { + case p: ProductGeneric[T] => f(using p.asInstanceOf) + case c: CoproductGeneric[T] => g(using c.asInstanceOf) + } +} \ No newline at end of file diff --git a/tests/pos/i13001/Test_2.scala b/tests/pos/i13001/Test_2.scala new file mode 100644 index 000000000000..42cacb760027 --- /dev/null +++ b/tests/pos/i13001/Test_2.scala @@ -0,0 +1,4 @@ +class Test: + import ArbitraryDerivation.given + private def test[A: Arbitrary]: Unit = {} + test[Foo] \ No newline at end of file diff --git a/tests/pos/i13128/A_1.scala b/tests/pos/i13128/A_1.scala new file mode 100644 index 000000000000..4a1c9335d2ec --- /dev/null +++ b/tests/pos/i13128/A_1.scala @@ -0,0 +1 @@ +opaque type Foo[T <: Int] = Int diff --git a/tests/pos/i13128/B_2.scala b/tests/pos/i13128/B_2.scala new file mode 100644 index 000000000000..797c917d3620 --- /dev/null +++ b/tests/pos/i13128/B_2.scala @@ -0,0 +1,3 @@ +def grabT[T <: Int](arg : Foo[T]) : T = ??? +final val t1 = grabT(??? : Foo[8]) +val t2 : 8 = t1 \ No newline at end of file diff --git a/tests/pos/i13190/A_1.scala b/tests/pos/i13190/A_1.scala new file mode 100644 index 000000000000..9bb9b20f2976 --- /dev/null +++ b/tests/pos/i13190/A_1.scala @@ -0,0 +1,3 @@ +object Opaque { + opaque type FieldType[K, +V] <: V = V +} \ No newline at end of file diff --git a/tests/pos/i13190/B_2.scala b/tests/pos/i13190/B_2.scala new file mode 100644 index 000000000000..2752778afa04 --- /dev/null +++ b/tests/pos/i13190/B_2.scala @@ -0,0 +1,15 @@ +import Opaque.* + +object Test { + type FindField[R <: scala.Tuple, K] = R match { + case FieldType[K, f] *: t => f + case _ *: t => FindField[t, K] + } + + val f: FieldType["A", Int] = ??? + val f1: Int = f + //val f2: Int = f + + type R = FieldType["A", Int] *: FieldType["B", Double] *: FieldType["C", String] *: FieldType["D", Boolean] *: EmptyTuple + summon[FindField[R, "B"] =:= Double] +}