From 1531900bffb2bed6288eda4e0945b0e6dea3f23d Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 21 Jun 2015 06:17:59 +1000 Subject: SI-6895 Test cases to explain the limitations in tcpoly inference I've determined that the failure in this bug report boils down to SI-2712. Submitting my working as neg tests for posterity. The type error disabmiguator develops a serious stutter with this example. I'll fix that in the following commit. --- test/files/neg/t6895.check | 6 ++++++ test/files/neg/t6895.scala | 26 ++++++++++++++++++++++++++ test/files/neg/t6895b.check | 9 +++++++++ test/files/neg/t6895b.scala | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 test/files/neg/t6895.check create mode 100644 test/files/neg/t6895.scala create mode 100644 test/files/neg/t6895b.check create mode 100644 test/files/neg/t6895b.scala diff --git a/test/files/neg/t6895.check b/test/files/neg/t6895.check new file mode 100644 index 0000000000..df01031fff --- /dev/null +++ b/test/files/neg/t6895.check @@ -0,0 +1,6 @@ +t6895.scala:19: error: polymorphic expression cannot be instantiated to expected type; + found : [F3[F3_P]]Foo[F3] + required: Foo[[X3]Bar[[X1]String]] + val nok: Foo[({type L[X3] = Bar[M]})#L] = barFoo /* Type inference can't unify F with L */ + ^ +one error found diff --git a/test/files/neg/t6895.scala b/test/files/neg/t6895.scala new file mode 100644 index 0000000000..5fb20d8c61 --- /dev/null +++ b/test/files/neg/t6895.scala @@ -0,0 +1,26 @@ +trait Foo[F1[F1_P]] +trait Bar[F2[F2_P]] + +class Test { + def barFoo[F3[F3_P]]: Foo[F3] = ??? + + // Now we can define a couple of type aliases: + type M[X1] = String + type N[X2] = Bar[M] + + // val ok1: Foo[N] = barFoo + // Foo[?F3] <:< Foo[Test.this.N] + // [X2]Test.this.N[X2] <:< [F3_P]?F3[F3_P] + // Test.this.N[X2] <:< ?F3[X2] + // true, ?F3=N + + // val ok2: Foo[({type L[X] = Bar[M]})#L] = barFoo[N] + + val nok: Foo[({type L[X3] = Bar[M]})#L] = barFoo /* Type inference can't unify F with L */ + // Foo[?F3] <:< Foo[[X3]Bar[[X1]String]] + // [X3]Bar[[X1]String] <:< ?F3 + // [X3]Bar[[X1]String] <:< [F3_P]?F3[F3_P] + // Bar[[X1]String] <:< ?F3[X3] + // X3 <:< [X1]String + // false +} diff --git a/test/files/neg/t6895b.check b/test/files/neg/t6895b.check new file mode 100644 index 0000000000..3ebdb69309 --- /dev/null +++ b/test/files/neg/t6895b.check @@ -0,0 +1,9 @@ +t6895b.scala:20: error: could not find implicit value for parameter e: Foo[[X]Bar[[X]Or[String,X],X]] + implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]] + ^ +t6895b.scala:23: error: polymorphic expression cannot be instantiated to expected type; + found : [F[_]]Foo[[X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]Bar[F,X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]] + required: Foo[[X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]Bar[[X]Or[String,X],X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]] + barFoo(null) : Foo[({type L[X] = Bar[StringOr, X]})#L] + ^ +two errors found diff --git a/test/files/neg/t6895b.scala b/test/files/neg/t6895b.scala new file mode 100644 index 0000000000..c465065011 --- /dev/null +++ b/test/files/neg/t6895b.scala @@ -0,0 +1,39 @@ +trait Foo[F[_]] +trait Bar[F[_], A] + +trait Or[A, B] + +class Test { + implicit def orFoo[A]: Foo[({type L[X] = Or[A, X]})#L] = ??? + implicit def barFoo[F[_]](implicit f: Foo[F]): Foo[({type L[X] = Bar[F, X]})#L] = ??? + + // Now we can define a couple of type aliases: + type StringOr[X] = Or[String, X] + type BarStringOr[X] = Bar[StringOr, X] + + // ok + implicitly[Foo[BarStringOr]] + barFoo[StringOr](null) : Foo[BarStringOr] + barFoo(null) : Foo[BarStringOr] + + // nok + implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]] + // Let's write the application explicitly, and then + // compile with just this line enabled and -explaintypes. + barFoo(null) : Foo[({type L[X] = Bar[StringOr, X]})#L] + + // Foo[[X]Bar[F,X]] <: Foo[[X]Bar[[X]Or[String,X],X]]? + // Bar[[X]Or[String,X],X] <: Bar[F,X]? + // F[_] <: Or[String,_]? + // false + // false + // false + + // Note that the type annotation above is typechecked as + // Foo[[X]Bar[[X]Or[String,X],X]], ie the type alias `L` + // is eta expanded. + // + // This is done so that it does not escape its defining scope. + // However, one this is done, higher kinded inference + // no longer is able to unify F with `StringOr` (SI-2712) +} -- cgit v1.2.3 From f8d816086f56096c05dfc769aa1ab0f6e583bb5a Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 16 Jul 2014 18:40:44 +0200 Subject: SI-8777 Avoid redundant disambiguation in error messages When printing types in error messages, we attempt to disambiguate symbol names by qualifying them in various ways. Type paramters symbols are qualified by adding `(in someMethod)`. However, the type errors generated by higher kinded subtyping can contain clones of type parameter symbols, as creater in `isPolySubType`. The disambiguation tries fruitlessly to distinguish them but ended up adding the same suffix to both names repeatedly. ``` found : [F[_]]Foo[[X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]Bar[F,X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]] required: Foo[[X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]Bar[[X]Or[String,X],X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]] ``` This commit limits the post qualification of type parameter symbols to a single attempt to limit the damage. An alternative might be to mark a clone (we could determine its status by checking whether it is a type parameter of its owner.) But I'm not sure how to present this information in a comphrenensible way, so for now I'm limiting my ambitions to stopping the stutter. --- src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala | 3 ++- test/files/neg/t6895b.check | 4 ++-- test/files/neg/t8777.check | 6 ++++++ test/files/neg/t8777.scala | 4 ++++ 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 test/files/neg/t8777.check create mode 100644 test/files/neg/t8777.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 059981aa37..65dea3178b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -309,6 +309,7 @@ trait TypeDiagnostics { // save the name because it will be mutated until it has been // distinguished from the other types in the same error message private val savedName = sym.name + private var postQualifiedWith: List[Symbol] = Nil def restoreName() = sym.name = savedName def modifyName(f: String => String) = sym setName newTypeName(f(sym.name.toString)) @@ -322,7 +323,7 @@ trait TypeDiagnostics { // functions to manipulate the name def preQualify() = modifyName(trueOwner.fullName + "." + _) - def postQualify() = modifyName(_ + "(in " + trueOwner + ")") + def postQualify() = if (!(postQualifiedWith contains trueOwner)) { postQualifiedWith ::= trueOwner; modifyName(_ + "(in " + trueOwner + ")") } def typeQualify() = if (sym.isTypeParameterOrSkolem) postQualify() def nameQualify() = if (trueOwner.isPackageClass) preQualify() else postQualify() diff --git a/test/files/neg/t6895b.check b/test/files/neg/t6895b.check index 3ebdb69309..565925127b 100644 --- a/test/files/neg/t6895b.check +++ b/test/files/neg/t6895b.check @@ -2,8 +2,8 @@ t6895b.scala:20: error: could not find implicit value for parameter e: Foo[[X]Ba implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]] ^ t6895b.scala:23: error: polymorphic expression cannot be instantiated to expected type; - found : [F[_]]Foo[[X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]Bar[F,X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]] - required: Foo[[X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]Bar[[X]Or[String,X],X(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)(in type L)]] + found : [F[_]]Foo[[X(in type L)]Bar[F,X(in type L)]] + required: Foo[[X(in type L)]Bar[[X]Or[String,X],X(in type L)]] barFoo(null) : Foo[({type L[X] = Bar[StringOr, X]})#L] ^ two errors found diff --git a/test/files/neg/t8777.check b/test/files/neg/t8777.check new file mode 100644 index 0000000000..cd05f1ec11 --- /dev/null +++ b/test/files/neg/t8777.check @@ -0,0 +1,6 @@ +t8777.scala:3: error: type mismatch; + found : Foo.this.TreePrinter(in trait Printers) + required: Foo.this.TreePrinter(in trait Printers) + super.newCodePrinter(out, tree, printRootPkg) + ^ +one error found diff --git a/test/files/neg/t8777.scala b/test/files/neg/t8777.scala new file mode 100644 index 0000000000..5b7d123202 --- /dev/null +++ b/test/files/neg/t8777.scala @@ -0,0 +1,4 @@ +trait Foo extends scala.tools.nsc.Global { + override def newCodePrinter(out: java.io.PrintWriter, tree: Tree, printRootPkg: Boolean): TreePrinter = + super.newCodePrinter(out, tree, printRootPkg) +} -- cgit v1.2.3 From 4a61719c1a3b57b47aa65409e83b87cff39145d3 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 21 Jun 2015 06:53:38 +1000 Subject: SI-8892 Fix incorrect qualification in error message Since beadafa2, we've ended up with nutty error messages for type errors involving aliases that target types in `java.lang` and `scala` packages. I think the intent of that change was to force the error messages to qualify types like `String` when needed, but to leave them unqualified by default. However, this led to this flat out wrong message in the enclosed test. found : B required: C.this.java.lang.B (which expands to) String I've changed the heuristic slightly limit this code to aliases that are eponymous with their targets. Still feels pretty kludgy, but we can at least book a little progress. --- src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala | 2 +- test/files/neg/t8892.check | 7 +++++++ test/files/neg/t8892.scala | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/t8892.check create mode 100644 test/files/neg/t8892.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 65dea3178b..5f2643cb25 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -318,7 +318,7 @@ trait TypeDiagnostics { */ def qualifyDefaultNamespaces() = { val intersect = Set(trueOwner, aliasOwner) intersect UnqualifiedOwners - if (intersect.nonEmpty) preQualify() + if (intersect.nonEmpty && tp.typeSymbolDirect.name == tp.typeSymbol.name) preQualify() } // functions to manipulate the name diff --git a/test/files/neg/t8892.check b/test/files/neg/t8892.check new file mode 100644 index 0000000000..5930be58c5 --- /dev/null +++ b/test/files/neg/t8892.check @@ -0,0 +1,7 @@ +t8892.scala:2: error: type mismatch; + found : B + required: C.this.B + (which expands to) String +class C[B](x: B) extends A { def f: B = x } + ^ +one error found diff --git a/test/files/neg/t8892.scala b/test/files/neg/t8892.scala new file mode 100644 index 0000000000..f857e6f115 --- /dev/null +++ b/test/files/neg/t8892.scala @@ -0,0 +1,2 @@ +trait A { type B = String } +class C[B](x: B) extends A { def f: B = x } -- cgit v1.2.3