Skip to content

Commit ffd2e97

Browse files
committed
Refactoring: Factor out the creation of typed anonymous classes.
There are several places where we create typed anonymous classes. All followed the same pattern, which we now factored out in a new `tpe.AnonClass` overload.
1 parent 6449e96 commit ffd2e97

File tree

4 files changed

+96
-94
lines changed

4 files changed

+96
-94
lines changed

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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -340,27 +340,35 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
340340
* Its position is the union of all functions in `fns`.
341341
*/
342342
def AnonClass(parents: List[Type], fns: List[TermSymbol], methNames: List[TermName])(using Context): Block = {
343-
val owner = fns.head.owner
343+
AnonClass(fns.head.owner, parents, fns.map(_.span).reduceLeft(_ union _)) { cls =>
344+
def forwarder(fn: TermSymbol, name: TermName) = {
345+
val fwdMeth = fn.copy(cls, name, Synthetic | Method | Final).entered.asTerm
346+
for overridden <- fwdMeth.allOverriddenSymbols do
347+
if overridden.is(Extension) then fwdMeth.setFlag(Extension)
348+
if !overridden.is(Deferred) then fwdMeth.setFlag(Override)
349+
DefDef(fwdMeth, ref(fn).appliedToArgss(_))
350+
}
351+
fns.lazyZip(methNames).map(forwarder)
352+
}
353+
}
354+
355+
/** An anonymous class
356+
*
357+
* new parents { body }
358+
*
359+
* with the specified owner and position.
360+
*/
361+
def AnonClass(owner: Symbol, parents: List[Type], coord: Coord)(body: ClassSymbol => List[Tree])(using Context): Block =
344362
val parents1 =
345363
if (parents.head.classSymbol.is(Trait)) {
346364
val head = parents.head.parents.head
347365
if (head.isRef(defn.AnyClass)) defn.AnyRefType :: parents else head :: parents
348366
}
349367
else parents
350-
val cls = newNormalizedClassSymbol(owner, tpnme.ANON_CLASS, Synthetic | Final, parents1,
351-
coord = fns.map(_.span).reduceLeft(_ union _))
368+
val cls = newNormalizedClassSymbol(owner, tpnme.ANON_CLASS, Synthetic | Final, parents1, coord = coord)
352369
val constr = newConstructor(cls, Synthetic, Nil, Nil).entered
353-
def forwarder(fn: TermSymbol, name: TermName) = {
354-
val fwdMeth = fn.copy(cls, name, Synthetic | Method | Final).entered.asTerm
355-
for overridden <- fwdMeth.allOverriddenSymbols do
356-
if overridden.is(Extension) then fwdMeth.setFlag(Extension)
357-
if !overridden.is(Deferred) then fwdMeth.setFlag(Override)
358-
DefDef(fwdMeth, ref(fn).appliedToArgss(_))
359-
}
360-
val forwarders = fns.lazyZip(methNames).map(forwarder)
361-
val cdef = ClassDef(cls, DefDef(constr), forwarders)
370+
val cdef = ClassDef(cls, DefDef(constr), body(cls))
362371
Block(cdef :: Nil, New(cls.typeRef, Nil))
363-
}
364372

365373
def Import(expr: Tree, selectors: List[untpd.ImportSelector])(using Context): Import =
366374
ta.assignType(untpd.Import(expr, selectors), newImportSymbol(ctx.owner, expr))

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -195,23 +195,26 @@ object Inlines:
195195
report.error("inline unapply methods with given parameters before the scrutinee are not supported", fun)
196196

197197
val sym = unapp.symbol
198-
val cls = newNormalizedClassSymbol(ctx.owner, tpnme.ANON_CLASS, Synthetic | Final, List(defn.ObjectType), coord = sym.coord)
199-
val constr = newConstructor(cls, Synthetic, Nil, Nil, coord = sym.coord).entered
200-
201-
val targs = fun match
202-
case TypeApply(_, targs) => targs
203-
case _ => Nil
204-
val unapplyInfo = sym.info match
205-
case info: PolyType => info.instantiate(targs.map(_.tpe))
206-
case info => info
207-
208-
val unappplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, unapplyInfo, coord = sym.coord).entered
209-
val unapply = DefDef(unappplySym, argss =>
210-
inlineCall(fun.appliedToArgss(argss).withSpan(unapp.span))(using ctx.withOwner(unappplySym))
211-
)
212-
val cdef = ClassDef(cls, DefDef(constr), List(unapply))
213-
val newUnapply = Block(cdef :: Nil, New(cls.typeRef, Nil))
214-
val newFun = newUnapply.select(unappplySym).withSpan(unapp.span)
198+
199+
var unapplySym1: Symbol = NoSymbol // created from within AnonClass() and used afterwards
200+
201+
val newUnapply = AnonClass(ctx.owner, List(defn.ObjectType), sym.coord) { cls =>
202+
val targs = fun match
203+
case TypeApply(_, targs) => targs
204+
case _ => Nil
205+
val unapplyInfo = sym.info match
206+
case info: PolyType => info.instantiate(targs.map(_.tpe))
207+
case info => info
208+
209+
val unapplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, unapplyInfo, coord = sym.coord).entered
210+
val unapply = DefDef(unapplySym.asTerm, argss =>
211+
inlineCall(fun.appliedToArgss(argss).withSpan(unapp.span))(using ctx.withOwner(unapplySym))
212+
)
213+
unapplySym1 = unapplySym
214+
List(unapply)
215+
}
216+
217+
val newFun = newUnapply.select(unapplySym1).withSpan(unapp.span)
215218
cpy.UnApply(unapp)(newFun, trailingImplicits, patterns)
216219
end inlinedUnapply
217220

