From c0450f0c12f265674bc657cfb469778cd35d1c40 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 19 Sep 2016 11:51:58 +1000 Subject: SD-226 Be lazier in Fields info transform for better performance Only mixin fields + accessors into class infos of classes that are either in the current run, or appear in a superclass chain of a class in the current run. This is analagous to what happens in the mixin phase. --- src/compiler/scala/tools/nsc/transform/Fields.scala | 9 ++++++++- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index 894d0a1701..c39491cf9e 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -305,6 +305,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor lazyCallingSuper setInfo tp } + private def needsMixin(cls: Symbol): Boolean = { + !(cls.isPackageClass || cls.isJavaDefined) && (currentRun.compiles(cls) || refChecks.isSeparatelyCompiledScalaSuperclass(cls)) + } + def apply(tp0: Type): Type = tp0 match { // TODO: make less destructive (name changes, decl additions, flag setting -- // none of this is actually undone when travelling back in time using atPhase) @@ -360,9 +364,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor ClassInfoType(parents, allDecls, clazz) } else tp + + case tp@ClassInfoType(parents, oldDecls, clazz) if !needsMixin(clazz) => tp + // mix in fields & accessors for all mixed in traits + case tp@ClassInfoType(parents, oldDecls, clazz) => - case tp@ClassInfoType(parents, oldDecls, clazz) if !clazz.isPackageClass => val site = clazz.thisType // setter conflicts cannot arise independently from a getter conflict, since a setter without a getter does not a val definition make diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 8034d056d7..24b4334ec4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -95,6 +95,9 @@ abstract class RefChecks extends Transform { ) } + private val separatelyCompiledScalaSuperclass = perRunCaches.newAnyRefMap[Symbol, Unit]() + final def isSeparatelyCompiledScalaSuperclass(sym: Symbol) = separatelyCompiledScalaSuperclass.contains(sym) + class RefCheckTransformer(unit: CompilationUnit) extends Transformer { var localTyper: analyzer.Typer = typer @@ -854,6 +857,8 @@ abstract class RefChecks extends Transform { // println("validate base type "+tp) val baseClass = tp.typeSymbol if (baseClass.isClass) { + if (!baseClass.isTrait && !baseClass.isJavaDefined && !currentRun.compiles(baseClass) && !separatelyCompiledScalaSuperclass.contains(baseClass)) + separatelyCompiledScalaSuperclass.update(baseClass, ()) val index = clazz.info.baseTypeIndex(baseClass) if (index >= 0) { if (seenTypes(index) forall (tp1 => !(tp1 <:< tp))) -- cgit v1.2.3 From e07585c256b3dd2ab4d197c5480d1d962607879e Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 27 Sep 2016 09:40:17 +1000 Subject: Make isSeparateCompiled... robust against rogue phase time travel We don't hit this code path during bootstrapping, but we could conceivably hit it with macros or compiler plugins peering into the future through atPhase before refchecks as run. Also rename a method to reflect the generality of the info transform (it does more than mixin, now.) --- src/compiler/scala/tools/nsc/transform/Fields.scala | 4 ++-- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala index c39491cf9e..b8b2b64fb8 100644 --- a/src/compiler/scala/tools/nsc/transform/Fields.scala +++ b/src/compiler/scala/tools/nsc/transform/Fields.scala @@ -305,7 +305,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor lazyCallingSuper setInfo tp } - private def needsMixin(cls: Symbol): Boolean = { + private def classNeedsInfoTransform(cls: Symbol): Boolean = { !(cls.isPackageClass || cls.isJavaDefined) && (currentRun.compiles(cls) || refChecks.isSeparatelyCompiledScalaSuperclass(cls)) } @@ -365,7 +365,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor } else tp - case tp@ClassInfoType(parents, oldDecls, clazz) if !needsMixin(clazz) => tp + case tp@ClassInfoType(parents, oldDecls, clazz) if !classNeedsInfoTransform(clazz) => tp // mix in fields & accessors for all mixed in traits case tp@ClassInfoType(parents, oldDecls, clazz) => diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 24b4334ec4..106b076eef 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -96,7 +96,13 @@ abstract class RefChecks extends Transform { } private val separatelyCompiledScalaSuperclass = perRunCaches.newAnyRefMap[Symbol, Unit]() - final def isSeparatelyCompiledScalaSuperclass(sym: Symbol) = separatelyCompiledScalaSuperclass.contains(sym) + final def isSeparatelyCompiledScalaSuperclass(sym: Symbol) = if (globalPhase.refChecked){ + separatelyCompiledScalaSuperclass.contains(sym) + } else { + // conservative approximation in case someone in pre-refchecks phase asks for `exitingFields(someClass.info)` + // and we haven't run the refchecks tree transform which populates `separatelyCompiledScalaSuperclass` + false + } class RefCheckTransformer(unit: CompilationUnit) extends Transformer { -- cgit v1.2.3