Skip to content

Commit 275c340

Browse files
committed
Merge pull request #500 from dotty-staging/implement/i499
Implement/i499
2 parents 3392ef7 + be61c78 commit 275c340

File tree

10 files changed

+91
-26
lines changed

10 files changed

+91
-26
lines changed

docs/SyntaxSummary.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ grammar.
112112
ArgTypes ::= ArgType {`,' ArgType}
113113
FunArgType ::= ArgType
114114
| `=>' ArgType PrefixOp(=>, t)
115-
ParamType ::= FunArgType
116-
| Type `*' PostfixOp(t, "*")
115+
ParamType ::= [`=>'] ParamValueType
116+
ParamValueType ::= Type [`*'] PostfixOp(t, "*")
117117
TypeArgs ::= `[' ArgTypes `]' ts
118118
Refinement ::= `{' [Dcl] {semi [Dcl]} `}' ds
119119
TypeBounds ::= [`>:' Type] [`<: Type] | INT TypeBoundsTree(lo, hi)

src/dotty/tools/dotc/ast/Desugar.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,13 @@ object desugar {
289289
val caseParams = constrVparamss.head.toArray
290290
val productElemMeths = for (i <- 0 until arity) yield
291291
syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeName), caseParams(i).name))
292+
def isRepeated(tree: Tree): Boolean = tree match {
293+
case PostfixOp(_, nme.raw.STAR) => true
294+
case ByNameTypeTree(tree1) => isRepeated(tree1)
295+
case _ => false
296+
}
292297
val hasRepeatedParam = constrVparamss.exists(_.exists {
293-
case ValDef(_, PostfixOp(_, nme.raw.STAR), _) => true
298+
case ValDef(_, tpt, _) => isRepeated(tpt)
294299
case _ => false
295300
})
296301
val copyMeths =

src/dotty/tools/dotc/ast/TreeInfo.scala

+5-4
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,12 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
160160
case _ => Nil
161161
}
162162

163-
/** Is tpt a vararg type of the form T* ? */
164-
def isRepeatedParamType(tpt: Tree)(implicit ctx: Context) = tpt match {
163+
/** Is tpt a vararg type of the form T* or => T*? */
164+
def isRepeatedParamType(tpt: Tree)(implicit ctx: Context): Boolean = tpt match {
165+
case ByNameTypeTree(tpt1) => isRepeatedParamType(tpt1)
165166
case tpt: TypeTree => tpt.typeOpt.isRepeatedParam
166-
case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS), _) => true
167-
case _ => false
167+
case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS), _) => true
168+
case _ => false
168169
}
169170

170171
/** Is name a left-associative operator? */

src/dotty/tools/dotc/core/TypeApplications.scala

+10-5
Original file line numberDiff line numberDiff line change
@@ -282,12 +282,17 @@ class TypeApplications(val self: Type) extends AnyVal {
282282

283283
/** Translate a type of the form From[T] to To[T], keep other types as they are.
284284
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
285+
* Do the same for by name types => From[T] and => To[T]
285286
*/
286-
def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type =
287-
if (self.derivesFrom(from))
288-
if (ctx.erasedTypes) to.typeRef
289-
else RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info)
290-
else self
287+
def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type = self match {
288+
case self @ ExprType(tp) =>
289+
self.derivedExprType(tp.translateParameterized(from, to))
290+
case _ =>
291+
if (self.derivesFrom(from))
292+
if (ctx.erasedTypes) to.typeRef
293+
else RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info)
294+
else self
295+
}
291296

292297
/** If this is repeated parameter type, its underlying Seq type,
293298
* or, if isJava is true, Array type, else the type itself.

src/dotty/tools/dotc/core/Types.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -2066,14 +2066,16 @@ object Types {
20662066
def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
20672067
apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType)
20682068
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
2069-
def paramInfo(param: Symbol): Type = param.info match {
2069+
def translateRepeated(tp: Type): Type = tp match {
2070+
case tp @ ExprType(tp1) => tp.derivedExprType(translateRepeated(tp1))
20702071
case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot =>
2071-
val typeSym = param.info.typeSymbol.asClass
2072+
val typeSym = tp.typeSymbol.asClass
20722073
assert(typeSym == defn.SeqClass || typeSym == defn.ArrayClass)
20732074
tp.translateParameterized(typeSym, defn.RepeatedParamClass)
20742075
case tp =>
20752076
tp
20762077
}
2078+
def paramInfo(param: Symbol): Type = translateRepeated(param.info)
20772079
def transformResult(mt: MethodType) =
20782080
resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _)))
20792081
apply(params map (_.name.asTermName), params map paramInfo)(transformResult _)

src/dotty/tools/dotc/parsing/Parsers.scala

+13-9
Original file line numberDiff line numberDiff line change
@@ -754,17 +754,21 @@ object Parsers {
754754
if (in.token == ARROW) atPos(in.skipToken()) { ByNameTypeTree(argType()) }
755755
else argType()
756756

757-
/** ParamType ::= FunArgType | ArgType `*'
757+
/** ParamType ::= [`=>'] ParamValueType
758758
*/
759759
def paramType(): Tree =
760-
if (in.token == ARROW) funArgType()
761-
else {
762-
val t = argType()
763-
if (isIdent(nme.raw.STAR)) {
764-
in.nextToken()
765-
atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) }
766-
} else t
767-
}
760+
if (in.token == ARROW) atPos(in.skipToken()) { ByNameTypeTree(paramValueType()) }
761+
else paramValueType()
762+
763+
/** ParamValueType ::= Type [`*']
764+
*/
765+
def paramValueType(): Tree = {
766+
val t = typ()
767+
if (isIdent(nme.raw.STAR)) {
768+
in.nextToken()
769+
atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) }
770+
} else t
771+
}
768772

