summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-09-01 13:37:49 +0000
committerMartin Odersky <odersky@gmail.com>2006-09-01 13:37:49 +0000
commitdef54abfbdcd86224920b951e8b8990bcbcfc04c (patch)
treec9c2b26963b2a028fc676dd842a658b9675c63c1 /src
parent3a4a6a3b66a98cc18cda27b0d008ee6aba425250 (diff)
downloadscala-def54abfbdcd86224920b951e8b8990bcbcfc04c.tar.gz
scala-def54abfbdcd86224920b951e8b8990bcbcfc04c.tar.bz2
scala-def54abfbdcd86224920b951e8b8990bcbcfc04c.zip
1. Added by name functions and nby-name implicits
2. Clarified code in Erasure
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala30
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala19
-rwxr-xr-xsrc/library/scala/ByNameFunction.scala26
6 files changed, 68 insertions, 17 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index d11c322bf7..2282802c24 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -157,7 +157,7 @@ abstract class TreeBuilder {
def makeBlock(stats: List[Tree]): Tree =
if (stats.isEmpty) Literal(())
else if (!stats.last.isTerm) Block(stats, Literal(()))
- else if (stats.length == 1) stats(0)
+ else if (stats.length == 1) stats.head
else Block(stats.init, stats.last)
/** Create tree for for-comprehension generator &lt;val pat0 &lt;- rhs0&gt; */
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 707b5e3748..1f03828acc 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -64,6 +64,7 @@ trait Definitions requires SymbolTable {
var CodeClass: Symbol = _
var CodeModule: Symbol = _
var PartialFunctionClass: Symbol = _
+ var ByNameFunctionClass: Symbol = _
var IterableClass: Symbol = _
def Iterable_next = getMember(IterableClass, nme.next)
def Iterable_hasNext = getMember(IterableClass, nme.hasNext)
@@ -506,6 +507,7 @@ trait Definitions requires SymbolTable {
CodeModule = getModule("scala.reflect.Code")
}
PartialFunctionClass = getClass("scala.PartialFunction")
+ ByNameFunctionClass = getClass("scala.ByNameFunction")
IterableClass = getClass("scala.Iterable")
IteratorClass = getClass("scala.Iterator")
SeqClass = getClass("scala.Seq")
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 4aa3d2f0de..ef1f066648 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -485,8 +485,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
val bridgesScope = newScope
val bridgeTarget = new HashMap[Symbol, Symbol]
var bridges: List[Tree] = List()
- val opc = atPhase(phase.prev.prev) { // bq: who understands prev comment "to avoid DEFERRED flags for interfaces"
- new overridingPairs.Cursor(owner) { // it seems we want types *before* explicitOuter
+ val opc = atPhase(currentRun.explicitOuterPhase) {
+ new overridingPairs.Cursor(owner) {
override def parents: List[Type] = List(owner.info.parents.head)
override def exclude(sym: Symbol): boolean =
!sym.isMethod || (sym hasFlag (PRIVATE | BRIDGE)) || super.exclude(sym)
@@ -496,7 +496,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
val member = opc.overriding
val other = opc.overridden
//Console.println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString);//DEBUG
- if (!atPhase(phase.prev.prev)(member hasFlag DEFERRED)) {
+ if (!atPhase(currentRun.explicitOuterPhase)(member hasFlag DEFERRED)) {
val otpe = erasure(other.tpe);
val bridgeNeeded = atPhase(phase.next) (
!(other.tpe =:= member.tpe) &&
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 15dda5b11a..0957e0c435 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -43,7 +43,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
// ------ Type transformation --------------------------------------------------------
- private val uncurry = new TypeMap {
+ private val uncurry: TypeMap = new TypeMap {
def apply(tp: Type): Type = tp match {
case MethodType(formals, MethodType(formals1, restpe)) =>
apply(MethodType(formals ::: formals1, restpe))
@@ -53,6 +53,9 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
apply(MethodType(List(), restpe))
case PolyType(tparams, restpe) =>
PolyType(tparams, apply(MethodType(List(), restpe)))
+ case TypeRef(pre, sym, List(arg1, arg2)) if (arg1.symbol == ByNameParamClass) =>
+ assert(sym == FunctionClass(1))
+ apply(typeRef(pre, definitions.ByNameFunctionClass, List(arg1.typeArgs(0), arg2)))
case TypeRef(pre, sym, List(arg)) if (sym == ByNameParamClass) =>
apply(functionType(List(), arg))
case TypeRef(pre, sym, args) if (sym == RepeatedParamClass) =>
@@ -62,12 +65,24 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
}
}
+ private val uncurryType = new TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case ClassInfoType(parents, decls, clazz) =>
+ val parents1 = List.mapConserve(parents)(uncurry)
+ if (parents1 eq parents) tp
+ else ClassInfoType(parents1, decls, clazz)
+ case PolyType(_, _) =>
+ mapOver(tp)
+ case _ =>
+ tp
+ }
+ }
+
/** - return symbol's transformed type,
* - if symbol is a def parameter with transformed type T, return () => T
*/
def transformInfo(sym: Symbol, tp: Type): Type =
- if (sym.isType) tp
- else uncurry(tp)
+ if (sym.isType) uncurryType(tp) else uncurry(tp)
class UnCurryTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
@@ -393,7 +408,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
Apply(Select(tree1 setType functionType(List(), tree1.tpe), nme.apply), List())))
else tree1;
}
- } setType uncurryTreeType(tree.tpe);
+ } setType uncurryTreeType(tree.tpe)
def postTransform(tree: Tree): Tree = atPhase(phase.next) {
def applyUnary(tree: Tree): Tree =
@@ -444,7 +459,12 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
if (name == nme.WILDCARD_STAR.toTypeName)
unit.error(tree.pos, " argument does not correspond to `*'-parameter");
applyUnary(tree);
- case Select(_, _) =>
+ case Select(qual, name) =>
+ /* Function1.apply to ByNameFunction.apply if qualifier is a ByNameFunction */
+ if (qual.tpe.symbol == ByNameFunctionClass) {
+ assert(tree.symbol.name == nme.apply && tree.symbol.owner == FunctionClass(1), tree.symbol)
+ tree.symbol = getMember(ByNameFunctionClass, nme.apply)
+ }
applyUnary(tree)
case TypeApply(_, _) =>
applyUnary(tree)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 0609fd6bfd..f56e651a8b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -64,7 +64,13 @@ trait Typers requires Analyzer {
case MethodType(_, _) => EmptyTree
case OverloadedType(_, _) => EmptyTree
case PolyType(_, _) => EmptyTree
- case _ => inferImplicit(pos, functionType(List(from), to), true, reportAmbiguous)
+ case _ =>
+ val result = inferImplicit(pos, functionType(List(from), to), true, reportAmbiguous)
+ if (result != EmptyTree) result
+ else inferImplicit(
+ pos,
+ functionType(List(appliedType(ByNameParamClass.typeConstructor, List(from))), to),
+ true, reportAmbiguous)
}
}
@@ -203,8 +209,8 @@ trait Typers requires Analyzer {
def checkParamsConvertible(pos: PositionType, tpe: Type): unit = tpe match {
case MethodType(formals, restpe) =>
- if (formals exists (.symbol.==(ByNameParamClass)))
- error(pos, "methods with `=>'-parameters cannot be converted to function values");
+ if (formals.exists(.symbol.==(ByNameParamClass)) && formals.length != 1)
+ error(pos, "methods with `=>'-parameter can be converted to function values only if they are unary")
if (formals exists (.symbol.==(RepeatedParamClass)))
error(pos, "methods with `*'-parameters cannot be converted to function values");
checkParamsConvertible(pos, restpe)
@@ -944,6 +950,8 @@ trait Typers requires Analyzer {
}
def typedFunction(fun: Function, mode: int, pt: Type): Tree = {
+ val codeExpected = !forCLDC && (pt.symbol isNonBottomSubClass CodeClass)
+
def decompose(pt: Type): Triple[Symbol, List[Type], Type] =
if (isFunctionType(pt)
||
@@ -953,8 +961,6 @@ trait Typers requires Analyzer {
else
Triple(FunctionClass(fun.vparams.length), fun.vparams map (x => NoType), WildcardType)
- val codeExpected = !forCLDC && (pt.symbol isNonBottomSubClass CodeClass)
-
val Triple(clazz, argpts, respt) = decompose(if (codeExpected) pt.typeArgs.head else pt)
if (fun.vparams.length != argpts.length)
@@ -1541,9 +1547,6 @@ trait Typers requires Analyzer {
else appliedType(ArrayClass.typeConstructor, List(elemtpt1.tpe)))
case fun @ Function(_, _) =>
-/*
- newTyper(context.makeNewScope(tree, context.owner)).typedFunction(fun, mode, pt)
-*/
if (tree.symbol == NoSymbol)
tree.symbol = context.owner.newValue(tree.pos, nme.ANON_FUN_NAME)
.setFlag(SYNTHETIC).setInfo(NoType)
diff --git a/src/library/scala/ByNameFunction.scala b/src/library/scala/ByNameFunction.scala
new file mode 100755
index 0000000000..0773c90863
--- /dev/null
+++ b/src/library/scala/ByNameFunction.scala
@@ -0,0 +1,26 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2006, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: PartialFunction.scala 7931 2006-06-20 16:34:51 +0000 (Tue, 20 Jun 2006) odersky $
+
+
+package scala;
+
+
+/** A partial function of type <code>PartialFunction[A, B]</code> is a
+ * unary function where the domain does not include all values of type
+ * <code>A</code>. The function <code>isDefinedAt</code> allows to
+ * test dynamically, if a value is in the domain of the function.
+ *
+ * @author Martin Odersky
+ * @version 1.0, 16/07/2003
+ */
+trait ByNameFunction[-A, +B] extends AnyRef {
+ def apply(x: => A): B
+}
+