aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Blanvillain <olivier.blanvillain@gmail.com>2016-09-15 16:59:40 +0200
committerOlivier Blanvillain <olivier.blanvillain@gmail.com>2016-09-15 17:03:09 +0200
commit5450507c663bca565b2b61b8afb1073c991c9827 (patch)
tree034fa122e9ef517626a5b54e3a9f954a08bd9a97
parent3f3df3d8f7638eb5cca9ae8162f8388373c912c6 (diff)
downloaddotty-5450507c663bca565b2b61b8afb1073c991c9827.tar.gz
dotty-5450507c663bca565b2b61b8afb1073c991c9827.tar.bz2
dotty-5450507c663bca565b2b61b8afb1073c991c9827.zip
Fix #1513: misaligned by name type parameter type bounds
-rw-r--r--src/dotty/tools/dotc/core/Types.scala4
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala32
-rw-r--r--tests/pos/t1513a.scala36
-rw-r--r--tests/pos/t1513b.scala16
4 files changed, 75 insertions, 13 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 87d94dcbe..cb423e186 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -2532,8 +2532,8 @@ object Types {
/** A type for polymorphic methods */
class PolyType(val paramNames: List[TypeName])(paramBoundsExp: GenericType => List[TypeBounds], resultTypeExp: GenericType => Type)
extends CachedGroundType with GenericType with MethodOrPoly {
- val paramBounds = paramBoundsExp(this)
- val resType = resultTypeExp(this)
+ val paramBounds: List[TypeBounds] = paramBoundsExp(this)
+ val resType: Type = resultTypeExp(this)
def variances = Nil
protected def computeSignature(implicit ctx: Context) = resultSignature
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 36404a68f..3266a38d1 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -321,21 +321,30 @@ trait TypeAssigner {
case pt: PolyType =>
val paramNames = pt.paramNames
if (hasNamedArg(args)) {
- val argMap = new mutable.HashMap[Name, Type]
+ // Type arguments which are specified by name (immutable after this first loop)
+ val namedArgMap = new mutable.HashMap[Name, Type]
for (NamedArg(name, arg) <- args)
- if (argMap.contains(name))
+ if (namedArgMap.contains(name))
ctx.error("duplicate name", arg.pos)
else if (!paramNames.contains(name))
ctx.error(s"undefined parameter name, required: ${paramNames.mkString(" or ")}", arg.pos)
else
- argMap(name) = arg.tpe
+ namedArgMap(name) = arg.tpe
+
+ // Holds indexes of non-named typed arguments in paramNames
val gapBuf = new mutable.ListBuffer[Int]
- def nextPoly = {
- val idx = gapBuf.length
+ def nextPoly(idx: Int) = {
+ val newIndex = gapBuf.length
gapBuf += idx
- PolyParam(pt, idx)
+ // Re-index unassigned type arguments that remain after transformation
+ PolyParam(pt, newIndex)
+ }
+
+ // Type parameters after naming assignment, conserving paramNames order
+ val normArgs: List[Type] = paramNames.zipWithIndex.map { case (pname, idx) =>
+ namedArgMap.getOrElse(pname, nextPoly(idx))
}
- val normArgs = paramNames.map(pname => argMap.getOrElse(pname, nextPoly))
+
val transform = new TypeMap {
def apply(t: Type) = t match {
case PolyParam(`pt`, idx) => normArgs(idx)
@@ -347,19 +356,20 @@ trait TypeAssigner {
else {
val gaps = gapBuf.toList
pt.derivedPolyType(
- gaps.map(paramNames.filterNot(argMap.contains)),
+ gaps.map(paramNames),
gaps.map(idx => transform(pt.paramBounds(idx)).bounds),
resultType1)
}
}
else {
val argTypes = args.tpes
- if (sameLength(argTypes, paramNames)|| ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes)
+ if (sameLength(argTypes, paramNames) || ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes)
else wrongNumberOfArgs(fn.tpe, "type ", pt.paramNames.length, tree.pos)
}
case _ =>
errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos)
}
+
tree.withType(ownType)
}
@@ -383,8 +393,8 @@ trait TypeAssigner {
def assignType(tree: untpd.Closure, meth: Tree, target: Tree)(implicit ctx: Context) =
tree.withType(
- if (target.isEmpty) meth.tpe.widen.toFunctionType(tree.env.length)
- else target.tpe)
+ if (target.isEmpty) meth.tpe.widen.toFunctionType(tree.env.length)
+ else target.tpe)
def assignType(tree: untpd.CaseDef, body: Tree)(implicit ctx: Context) =
tree.withType(body.tpe)
diff --git a/tests/pos/t1513a.scala b/tests/pos/t1513a.scala
new file mode 100644
index 000000000..3c4c02376
--- /dev/null
+++ b/tests/pos/t1513a.scala
@@ -0,0 +1,36 @@
+object Test {
+ // Heterogeneous lists and natural numbers as defined in shapeless.
+
+ sealed trait HList
+ sealed trait ::[H, T <: HList] extends HList
+ sealed trait HNil extends HList
+
+ sealed trait Nat
+ sealed trait Succ[P <: Nat] extends Nat
+ sealed trait Zero extends Nat
+
+ // Accessor type class to compute the N'th element of an HList L.
+
+ trait Accessor[L <: HList, N <: Nat] { type Out }
+ object Accessor {
+ type Aux[L <: HList, N <: Nat, O] = Accessor[L, N] { type Out = O }
+
+ // (H :: T).At[Zero] = H
+ implicit def caseZero[H, T <: HList]: Aux[H :: T, Zero, H] = ???
+
+ // T.At[N] = O => (H :: T).At[Succ[N]] = O
+ implicit def caseN[H, T <: HList, N <: Nat, O]
+ (implicit a: Aux[T, N, O]): Aux[H :: T, Succ[N], O] = ???
+ }
+
+ case class Proxy[T]()
+
+ def at1[NN <: Nat, OO] (implicit e: Accessor.Aux[String :: HNil, NN, OO]): OO = ???
+ def at2[NN <: Nat, OO](p: Proxy[NN])(implicit e: Accessor.Aux[String :: HNil, NN, OO]): OO = ???
+
+ // N is fixed by a value
+ at2(Proxy[Zero]): String
+
+ // N is fixed as a type parameter (by name)
+ at1[NN = Zero]: String
+}
diff --git a/tests/pos/t1513b.scala b/tests/pos/t1513b.scala
new file mode 100644
index 000000000..881187be0
--- /dev/null
+++ b/tests/pos/t1513b.scala
@@ -0,0 +1,16 @@
+object Test {
+ def f[T1 <: String, T2 <: Int, T3 <: Boolean](a1: T1, a2: T2, a3: T3) = ()
+
+ f ("", 1, true)
+ f[T1 = String] ("", 1, true)
+ f[T2 = Int] ("", 1, true)
+ f[T3 = Boolean] ("", 1, true)
+ f[T1 = String, T2 = Int] ("", 1, true)
+ f[T1 = String, T3 = Boolean] ("", 1, true)
+ f[T2 = Int, T1 = String] ("", 1, true)
+ f[T2 = Int, T3 = Boolean] ("", 1, true)
+ f[T3 = Boolean, T2 = Int] ("", 1, true)
+ f[T3 = Boolean, T1 = String] ("", 1, true)
+ f[T1 = String, T2 = Int, T3 = Boolean]("", 1, true)
+ f[String, Int, Boolean] ("", 1, true)
+}