aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala59
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala12
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala2
5 files changed, 48 insertions, 29 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index b2f22da20..f7727779d 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -167,11 +167,11 @@ object TypeApplications {
}
}
- /** Adapt all arguments to possible higher-kinded type parameters using adaptIfHK
+ /** Adapt all arguments to possible higher-kinded type parameters using etaExpandIfHK
*/
- def adaptArgs(tparams: List[Symbol], args: List[Type])(implicit ctx: Context): List[Type] =
+ def etaExpandIfHK(tparams: List[Symbol], args: List[Type])(implicit ctx: Context): List[Type] =
if (tparams.isEmpty) args
- else args.zipWithConserve(tparams)((arg, tparam) => arg.adaptIfHK(tparam.infoOrCompleter))
+ else args.zipWithConserve(tparams)((arg, tparam) => arg.etaExpandIfHK(tparam.infoOrCompleter))
def argRefs(rt: RefinedType, n: Int)(implicit ctx: Context) =
List.range(0, n).map(i => RefinedThis(rt).select(tpnme.hkArg(i)))
@@ -340,11 +340,21 @@ class TypeApplications(val self: Type) extends AnyVal {
self.EtaExpand(self.typeParams)
}
- /** Adapt argument A to type parameter P in the case P is higher-kinded.
- * This means:
- * (1) Make sure that A is a type lambda, if necessary by eta-expanding it.
- * (2) Make sure the variances of the type lambda
- * agrees with variances of corresponding higherkinded type parameters. Example:
+ /** Eta expand if `self` is a (non-lambda) class reference and `bound` is a higher-kinded type */
+ def etaExpandIfHK(bound: Type)(implicit ctx: Context): Type = {
+ val boundLambda = bound.LambdaTrait
+ val hkParams = boundLambda.typeParams
+ if (hkParams.isEmpty) self
+ else self match {
+ case self: TypeRef if self.symbol.isClass && self.typeParams.length == hkParams.length =>
+ EtaExpansion(self)
+ case _ => self
+ }
+ }
+
+ /** If argument A and type parameter P are higher-kinded, adapt the variances
+ * of A to those of P, ensuring that the variances of the type lambda A
+ * agree with the variances of corresponding higherkinded type parameters of P. Example:
*
* class Companion[+CC[X]]
* Companion[List]
@@ -367,25 +377,26 @@ class TypeApplications(val self: Type) extends AnyVal {
* and the second is not a subtype of the first. So if we have overridding memebrs of the two
* types we get an error.
*/
- def adaptIfHK(bound: Type)(implicit ctx: Context): Type = {
+ def adaptHkVariances(bound: Type)(implicit ctx: Context): Type = {
val boundLambda = bound.LambdaTrait
val hkParams = boundLambda.typeParams
if (hkParams.isEmpty) self
- else self match {
- case self: TypeRef if self.symbol.isClass && self.typeParams.length == hkParams.length =>
- EtaExpansion(self).adaptIfHK(bound)
- case _ =>
- def adaptArg(arg: Type): Type = arg match {
- case arg: TypeRef
- if arg.symbol.isLambdaTrait &&
- !arg.symbol.typeParams.corresponds(boundLambda.typeParams)(_.variance == _.variance) =>
- arg.prefix.select(boundLambda)
- case arg: RefinedType =>
- arg.derivedRefinedType(adaptArg(arg.parent), arg.refinedName, arg.refinedInfo)
- case _ =>
- arg
- }
- adaptArg(self)
+ else {
+ def adaptArg(arg: Type): Type = arg match {
+ case arg: TypeRef if arg.symbol.isLambdaTrait &&
+ !arg.symbol.typeParams.corresponds(hkParams)(_.variance == _.variance) &&
+ arg.symbol.typeParams.corresponds(hkParams)(varianceConforms) =>
+ arg.prefix.select(boundLambda)
+ case arg: RefinedType =>
+ arg.derivedRefinedType(adaptArg(arg.parent), arg.refinedName, arg.refinedInfo)
+ case arg @ TypeAlias(alias) =>
+ arg.derivedTypeAlias(adaptArg(alias))
+ case arg @ TypeBounds(lo, hi) =>
+ arg.derivedTypeBounds(lo, adaptArg(hi))
+ case _ =>
+ arg
+ }
+ adaptArg(self)
}
}
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index bf82bfe09..14b5a403c 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -703,11 +703,19 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* Further, no refinement refers back to the refined type via a refined this.
* The precondition is established by `skipMatching`.
*/
- private def isSubRefinements(tp1: RefinedType, tp2: RefinedType, limit: Type): Boolean =
- isSubType(tp1.refinedInfo, tp2.refinedInfo) && (
+ private def isSubRefinements(tp1: RefinedType, tp2: RefinedType, limit: Type): Boolean = {
+ def hasSubRefinement(tp1: RefinedType, refine2: Type): Boolean = {
+ isSubType(tp1.refinedInfo, refine2) || {
+ // last effort: try to adapt variances of higher-kinded types if this is sound.
+ val adapted2 = refine2.adaptHkVariances(tp1.parent.member(tp1.refinedName).symbol.info)
+ adapted2.ne(refine2) && hasSubRefinement(tp1, adapted2)
+ }
+ }
+ hasSubRefinement(tp1, tp2.refinedInfo) && (
(tp2.parent eq limit) ||
isSubRefinements(
tp1.parent.asInstanceOf[RefinedType], tp2.parent.asInstanceOf[RefinedType], limit))
+ }
/** A type has been covered previously in subtype checking if it
* is some combination of TypeRefs that point to classes, where the
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index b0e31202f..618e3ceea 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -715,7 +715,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
else TypeRef(pre, sym.name.asTypeName)
val args = until(end, readTypeRef)
if (sym == defn.ByNameParamClass2x) ExprType(args.head)
- else if (args.nonEmpty) tycon.safeAppliedTo(adaptArgs(sym.typeParams, args))
+ else if (args.nonEmpty) tycon.safeAppliedTo(etaExpandIfHK(sym.typeParams, args))
else if (sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams)
else tycon
case TYPEBOUNDStpe =>
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index c6053d0fd..941b35d71 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -614,7 +614,7 @@ trait Applications extends Compatibility { self: Typer =>
}
def adaptTypeArg(tree: tpd.Tree, bound: Type)(implicit ctx: Context): tpd.Tree =
- tree.withType(tree.tpe.adaptIfHK(bound))
+ tree.withType(tree.tpe.etaExpandIfHK(bound))
/** Rewrite `new Array[T](....)` trees to calls of newXYZArray methods. */
def convertNewArray(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index fedbc98b8..ca37614bf 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -853,7 +853,7 @@ class Namer { typer: Typer =>
val tycon = tp.withoutArgs(args)
val tycon1 = this(tycon)
val tparams = tycon.typeParams
- val args1 = if (args.length == tparams.length) adaptArgs(tparams, args) else args
+ val args1 = if (args.length == tparams.length) etaExpandIfHK(tparams, args) else args
if ((tycon1 eq tycon) && (args1 eq args)) tp else tycon1.appliedTo(args1)
} else mapOver(tp)
case _ => mapOver(tp)