Skip to content

Commit b9a7b2f

Browse files
committed
Only generate isDefined and applyOrElse for partial function literals
This is done by extending `scala.runtime.AbstractPartialFunction`.
1 parent ac489db commit b9a7b2f

File tree

4 files changed

+26
-18
lines changed

4 files changed

+26
-18
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
282282
val parents1 =
283283
if (parents.head.classSymbol.is(Trait)) parents.head.parents.head :: parents
284284
else parents
285-
val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_CLASS, Synthetic, parents1,
285+
val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_CLASS, Synthetic | Final, parents1,
286286
coord = fns.map(_.pos).reduceLeft(_ union _))
287287
val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered
288288
def forwarder(fn: TermSymbol, name: TermName) = {
289-
var flags = Synthetic | Method
289+
var flags = Synthetic | Method | Final
290290
def isOverriden(denot: SingleDenotation) = fn.info.overrides(denot.info, matchLoosely = true)
291291
val isOverride = parents.exists(_.member(name).hasAltWith(isOverriden))
292292
if (isOverride) flags = flags | Override

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,14 @@ class Definitions {
585585

586586
lazy val PartialFunctionType: TypeRef = ctx.requiredClassRef("scala.PartialFunction")
587587
def PartialFunctionClass(implicit ctx: Context) = PartialFunctionType.symbol.asClass
588-
588+
lazy val PartialFunction_isDefinedAtR = PartialFunctionClass.requiredMethodRef(nme.isDefinedAt)
589+
def PartialFunction_isDefinedAt(implicit ctx: Context) = PartialFunction_isDefinedAtR.symbol
589590
lazy val PartialFunction_applyOrElseR = PartialFunctionClass.requiredMethodRef(nme.applyOrElse)
590591
def PartialFunction_applyOrElse(implicit ctx: Context) = PartialFunction_applyOrElseR.symbol
591592

592593
lazy val AbstractPartialFunctionType: TypeRef = ctx.requiredClassRef("scala.runtime.AbstractPartialFunction")
593594
def AbstractPartialFunctionClass(implicit ctx: Context) = AbstractPartialFunctionType.symbol.asClass
595+
594596
lazy val FunctionXXLType: TypeRef = ctx.requiredClassRef("scala.FunctionXXL")
595597
def FunctionXXLClass(implicit ctx: Context) = FunctionXXLType.symbol.asClass
596598

compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,24 +73,21 @@ class ExpandSAMs extends MiniPhase {
7373
}
7474

7575
val applyRhs = applyDef.rhs
76-
val applyFn = applyDef.symbol.asTerm
76+
val applyFn = applyDef.symbol
7777

78-
val MethodTpe(paramNames, paramTypes, _) = applyFn.info
79-
val isDefinedAtFn = applyFn.copy(
80-
name = nme.isDefinedAt,
81-
flags = Synthetic | Method,
82-
info = MethodType(paramNames, paramTypes, defn.BooleanType)).asTerm
83-
84-
val applyOrElseFn = applyFn.copy(
85-
name = nme.applyOrElse,
86-
flags = Synthetic | Method,
87-
info = tpt.tpe.memberInfo(defn.PartialFunction_applyOrElse)).asTerm
78+
def overrideSym(sym: Symbol) = sym.copy(
79+
owner = applyFn.owner,
80+
flags = Synthetic | Method | Final,
81+
info = tpt.tpe.memberInfo(sym),
82+
coord = tree.pos).asTerm
83+
val isDefinedAtFn = overrideSym(defn.PartialFunction_isDefinedAt)
84+
val applyOrElseFn = overrideSym(defn.PartialFunction_applyOrElse)
8885

8986
def isDefinedAtRhs(paramRefss: List[List[Tree]]) = {
9087
val tru = Literal(Constant(true))
9188
applyRhs match {
9289
case tree @ Match(_, cases) =>
93-
def translateCase(cdef: CaseDef)=
90+
def translateCase(cdef: CaseDef) =
9491
cpy.CaseDef(cdef)(body = tru).changeOwner(applyFn, isDefinedAtFn)
9592
val paramRef = paramRefss.head.head
9693
val defaultValue = Literal(Constant(false))
@@ -109,15 +106,19 @@ class ExpandSAMs extends MiniPhase {
109106
val defaultValue = defaultRef.select(nme.apply).appliedTo(paramRef)
110107
translateMatch(tree, paramRef, cases.map(translateCase), defaultValue)
111108
case _ =>
112-
ref(applyFn).appliedTo(paramRef)
109+
applyRhs
110+
.changeOwner(applyFn, applyOrElseFn)
111+
.subst(param.symbol :: Nil, paramRef.symbol :: Nil)
113112
}
114113
}
115114

116115
val isDefinedAtDef = transformFollowingDeep(DefDef(isDefinedAtFn, isDefinedAtRhs(_)))
117116
val applyOrElseDef = transformFollowingDeep(DefDef(applyOrElseFn, applyOrElseRhs(_)))
118117

119-
val anonCls = AnonClass(tpt.tpe :: Nil, List(applyFn, isDefinedAtFn, applyOrElseFn), List(nme.apply, nme.isDefinedAt, nme.applyOrElse))
120-
cpy.Block(tree)(List(applyDef, isDefinedAtDef, applyOrElseDef), anonCls)
118+
val tpArgs = tpt.tpe.baseType(defn.PartialFunctionClass).argInfos
119+
val parent = defn.AbstractPartialFunctionType.appliedTo(tpArgs)
120+
val anonCls = AnonClass(parent :: Nil, List(isDefinedAtFn, applyOrElseFn), List(nme.isDefinedAt, nme.applyOrElse))
121+
cpy.Block(tree)(List(isDefinedAtDef, applyOrElseDef), anonCls)
121122
}
122123

123124
private def checkRefinements(tpe: Type, pos: Position)(implicit ctx: Context): Type = tpe.dealias match {

tests/pos/i4177.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@ class Test {
1111
val e: PartialFunction[String, String] = { case x @ "abc" => x }
1212
val f: PartialFunction[String, String] = x => x match { case "abc" => x }
1313
val g: PartialFunction[String, String] = x => x match { case "abc" if x.isEmpty => x }
14+
15+
type P = PartialFunction[String,String]
16+
val h: P = { case x => x.toString }
17+
18+
val i: PartialFunction[Int, Int] = { x => x match { case x => x } }
1419
}
1520
}

0 commit comments

Comments
 (0)