Skip to content

Commit fa4c1de

Browse files
committed
Merge pull request scala#958 from adriaanm/ticket-1832
SI-1832 consistent symbols in casedef's pattern&body
2 parents 31f6029 + 6015a54 commit fa4c1de

File tree

3 files changed

+75
-57
lines changed

3 files changed

+75
-57
lines changed

src/compiler/scala/tools/nsc/transform/UnCurry.scala

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -225,38 +225,15 @@ abstract class UnCurry extends InfoTransform
225225
}
226226

227227

228-
/* Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to
228+
/** Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to
229229
*
230230
* class $anon() extends AbstractFunctionN[T_1, .., T_N, R] with Serializable {
231231
* def apply(x_1: T_1, ..., x_N: T_n): R = body
232232
* }
233233
* new $anon()
234234
*
235-
* transform a function node (x => body) of type PartialFunction[T, R] where
236-
* body = expr match { case P_i if G_i => E_i }_i=1..n
237-
* to:
235+
* If `settings.XoldPatmat.value`, also synthesized AbstractPartialFunction subclasses (see synthPartialFunction).
238236
*
239-
//TODO: correct code template below
240-
* class $anon() extends AbstractPartialFunction[T, R] with Serializable {
241-
* def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match {
242-
* case P_1 if G_1 => E_1
243-
* ...
244-
* case P_n if G_n => E_n
245-
* case _ => default(expr)
246-
* }
247-
* def isDefinedAt(x: T): boolean = (x: @unchecked) match {
248-
* case P_1 if G_1 => true
249-
* ...
250-
* case P_n if G_n => true
251-
* case _ => false
252-
* }
253-
* }
254-
* new $anon()
255-
*
256-
* However, if one of the patterns P_i if G_i is a default pattern,
257-
* drop the last default clause in the definition of `apply` and generate for `_isDefinedAt` instead
258-
*
259-
* def isDefinedAtCurrent(x: T): boolean = true
260237
*/
261238
def transformFunction(fun: Function): Tree =
262239
deEta(fun) match {
@@ -300,6 +277,28 @@ abstract class UnCurry extends InfoTransform
300277

301278
}
302279

280+
/** Transform a function node (x => body) of type PartialFunction[T, R] where
281+
* body = expr match { case P_i if G_i => E_i }_i=1..n
282+
* to (assuming none of the cases is a default case):
283+
*
284+
* class $anon() extends AbstractPartialFunction[T, R] with Serializable {
285+
* def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match {
286+
* case P_1 if G_1 => E_1
287+
* ...
288+
* case P_n if G_n => E_n
289+
* case _ => default(expr)
290+
* }
291+
* def isDefinedAt(x: T): boolean = (x: @unchecked) match {
292+
* case P_1 if G_1 => true
293+
* ...
294+
* case P_n if G_n => true
295+
* case _ => false
296+
* }
297+
* }
298+
* new $anon()
299+
*
300+
* If there's a default case, the original match is used for applyOrElse, and isDefinedAt returns `true`
301+
*/
303302
def synthPartialFunction(fun: Function) = {
304303
if (!settings.XoldPatmat.value) debugwarn("Under the new pattern matching scheme, PartialFunction should have been synthesized during typers.")
305304

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3884,40 +3884,51 @@ trait Typers extends Modes with Adaptations with Tags {
38843884
}
38853885
}
38863886

