From 6a3aab8241cc5379bcffb7644bdbaa04ba12ce5b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Apr 2015 18:04:09 +0200 Subject: Allow byname repated parameters Implements #499 --- src/dotty/tools/dotc/ast/Desugar.scala | 7 ++++++- src/dotty/tools/dotc/ast/TreeInfo.scala | 9 +++++---- src/dotty/tools/dotc/core/TypeApplications.scala | 17 +++++++++++------ src/dotty/tools/dotc/core/Types.scala | 6 ++++-- src/dotty/tools/dotc/parsing/Parsers.scala | 22 +++++++++++++--------- src/dotty/tools/dotc/typer/Applications.scala | 7 +++++-- 6 files changed, 44 insertions(+), 24 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 0c13d1ecc..f7904abc0 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -289,8 +289,13 @@ object desugar { val caseParams = constrVparamss.head.toArray val productElemMeths = for (i <- 0 until arity) yield syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeName), caseParams(i).name)) + def isRepeated(tree: Tree): Boolean = tree match { + case PostfixOp(_, nme.raw.STAR) => true + case ByNameTypeTree(tree1) => isRepeated(tree1) + case _ => false + } val hasRepeatedParam = constrVparamss.exists(_.exists { - case ValDef(_, PostfixOp(_, nme.raw.STAR), _) => true + case ValDef(_, tpt, _) => isRepeated(tpt) case _ => false }) val copyMeths = diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index a7f89337c..1ba7acb48 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -160,11 +160,12 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => case _ => Nil } - /** Is tpt a vararg type of the form T* ? */ - def isRepeatedParamType(tpt: Tree)(implicit ctx: Context) = tpt match { + /** Is tpt a vararg type of the form T* or => T*? */ + def isRepeatedParamType(tpt: Tree)(implicit ctx: Context): Boolean = tpt match { + case ByNameTypeTree(tpt1) => isRepeatedParamType(tpt1) case tpt: TypeTree => tpt.typeOpt.isRepeatedParam - case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS), _) => true - case _ => false + case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS), _) => true + case _ => false } /** Is name a left-associative operator? */ diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index de42b3e5f..a5e24c5ff 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -279,15 +279,20 @@ class TypeApplications(val self: Type) extends AnyVal { default } } - + /** Translate a type of the form From[T] to To[T], keep other types as they are. * `from` and `to` must be static classes, both with one type parameter, and the same variance. + * Do the same for by name types => From[T] and => To[T] */ - def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type = - if (self.derivesFrom(from)) - if (ctx.erasedTypes) to.typeRef - else RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info) - else self + def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type = self match { + case self @ ExprType(tp) => + self.derivedExprType(tp.translateParameterized(from, to)) + case _ => + if (self.derivesFrom(from)) + if (ctx.erasedTypes) to.typeRef + else RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info) + else self + } /** If this is repeated parameter type, its underlying Seq type, * or, if isJava is true, Array type, else the type itself. diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index e290e8868..595732b37 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2066,14 +2066,16 @@ object Types { def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType) def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = { - def paramInfo(param: Symbol): Type = param.info match { + def translateRepeated(tp: Type): Type = tp match { + case tp @ ExprType(tp1) => tp.derivedExprType(translateRepeated(tp1)) case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot => - val typeSym = param.info.typeSymbol.asClass + val typeSym = tp.typeSymbol.asClass assert(typeSym == defn.SeqClass || typeSym == defn.ArrayClass) tp.translateParameterized(typeSym, defn.RepeatedParamClass) case tp => tp } + def paramInfo(param: Symbol): Type = translateRepeated(param.info) def transformResult(mt: MethodType) = resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _))) apply(params map (_.name.asTermName), params map paramInfo)(transformResult _) diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index cbefb81fe..dd2c9bcaa 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -754,17 +754,21 @@ object Parsers { if (in.token == ARROW) atPos(in.skipToken()) { ByNameTypeTree(argType()) } else argType() - /** ParamType ::= FunArgType | ArgType `*' + /** ParamType ::= [`=>'] ParamValueType */ def paramType(): Tree = - if (in.token == ARROW) funArgType() - else { - val t = argType() - if (isIdent(nme.raw.STAR)) { - in.nextToken() - atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) } - } else t - } + if (in.token == ARROW) atPos(in.skipToken()) { ByNameTypeTree(paramValueType()) } + else paramValueType() + + /** ParamValueType ::= Type [`*'] + */ + def paramValueType(): Tree = { + val t = typ() + if (isIdent(nme.raw.STAR)) { + in.nextToken() + atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) } + } else t + } /** TypeArgs ::= `[' ArgType {`,' ArgType} `]' */ diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index c5bd70c1e..dd30c45c0 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -330,7 +330,7 @@ trait Applications extends Compatibility { self: Typer => case arg :: Nil if isVarArg(arg) => addTyped(arg, formal) case _ => - val elemFormal = formal.argTypesLo.head + val elemFormal = formal.widenExpr.argTypesLo.head args foreach (addTyped(_, elemFormal)) makeVarArg(args.length, elemFormal) } @@ -842,7 +842,10 @@ trait Applications extends Compatibility { self: Typer => val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, tp1.instantiateBounds) isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2) case tp1: MethodType => - def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp + def repeatedToSingle(tp: Type): Type = tp match { + case tp @ ExprType(tp1) => tp.derivedExprType(repeatedToSingle(tp1)) + case _ => if (tp.isRepeatedParam) tp.argTypesHi.head else tp + } isApplicable(alt2, tp1.paramTypes map repeatedToSingle, WildcardType) || tp1.paramTypes.isEmpty && tp2.isInstanceOf[MethodOrPoly] case _ => -- cgit v1.2.3