From dd8398d2e5f0c6267c73ebfb0b12ab3610f1cc1f Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 24 Jun 2021 00:13:30 +0200 Subject: [PATCH] ProtoTypes#normalizedCompatible: keep more constraints Remove the extra condition where we only kept constraints if the new TyperState does not contain new type variables, this used to be needed to compile tests/pos/i6682a.scala with -Ycheck:all, otherwise we would get: assertion failed: Types differ Original type : (y: PolyFunction{apply: [T](y: T): y.type => Int}): y.type => Int After checking: (y: PolyFunction{apply: [T](y: T): y.type => Int}): y.type => Int But it turns out that 55a223c7ab3231cc0c0e138eda29ba29ec2c989d fixed that. Fixes #12126. --- .../dotty/tools/dotc/typer/ProtoTypes.scala | 15 +---- tests/pos/i12126.scala | 59 +++++++++++++++++++ 2 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 tests/pos/i12126.scala diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 7e7132307b0e..64bf32c49f91 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -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) diff --git a/tests/pos/i12126.scala b/tests/pos/i12126.scala new file mode 100644 index 000000000000..cffa7fbcbbca --- /dev/null +++ b/tests/pos/i12126.scala @@ -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)) +