Skip to content

Commit 9498b06

Browse files
committed
Optimize some matches of large methods
1 parent e078d67 commit 9498b06

File tree

3 files changed

+135
-108
lines changed

3 files changed

+135
-108
lines changed

compiler/src/dotty/tools/dotc/config/Feature.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ object Feature:
2323
def toPrefix(sym: Symbol): String =
2424
if !sym.exists || sym == defn.LanguageModule.moduleClass then ""
2525
else toPrefix(sym.owner) + sym.name.stripModuleClassSuffix + "."
26-
val prefix = if owner ne NoSymbol then toPrefix(owner) else ""
27-
ctx.base.settings.language.value.contains(prefix + feature)
26+
val fullName = if owner ne NoSymbol then toPrefix(owner) + feature else feature.toString
27+
ctx.base.settings.language.value.contains(fullName)
2828

2929
/** Is `feature` enabled by by an import? This is the case if the feature
3030
* is imported by a named import

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ class TypeApplications(val self: Type) extends AnyVal {
211211
*/
212212
def hkResult(using Context): Type = self.dealias match {
213213
case self: TypeRef =>
214-
if (self.symbol == defn.AnyKindClass) self else self.info.hkResult
214+
if self.symbol.isClass then
215+
if self.symbol == defn.AnyKindClass then self else NoType
216+
else self.info.hkResult
215217
case self: AppliedType =>
216218
if (self.tycon.typeSymbol.isClass) NoType else self.superType.hkResult
217219
case self: HKTypeLambda => self.resultType

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

Lines changed: 130 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
231231
}
232232

