diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2009-06-25 11:38:05 +0000 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2009-06-25 11:38:05 +0000 |
commit | ae85676cb414628f4bcc2a302e7de8dd031b75e8 (patch) | |
tree | 1bfb20c27955f81873f0e5c18ab6c0c2975c5f70 /src | |
parent | 6c0ba3ee65cb5669efd2cdde7ea5cc1b6d59adc7 (diff) | |
download | scala-ae85676cb414628f4bcc2a302e7de8dd031b75e8.tar.gz scala-ae85676cb414628f4bcc2a302e7de8dd031b75e8.tar.bz2 scala-ae85676cb414628f4bcc2a302e7de8dd031b75e8.zip |
named arguments only at top level in () paramet...
named arguments only at top level in () parameters.
Diffstat (limited to 'src')
5 files changed, 65 insertions, 64 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 1b8777a642..6741a8bea5 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -690,7 +690,17 @@ trait Trees { /** Assignment */ case class Assign(lhs: Tree, rhs: Tree) - extends TermTree + extends TermTree { + def namedArg = false + } + + /** Either an assignment or a named argument. Only appears in argument lists, + * eliminated by typecheck. + */ + class AssignOrNamedArg(lhs: Tree, rhs: Tree) + extends Assign(lhs, rhs) { + override def namedArg = true + } /** Conditional expression */ case class If(cond: Tree, thenp: Tree, elsep: Tree) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 442b9f5d5b..9d6a8af329 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -689,14 +689,8 @@ self => /** Types ::= Type {`,' Type} */ - def types(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): List[Tree] = { - val ts = new ListBuffer[Tree] += argType(isPattern, isTypeApply, isFuncArg) - while (in.token == COMMA) { - in.nextToken() - ts += argType(isPattern, isTypeApply, isFuncArg) - } - ts.toList - } + def types(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): List[Tree] = + exprs(() => argType(isPattern, isTypeApply, isFuncArg)) /** Type ::= InfixType `=>' Type * | `(' [`=>' Type] `)' `=>' Type @@ -817,7 +811,7 @@ self => * | SimpleType `#' Id * | StableId * | Path `.' type - * | `(' Types [`,'] `)' + * | `(' Types `)' * | WildcardType */ def simpleType(isPattern: Boolean): Tree = { @@ -914,11 +908,11 @@ self => /** Exprs ::= Expr {`,' Expr} */ - def exprs(): List[Tree] = { - val ts = new ListBuffer[Tree] += expr() + def exprs(part: () => Tree = expr _): List[Tree] = { + val ts = new ListBuffer[Tree] += part() while (in.token == COMMA) { in.nextToken() - ts += expr() + ts += part() } ts.toList } @@ -1155,7 +1149,7 @@ self => * SimpleExpr1 ::= literal * | xLiteral * | Path - * | `(' [Exprs [`,']] `)' + * | `(' [Exprs] `)' * | SimpleExpr `.' Id * | SimpleExpr TypeArgs * | SimpleExpr1 ArgumentExprs @@ -1239,10 +1233,19 @@ self => } } - /** ArgumentExprs ::= `(' [Exprs [`,']] `)' + /** ArgumentExprs ::= `(' [Exprs] `)' * | [nl] BlockExpr */ def argumentExprs(): List[Tree] = { + def args(): List[Tree] = exprs(() => { + val maybeNamed = isIdent + expr() match { + case a @ Assign(id, rhs) if maybeNamed => + atPos(a.pos) { new AssignOrNamedArg(id, rhs) } + case e => e + } + }) + // if arg has the form "x$1 => a = x$1" it's treated as "a = x$1" with x$1 // in placeholderParams. This allows e.g. "val f: Int => Int = foo(a = 1, b = _)" def convertArg(arg: Tree): Tree = arg match { @@ -1252,7 +1255,7 @@ self => rhs match { case Ident(`pname1`) | Typed(Ident(`pname1`), _) => placeholderParams = vd :: placeholderParams - atPos(arg.pos) { Assign(Ident(aname), Ident(pname1)) } + atPos(arg.pos) { new AssignOrNamedArg(Ident(aname), Ident(pname1)) } case _ => arg } case _ => arg @@ -1261,7 +1264,7 @@ self => if (in.token == LBRACE) List(blockExpr()) else - surround(LPAREN, RPAREN)(if (in.token == RPAREN) List() else (exprs() map convertArg), List()) + surround(LPAREN, RPAREN)(if (in.token == RPAREN) List() else (args() map convertArg), List()) } /** BlockExpr ::= `{' (CaseClauses | Block) `}' @@ -1354,17 +1357,9 @@ self => /** Patterns ::= Pattern { `,' Pattern } * SeqPatterns ::= SeqPattern { `,' SeqPattern } - * - * (also eats trailing comma if it finds one) */ - def patterns(seqOK: Boolean): List[Tree] = { - val ts = new ListBuffer[Tree] += pattern(seqOK) - while (in.token == COMMA) { - in.nextToken() - ts += pattern(seqOK) - } - ts.toList - } + def patterns(seqOK: Boolean): List[Tree] = + exprs(() => pattern(seqOK)) /** Pattern ::= Pattern1 { `|' Pattern1 } * SeqPattern ::= SeqPattern1 { `|' SeqPattern1 } @@ -1453,15 +1448,15 @@ self => * | `_' * | literal * | XmlPattern - * | StableId [TypeArgs] [`(' [SeqPatterns [`,']] `)'] - * | `(' [Patterns [`,']] `)' + * | StableId [TypeArgs] [`(' [SeqPatterns] `)'] + * | `(' [Patterns] `)' * SimpleSeqPattern ::= varid * | `_' * | literal * | XmlPattern * | `<' xLiteralPattern - * | StableId [TypeArgs] [`(' [SeqPatterns [`,']] `)'] - * | `(' [SeqPatterns [`,']] `)' + * | StableId [TypeArgs] [`(' [SeqPatterns] `)'] + * | `(' [SeqPatterns] `)' * * XXX: Hook for IDE */ @@ -1833,11 +1828,7 @@ self => */ def importClause(): List[Tree] = { accept(IMPORT) - val ts = new ListBuffer[Tree] += importExpr() - while (in.token == COMMA) { - in.nextToken(); ts += importExpr() - } - ts.toList + exprs(() => importExpr()) } /** ImportExpr ::= StableId `.' (Id | `_' | ImportSelectors) @@ -2208,7 +2199,7 @@ self => } } - /** ClassParents ::= AnnotType {`(' [Exprs [`,']] `)'} {with AnnotType} + /** ClassParents ::= AnnotType {`(' [Exprs] `)'} {with AnnotType} * TraitParents ::= AnnotType {with AnnotType} */ def templateParents(isTrait: Boolean): (List[Tree], List[List[Tree]]) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index d922d23f94..ba0a36cadf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -823,6 +823,8 @@ trait Infer { sym2 == NoSymbol || isProperSubClassOrObject(sym1.owner, sym2.owner) def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type, sym1: Symbol, sym2: Symbol): Boolean = + // ftpe1 / ftpe2 are OverloadedTypes (possibly with one single alternative) if they + // denote the type of an "apply" member method (see "followApply") ftpe1.isError || { val specificCount = (if (isAsSpecific(ftpe1, ftpe2)) 1 else 0) - (if (isAsSpecific(ftpe2, ftpe1) && @@ -1536,7 +1538,6 @@ trait Infer { // (tupling would work) }) - def improves(sym1: Symbol, sym2: Symbol) = sym2 == NoSymbol || sym2.isError || isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 20cf790ca8..f8dd35cfdd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -23,7 +23,7 @@ trait NamesDefaults { self: Analyzer => val noApplyInfo = NamedApplyInfo(None, Nil, Nil, null) def nameOf(arg: Tree) = arg match { - case Assign(Ident(name), rhs) => Some(name) + case a @ Assign(Ident(name), rhs) if a.namedArg => Some(name) case _ => None } def isNamed(arg: Tree) = nameOf(arg).isDefined @@ -327,7 +327,7 @@ trait NamesDefaults { self: Analyzer => val default2 = (default1 /: previousArgss)((tree, args) => Apply(tree, args.map(_.duplicate)).setPos(pos)) if (positional) default2 - else Assign(Ident(p.name), default2) + else atPos(pos) { new AssignOrNamedArg(Ident(p.name), default2) } }) (givenArgs ::: defaultArgs, Nil) } else (givenArgs, missing filter (! _.hasFlag(DEFAULTPARAM))) @@ -348,14 +348,14 @@ trait NamesDefaults { self: Analyzer => val argPos = (new Array[Int](args.length)) map (x => -1) var positionalAllowed = true val namelessArgs = for ((arg, index) <- (args.zipWithIndex)) yield arg match { - case Assign(Ident(name), rhs) => + case a @ Assign(Ident(name), rhs) if a.namedArg => val pos = params.indexWhere(p => p.name == name && !p.hasFlag(SYNTHETIC)) if (pos == -1) { if (positionalAllowed) { argPos(index) = index // prevent isNamed from being true when calling doTypedApply recursively, // treat the arg as an assignment of type Unit - Block(List(), arg) + Assign(a.lhs, rhs).setPos(arg.pos) } else { errorTree(arg, "unknown parameter name: "+ name) } @@ -377,10 +377,7 @@ trait NamesDefaults { self: Analyzer => case _: TypeError => positionalAllowed = false argPos(index) = pos - // if `rhs' has the form `x = ...`, wrap it into a block, prevent - // treating it as named argument again. - if (isNamed(rhs)) Block(List(), rhs) - else rhs + rhs case t: Tree => errorTree(arg, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+ "name of the method and the name of a variable currently in scope.") diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d82c995e05..d91f680123 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -182,10 +182,11 @@ trait Typers { self: Analyzer => case (arg, param) => if (arg != SearchFailure) { if (positional) List(arg.tree) - else List(atPos(arg.tree.pos)(Assign(Ident(param.name), (arg.tree)))) + else List(atPos(arg.tree.pos)(new AssignOrNamedArg(Ident(param.name), (arg.tree)))) } else { if (!param.hasFlag(DEFAULTPARAM)) - context.error(fun.pos, "could not find implicit value for parameter "+ param.name +":"+ param.tpe +".") + context.error(fun.pos, "could not find implicit value for parameter "+ + param.name +":"+ param.tpe +".") positional = false Nil } @@ -1526,8 +1527,11 @@ trait Typers { self: Analyzer => } } - if (meth.paramss.exists(_.exists(_.tpe.typeSymbol == RepeatedParamClass))) - error(meth.pos, "methods with `*'-parameters are not allowed to have default arguments") + if (meth.paramss.exists( ps => { + ps.exists(_.hasFlag(DEFAULTPARAM)) && + (ps.last.tpe.typeSymbol == RepeatedParamClass) + })) + error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments") } treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType @@ -1912,16 +1916,13 @@ trait Typers { self: Analyzer => if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) { // remove alternatives with wrong number of parameters without looking at types. // less expensive than including them in inferMethodAlternatvie (see below). - def shapeType(arg: Tree): Type = { - def shape(arg1: Tree, toplevel: Boolean): Type = arg1 match { - case Function(vparams, body) => - functionType(vparams map (vparam => AnyClass.tpe), shape(body, false)) - case Assign(Ident(name), rhs) if toplevel => - NamedType(name, shape(rhs, false)) - case _ => - NothingClass.tpe - } - shape(arg, true) + def shapeType(arg: Tree): Type = arg match { + case Function(vparams, body) => + functionType(vparams map (vparam => AnyClass.tpe), shapeType(body)) + case a @ Assign(Ident(name), rhs) if a.namedArg => + NamedType(name, shapeType(rhs)) + case _ => + NothingClass.tpe } val argtypes = args map shapeType val pre = fun.symbol.tpe.prefix @@ -1949,11 +1950,12 @@ trait Typers { self: Analyzer => val argtpes = new ListBuffer[Type] val amode = argMode(fun, mode) val args1 = args map { - case Assign(Ident(name), rhs) => + case arg @ Assign(Ident(name), rhs) if arg.namedArg => // named args: only type the righthand sides ("unknown identifier" errors otherwise) val rhs1 = typedArg(rhs, amode, 0, WildcardType) argtpes += NamedType(name, rhs1.tpe.deconst) - Assign(Ident(name), rhs1) // untyped; that's ok because we call doTypedApply + // the assign is untyped; that's ok because we call doTypedApply + atPos(arg.pos) { new AssignOrNamedArg(arg.lhs , rhs1) } case arg => val arg1 = typedArg(arg, amode, 0, WildcardType) argtpes += arg1.tpe.deconst @@ -2348,7 +2350,7 @@ trait Typers { self: Analyzer => } else { val args = if (argss.head.length == 1 && !isNamed(argss.head.head)) - List(Assign(Ident(nme.value), argss.head.head)) + List(new AssignOrNamedArg(Ident(nme.value), argss.head.head)) else argss.head val annScope = annType.decls .filter(sym => sym.isMethod && !sym.isConstructor && sym.hasFlag(JAVA)) @@ -2356,7 +2358,7 @@ trait Typers { self: Analyzer => names ++= (if (isJava) annScope.iterator else typedFun.tpe.params.iterator) val nvPairs = args map { - case arg @ Assign(Ident(name), rhs) => + case arg @ Assign(Ident(name), rhs) if arg.namedArg => val sym = if (isJava) annScope.lookupWithContext(name)(context.owner) else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol) if (sym == NoSymbol) { |