diff options
author | Martin Odersky <odersky@gmail.com> | 2013-12-31 10:36:42 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-12-31 11:44:17 +0100 |
commit | 3edab6ec1444b19203381612fba3e16ca1bafc95 (patch) | |
tree | 7e1985909b62c47004aeb29017bc05375eeba39d | |
parent | 4a175b13e4fcefc7cb3cf70da254205a14dc2418 (diff) | |
download | dotty-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.scala | 29 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 6 | ||||
-rw-r--r-- | tests/pos/hk.scala | 35 |
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 |