233233
override def transform(tree: Tree)(using Context): Tree =
234-
try tree match {
234+
235+
def transformNamed(tree: Tree): Tree = tree match
235236
case tree: Ident if !tree.isType =>
236237
tree.tpe match {
237238
case tpe: ThisType => This(tpe.cls).withSpan(tree.span)
@@ -244,61 +245,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
244245
}
245246
else
246247
transformSelect(tree, Nil)
247-
case tree: Apply =>
248-
val methType = tree.fun.tpe.widen
249-
val app =
250-
if (methType.isErasedMethod)
251-
tpd.cpy.Apply(tree)(
252-
tree.fun,
253-
tree.args.mapConserve(arg =>
254-
if (methType.isImplicitMethod && arg.span.isSynthetic) ref(defn.Predef_undefined)
255-
else dropInlines.transform(arg)))
256-
else
257-
tree
258-
def app1 =
259-
// reverse order of transforming args and fun. This way, we get a chance to see other
260-
// well-formedness errors before reporting errors in possible inferred type args of fun.
261-
val args1 = transform(app.args)
262-
cpy.Apply(app)(transform(app.fun), args1)
263-
methPart(app) match
264-
case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) =>
265-
// need to check instantiability here, because the type of the New itself
266-
// might be a type constructor.
267-
Checking.checkInstantiable(tree.tpe, nu.srcPos)
268-
withNoCheckNews(nu :: Nil)(app1)
269-
case _ =>
270-
app1
271-
case UnApply(fun, implicits, patterns) =>
272-
// Reverse transform order for the same reason as in `app1` above.
273-
val patterns1 = transform(patterns)
274-
cpy.UnApply(tree)(transform(fun), transform(implicits), patterns1)
275-
case tree: TypeApply =>
276-
if tree.symbol.isQuote then
277-
ctx.compilationUnit.needsStaging = true
278-
val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree)
279-
args.foreach(checkInferredWellFormed)
280-
if (fn.symbol != defn.ChildAnnot.primaryConstructor)
281-
// Make an exception for ChildAnnot, which should really have AnyKind bounds
282-
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
283-
fn match {
284-
case sel: Select =>
285-
val args1 = transform(args)
286-
val sel1 = transformSelect(sel, args1)
287-
cpy.TypeApply(tree1)(sel1, args1)
288-
case _ =>
289-
super.transform(tree1)
290-
}
291-
case Inlined(call, bindings, expansion) if !call.isEmpty =>
292-
val pos = call.sourcePos
293-
val callTrace = Inliner.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source))
294-
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call)))
295-
case templ: Template =>
296-
withNoCheckNews(templ.parents.flatMap(newPart)) {
297-
forwardParamAccessors(templ)
298-
synthMbr.addSyntheticMembers(
299-
superAcc.wrapTemplate(templ)(
300-
super.transform(_).asInstanceOf[Template]))
301-
}
302248
case tree: ValDef =>
303249
val tree1 = cpy.ValDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol))
304250
processValOrDefDef(super.transform(tree1))
@@ -307,20 +253,88 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
307253
val tree1 = cpy.DefDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol))
308254
processValOrDefDef(superAcc.wrapDefDef(tree1)(super.transform(tree1).asInstanceOf[DefDef]))
309255
case tree: TypeDef =>
310-
val sym = tree.symbol
311-
if (sym.isClass)
312-
VarianceChecker.check(tree)
313-
// Add SourceFile annotation to top-level classes
314-
if sym.owner.is(Package)
315-
&& ctx.compilationUnit.source.exists
316-
&& sym != defn.SourceFileAnnot
317-
then
318-
sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))
319-
else (tree.rhs, sym.info) match
320-
case (rhs: LambdaTypeTree, bounds: TypeBounds) =>
321-
VarianceChecker.checkLambda(rhs, bounds)
322-
case _ =>
256+
def checkTypeDef() =
257+
val sym = tree.symbol
258+
if sym.isClass then
259+
VarianceChecker.check(tree)
260+
// Add SourceFile annotation to top-level classes
261+
if sym.owner.is(Package)
262+
&& ctx.compilationUnit.source.exists
263+
&& sym != defn.SourceFileAnnot
264+
then
265+
sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))
266+
else (tree.rhs, sym.info) match
267+
case (rhs: LambdaTypeTree, bounds: TypeBounds) =>
268+
VarianceChecker.checkLambda(rhs, bounds)
269+
case _ =>
270+
checkTypeDef()
323271
processMemberDef(super.transform(tree))
272+
case _ =>
273+
super.transform(tree)
274+
end transformNamed
275+
276+
def transformUnnamed(tree: Tree): Tree = tree match
277+
case tree: Apply =>
278+
def transformApply() =
279+
val methType = tree.fun.tpe.widen
280+
val app =
281+
if (methType.isErasedMethod)
282+
tpd.cpy.Apply(tree)(
283+
tree.fun,
284+
tree.args.mapConserve(arg =>
285+
if (methType.isImplicitMethod && arg.span.isSynthetic) ref(defn.Predef_undefined)
286+
else dropInlines.transform(arg)))
287+
else tree
288+
def app1 =
289+
// reverse order of transforming args and fun. This way, we get a chance to see other
290+
// well-formedness errors before reporting errors in possible inferred type args of fun.
291+
val args1 = transform(app.args)
292+
cpy.Apply(app)(transform(app.fun), args1)
293+
methPart(app) match
294+
case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) =>
295+
// need to check instantiability here, because the type of the New itself
296+
// might be a type constructor.
297+
Checking.checkInstantiable(tree.tpe, nu.srcPos)
298+
withNoCheckNews(nu :: Nil)(app1)
299+
case _ =>
300+
app1
301+
transformApply()
302+
case UnApply(fun, implicits, patterns) =>
303+
// Reverse transform order for the same reason as in `app1` above.
304+
val patterns1 = transform(patterns)
305+
cpy.UnApply(tree)(transform(fun), transform(implicits), patterns1)
306+
case tree: TypeApply =>
307+
def transformTypeApply() =
308+
if tree.symbol.isQuote then
309+
ctx.compilationUnit.needsStaging = true
310+
val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree)
311+
args.foreach(checkInferredWellFormed)
312+
if fn.symbol != defn.ChildAnnot.primaryConstructor then
313+
// Make an exception for ChildAnnot, which should really have AnyKind bounds
314+
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
315+
fn match
316+
case sel: Select =>
317+
val args1 = transform(args)
318+
val sel1 = transformSelect(sel, args1)
319+
cpy.TypeApply(tree1)(sel1, args1)
320+
case _ =>
321+
super.transform(tree1)
322+
transformTypeApply()
323+
case Inlined(call, bindings, expansion) if !call.isEmpty =>
324+
def transformInlined() =
325+
val pos = call.sourcePos
326+
val callTrace = Inliner.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source))
327+
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call)))
328+
transformInlined()
329+
case templ: Template =>
330+
def transformTemplate() =
331+
withNoCheckNews(templ.parents.flatMap(newPart)) {
332+
forwardParamAccessors(templ)
333+
synthMbr.addSyntheticMembers(
334+
superAcc.wrapTemplate(templ)(
335+
super.transform(_).asInstanceOf[Template]))
336+
}
337+
transformTemplate()
324338
case tree: New if isCheckable(tree) =>
325339
Checking.checkInstantiable(tree.tpe, tree.srcPos)
326340
super.transform(tree)
@@ -330,14 +344,16 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
330344
case tree @ Annotated(annotated, annot) =>
331345
cpy.Annotated(tree)(transform(annotated), transformAnnot(annot))
332346
case tree: AppliedTypeTree =>
333-
if (tree.tpt.symbol == defn.andType)
334-
Checking.checkNonCyclicInherited(tree.tpe, tree.args.tpes, EmptyScope, tree.srcPos)
335-
// Ideally, this should be done by Typer, but we run into cyclic references
336-
// when trying to typecheck self types which are intersections.
337-
else if (tree.tpt.symbol == defn.orType)
338-
() // nothing to do
339-
else
340-
Checking.checkAppliedType(tree)
347+
def checkAppliedTypeTree() =
348+
if (tree.tpt.symbol == defn.andType)
349+
Checking.checkNonCyclicInherited(tree.tpe, tree.args.tpes, EmptyScope, tree.srcPos)
350+
// Ideally, this should be done by Typer, but we run into cyclic references
351+
// when trying to typecheck self types which are intersections.
352+
else if (tree.tpt.symbol == defn.orType)
353+
() // nothing to do
354+
else
355+
Checking.checkAppliedType(tree)
356+
checkAppliedTypeTree()
341357
super.transform(tree)
342358
case SingletonTypeTree(ref) =>
343359
Checking.checkRealizable(ref.tpe, ref.srcPos)
@@ -350,20 +366,24 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
350366
}
351367
)
352368
case Import(expr, selectors) =>
353-
val exprTpe = expr.tpe
354-
val seen = mutable.Set.empty[Name]
355-
356-
def checkIdent(sel: untpd.ImportSelector): Unit =
357-
if !exprTpe.member(sel.name).exists
358-
&& !exprTpe.member(sel.name.toTypeName).exists
359-
&& !exprTpe.member(sel.name.toExtensionName).exists then
360-
report.error(NotAMember(exprTpe, sel.name, "value"), sel.imported.srcPos)
361-
if seen.contains(sel.name) then
362-
report.error(ImportRenamedTwice(sel.imported), sel.imported.srcPos)
363-
seen += sel.name
364-
365-
for sel <- selectors do
366-
if !sel.isWildcard then checkIdent(sel)
369+
def checkImport() =
370+
val exprTpe = expr.tpe
371+
val seen = mutable.Set.empty[Name]
372+
373+
def checkIdent(sel: untpd.ImportSelector): Unit =
374+
if !exprTpe.member(sel.name).exists
375+
&& !exprTpe.member(sel.name.toTypeName).exists
376+
&& !exprTpe.member(sel.name.toExtensionName).exists
377+
then
378+
report.error(NotAMember(exprTpe, sel.name, "value"), sel.imported.srcPos)
379+
if seen.contains(sel.name) then
380+
report.error(ImportRenamedTwice(sel.imported), sel.imported.srcPos)
381+
seen += sel.name
382+
383+
for sel <- selectors do
384+
if !sel.isWildcard then checkIdent(sel)
385+
end checkImport
386+
checkImport()
367387
super.transform(tree)
368388
case Typed(Ident(nme.WILDCARD), _) =>
369389
withMode(Mode.Pattern)(super.transform(tree))
@@ -375,22 +395,27 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
375395
// (which translates to)
376396
// case x: (_: Tree[?])
377397
case m @ MatchTypeTree(bounds, selector, cases) =>
378-
// Analog to the case above for match types
379-
def tranformIgnoringBoundsCheck(x: CaseDef): CaseDef =
380-
withMode(Mode.Pattern)(super.transform(x)).asInstanceOf[CaseDef]
381-
cpy.MatchTypeTree(tree)(
382-
super.transform(bounds),
383-
super.transform(selector),
384-
cases.mapConserve(tranformIgnoringBoundsCheck)
385-
)
398+
def transformMatchTypeTree() =
399+
// Analog to the case above for match types
400+
def tranformIgnoringBoundsCheck(x: CaseDef): CaseDef =
401+
withMode(Mode.Pattern)(super.transform(x)).asInstanceOf[CaseDef]
402+
cpy.MatchTypeTree(tree)(
403+
super.transform(bounds),
404+
super.transform(selector),
405+
cases.mapConserve(tranformIgnoringBoundsCheck)
406+
)
407+
transformMatchTypeTree()
386408
case tree =>
387409
super.transform(tree)
388-
}
389-
catch {
390-
case ex : AssertionError =>
391-
println(i"error while transforming $tree")
392-
throw ex
393-
}
410+
end transformUnnamed
411+
412+
try tree match
413+
case tree: NameTree => transformNamed(tree)
414+
case _ => transformUnnamed(tree)
415+
catch case ex : AssertionError =>
416+
println(i"error while transforming $tree")
417+
throw ex
418+
end transform
394419

395420
/** Transforms the rhs tree into a its default tree if it is in an `erased` val/def.
396421
* Performed to shrink the tree that is known to be erased later.

0 commit comments

Comments
 (0)