summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosh Suereth <Joshua.Suereth@gmail.com>2012-07-21 06:48:23 -0700
committerJosh Suereth <Joshua.Suereth@gmail.com>2012-07-21 06:48:23 -0700
commitfa4c1de6e7dc5e5703ccf822c5815da9e8ae47ed (patch)
treee68598cc3e9209e829b5e4a735b8f73b9a73dcde /src
parent31f60292c9c03b1c0347b3cfbd0fefdecdf83e79 (diff)
parent6015a54812a5003933da7924f74ac8bde3adfdff (diff)
downloadscala-fa4c1de6e7dc5e5703ccf822c5815da9e8ae47ed.tar.gz
scala-fa4c1de6e7dc5e5703ccf822c5815da9e8ae47ed.tar.bz2
scala-fa4c1de6e7dc5e5703ccf822c5815da9e8ae47ed.zip
Merge pull request #958 from adriaanm/ticket-1832
SI-1832 consistent symbols in casedef's pattern&body
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala49
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala75
2 files changed, 67 insertions, 57 deletions
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.")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7dff055172..dbe65c16d8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3884,40 +3884,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)