From cacc27fd6e747324fa97f8bcafe01684b6a18bc0 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 10 Jul 2025 16:52:44 +0200 Subject: [PATCH 1/3] Add TypeParamRef handling in isSingletonBounded --- .../src/dotty/tools/dotc/core/Types.scala | 18 ++++++ tests/pos/i22922.scala | 57 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/pos/i22922.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 28995d4ddf13..61a725fc4b54 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -338,6 +338,24 @@ object Types extends TypeUtils { case AndType(tpL, tpR) => tpL.isEffectivelySingleton || tpR.isEffectivelySingleton case _ => false + /** Is this upper-bounded by a (possibly aliased) singleton type? + * Overridden in TypeVar + */ + def isSingletonBounded(frozen: Boolean)(using Context): Boolean = this.dealias.normalized match + case tp: SingletonType => tp.isStable + case tp: TypeParamRef => + ctx.typerState.constraint.bounds(tp).hi.isSingletonBounded(frozen) + case tp: TypeRef => + tp.name == tpnme.Singleton && tp.symbol == defn.SingletonClass + || tp.superType.isSingletonBounded(frozen) + case tp: TypeVar if !tp.isInstantiated => + if frozen then tp frozen_<:< defn.SingletonType else tp <:< defn.SingletonType + case tp: HKTypeLambda => false + case tp: TypeProxy => tp.superType.isSingletonBounded(frozen) + case tp: AndType => tp.tp1.isSingletonBounded(frozen) || tp.tp2.isSingletonBounded(frozen) + case tp: OrType => tp.tp1.isSingletonBounded(frozen) && tp.tp2.isSingletonBounded(frozen) + case _ => false + /** Is this type of kind `AnyKind`? */ def hasAnyKind(using Context): Boolean = { @tailrec def loop(tp: Type): Boolean = tp match { diff --git a/tests/pos/i22922.scala b/tests/pos/i22922.scala new file mode 100644 index 000000000000..a65c99d6bd46 --- /dev/null +++ b/tests/pos/i22922.scala @@ -0,0 +1,57 @@ +abstract class Computation[+A, -U] +type !![+A, -U] = Computation[A, U] +type Const[C] = [_] =>> C + +final class EffectImpl[Fx]: + sealed trait ThisInterpreter extends Interpreter.Unsealed: + final override type Elim = Fx + abstract class Stateless[F[+_], G[+_], Fx] + extends Interpreter.Stateless[F, G, Fx] + with ThisInterpreter + +trait Effect: + val impl: EffectImpl[this.type] = ??? + +trait SourceEffect[O] extends Effect: + abstract class Stateless[U] extends StatelessReturn[Unit, U] + abstract class StatelessReturn[R, U] extends impl.Stateless[Const[Unit], Const[R], U] + +sealed trait Handler[From[+_], To[+_], Elim, Intro]: + final def handle[V] = new HandleSyntax[V] + final class HandleSyntax[V]: + def apply[A, W](comp: From[A] !! W)(using CanPartiallyHandle[V, W, Elim]): To[A] !! (V & Intro) = ??? + +sealed trait CanPartiallyHandle[U, V, W] // missing in StreamImpl.map +object CanPartiallyHandle: + given [U, V, W](using (W & U) <:< V): CanPartiallyHandle[U, V, W] = ??? + +sealed trait Interpreter: + type From[+A] + type To[+A] + type Elim + type Intro + + final def toHandler: Handler[From, To, Elim, Intro] = ??? +object Interpreter: + trait Unsealed extends Interpreter + abstract class Stateless[F[+_], G[+_], Fx] extends Interpreter: + final override type From[+A] = F[A] + final override type To[+A] = G[A] + final override type Intro = Fx + +object Syntax: + extension [U](comp: Unit !! U) + def asStream[A, V](fx: SourceEffect[A])(using (fx.type & V) =:= U): Stream[A, V] = ??? + +sealed abstract class Stream[+A, -U]: + def map[B](f: A => B): Stream[B, U] + +import Syntax.* +final case class StreamImpl[A, U](Fx: SourceEffect[A])(val compute: Unit !! (U & Fx.type)) + extends Stream[A, U]: + type Fx = Fx.type + override def map[B](f: A => B): Stream[B, U] = + case object Fx2 extends SourceEffect[B] + new Fx.Stateless[Fx2.type] {}.toHandler + .handle(compute) + .asStream(Fx2) // error From 64e83c7299a3001daa62a36bb3126dbac1cbb277 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 23 Jul 2025 14:58:36 +0200 Subject: [PATCH 2/3] Add TypeParamRef handling in isSingletonBounded [Cherry-picked 71c9ad65528c52f721dd83fdc1d71a9907e3f336][modified] From 12801e446a822846909763cd76111c2eedcb83a8 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 11 Jul 2025 13:11:41 +0200 Subject: [PATCH 3/3] Fix logic in isSingletonBounded for OrType case [Cherry-picked f14fa1050d1a4a87b394609af5e474d71e348e62] --- compiler/src/dotty/tools/dotc/core/Types.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 61a725fc4b54..2e0b227bba7c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -353,7 +353,6 @@ object Types extends TypeUtils { case tp: HKTypeLambda => false case tp: TypeProxy => tp.superType.isSingletonBounded(frozen) case tp: AndType => tp.tp1.isSingletonBounded(frozen) || tp.tp2.isSingletonBounded(frozen) - case tp: OrType => tp.tp1.isSingletonBounded(frozen) && tp.tp2.isSingletonBounded(frozen) case _ => false /** Is this type of kind `AnyKind`? */