769773
/** TypeArgs ::= `[' ArgType {`,' ArgType} `]'
770774
*/

src/dotty/tools/dotc/printing/RefinedPrinter.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
6363
}
6464

6565
override def toTextPrefix(tp: Type): Text = controlled {
66-
def isOmittable(sym: Symbol) =
66+
def isOmittable(sym: Symbol) =
6767
if (ctx.settings.verbose.value) false
6868
else if (homogenizedView) isEmptyPrefix(sym) // drop <root> and anonymous classes, but not scala, Predef.
6969
else isOmittablePrefix(sym)
@@ -351,6 +351,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
351351
toTextLocal(tpt) ~ " " ~ blockText(refines)
352352
case AppliedTypeTree(tpt, args) =>
353353
toTextLocal(tpt) ~ "[" ~ Text(args map argText, ", ") ~ "]"
354+
case ByNameTypeTree(tpt) =>
355+
"=> " ~ toTextLocal(tpt)
354356
case TypeBoundsTree(lo, hi) =>
355357
optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _)
356358
case Bind(name, body) =>

src/dotty/tools/dotc/typer/Applications.scala

+5-2
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ trait Applications extends Compatibility { self: Typer =>
330330
case arg :: Nil if isVarArg(arg) =>
331331
addTyped(arg, formal)
332332
case _ =>
333-
val elemFormal = formal.argTypesLo.head
333+
val elemFormal = formal.widenExpr.argTypesLo.head
334334
args foreach (addTyped(_, elemFormal))
335335
makeVarArg(args.length, elemFormal)
336336
}
@@ -842,7 +842,10 @@ trait Applications extends Compatibility { self: Typer =>
842842
val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, tp1.instantiateBounds)
843843
isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2)
844844
case tp1: MethodType =>
845-
def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp
845+
def repeatedToSingle(tp: Type): Type = tp match {
846+
case tp @ ExprType(tp1) => tp.derivedExprType(repeatedToSingle(tp1))
847+
case _ => if (tp.isRepeatedParam) tp.argTypesHi.head else tp
848+
}
846849
isApplicable(alt2, tp1.paramTypes map repeatedToSingle, WildcardType) ||
847850
tp1.paramTypes.isEmpty && tp2.isInstanceOf[MethodOrPoly]
848851
case _ =>

tests/pos/byNameVarargs.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package test
2+
3+
object O {
4+
5+
def byname(xs: => Int*) = xs.sum
6+
def byval(xs: Int*) = xs.sum
7+
8+
def a = 1
9+
def b = 2
10+
11+
byval(a, b)
12+
byname(a, b)
13+
14+
}
15+

tests/run/byNameVarargs/i499.scala

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
object Test {
2+
def foo(a: => Any*) = ()
3+
def bar(a: => Any*) = foo(a : _*)
4+
def baz(a: => Seq[Any]) = foo(a : _*)
5+
bar(???, ???)
6+
baz(Seq(???, ???))
7+
baz(Array(???, ???))
8+
9+
def foo1(a => Any, b: => Any*) = ()
10+
foo1(???)
11+
foo1(???, ???, ???)
12+
13+
def assertFails(a => Any) = {
14+
var failed = false
15+
try {
16+
a
17+
} catch {
18+
case e => failed = true
19+
}
20+
assert(failed)
21+
}
22+
23+
def forceLength(b: => Any*) = b.length
24+
assertFails(forceLength(???))
25+
26+
def forceHead(b: => Any*) = b(0)
27+
assertFails(forceHead(1, ???))
28+
}

0 commit comments

Comments
 (0)