From 8375e3a1ea9b0c13efb3188c844fe2a0c180c11e Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 18 Jul 2016 09:13:32 +0100 Subject: [PATCH 1/2] Better test for #1181 Now that we implement partial higher-order unification (SI-2712 fix) i1181.scala will compile even if `Alias[Int]` gets dealiased to `(Int, Int)` because we can unify the latter with `M[_]` where `M = [X] -> (Int, X)`. The new test will only succeed if `Alias[Int, Int]` is not dealiased because we will never unify `Foo[Int]` with `M[_,_]`. --- tests/pos/i1181b.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/pos/i1181b.scala diff --git a/tests/pos/i1181b.scala b/tests/pos/i1181b.scala new file mode 100644 index 000000000000..7694aed0b770 --- /dev/null +++ b/tests/pos/i1181b.scala @@ -0,0 +1,11 @@ +class Foo[A] + +object Test { + def foo[M[_,_]](x: M[Int,Int]) = x + + type Alias[X,Y] = Foo[X] + val x: Alias[Int,Int] = new Foo[Int] + + foo[Alias](x) // ok + foo(x) +} From 6c263447cfaea86979b1e41d687e312204430a33 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 18 Jul 2016 09:24:43 +0100 Subject: [PATCH 2/2] HK reduction: Remove special-case for typerefs The special case: case stripped: TypeRef => stripped.symbol.is(BaseTypeArg) is wrong because you might still want to reduce applications involving TypeRefs which are not base class parameters, like in: class Foo[A] type Alias[X] = Foo[X] val x: Alias[Int] = ??? `Alias` is a TypeRef so before this commit `Alias[Int]` was never reduced to `Foo[Int]`. It should have been: case stripped: TypeRef if stripped.symbol.is(BaseTypeArg) => true But even this is incorrect: it assumes that we can always safely reduce HK applications involving base class parameters, this is not the case when the parameter kind is different from the rhs kind as illustrated by `i1181c.scala`. We fix this by simply dropping the special case. --- src/dotty/tools/dotc/config/Config.scala | 5 ++--- .../tools/dotc/core/TypeApplications.scala | 19 +++++++------------ tests/pos/i1181c.scala | 11 +++++++++++ 3 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 tests/pos/i1181c.scala diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index a50945108f04..0949d7fee4fa 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -98,9 +98,8 @@ object Config { final val splitProjections = false /** If this flag is on, always rewrite an application `S[Ts]` where `S` is an alias for - * `[Xs] -> U` to `[Xs := Ts]U`. If this flag is off, the rewriting is only done if `S` is a - * reference to an instantiated parameter. Turning this flag on was observed to - * give a ~6% speedup on the JUnit test suite. + * `[Xs] -> U` to `[Xs := Ts]U`. + * Turning this flag on was observed to give a ~6% speedup on the JUnit test suite. */ final val simplifyApplications = true diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 314233709473..cb11d3fdc398 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -470,18 +470,13 @@ class TypeApplications(val self: Type) extends AnyVal { case dealiased: TypeLambda => def tryReduce = if (!args.exists(_.isInstanceOf[TypeBounds])) { - val followAlias = stripped match { - case stripped: TypeRef => - stripped.symbol.is(BaseTypeArg) - case _ => - Config.simplifyApplications && { - dealiased.resType match { - case AppliedType(tyconBody, _) => - variancesConform(typParams, tyconBody.typeParams) - // Reducing is safe for type inference, as kind of type constructor does not change - case _ => false - } - } + val followAlias = Config.simplifyApplications && { + dealiased.resType match { + case AppliedType(tyconBody, _) => + variancesConform(typParams, tyconBody.typeParams) + // Reducing is safe for type inference, as kind of type constructor does not change + case _ => false + } } if ((dealiased eq stripped) || followAlias) dealiased.instantiate(args) else HKApply(self, args) diff --git a/tests/pos/i1181c.scala b/tests/pos/i1181c.scala new file mode 100644 index 000000000000..940629259eae --- /dev/null +++ b/tests/pos/i1181c.scala @@ -0,0 +1,11 @@ +class Foo[A] + +trait Bar[DD[_,_]] { + val x: DD[Int, Int] +} + +trait Baz extends Bar[[X,Y] -> Foo[X]] { + def foo[M[_,_]](x: M[Int, Int]) = x + + foo(x) +}