summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@epfl.ch>2009-06-20 08:19:40 +0000
committerLukas Rytz <lukas.rytz@epfl.ch>2009-06-20 08:19:40 +0000
commit0e170e4b695adafb3f3d5823026ccf8d10047be3 (patch)
tree58dd5a4ca9e73602222733720c5ead9612e0282e /src
parent60810d5c03ef614497d3a8ba5ad23d44e48194a8 (diff)
downloadscala-0e170e4b695adafb3f3d5823026ccf8d10047be3.tar.gz
scala-0e170e4b695adafb3f3d5823026ccf8d10047be3.tar.bz2
scala-0e170e4b695adafb3f3d5823026ccf8d10047be3.zip
improvements to names / defaults (implicits, ty...
improvements to names / defaults (implicits, type of defaults, #2064, ...)
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala17
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala62
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala71
5 files changed, 115 insertions, 70 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 41b2cc53a7..9cf11f2284 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -146,6 +146,15 @@ abstract class LambdaLift extends InfoTransform {
if (!(ss contains sym)) {
ss addEntry sym
renamable addEntry sym
+ atPhase(currentRun.picklerPhase) {
+ // The param symbol in the MethodType should not be renamed, only the symbol in scope. This way,
+ // parameter names for named arguments are not changed. Example: without cloning the MethodType,
+ // def closure(x: Int) = { () => x }
+ // would have the signatrue
+ // closure: (x$1: Int)() => Int
+ if (sym.hasFlag(PARAM) && sym.owner.info.paramss.exists(_.contains(sym)))
+ sym.owner.setInfo(sym.owner.info.cloneInfo(sym.owner))
+ }
changedFreeVars = true
if (settings.debug.value) log("" + sym + " is free in " + owner);
if (sym.isVariable && !(sym hasFlag CAPTURED)) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index e57e8bcc71..d922d23f94 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -735,18 +735,13 @@ trait Infer {
}
} else {
// not enough arguments, check if applicable using defaults
- val namedArgtpes = argtpes0.dropWhile {
- case NamedType(name, _) => params.forall(_.name != name)
- case _ => true
- }
- val namedParams = params.drop(argtpes0.length - namedArgtpes.length)
- val missingParams = namedParams.filter(p => namedArgtpes.forall {
- case NamedType(name, _) => name != p.name
- case _ => true
- })
- if (missingParams.exists(!_.hasFlag(DEFAULTPARAM))) tryTupleApply
+ val missing = missingParams[Type](argtpes0, params, {
+ case NamedType(name, _) => Some(name)
+ case _ => None
+ })._1
+ if (missing.exists(!_.hasFlag(DEFAULTPARAM))) tryTupleApply
else {
- val argtpes1 = argtpes0 ::: missingParams.map {
+ val argtpes1 = argtpes0 ::: missing.map {
p => NamedType(p.name, p.tpe) // add defaults as named arguments
}
isApplicable(undetparams, ftpe, argtpes1, pt)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 9c41249426..61e59f2b2e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -940,9 +940,6 @@ trait Namers { self: Analyzer =>
UnTyper.traverse(p1)
p1
}))
- // let the compiler infer the return type of the defaultGetter. needed in "foo[T](a: T = 1)"
- val defTpt = TypeTree()
- val defRhs = copyUntyped(vparam.rhs)
val parentNamer = if (isConstr) {
val (cdef, nmr) = moduleNamer.getOrElse {
@@ -965,6 +962,29 @@ trait Namers { self: Analyzer =>
}
}
+ // If the parameter type mentions any type parameter of the method, let the compiler infer the
+ // return type of the default getter => allow "def foo[T](x: T = 1)" to compile.
+ // This is better than always inferring the result type, for example in
+ // def f(i: Int, m: Int => Int = identity _) = m(i)
+ // if we infer the default's type, we get "Nothing => Nothing", and the default is not usable.
+ val names = deftParams map { case TypeDef(_, name, _, _) => name }
+ object subst extends Transformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Ident(name) if (names contains name) =>
+ TypeTree()
+ case _ =>
+ super.transform(tree)
+ }
+ def apply(tree: Tree) = {
+ val r = transform(tree)
+ if (r.find(_.isEmpty).isEmpty) r
+ else TypeTree()
+ }
+ }
+
+ val defTpt = subst(copyUntyped(vparam.tpt))
+ val defRhs = copyUntyped(vparam.rhs)
+
val defaultTree = atPos(vparam.pos) {
DefDef(
Modifiers(meth.flags & (PRIVATE | PROTECTED | FINAL)) | SYNTHETIC | DEFAULTPARAM | oflag,
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 0ede740b00..20cf790ca8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -115,23 +115,25 @@ trait NamesDefaults { self: Analyzer =>
val isConstr = baseFun.symbol.isConstructor
val blockTyper = newTyper(context.makeNewScope(tree, context.owner)(BlockScopeKind(context.depth)))
- // baseFun1: the extract the function from a potential TypeApply
- // defaultTargs: type arguments to be used for calling defaultGetters
- // funTargs: type arguments on baseFun, used to reconstruct TypeApply in blockWith(Out)Qualifier
- val (baseFun1, defaultTargs, funTargs) = baseFun match {
+ // baseFun1: extract the function from a potential TypeApply
+ // funTargs: type arguments on baseFun, used to reconstruct TypeApply in blockWith(Out)Qualifier
+ // defaultTargs: type arguments to be used for calling defaultGetters. If the type arguments are given
+ // in the source code, re-use them for default getter. Otherwise infer the default getter's t-args.
+ val (baseFun1, funTargs, defaultTargs) = baseFun match {
case TypeApply(fun, targs) =>
val targsInSource =
if (targs.forall(a => context.undetparams contains a.symbol)) Nil
else targs
- (fun, targsInSource, targs)
+ (fun, targs, targsInSource)
case Select(New(tpt @ TypeTree()), _) if isConstr =>
- val targs = tpt.tpe match {
- case TypeRef(pre, sym, args) if (args forall (a => context.undetparams contains a)) =>
+ val targsInSource = tpt.tpe match {
+ case TypeRef(pre, sym, args)
+ if (!args.forall(a => context.undetparams contains a.typeSymbol)) =>
args.map(TypeTree(_))
case _ => Nil
}
- (baseFun, targs, Nil)
+ (baseFun, Nil, targsInSource)
case _ => (baseFun, Nil, Nil)
}
@@ -286,6 +288,20 @@ trait NamesDefaults { self: Analyzer =>
}
}
+ def missingParams[T](args: List[T], params: List[Symbol], argName: T => Option[Name] = nameOf _): (List[Symbol], Boolean) = {
+ val namedArgs = args.dropWhile(arg => {
+ val n = argName(arg)
+ n.isEmpty || params.forall(p => p.name != n.get)
+ })
+ val namedParams = params.drop(args.length - namedArgs.length)
+ // missing: keep those with a name which doesn't exist in namedArgs
+ val missingParams = namedParams.filter(p => namedArgs.forall(arg => {
+ val n = argName(arg)
+ n.isEmpty || n.get != p.name
+ }))
+ val allPositional = missingParams.length == namedParams.length
+ (missingParams, allPositional)
+ }
/**
* Extend the argument list `givenArgs' with default arguments. Defaults are added
@@ -297,35 +313,24 @@ trait NamesDefaults { self: Analyzer =>
* the argument list (y = "lt") is transformed to (y = "lt", x = foo$default$1())
*/
def addDefaults(givenArgs: List[Tree], qual: Option[Tree], targs: List[Tree],
- previousArgss: List[List[Tree]], params: List[Symbol]): (List[Tree], List[Symbol]) = {
+ previousArgss: List[List[Tree]], params: List[Symbol], pos: util.Position): (List[Tree], List[Symbol]) = {
if (givenArgs.length < params.length) {
- val namedArgs = givenArgs.dropWhile( arg => {
- val n = nameOf(arg)
- !(n.isDefined && params.exists(p => p.name == n.get))
- })
- val namedParams = params.drop(givenArgs.length - namedArgs.length)
-
- def missing(p: Symbol): Boolean = !namedArgs.exists {
- case Assign(Ident(name), _) => name == p.name
- case _ => false
- }
-
- val missingParams = namedParams filter missing
-
- if (missingParams forall (_.hasFlag(DEFAULTPARAM))) {
- val defaultArgs = missingParams map (p => {
+ val (missing, positional) = missingParams(givenArgs, params)
+ if (missing forall (_.hasFlag(DEFAULTPARAM))) {
+ val defaultArgs = missing map (p => {
var default1 = qual match {
case Some(q) => gen.mkAttributedSelect(q.duplicate, p.defaultGetter)
case None => gen.mkAttributedRef(p.defaultGetter)
}
default1 = if (targs.isEmpty) default1
- else TypeApply(default1, targs.map(_.duplicate)).setPos(p.pos)
+ else TypeApply(default1, targs.map(_.duplicate)).setPos(pos)
val default2 = (default1 /: previousArgss)((tree, args) =>
- Apply(tree, args.map(_.duplicate)).setPos(p.pos))
- Assign(Ident(p.name), default2)
+ Apply(tree, args.map(_.duplicate)).setPos(pos))
+ if (positional) default2
+ else Assign(Ident(p.name), default2)
})
(givenArgs ::: defaultArgs, Nil)
- } else (givenArgs, missingParams filter (! _.hasFlag(DEFAULTPARAM)))
+ } else (givenArgs, missing filter (! _.hasFlag(DEFAULTPARAM)))
} else (givenArgs, Nil)
}
@@ -342,7 +347,6 @@ trait NamesDefaults { self: Analyzer =>
// maps indicies from (order written by user) to (order of definition)
val argPos = (new Array[Int](args.length)) map (x => -1)
var positionalAllowed = true
- // @LUC TODO: make faster (don't use zipWithIndex)
val namelessArgs = for ((arg, index) <- (args.zipWithIndex)) yield arg match {
case Assign(Ident(name), rhs) =>
val pos = params.indexWhere(p => p.name == name && !p.hasFlag(SYNTHETIC))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index e324e5793f..71e0af421f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -174,23 +174,32 @@ trait Typers { self: Analyzer =>
/** Find implicit arguments and pass them to given tree.
*/
- def applyImplicitArgs(tree: Tree): Tree = tree.tpe match {
+ def applyImplicitArgs(fun: Tree): Tree = fun.tpe match {
case MethodType(params, _) =>
- def implicitArg(pt: Type): SearchResult = {
- val result = inferImplicit(tree, pt, true, context)
- if (result == SearchFailure)
- context.error(tree.pos, "no implicit argument matching parameter type "+pt+" was found.")
- result
- }
+ def implicitArg(pt: Type): SearchResult =
+ inferImplicit(fun, pt, true, context)
+
+ var positional = true
val argResults = params map (_.tpe) map implicitArg
- val args = argResults map (_.tree)
+ val args = argResults.zip(params) flatMap {
+ case (arg, param) =>
+ if (arg != SearchFailure) {
+ if (positional) List(arg.tree)
+ else List(atPos(arg.tree.pos)(Assign(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 +".")
+ positional = false
+ Nil
+ }
+ }
for (s <- argResults map (_.subst)) {
- s traverse tree
+ s traverse fun
for (arg <- args) s traverse arg
}
- Apply(tree, args) setPos tree.pos
+ Apply(fun, args) setPos fun.pos
case ErrorType =>
- tree
+ fun
}
/** Infer an implicit conversion (``view'') between two types.
@@ -795,7 +804,7 @@ trait Typers { self: Analyzer =>
val tree1 = etaExpand(context.unit, tree)
//println("eta "+tree+" ---> "+tree1+":"+tree1.tpe)
typed(tree1, mode, pt)
- } else if (!meth.isConstructor && mt.paramTypes.isEmpty) { // (4.3)
+ } else if (!meth.isConstructor && mt.params.isEmpty) { // (4.3)
adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt)
} else if (context.implicitsEnabled) {
errorTree(tree, "missing arguments for "+meth+meth.locationString+
@@ -1990,6 +1999,9 @@ trait Typers { self: Analyzer =>
*/
def tryNamesDefaults: Tree = {
if (mt.isErroneous) setError(tree)
+ else if ((mode & PATTERNmode) != 0)
+ // #2064
+ errorTree(tree, "wrong number of arguments for "+ treeSymTypeMsg(fun))
else if (args.length > formals.length) {
tryTupleApply.getOrElse {
errorTree(tree, "too many arguments for "+treeSymTypeMsg(fun))
@@ -2020,22 +2032,27 @@ trait Typers { self: Analyzer =>
if (fun1.isErroneous) setError(tree)
else {
assert(isNamedApplyBlock(fun1), fun1)
- val NamedApplyInfo(qual, targs, previousArgss, _) =
- context.namedApplyBlockInfo.get._2
- val (allArgs, missing) = addDefaults(args, qual, targs, previousArgss, mt.params)
+ val NamedApplyInfo(qual, targs, previousArgss, _) = context.namedApplyBlockInfo.get._2
+ val blockIsEmpty = fun1 match {
+ case Block(Nil, _) =>
+ // if the block does not have any ValDef we can remove it. Note that the call to
+ // "transformNamedApplication" is always needed in order to obtain targs/previousArgss
+ context.namedApplyBlockInfo = None
+ true
+ case _ => false
+ }
+ val (allArgs, missing) = addDefaults(args, qual, targs, previousArgss, params, fun.pos)
if (allArgs.length == formals.length) {
- // a default for each missing argument was found
- val (namelessArgs, argPos) = removeNames(Typer.this)(allArgs, params)
- if (namelessArgs exists (_.isErroneous)) setError(tree)
- else
- transformNamedApplication(Typer.this, mode, pt)(
- treeCopy.Apply(tree, fun1, namelessArgs), argPos)
+ doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
} else {
tryTupleApply.getOrElse {
val suffix =
if (missing.isEmpty) ""
- else ", unspecified parameter"+ (if (missing.length > 1) "s: " else ": ") +
- (missing.take(3).mkString(", ")) + (if (missing.length > 3) ", ..." else "")
+ else {
+ val missingStr = missing.take(3).map(_.name).mkString(", ") + (if (missing.length > 3) ", ..." else ".")
+ val sOpt = if (missing.length > 1) "s" else ""
+ ".\nUnspecified value parameter"+ sOpt +" "+ missingStr
+ }
errorTree(tree, "not enough arguments for "+treeSymTypeMsg(fun) + suffix)
}
}
@@ -2043,10 +2060,10 @@ trait Typers { self: Analyzer =>
}
}
- if (formals.length != args.length || // wrong nb of arguments
- args.exists(isNamed(_)) || // uses a named argument
- isNamedApplyBlock(fun)) { // fun was transformed to a named apply block =>
- // integrate this application into the block
+ if (formals.length != args.length || // wrong nb of arguments
+ args.exists(isNamed(_)) || // uses a named argument
+ isNamedApplyBlock(fun)) { // fun was transformed to a named apply block =>
+ // integrate this application into the block
tryNamesDefaults
} else {
val tparams = context.extractUndetparams()