aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-12-31 10:36:42 +0100
committerMartin Odersky <odersky@gmail.com>2013-12-31 11:44:17 +0100
commit3edab6ec1444b19203381612fba3e16ca1bafc95 (patch)
tree7e1985909b62c47004aeb29017bc05375eeba39d
parent4a175b13e4fcefc7cb3cf70da254205a14dc2418 (diff)
downloaddotty-3edab6ec1444b19203381612fba3e16ca1bafc95.tar.gz
dotty-3edab6ec1444b19203381612fba3e16ca1bafc95.tar.bz2
dotty-3edab6ec1444b19203381612fba3e16ca1bafc95.zip
Upgrades to handle subtyping between parameterized and higher-kinded types.
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala29
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala8
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala6
-rw-r--r--tests/pos/hk.scala35
4 files changed, 68 insertions, 10 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 5dbfc894d..7e04a2812 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -249,7 +249,10 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp1: PolyParam =>
(tp1 == tp2) ||
isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
- assert(frozenConstraint || !(tp2 isRef defn.NothingClass)) // !!!DEBUG
+ if (!frozenConstraint &&
+ (tp2 isRef defn.NothingClass) &&
+ ctx.typerState.isGlobalCommittable)
+ ctx.log(s"!!! instantiating to Nothing: $tp1")
if (constraint contains tp1) addConstraint(tp1, tp2.dealias, fromBelow = false)
else thirdTry(tp1, tp2)
}
@@ -287,12 +290,12 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: NamedType =>
thirdTryNamed(tp1, tp2)
case tp2 @ RefinedType(parent2, name2) =>
- tp1 match {
- case tp1 @ RefinedType(parent1, name1) if (name1 == name2) && name1.isTypeName =>
+ tp1.widen match {
+ case tp1 @ RefinedType(parent1, name1) if nameMatches(name1, name2, tp1, tp2) =>
// optimized case; all info on tp1.name2 is in refinement tp1.refinedInfo.
isSubType(tp1, parent2) && isSubType(tp1.refinedInfo, tp2.refinedInfo)
case _ =>
- def hasMatchingMember(name: Name): Boolean = traceIndented(s"hasMatchingMember($name)") (
+ def hasMatchingMember(name: Name): Boolean = traceIndented(s"hasMatchingMember($name) ${tp1.member(name)}") (
tp1.member(name).hasAltWith(alt => isSubType(alt.info, tp2.refinedInfo))
||
{ // special case for situations like:
@@ -408,6 +411,24 @@ class TypeComparer(initctx: Context) extends DotClass {
case _ => proto.isMatchedBy(tp)
}
+ /** Tow refinement names match if they are the same or one is the
+ * name of a type parameter of its parent type, and the other is
+ * the corresponding higher-kinded parameter name
+ */
+ private def nameMatches(name1: Name, name2: Name, tp1: Type, tp2: Type) =
+ name1.isTypeName &&
+ (name1 == name2 || isHKAlias(name1, name2, tp2) || isHKAlias(name2, name1, tp1))
+
+ /** Is name1 a higher-kinded parameter name and name2 a corresponding
+ * type parameter name?
+ */
+ private def isHKAlias(name1: Name, name2: Name, tp2: Type) =
+ name1.isHkParamName && {
+ val i = name1.hkParamIndex
+ val tparams = tp2.safeUnderlyingTypeParams
+ i < tparams.length && tparams(i).name == name2
+ }
+
/** Can type `tp` be constrained from above by adding a constraint to
* a typevar that it refers to? In that case we have to be careful not
* to approximate with the lower bound of a type in `thridTryNamed`. Instead,
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index b3c70c3d4..52006bd74 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -260,16 +260,16 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
case tree @ TypeDef(mods, name, rhs) =>
atOwner(tree) {
- def typeDefText(rhsText: Text) =
- modText(mods, "type") ~~ toText(name) ~ tparamsText(tree.tparams) ~ rhsText
+ def typeDefText(rhsText: Text) = {
+ val rhsText1 = if (tree.hasType) toText(tree.symbol.info) else rhsText
+ modText(mods, "type") ~~ toText(name) ~ tparamsText(tree.tparams) ~ rhsText1
+ }
rhs match {
case impl: Template =>
modText(mods, if (mods is Trait) "trait" else "class") ~~ toText(name) ~ toText(impl) ~
(if (tree.hasType && ctx.settings.verbose.value) s"[decls = ${tree.symbol.info.decls}]" else "")
case rhs: TypeBoundsTree =>
typeDefText(toText(rhs))
- case rhs: TypeTree =>
- typeDefText(toText(rhs))
case _ =>
typeDefText(optText(rhs)(" = " ~ _))
}
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 25006d72f..978c9965d 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -492,8 +492,10 @@ class Namer { typer: Typer =>
if (tparamSyms.nonEmpty) bounds.higherKinded(tparamSyms)
else rhsType
case _ =>
- if (tparamSyms.nonEmpty) rhsType.LambdaAbstract(tparamSyms)(ctx.error(_, _))
- else TypeAlias(rhsType, if (sym is Local) sym.variance else 0)
+ val abstractedRhsType =
+ if (tparamSyms.nonEmpty) rhsType.LambdaAbstract(tparamSyms)(ctx.error(_, _))
+ else rhsType
+ TypeAlias(abstractedRhsType, if (sym is Local) sym.variance else 0)
}
}
} \ No newline at end of file
diff --git a/tests/pos/hk.scala b/tests/pos/hk.scala
new file mode 100644
index 000000000..f2f10bbfb
--- /dev/null
+++ b/tests/pos/hk.scala
@@ -0,0 +1,35 @@
+import language.higherKinds
+
+object higherKinded {
+
+ type Untyped = Null
+
+ class Tree[-T >: Untyped] {
+ type ThisType[-U >: Untyped] <: Tree[U]
+ def withString(s: String): ThisType[String] = withString(s)
+ }
+
+ class Ident[-T >: Untyped] extends Tree[T] {
+ type ThisType[-U] = Ident[U]
+ }
+
+ val id = new Ident[Integer]
+
+ val y = id.withString("abc")
+
+ val z: Ident[String] = y
+
+ val zz: tpd.Tree = y
+
+ abstract class Instance[T >: Untyped] {
+ type Tree = higherKinded.Tree[T]
+ }
+
+ object tpd extends Instance[String]
+
+ def transform(tree: Tree[String]) = {
+ val tree1 = tree.withString("")
+ tree1: Tree[String]
+ }
+
+} \ No newline at end of file