From 8b0259f8f4f2773560efa985142eaf167f597a24 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 20 Jul 2012 14:46:01 +0200 Subject: update docs for (partial) fun synth in uncurry --- .../scala/tools/nsc/transform/UnCurry.scala | 49 +++++++++++----------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index efc3d25ed0..2983c65e78 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -225,38 +225,15 @@ abstract class UnCurry extends InfoTransform } - /* Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to + /** Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to * * class $anon() extends AbstractFunctionN[T_1, .., T_N, R] with Serializable { * def apply(x_1: T_1, ..., x_N: T_n): R = body * } * new $anon() * - * transform a function node (x => body) of type PartialFunction[T, R] where - * body = expr match { case P_i if G_i => E_i }_i=1..n - * to: + * If `settings.XoldPatmat.value`, also synthesized AbstractPartialFunction subclasses (see synthPartialFunction). * - //TODO: correct code template below - * class $anon() extends AbstractPartialFunction[T, R] with Serializable { - * def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match { - * case P_1 if G_1 => E_1 - * ... - * case P_n if G_n => E_n - * case _ => default(expr) - * } - * def isDefinedAt(x: T): boolean = (x: @unchecked) match { - * case P_1 if G_1 => true - * ... - * case P_n if G_n => true - * case _ => false - * } - * } - * new $anon() - * - * However, if one of the patterns P_i if G_i is a default pattern, - * drop the last default clause in the definition of `apply` and generate for `_isDefinedAt` instead - * - * def isDefinedAtCurrent(x: T): boolean = true */ def transformFunction(fun: Function): Tree = deEta(fun) match { @@ -300,6 +277,28 @@ abstract class UnCurry extends InfoTransform } + /** Transform a function node (x => body) of type PartialFunction[T, R] where + * body = expr match { case P_i if G_i => E_i }_i=1..n + * to (assuming none of the cases is a default case): + * + * class $anon() extends AbstractPartialFunction[T, R] with Serializable { + * def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match { + * case P_1 if G_1 => E_1 + * ... + * case P_n if G_n => E_n + * case _ => default(expr) + * } + * def isDefinedAt(x: T): boolean = (x: @unchecked) match { + * case P_1 if G_1 => true + * ... + * case P_n if G_n => true + * case _ => false + * } + * } + * new $anon() + * + * If there's a default case, the original match is used for applyOrElse, and isDefinedAt returns `true` + */ def synthPartialFunction(fun: Function) = { if (!settings.XoldPatmat.value) debugwarn("Under the new pattern matching scheme, PartialFunction should have been synthesized during typers.") -- cgit v1.2.3 From 6015a54812a5003933da7924f74ac8bde3adfdff Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 20 Jul 2012 16:39:11 +0200 Subject: SI-1832 consistent symbols in casedef's pattern&body the only change to typedBind in this commit (beyond refactoring to keep my eyes from bleeding), is explained by the added comment: have to imperatively set the symbol for this bind to keep it in sync with the symbols used in the body of a case when type checking a case we imperatively update the symbols in the body of the case those symbols are bound by the symbols in the Binds in the pattern of the case, so, if we set the symbols in the case body, but not in the patterns, then re-type check the casedef (for a second try in typedApply for example -- SI-1832), we are no longer in sync: the body has symbols set that do not appear in the patterns since body1 is not necessarily equal to body, we must return a copied tree, but we must still mutate the original bind --- .../scala/tools/nsc/typechecker/Typers.scala | 75 +++++++++++++--------- test/files/pos/t1832.scala | 8 +++ 2 files changed, 51 insertions(+), 32 deletions(-) create mode 100644 test/files/pos/t1832.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9371af4848..f4af6a6497 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3883,40 +3883,51 @@ trait Typers extends Modes with Adaptations with Tags { } } - def typedBind(name: Name, body: Tree) = { - var vble = tree.symbol - def typedBindType(name: TypeName) = { - assert(body == EmptyTree, context.unit + " typedBind: " + name.debugString + " " + body + " " + body.getClass) - if (vble == NoSymbol) - vble = - if (isFullyDefined(pt)) - context.owner.newAliasType(name, tree.pos) setInfo pt - else - context.owner.newAbstractType(name, tree.pos) setInfo TypeBounds.empty - val rawInfo = vble.rawInfo - vble = if (vble.name == tpnme.WILDCARD) context.scope.enter(vble) - else namer.enterInScope(vble) - tree setSymbol vble setType vble.tpe - } - def typedBindTerm(name: TermName) = { - if (vble == NoSymbol) - vble = context.owner.newValue(name, tree.pos) - if (vble.name.toTermName != nme.WILDCARD) { - if ((mode & ALTmode) != 0) - VariableInPatternAlternativeError(tree) - vble = namer.enterInScope(vble) - } - val body1 = typed(body, mode, pt) - vble.setInfo( - if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) - else body1.tpe) - treeCopy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // burak, was: pt - } + def typedBind(name: Name, body: Tree) = name match { - case x: TypeName => typedBindType(x) - case x: TermName => typedBindTerm(x) + case name: TypeName => assert(body == EmptyTree, context.unit + " typedBind: " + name.debugString + " " + body + " " + body.getClass) + val sym = + if (tree.symbol != NoSymbol) tree.symbol + else { + if (isFullyDefined(pt)) + context.owner.newAliasType(name, tree.pos) setInfo pt + else + context.owner.newAbstractType(name, tree.pos) setInfo TypeBounds.empty + } + + if (name != tpnme.WILDCARD) namer.enterInScope(sym) + else context.scope.enter(sym) + + tree setSymbol sym setType sym.tpe + + case name: TermName => + val sym = + if (tree.symbol != NoSymbol) tree.symbol + else context.owner.newValue(name, tree.pos) + + if (name != nme.WILDCARD) { + if ((mode & ALTmode) != 0) VariableInPatternAlternativeError(tree) + namer.enterInScope(sym) + } + + val body1 = typed(body, mode, pt) + val symTp = + if (treeInfo.isSequenceValued(body)) seqType(body1.tpe) + else body1.tpe + sym setInfo symTp + + // have to imperatively set the symbol for this bind to keep it in sync with the symbols used in the body of a case + // when type checking a case we imperatively update the symbols in the body of the case + // those symbols are bound by the symbols in the Binds in the pattern of the case, + // so, if we set the symbols in the case body, but not in the patterns, + // then re-type check the casedef (for a second try in typedApply for example -- SI-1832), + // we are no longer in sync: the body has symbols set that do not appear in the patterns + // since body1 is not necessarily equal to body, we must return a copied tree, + // but we must still mutate the original bind + tree setSymbol sym + treeCopy.Bind(tree, name, body1) setSymbol sym setType body1.tpe } - } + def typedArrayValue(elemtpt: Tree, elems: List[Tree]) = { val elemtpt1 = typedType(elemtpt, mode) diff --git a/test/files/pos/t1832.scala b/test/files/pos/t1832.scala new file mode 100644 index 0000000000..c7b1ffb838 --- /dev/null +++ b/test/files/pos/t1832.scala @@ -0,0 +1,8 @@ +trait Cloning { + trait Foo + def fn(g: Any => Unit): Foo + + implicit def mkStar(i: Int) = new { def *(a: Foo): Foo = null } + + val pool = 4 * fn { case ghostSYMBOL: Int => ghostSYMBOL * 2 } +} \ No newline at end of file -- cgit v1.2.3