diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 53b072fdeec8..721bac57d907 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -174,7 +174,7 @@ object Trees { def toList: List[Tree[T]] = this :: Nil /** if this tree is the empty tree, the alternative, else this tree */ - def orElse[U >: Untyped <: T](that: => Tree[U]): Tree[U] = + inline def orElse[U >: Untyped <: T](inline that: Tree[U]): Tree[U] = if (this eq genericEmptyTree) that else this /** The number of nodes in this tree */ diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 2c3f88c1ce5c..b1d2addfe6af 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -181,6 +181,7 @@ class ScalaSettings extends Settings.SettingGroup { val YnoDecodeStacktraces: Setting[Boolean] = BooleanSetting("-Yno-decode-stacktraces", "Show raw StackOverflow stacktraces, instead of decoding them into triggering operations.") val Yinstrument: Setting[Boolean] = BooleanSetting("-Yinstrument", "Add instrumentation code that counts allocations and closure creations.") + val YinstrumentDefs: Setting[Boolean] = BooleanSetting("-Yinstrument-defs", "Add instrumentation code that counts method calls; needs -Yinstrument to be set, too.") /** Dottydoc specific settings */ val siteRoot: Setting[String] = StringSetting( diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index b2258dee613d..179b40a18bb4 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -674,7 +674,7 @@ object Contexts { final def retractMode(mode: Mode): c.type = c.setMode(c.mode &~ mode) } - private def exploreCtx(using Context): Context = + private def exploreCtx(using Context): FreshContext = util.Stats.record("explore") val base = ctx.base import base._ @@ -701,6 +701,10 @@ object Contexts { val ectx = exploreCtx try op(using ectx) finally wrapUpExplore(ectx) + inline def exploreInFreshCtx[T](inline op: FreshContext ?=> T)(using Context): T = + val ectx = exploreCtx + try op(using ectx) finally wrapUpExplore(ectx) + private def changeOwnerCtx(owner: Symbol)(using Context): Context = val base = ctx.base import base._ diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 73e98461046e..752ab3aaa955 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -237,7 +237,7 @@ object Denotations { def mapInfo(f: Type => Type)(using Context): Denotation /** If this denotation does not exist, fallback to alternative */ - final def orElse(that: => Denotation): Denotation = if (this.exists) this else that + inline def orElse(inline that: Denotation): Denotation = if (this.exists) this else that /** The set of alternative single-denotations making up this denotation */ final def alternatives: List[SingleDenotation] = altsWith(alwaysTrue) @@ -596,7 +596,7 @@ object Denotations { def mapInfo(f: Type => Type)(using Context): SingleDenotation = derivedSingleDenotation(symbol, f(info)) - def orElse(that: => SingleDenotation): SingleDenotation = if (this.exists) this else that + inline def orElse(inline that: SingleDenotation): SingleDenotation = if (this.exists) this else that def altsWith(p: Symbol => Boolean): List[SingleDenotation] = if (exists && p(symbol)) this :: Nil else Nil diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 9b0b42734381..7ba320159531 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -239,7 +239,7 @@ object Symbols { } /** This symbol, if it exists, otherwise the result of evaluating `that` */ - def orElse(that: => Symbol)(using Context): Symbol = + inline def orElse(inline that: Symbol)(using Context): Symbol = if (this.exists) this else that /** If this symbol satisfies predicate `p` this symbol, otherwise `NoSymbol` */ diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 19800fc635e6..e0feca8c8d1b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -793,7 +793,8 @@ object Types { */ final def memberNames(keepOnly: NameFilter, pre: Type = this)(using Context): Set[Name] = this match { case tp: ClassInfo => - tp.cls.classDenot.memberNames(keepOnly) filter (keepOnly(pre, _)) + val names = tp.cls.classDenot.memberNames(keepOnly) + if keepOnly.isStable then names else names.filter(keepOnly(pre, _)) case tp: RefinedType => val ns = tp.parent.memberNames(keepOnly, pre) if (keepOnly(pre, tp.refinedName)) ns + tp.refinedName else ns @@ -5665,6 +5666,11 @@ object Types { */ abstract class NameFilter { def apply(pre: Type, name: Name)(using Context): Boolean + + /** Filter does not need to be rechecked with full prefix, if it + * has been already checked for the class denotation of the prefix + */ + def isStable: Boolean } /** A filter for names of abstract types of a given type */ @@ -5674,6 +5680,7 @@ object Types { val mbr = pre.nonPrivateMember(name) mbr.symbol.is(Deferred) && mbr.info.isInstanceOf[RealTypeBounds] } + def isStable = false } /** A filter for names of abstract types of a given type */ @@ -5683,12 +5690,14 @@ object Types { val mbr = pre.member(name) mbr.symbol.isType && !mbr.symbol.isClass } + def isStable = false } /** A filter for names of deferred term definitions of a given type */ object abstractTermNameFilter extends NameFilter { def apply(pre: Type, name: Name)(using Context): Boolean = name.isTermName && pre.nonPrivateMember(name).hasAltWith(_.symbol.is(Deferred)) + def isStable = false } /** A filter for names of type aliases of a given type */ @@ -5698,19 +5707,23 @@ object Types { val mbr = pre.nonPrivateMember(name) mbr.symbol.isAliasType } + def isStable = false } object typeNameFilter extends NameFilter { def apply(pre: Type, name: Name)(using Context): Boolean = name.isTypeName + def isStable = true } object fieldFilter extends NameFilter { def apply(pre: Type, name: Name)(using Context): Boolean = name.isTermName && (pre member name).hasAltWith(!_.symbol.is(Method)) + def isStable = true } object takeAllFilter extends NameFilter { def apply(pre: Type, name: Name)(using Context): Boolean = true + def isStable = true } object implicitFilter extends NameFilter { @@ -5719,6 +5732,7 @@ object Types { * no post-filtering is needed. */ def apply(pre: Type, name: Name)(using Context): Boolean = true + def isStable = true } // ----- Debug --------------------------------------------------------- diff --git a/compiler/src/dotty/tools/dotc/interactive/Completion.scala b/compiler/src/dotty/tools/dotc/interactive/Completion.scala index c5de3024fcd2..4bb1a828d731 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Completion.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Completion.scala @@ -323,6 +323,7 @@ object Completion { private object completionsFilter extends NameFilter { def apply(pre: Type, name: Name)(using Context): Boolean = !name.isConstructorName && name.toTermName.info.kind == SimpleNameKind + def isStable = true } } diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 241319ea6ff7..bdf74623b244 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -565,7 +565,7 @@ object Scanners { lastOffset = prev.lastOffset lineOffset = prev.lineOffset } - token match { + (token: @switch) match { case CASE => lookAhead() if (token == CLASS) fuse(CASECLASS) @@ -601,8 +601,8 @@ object Scanners { if colonSyntax then observeColonEOL() case RBRACE | RPAREN | RBRACKET => closeIndented() - case EOF if !source.maybeIncomplete => - closeIndented() + case EOF => + if !source.maybeIncomplete then closeIndented() case _ => } } diff --git a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala index b4d2c541f2c5..676cf00e2f46 100644 --- a/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala +++ b/compiler/src/dotty/tools/dotc/transform/Instrumentation.scala @@ -74,6 +74,21 @@ class Instrumentation extends MiniPhase { thisPhase => private def ok(using Context) = !ctx.owner.ownersIterator.exists(_.name.toString.startsWith("Stats")) + override def transformDefDef(tree: DefDef)(using Context): Tree = + val sym = tree.symbol + if ctx.settings.YinstrumentDefs.value + && ok + && sym.exists + && !sym.isOneOf(Synthetic | Artifact) + then + def icall = record(i"method/${sym.fullName}", tree) + def rhs1 = tree.rhs match + case rhs @ Block(stats, expr) => cpy.Block(rhs)(icall :: stats, expr) + case _: Match | _: If | _: Try | _: Labeled => cpy.Block(tree.rhs)(icall :: Nil, tree.rhs) + case rhs => rhs + cpy.DefDef(tree)(rhs = rhs1) + else tree + override def transformApply(tree: Apply)(using Context): Tree = tree.fun match { case Select(nu: New, _) => cpy.Block(tree)(record(i"alloc/${nu.tpe}", tree) :: Nil, tree) diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index e70f720501fe..9adc11585638 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -22,12 +22,19 @@ object SymUtils { extension (self: Symbol) { - /** All traits implemented by a class or trait except for those inherited through the superclass. */ + /** All traits implemented by a class or trait except for those inherited + * through the superclass. Traits are given in the order they appear in the + * parents clause (which is the reverse of their order in baseClasses) + */ def directlyInheritedTraits(using Context): List[ClassSymbol] = { val superCls = self.asClass.superClass val baseClasses = self.asClass.baseClasses if (baseClasses.isEmpty) Nil - else baseClasses.tail.takeWhile(_ ne superCls).reverse + else + def recur(bcs: List[ClassSymbol], acc: List[ClassSymbol]): List[ClassSymbol] = bcs match + case bc :: bcs1 => if bc eq superCls then acc else recur(bcs1, bc :: acc) + case nil => acc + recur(baseClasses.tail, Nil) } /** All traits implemented by a class, except for those inherited through the superclass. diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 14ece3c6c594..d52e672f1cee 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -245,10 +245,12 @@ object Implicits: if refs.isEmpty && (!considerExtension || companionRefs.isEmpty) then Nil else - val nestedCtx = ctx.fresh.addMode(Mode.TypevarsMissContext) val candidates = new mutable.ListBuffer[Candidate] def tryCandidate(extensionOnly: Boolean)(ref: ImplicitRef) = - var ckind = explore(candidateKind(ref.underlyingRef))(using nestedCtx) + var ckind = exploreInFreshCtx { (using ctx: FreshContext) => + ctx.setMode(ctx.mode | Mode.TypevarsMissContext) + candidateKind(ref.underlyingRef) + } if extensionOnly then ckind &= Candidate.Extension if ckind != Candidate.None then candidates += Candidate(ref, ckind, level) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index d09dad5ca063..1a6fca704e7d 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -29,6 +29,7 @@ object RefChecks { private val defaultMethodFilter = new NameFilter { def apply(pre: Type, name: Name)(using Context): Boolean = name.is(DefaultGetterName) + def isStable = true } /** Only one overloaded alternative is allowed to define default arguments */ @@ -490,10 +491,9 @@ object RefChecks { */ def missingTermSymbols: List[Symbol] = val buf = new mutable.ListBuffer[Symbol] - for bc <- clazz.baseClasses - sym <- bc.info.decls.toList - if sym.is(DeferredTerm) && !isImplemented(sym) && !ignoreDeferred(sym) - do buf += sym + for bc <- clazz.baseClasses; sym <- bc.info.decls.toList do + if sym.is(DeferredTerm) && !isImplemented(sym) && !ignoreDeferred(sym) then + buf += sym buf.toList // 2. Check that only abstract classes have deferred members