Skip to content

ProtoTypes#normalizedCompatible: keep more constraints #12924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))