@@ -463,4 +466,4 @@ object Inlines:
463466
// the opaque type itself. An example is in pos/opaque-inline1.scala.
464467
end expand
465468
end InlineCall
466-
end Inlines
469+
end Inlines

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

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -124,55 +124,54 @@ class ExpandSAMs extends MiniPhase:
124124
val parents = List(
125125
defn.AbstractPartialFunctionClass.typeRef.appliedTo(anonTpe.firstParamTypes.head, anonTpe.resultType),
126126
defn.SerializableType)
127-
val pfSym = newNormalizedClassSymbol(anonSym.owner, tpnme.ANON_CLASS, Synthetic | Final, parents, coord = tree.span)
128-
129-
def overrideSym(sym: Symbol) = sym.copy(
130-
owner = pfSym,
131-
flags = Synthetic | Method | Final | Override,
132-
info = tpe.memberInfo(sym),
133-
coord = tree.span).asTerm.entered
134-
val isDefinedAtFn = overrideSym(defn.PartialFunction_isDefinedAt)
135-
val applyOrElseFn = overrideSym(defn.PartialFunction_applyOrElse)
136-
137-
def translateMatch(tree: Match, pfParam: Symbol, cases: List[CaseDef], defaultValue: Tree)(using Context) = {
138-
val selector = tree.selector
139-
val selectorTpe = selector.tpe.widen
140-
val defaultSym = newSymbol(pfParam.owner, nme.WILDCARD, SyntheticCase, selectorTpe)
141-
val defaultCase =
142-
CaseDef(
143-
Bind(defaultSym, Underscore(selectorTpe)),
144-
EmptyTree,
145-
defaultValue)
146-
val unchecked = selector.annotated(New(ref(defn.UncheckedAnnot.typeRef)))
147-
cpy.Match(tree)(unchecked, cases :+ defaultCase)
148-
.subst(param.symbol :: Nil, pfParam :: Nil)
149-
// Needed because a partial function can be written as:
150-
// param => param match { case "foo" if foo(param) => param }
151-
// And we need to update all references to 'param'
152-
}
153127