3887-
def typedBind(name: Name, body: Tree) = {
3888-
var vble = tree.symbol
3889-
def typedBindType(name: TypeName) = {
3890-
assert(body == EmptyTree, context.unit + " typedBind: " + name.debugString + " " + body + " " + body.getClass)
3891-
if (vble == NoSymbol)
3892-
vble =
3893-
if (isFullyDefined(pt))
3894-
context.owner.newAliasType(name, tree.pos) setInfo pt
3895-
else
3896-
context.owner.newAbstractType(name, tree.pos) setInfo TypeBounds.empty
3897-
val rawInfo = vble.rawInfo
3898-
vble = if (vble.name == tpnme.WILDCARD) context.scope.enter(vble)
3899-
else namer.enterInScope(vble)
3900-
tree setSymbol vble setType vble.tpe
3901-
}
3902-
def typedBindTerm(name: TermName) = {
3903-
if (vble == NoSymbol)
3904-
vble = context.owner.newValue(name, tree.pos)
3905-
if (vble.name.toTermName != nme.WILDCARD) {
3906-
if ((mode & ALTmode) != 0)
3907-
VariableInPatternAlternativeError(tree)
3908-
vble = namer.enterInScope(vble)
3909-
}
3910-
val body1 = typed(body, mode, pt)
3911-
vble.setInfo(
3912-
if (treeInfo.isSequenceValued(body)) seqType(body1.tpe)
3913-
else body1.tpe)
3914-
treeCopy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // burak, was: pt
3915-
}
3887+
def typedBind(name: Name, body: Tree) =
39163888
name match {
3917-
case x: TypeName => typedBindType(x)
3918-
case x: TermName => typedBindTerm(x)
3889+
case name: TypeName => assert(body == EmptyTree, context.unit + " typedBind: " + name.debugString + " " + body + " " + body.getClass)
3890+
val sym =
3891+
if (tree.symbol != NoSymbol) tree.symbol
3892+
else {
3893+
if (isFullyDefined(pt))
3894+
context.owner.newAliasType(name, tree.pos) setInfo pt
3895+
else
3896+
context.owner.newAbstractType(name, tree.pos) setInfo TypeBounds.empty
3897+
}
3898+
3899+
if (name != tpnme.WILDCARD) namer.enterInScope(sym)
3900+
else context.scope.enter(sym)
3901+
3902+
tree setSymbol sym setType sym.tpe
3903+
3904+
case name: TermName =>
3905+
val sym =
3906+
if (tree.symbol != NoSymbol) tree.symbol
3907+
else context.owner.newValue(name, tree.pos)
3908+
3909+
if (name != nme.WILDCARD) {
3910+
if ((mode & ALTmode) != 0) VariableInPatternAlternativeError(tree)
3911+
namer.enterInScope(sym)
3912+
}
3913+
3914+
val body1 = typed(body, mode, pt)
3915+
val symTp =
3916+
if (treeInfo.isSequenceValued(body)) seqType(body1.tpe)
3917+
else body1.tpe
3918+
sym setInfo symTp
3919+
3920+
// have to imperatively set the symbol for this bind to keep it in sync with the symbols used in the body of a case
3921+
// when type checking a case we imperatively update the symbols in the body of the case
3922+
// those symbols are bound by the symbols in the Binds in the pattern of the case,
3923+
// so, if we set the symbols in the case body, but not in the patterns,
3924+
// then re-type check the casedef (for a second try in typedApply for example -- SI-1832),
3925+
// we are no longer in sync: the body has symbols set that do not appear in the patterns
3926+
// since body1 is not necessarily equal to body, we must return a copied tree,
3927+
// but we must still mutate the original bind
3928+
tree setSymbol sym
3929+
treeCopy.Bind(tree, name, body1) setSymbol sym setType body1.tpe
39193930
}
3920-
}
3931+
39213932

39223933
def typedArrayValue(elemtpt: Tree, elems: List[Tree]) = {
39233934
val elemtpt1 = typedType(elemtpt, mode)

test/files/pos/t1832.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait Cloning {
2+
trait Foo
3+
def fn(g: Any => Unit): Foo
4+
5+
implicit def mkStar(i: Int) = new { def *(a: Foo): Foo = null }
6+
7+
val pool = 4 * fn { case ghostSYMBOL: Int => ghostSYMBOL * 2 }
8+
}

0 commit comments

Comments
 (0)