From 8441de7a907996361a78d744d3364cee3d558f84 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 29 Jan 2016 21:48:55 +0100 Subject: Allow Named Arguments in TypeArgs Lets one also pass named arguments to methods. --- src/dotty/tools/dotc/typer/Applications.scala | 11 +++++-- src/dotty/tools/dotc/typer/TypeAssigner.scala | 44 ++++++++++++++++++++++++--- src/dotty/tools/dotc/typer/Typer.scala | 6 +--- 3 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src/dotty/tools/dotc/typer') diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index c7acd3c1f..098385d4b 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -603,12 +603,19 @@ trait Applications extends Compatibility { self: Typer => protected def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree = throw new Error(s"unexpected type.\n fun = $fun,\n methPart(fun) = ${methPart(fun)},\n methPart(fun).tpe = ${methPart(fun).tpe},\n tpe = ${fun.tpe}") + def typedNamedArgs(args: List[untpd.Tree])(implicit ctx: Context) = + for (arg @ NamedArg(id, argtpt) <- args) yield { + val argtpt1 = typedType(argtpt) + cpy.NamedArg(arg)(id, argtpt1).withType(argtpt1.tpe) + } + def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") { - var typedArgs = tree.args mapconserve (typedType(_)) + val isNamed = hasNamedArg(tree.args) + var typedArgs = if (isNamed) typedNamedArgs(tree.args) else tree.args.mapconserve(typedType(_)) val typedFn = typedExpr(tree.fun, PolyProto(typedArgs.tpes, pt)) typedFn.tpe.widen match { case pt: PolyType => - if (typedArgs.length <= pt.paramBounds.length) + if (typedArgs.length <= pt.paramBounds.length && !isNamed) typedArgs = typedArgs.zipWithConserve(pt.paramBounds)(adaptTypeArg) case _ => } diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 9ee67684d..1c66414a1 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -8,7 +8,8 @@ import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._ import util.Positions._ import config.Printers._ -import NameOps._ +import ast.Trees._ +import collection.mutable trait TypeAssigner { import tpd._ @@ -310,9 +311,44 @@ trait TypeAssigner { def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(implicit ctx: Context) = { val ownType = fn.tpe.widen match { case pt: PolyType => - val argTypes = args.tpes - if (sameLength(argTypes, pt.paramNames)|| ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes) - else errorType(d"wrong number of type parameters for ${fn.tpe}; expected: ${pt.paramNames.length}", tree.pos) + val paramNames = pt.paramNames + if (hasNamedArg(args)) { + val argMap = new mutable.HashMap[Name, Type] + for (NamedArg(name, arg) <- args) + if (argMap.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 + val gapBuf = new mutable.ListBuffer[Int] + def nextPoly = { + val idx = gapBuf.length + gapBuf += idx + PolyParam(pt, 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) + case _ => mapOver(t) + } + } + val resultType1 = transform(pt.resultType) + if (gapBuf.isEmpty) resultType1 + else { + val gaps = gapBuf.toList + pt.derivedPolyType( + gaps.map(paramNames.filterNot(argMap.contains)), + 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) + else errorType(d"wrong number of type parameters for ${fn.tpe}; expected: ${pt.paramNames.length}", tree.pos) + } case _ => errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 0ff2241fb..fc2bf2381 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -893,11 +893,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit else { var args = tree.args val args1 = - if (hasNamedArg(args)) - for (arg @ NamedArg(id, argtpt) <- args) yield { - val argtpt1 = typedType(argtpt) - cpy.NamedArg(arg)(id, argtpt1).withType(argtpt1.tpe) - } + if (hasNamedArg(args)) typedNamedArgs(args) else { if (args.length != tparams.length) { ctx.error(d"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}", tree.pos) -- cgit v1.2.3