From 17469b82ca7afc5376bc3906bb5b64d10f38a100 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 14 Feb 2017 16:38:48 +0100 Subject: [PATCH 1/6] Tweak printing of polymrophic methods Omit the `=>' if a PolyType has a MethodType as result type. --- compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala | 3 ++- tests/neg/i1747.scala | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i1747.scala diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index ac25f7cfdf4b..1c3ff8ea063a 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -177,7 +177,8 @@ class PlainPrinter(_ctx: Context) extends Printer { varianceString(variance) ~ name.toString ~ toText(bounds) changePrec(GlobalPrec) { "[" ~ Text((tp.variances, tp.paramNames, tp.paramBounds).zipped.map(paramText), ", ") ~ - "] => " ~ toTextGlobal(tp.resultType) + "]" ~ (" => " provided !tp.resultType.isInstanceOf[MethodType]) ~ + toTextGlobal(tp.resultType) } case tp: PolyParam => polyParamNameString(tp) ~ polyHash(tp.binder) diff --git a/tests/neg/i1747.scala b/tests/neg/i1747.scala new file mode 100644 index 000000000000..9675de992cb3 --- /dev/null +++ b/tests/neg/i1747.scala @@ -0,0 +1,3 @@ +class Coll[E] extends java.util.Collection[E] { + def toArray[T](a: Array[T]): Array[T] = ??? // error: cannot override +} From b89738672662863168453a1bd6c6c47a6ff07f11 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 14 Feb 2017 16:53:41 +0100 Subject: [PATCH 2/6] Avoid automatism for passing variances to PolyTypes We used to "fill-in" with zeroes if variances were missing. I now think that;'s too error-prone. Better define all variances explicitly. --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 3 ++- compiler/src/dotty/tools/dotc/core/Types.scala | 7 +++---- .../dotty/tools/dotc/transform/FullParameterization.scala | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 2797bb8a6211..c61e92f3a111 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -9,6 +9,7 @@ import scala.annotation.{ switch, meta } import scala.collection.{ mutable, immutable } import PartialFunction._ import collection.mutable +import util.common.alwaysZero import scala.reflect.api.{ Universe => ApiUniverse } object Definitions { @@ -152,7 +153,7 @@ class Definitions { resultTypeFn: PolyType => Type, flags: FlagSet = EmptyFlags) = { val tparamNames = tpnme.syntheticTypeParamNames(typeParamCount) val tparamBounds = tparamNames map (_ => TypeBounds.empty) - val ptype = PolyType(tparamNames)(_ => tparamBounds, resultTypeFn) + val ptype = PolyType(tparamNames, tparamNames.map(alwaysZero))(_ => tparamBounds, resultTypeFn) enterMethod(cls, name, ptype, flags) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ae91228538db..1174e863e637 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2603,7 +2603,7 @@ object Types { case t => mapOver(t) } } - PolyType(paramNames ++ that.paramNames)( + PolyType(paramNames ++ that.paramNames, variances ++ that.variances)( x => this.paramBounds.mapConserve(_.subst(this, x).bounds) ++ that.paramBounds.mapConserve(shift(_).subst(that, x).bounds), x => shift(that.resultType).subst(that, x).subst(this, x)) @@ -2634,11 +2634,10 @@ object Types { } object PolyType { - def apply(paramNames: List[TypeName], variances: List[Int] = Nil)( + def apply(paramNames: List[TypeName], variances: List[Int])( paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)(implicit ctx: Context): PolyType = { - val vs = if (variances.isEmpty) paramNames.map(alwaysZero) else variances - unique(new PolyType(paramNames, vs)(paramBoundsExp, resultTypeExp)) + unique(new PolyType(paramNames, variances)(paramBoundsExp, resultTypeExp)) } def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] = diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index 6c69c735bde7..9e43fc999971 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -101,6 +101,7 @@ trait FullParameterization { } val ctparams = if (abstractOverClass) clazz.typeParams else Nil val ctnames = ctparams.map(_.name.unexpandedName) + val ctvariances = ctparams.map(_.variance) /** The method result type */ def resultType(mapClassParams: Type => Type) = { @@ -122,14 +123,14 @@ trait FullParameterization { info match { case info: PolyType => - PolyType(info.paramNames ++ ctnames)( + PolyType(info.paramNames ++ ctnames, info.variances ++ ctvariances)( pt => (info.paramBounds.map(mapClassParams(_, pt).bounds) ++ mappedClassBounds(pt)).mapConserve(_.subst(info, pt).bounds), pt => resultType(mapClassParams(_, pt)).subst(info, pt)) case _ => if (ctparams.isEmpty) resultType(identity) - else PolyType(ctnames)(mappedClassBounds, pt => resultType(mapClassParams(_, pt))) + else PolyType(ctnames, ctvariances)(mappedClassBounds, pt => resultType(mapClassParams(_, pt))) } } From ef383a8a05547432c01d779976a4ea4ca2dffab9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 14 Feb 2017 18:03:25 +0100 Subject: [PATCH 3/6] Better error message for Java/Scala method discrepancies --- .../dotty/tools/dotc/typer/ErrorReporting.scala | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 1238ad5687b1..9d6a01ab7373 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -111,11 +111,23 @@ object ErrorReporting { errorTree(tree, typeMismatchMsg(normalize(tree.tpe, pt), pt, implicitFailure.postscript)) /** A subtype log explaining why `found` does not conform to `expected` */ - def whyNoMatchStr(found: Type, expected: Type) = - if (ctx.settings.explaintypes.value) + def whyNoMatchStr(found: Type, expected: Type) = { + def dropJavaMethod(tp: Type): Type = tp match { + case tp: PolyType => + tp.derivedPolyType(resType = dropJavaMethod(tp.resultType)) + case tp: JavaMethodType => + MethodType(tp.paramNames, tp.paramTypes, dropJavaMethod(tp.resultType)) + case tp => tp + } + val found1 = dropJavaMethod(found) + val expected1 = dropJavaMethod(expected) + if ((found1 eq found) != (expected eq expected1) && (found1 <:< expected1)) + "\n (Note that Scala's and Java's representation of this type differs)" + else if (ctx.settings.explaintypes.value) "\n" + ctx.typerState.show + "\n" + TypeComparer.explained((found <:< expected)(_)) else "" + } def typeMismatchMsg(found: Type, expected: Type, postScript: String = "") = { // replace constrained polyparams and their typevars by their bounds where possible From aa561a034cb9205d05737a602dc2268ec798fa53 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 15 Feb 2017 14:41:02 +0100 Subject: [PATCH 4/6] Fix test case --- tests/neg/i1747.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neg/i1747.scala b/tests/neg/i1747.scala index 9675de992cb3..b35e364fad61 100644 --- a/tests/neg/i1747.scala +++ b/tests/neg/i1747.scala @@ -1,3 +1,3 @@ class Coll[E] extends java.util.Collection[E] { - def toArray[T](a: Array[T]): Array[T] = ??? // error: cannot override + def toArray[T](a: Array[T]): Array[T] = ??? // error: cannot override // error } From 506d17c7652e5dbb94631e9537b0e76ac53dee96 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 15 Feb 2017 14:41:24 +0100 Subject: [PATCH 5/6] Unrelated cleanup: Make SearchResult sealed. --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6949221fb7f0..48cf0cface76 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -220,7 +220,7 @@ object Implicits { } /** The result of an implicit search */ - abstract class SearchResult extends Showable { + sealed abstract class SearchResult extends Showable { def toText(printer: Printer): Text = printer.toText(this) } From 779eaf6b9898e4ec8e2e3cdfbf0d36aeede3926e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 15 Feb 2017 16:11:20 +0100 Subject: [PATCH 6/6] Fix test case^2 --- tests/neg/i1747.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/neg/i1747.scala b/tests/neg/i1747.scala index b35e364fad61..54492aaed393 100644 --- a/tests/neg/i1747.scala +++ b/tests/neg/i1747.scala @@ -1,3 +1,3 @@ -class Coll[E] extends java.util.Collection[E] { - def toArray[T](a: Array[T]): Array[T] = ??? // error: cannot override // error +class Coll[E] extends java.util.Collection[E] { // error: needs to be abstract + def toArray[T](a: Array[T]): Array[T] = ??? // error: cannot override }