154-
def isDefinedAtRhs(paramRefss: List[List[Tree]])(using Context) = {
155-
val tru = Literal(Constant(true))
156-
def translateCase(cdef: CaseDef) =
157-
cpy.CaseDef(cdef)(body = tru).changeOwner(anonSym, isDefinedAtFn)
158-
val paramRef = paramRefss.head.head
159-
val defaultValue = Literal(Constant(false))
160-
translateMatch(pfRHS, paramRef.symbol, pfRHS.cases.map(translateCase), defaultValue)
161-
}
128+
AnonClass(anonSym.owner, parents, tree.span) { pfSym =>
129+
def overrideSym(sym: Symbol) = sym.copy(
130+
owner = pfSym,
131+
flags = Synthetic | Method | Final | Override,
132+
info = tpe.memberInfo(sym),
133+
coord = tree.span).asTerm.entered
134+
val isDefinedAtFn = overrideSym(defn.PartialFunction_isDefinedAt)
135+
val applyOrElseFn = overrideSym(defn.PartialFunction_applyOrElse)
136+
137+
def translateMatch(tree: Match, pfParam: Symbol, cases: List[CaseDef], defaultValue: Tree)(using Context) = {
138+
val selector = tree.selector
139+
val selectorTpe = selector.tpe.widen
140+
val defaultSym = newSymbol(pfParam.owner, nme.WILDCARD, SyntheticCase, selectorTpe)
141+
val defaultCase =
142+
CaseDef(
143+
Bind(defaultSym, Underscore(selectorTpe)),
144+
EmptyTree,
145+
defaultValue)
146+
val unchecked = selector.annotated(New(ref(defn.UncheckedAnnot.typeRef)))
147+
cpy.Match(tree)(unchecked, cases :+ defaultCase)
148+
.subst(param.symbol :: Nil, pfParam :: Nil)
149+
// Needed because a partial function can be written as:
150+
// param => param match { case "foo" if foo(param) => param }
151+
// And we need to update all references to 'param'
152+
}
162153

163-
def applyOrElseRhs(paramRefss: List[List[Tree]])(using Context) = {
164-
val List(paramRef, defaultRef) = paramRefss(1)
165-
def translateCase(cdef: CaseDef) =
166-
cdef.changeOwner(anonSym, applyOrElseFn)
167-
val defaultValue = defaultRef.select(nme.apply).appliedTo(paramRef)
168-
translateMatch(pfRHS, paramRef.symbol, pfRHS.cases.map(translateCase), defaultValue)
169-
}
154+
def isDefinedAtRhs(paramRefss: List[List[Tree]])(using Context) = {
155+
val tru = Literal(Constant(true))
156+
def translateCase(cdef: CaseDef) =
157+
cpy.CaseDef(cdef)(body = tru).changeOwner(anonSym, isDefinedAtFn)
158+
val paramRef = paramRefss.head.head
159+
val defaultValue = Literal(Constant(false))
160+
translateMatch(pfRHS, paramRef.symbol, pfRHS.cases.map(translateCase), defaultValue)
161+
}
170162

171-
val constr = newConstructor(pfSym, Synthetic, Nil, Nil).entered
172-
val isDefinedAtDef = transformFollowingDeep(DefDef(isDefinedAtFn, isDefinedAtRhs(_)(using ctx.withOwner(isDefinedAtFn))))
173-
val applyOrElseDef = transformFollowingDeep(DefDef(applyOrElseFn, applyOrElseRhs(_)(using ctx.withOwner(applyOrElseFn))))
174-
val pfDef = ClassDef(pfSym, DefDef(constr), List(isDefinedAtDef, applyOrElseDef))
175-
cpy.Block(tree)(pfDef :: Nil, New(pfSym.typeRef, Nil))
163+
def applyOrElseRhs(paramRefss: List[List[Tree]])(using Context) = {
164+
val List(paramRef, defaultRef) = paramRefss(1)
165+
def translateCase(cdef: CaseDef) =
166+
cdef.changeOwner(anonSym, applyOrElseFn)
167+
val defaultValue = defaultRef.select(nme.apply).appliedTo(paramRef)
168+
translateMatch(pfRHS, paramRef.symbol, pfRHS.cases.map(translateCase), defaultValue)
169+
}
170+
171+
val isDefinedAtDef = transformFollowingDeep(DefDef(isDefinedAtFn, isDefinedAtRhs(_)(using ctx.withOwner(isDefinedAtFn))))
172+
val applyOrElseDef = transformFollowingDeep(DefDef(applyOrElseFn, applyOrElseRhs(_)(using ctx.withOwner(applyOrElseFn))))
173+
List(isDefinedAtDef, applyOrElseDef)
174+
}
176175
}
177176

178177
private def checkRefinements(tpe: Type, tree: Tree)(using Context): Type = tpe.dealias match {
@@ -184,4 +183,3 @@ class ExpandSAMs extends MiniPhase:
184183
tpe
185184
}
186185
end ExpandSAMs
187-

compiler/src/dotty/tools/dotc/transform/sjs/PrepJSInterop.scala

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -292,25 +292,18 @@ class PrepJSInterop extends MacroTransform with IdentityDenotTransformer { thisP
292292

293293
assert(currentOwner.isTerm, s"unexpected owner: $currentOwner at ${tree.sourcePos}")
294294

295-
val cls = newNormalizedClassSymbol(currentOwner, tpnme.ANON_CLASS, Synthetic | Final,
296-
List(jsdefn.DynamicImportThunkType), coord = span)
297-
val constr = newConstructor(cls, Synthetic, Nil, Nil).entered
298-
299-
val applySym = newSymbol(cls, nme.apply, Method, MethodType(Nil, Nil, defn.AnyType), coord = span).entered
300-
val newBody = transform(body).changeOwnerAfter(currentOwner, applySym, thisPhase)
301-
val applyDefDef = DefDef(applySym, newBody)
302-
303-
// class $anon extends DynamicImportThunk
304-
val cdef = ClassDef(cls, DefDef(constr), List(applyDefDef)).withSpan(span)
295+
// new DynamicImportThunk { def apply(): Any = body }
296+
val dynamicImportThunkAnonClass = AnonClass(currentOwner, List(jsdefn.DynamicImportThunkType), span) { cls =>
297+
val applySym = newSymbol(cls, nme.apply, Method, MethodType(Nil, Nil, defn.AnyType), coord = span).entered
298+
val newBody = transform(body).changeOwnerAfter(currentOwner, applySym, thisPhase)
299+
val applyDefDef = DefDef(applySym, newBody)
300+
List(applyDefDef)
301+
}
305302

306-
/* runtime.DynamicImport[A]({
307-
* class $anon ...
308-
* new $anon
309-
* })
310-
*/
303+
// runtime.DynamicImport[A](new ...)
311304
ref(jsdefn.Runtime_dynamicImport)
312305
.appliedToTypeTree(tpeArg)
313-
.appliedTo(Block(cdef :: Nil, New(cls.typeRef, Nil)))
306+
.appliedTo(dynamicImportThunkAnonClass)
314307

315308
// Compile-time errors and warnings for js.Dynamic.literal
316309
case Apply(Apply(fun, nameArgs), args)

0 commit comments

Comments
 (0)