Skip to content

Commit

Permalink
Merge pull request scala#12924 from dotty-staging/fix-i12126
Browse files Browse the repository at this point in the history
ProtoTypes#normalizedCompatible: keep more constraints
  • Loading branch information
odersky authored Jun 25, 2021
2 parents ecbe3d2 + dd8398d commit 0722bf4
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 13 deletions.
15 changes: 2 additions & 13 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,8 @@ object ProtoTypes {
i"""normalizedCompatible for $poly, $pt = $result
|constraint was: ${ctx.typerState.constraint}
|constraint now: ${newctx.typerState.constraint}""")
if result
&& (ctx.typerState.constraint ne newctx.typerState.constraint)
&& {
val existingVars = ctx.typerState.uninstVars.toSet
newctx.typerState.uninstVars.forall(existingVars.contains)
}
then newctx.typerState.commit()
// If the new constrait contains fresh type variables we cannot keep it,
// since those type variables are not instantiated anywhere in the source.
// See pos/i6682a.scala for a test case. See pos/11243.scala and pos/i5773b.scala
// for tests where it matters that we keep the constraint otherwise.
// TODO: A better solution would clean the new constraint, so that it "avoids"
// the problematic type variables. But we have not implemented such an algorithm yet.
if result && (ctx.typerState.constraint ne newctx.typerState.constraint) then
newctx.typerState.commit()
result
case _ => testCompat
else explore(testCompat)
Expand Down
59 changes: 59 additions & 0 deletions tests/pos/i12126.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
object Structures:

trait Functor[F[_]]:
extension [A](fa: F[A])
def map[B](f: A => B): F[B]
def as[B](b: B): F[B] = map(_ => b)
def void: F[Unit] = as(())

trait Applicative[F[_]] extends Functor[F]:
def pure[A](a: A): F[A]
def unit: F[Unit] = pure(())
extension[A](fa: F[A])
def map2[B, C](fb: F[B], f: (A, B) => C): F[C]
def map[B](f: A => B): F[B] =
fa.map2(unit, (a, _) => f(a))

trait Monad[F[_]] extends Applicative[F]:
extension[A](fa: F[A])
def flatMap[B](f: A => F[B]): F[B]
override def map[B](f: A => B): F[B] =
flatMap(a => pure(f(a)))
def map2[B, C](fb: F[B], f: (A, B) => C): F[C] =
flatMap(a => fb.map(b => f(a, b)))

given Monad[List] with
def pure[A](a: A) = List(a)
extension[A](fa: List[A])
def flatMap[B](f: A => List[B]) = fa.flatMap(f)

given Monad[Option] with
def pure[A](a: A) = Some(a)
extension[A](fa: Option[A])
def flatMap[B](f: A => Option[B]) = fa.flatMap(f)


opaque type Kleisli[F[_], A, B] = A => F[B]

extension [F[_], A, B](k: Kleisli[F, A, B])
def apply(a: A): F[B] = k(a)

object Kleisli:
def apply[F[_], A, B](f: A => F[B]): Kleisli[F, A, B] = f

given [F[_], A](using F: Monad[F]): Monad[[B] =>> Kleisli[F, A, B]] with
def pure[B](b: B) = Kleisli(_ => F.pure(b))
extension[B](k: Kleisli[F, A, B])
def flatMap[C](f: B => Kleisli[F, A, C]) =
a => k(a).flatMap(b => f(b)(a))

end Structures

@main def run =
import Structures.{*, given}
println(List(1, 2, 3).map2(List(4, 5, 6), (_, _)))

val p: Kleisli[Option, Int, Int] = Kleisli((x: Int) => if x % 2 == 0 then Some(x) else None)
val q: Kleisli[Option, Int, Int] = summon[Applicative[[B] =>> Kleisli[Option, Int, B]]].pure(20)
println(p.map2(q, _ + _)(42))

0 comments on commit 0722bf4

Please sign in to comment.