From def54abfbdcd86224920b951e8b8990bcbcfc04c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2006 13:37:49 +0000 Subject: 1. Added by name functions and nby-name implicits 2. Clarified code in Erasure --- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 2 +- .../scala/tools/nsc/symtab/Definitions.scala | 2 ++ .../scala/tools/nsc/transform/Erasure.scala | 6 ++--- .../scala/tools/nsc/transform/UnCurry.scala | 30 ++++++++++++++++++---- .../scala/tools/nsc/typechecker/Typers.scala | 19 ++++++++------ src/library/scala/ByNameFunction.scala | 26 +++++++++++++++++++ 6 files changed, 68 insertions(+), 17 deletions(-) create mode 100755 src/library/scala/ByNameFunction.scala 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 <val pat0 <- rhs0> */ 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 PartialFunction[A, B] is a + * unary function where the domain does not include all values of type + * A. The function isDefinedAt 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 +} + -- cgit v1.2.3