diff options
author | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-07-21 06:48:23 -0700 |
---|---|---|
committer | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-07-21 06:48:23 -0700 |
commit | fa4c1de6e7dc5e5703ccf822c5815da9e8ae47ed (patch) | |
tree | e68598cc3e9209e829b5e4a735b8f73b9a73dcde | |
parent | 31f60292c9c03b1c0347b3cfbd0fefdecdf83e79 (diff) | |
parent | 6015a54812a5003933da7924f74ac8bde3adfdff (diff) | |
download | scala-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
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 49 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 75 | ||||
-rw-r--r-- | test/files/pos/t1832.scala | 8 |
3 files changed, 75 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) 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 |