From f039fa7fa2544998426764bd05ea8f18179eb0bd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 1 Oct 2013 14:21:27 +0200 Subject: Added option -Yheartbeat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … which shows snapshot of the callstack of tracked operations at fixed intervals. --- src/dotty/tools/dotc/Run.scala | 4 +- src/dotty/tools/dotc/config/ScalaSettings.scala | 3 +- src/dotty/tools/dotc/core/Types.scala | 121 ++++++----- src/dotty/tools/dotc/typer/Applications.scala | 54 ++--- src/dotty/tools/dotc/typer/Implicits.scala | 29 +-- src/dotty/tools/dotc/typer/Inferencing.scala | 21 +- src/dotty/tools/dotc/typer/Typer.scala | 255 ++++++++++++------------ src/dotty/tools/dotc/util/Stats.scala | 43 +++- 8 files changed, 307 insertions(+), 223 deletions(-) diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index 962221994..a00fda36b 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -4,7 +4,7 @@ package dotc import core._ import Contexts._, Periods._, Symbols._ import io.PlainFile -import util.{SourceFile, NoSource} +import util.{SourceFile, NoSource, Stats} class Run(comp: Compiler)(implicit ctx: Context) { @@ -19,7 +19,7 @@ class Run(comp: Compiler)(implicit ctx: Context) { } } - def compile(fileNames: List[String]): Unit = { + def compile(fileNames: List[String]): Unit = Stats.monitorHeartBeat { val sources = fileNames map getSource if (sources forall (_.exists)) { units = sources map (new CompilationUnit(_)) diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala index 68f56d6d9..f1ca5bd6c 100644 --- a/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -141,8 +141,7 @@ class ScalaSettings extends Settings.SettingGroup { val Yinvalidate = StringSetting("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "") val noSelfCheck = BooleanSetting("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") val YshowSuppressedErrors = BooleanSetting("-Yshow-suppressed-errors", "Also show follow-on errors and warnings that are normally supressed.") - val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes") - + val Yheartbeat = BooleanSetting("-Yheartbeat", "show heartbeat stack trace of compiler operations.") def stop = stopAfter /** Area-specific debug output. diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index c751f1983..d8145e13c 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -15,6 +15,7 @@ import Decorators._ import Denotations._ import Periods._ import util.Positions.Position +import util.Stats.track import ast.tpd._, printing.Texts._ import transform.Erasure import printing.Printer @@ -154,8 +155,9 @@ object Types { * Lazy values are not allowed to have volatile type, as otherwise * unsoundness can result. */ - final def isVolatile(implicit ctx: Context): Boolean = + final def isVolatile(implicit ctx: Context): Boolean = track("isVolatile") { ctx.isVolatile(this) + } /** Does the type carry an annotation that is an instance of `cls`? */ final def hasAnnotation(cls: ClassSymbol)(implicit ctx: Context): Boolean = stripTypeVar match { @@ -274,12 +276,14 @@ object Types { * in linearization order, with the class itself as first element. * Inherited by all type proxies. `Nil` for all other types. */ - final def baseClasses(implicit ctx: Context): List[ClassSymbol] = this match { - case tp: TypeProxy => - tp.underlying.baseClasses - case tp: ClassInfo => - tp.cls.baseClasses - case _ => Nil + final def baseClasses(implicit ctx: Context): List[ClassSymbol] = track("baseClasses") { + this match { + case tp: TypeProxy => + tp.underlying.baseClasses + case tp: ClassInfo => + tp.cls.baseClasses + case _ => Nil + } } /** The type parameters of this type are: @@ -293,27 +297,29 @@ object Types { * For an intersection type A & B, the type parameters of its left operand, A. * Empty list for all other types. */ - final def typeParams(implicit ctx: Context): List[TypeSymbol] = this match { - case tp: ClassInfo => - tp.cls.typeParams - case tp: TypeRef => - val tsym = tp.typeSymbol - if (tsym.isClass) tsym.typeParams - else if (tsym.isAliasType) tp.underlying.typeParams - else tp.info.bounds.hi match { - case AndType(hkBound, other) if defn.hkTraits contains hkBound.typeSymbol => - hkBound.typeSymbol.typeParams - case _ => - Nil - } - case tp: RefinedType => - tp.parent.typeParams filterNot (_.name == tp.refinedName) - case tp: TypeProxy => - tp.underlying.typeParams - case tp: AndType => - tp.tp1.typeParams - case _ => - Nil + final def typeParams(implicit ctx: Context): List[TypeSymbol] = track("typeParams") { + this match { + case tp: ClassInfo => + tp.cls.typeParams + case tp: TypeRef => + val tsym = tp.typeSymbol + if (tsym.isClass) tsym.typeParams + else if (tsym.isAliasType) tp.underlying.typeParams + else tp.info.bounds.hi match { + case AndType(hkBound, other) if defn.hkTraits contains hkBound.typeSymbol => + hkBound.typeSymbol.typeParams + case _ => + Nil + } + case tp: RefinedType => + tp.parent.typeParams filterNot (_.name == tp.refinedName) + case tp: TypeProxy => + tp.underlying.typeParams + case tp: AndType => + tp.tp1.typeParams + case _ => + Nil + } } def uninstantiatedTypeParams(implicit ctx: Context): List[TypeSymbol] = @@ -338,12 +344,14 @@ object Types { * The result is either a SymDenotation or a MultiDenotation of SymDenotations. * The info(s) are the original symbol infos, no translation takes place. */ - final def decl(name: Name)(implicit ctx: Context): Denotation = + final def decl(name: Name)(implicit ctx: Context): Denotation = track("decl") { findDecl(name, EmptyFlags) + } /** A denotation containing the non-private declaration(s) in this type with the given name */ - final def nonPrivateDecl(name: Name)(implicit ctx: Context): Denotation = + final def nonPrivateDecl(name: Name)(implicit ctx: Context): Denotation = track("nonPrivateDecl") { findDecl(name, Private) + } /** A denotation containing the declaration(s) in this type with the given * name, as seen from prefix type `pre`. Declarations that have a flag @@ -359,15 +367,17 @@ object Types { } /** The member of this type with the given name */ - final def member(name: Name)(implicit ctx: Context): Denotation = + final def member(name: Name)(implicit ctx: Context): Denotation = track("member-" + name) { try findMember(name, this, EmptyFlags) catch { case ex: Throwable => println(s"error occurred during: $this member $name"); throw ex // DEBUG } + } /** The non-private member of this type with the given name. */ - final def nonPrivateMember(name: Name)(implicit ctx: Context): Denotation = + final def nonPrivateMember(name: Name)(implicit ctx: Context): Denotation = track("nonPrivateMember") { findMember(name, this, Flags.Private) + } /** Find member of this type with given name and * produce a denotation that contains the type of the member @@ -448,32 +458,37 @@ object Types { /** The set of names that denote an abstract member of this type * which is also an abstract member of `pre`. */ - final def abstractMemberNames(pre: Type = this)(implicit ctx: Context): Set[Name] = + final def abstractMemberNames(pre: Type = this)(implicit ctx: Context): Set[Name] = track("abstractMemberNames") { memberNames(abstractTypeNameFilter, pre) | memberNames(abstractTermNameFilter, pre) + } /** The set of abstract term members of this type. */ - final def abstractTermMembers(implicit ctx: Context): Set[SingleDenotation] = + final def abstractTermMembers(implicit ctx: Context): Set[SingleDenotation] = track("abstractTermMembers") { memberNames(abstractTermNameFilter).flatMap(member(_).altsWith(_ is Deferred)) + } /** The set of abstract type members of this type. */ - final def abstractTypeMembers(implicit ctx: Context): Set[SingleDenotation] = + final def abstractTypeMembers(implicit ctx: Context): Set[SingleDenotation] = track("abstractTypeMembers") { memberNames(abstractTypeNameFilter).map(member(_).asInstanceOf[SingleDenotation]) + } /** The set of abstract members of this type. */ final def abstractMembers(implicit ctx: Context): Set[SingleDenotation] = abstractTermMembers | abstractTypeMembers /** The set of type members of this type */ - final def typeMembers(implicit ctx: Context): Set[SingleDenotation] = + final def typeMembers(implicit ctx: Context): Set[SingleDenotation] = track("typeMembers") { memberNames(typeNameFilter).map(member(_).asInstanceOf[SingleDenotation]) + } /** The set of implicit members of this type */ - final def implicitMembers(implicit ctx: Context): List[TermRef] = + final def implicitMembers(implicit ctx: Context): List[TermRef] = track("implicitMembers") { memberNames(implicitFilter).toList .flatMap(name => member(name) .altsWith(_ is Implicit) .map(d => TermRef.withSym(this, d.symbol.asTerm).withDenot(d))) + } /** The info of `sym`, seen as a member of this type. */ final def memberInfo(sym: Symbol)(implicit ctx: Context): Type = @@ -482,21 +497,24 @@ object Types { /** This type seen as if it were the type of a member of prefix type `pre` * declared in class `cls`. */ - final def asSeenFrom(pre: Type, cls: Symbol)(implicit ctx: Context): Type = + final def asSeenFrom(pre: Type, cls: Symbol)(implicit ctx: Context): Type = track("asSeenFrom") { if (!cls.membersNeedAsSeenFrom(pre)) this else ctx.asSeenFrom(this, pre, cls, null) + } // ----- Subtype-related -------------------------------------------- /** Is this type a subtype of that type? */ - final def <:<(that: Type)(implicit ctx: Context): Boolean = + final def <:<(that: Type)(implicit ctx: Context): Boolean = track("<:<") { ctx.typeComparer.isSubType(this, that) + } /** Is this type the same as that type? * This is the case iff `this <:< that` and `that <:< this`. */ - final def =:=(that: Type)(implicit ctx: Context): Boolean = + final def =:=(that: Type)(implicit ctx: Context): Boolean = track("=:=") { ctx.typeComparer.isSameType(this, that) + } /** Is this type close enough to that type so that members * with the two type would override each other? @@ -510,9 +528,10 @@ object Types { * - Or phase.erasedTypes is false and both types are neither method nor * poly types. */ - def matches(that: Type)(implicit ctx: Context): Boolean = + def matches(that: Type)(implicit ctx: Context): Boolean = track("matches") { ctx.typeComparer.matchesType( this, that, alwaysMatchSimple = !ctx.phase.erasedTypes) + } /** The non-private symbol with given name in the given class that matches this type. * @param inClass The class containing the symbol's definition @@ -531,16 +550,20 @@ object Types { } /** The basetype of this type with given class symbol */ - final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ { base.denot match { - case classd: ClassDenotation => classd.baseTypeOf(this) - case _ => NoType - }} + final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ track("baseType") { + base.denot match { + case classd: ClassDenotation => classd.baseTypeOf(this) + case _ => NoType + } + } - def & (that: Type)(implicit ctx: Context): Type = + def & (that: Type)(implicit ctx: Context): Type = track("&") { ctx.typeComparer.glb(this, that) + } - def | (that: Type)(implicit ctx: Context): Type = + def | (that: Type)(implicit ctx: Context): Type = track("|") { ctx.typeComparer.lub(this, that) + } // ----- Unwrapping types ----------------------------------------------- @@ -770,7 +793,7 @@ object Types { // ----- Modeling type application -------------------------------- /** Encode the type resulting from applying this type to given arguments */ - final def appliedTo(args: List[Type])(implicit ctx: Context): Type = { + final def appliedTo(args: List[Type])(implicit ctx: Context): Type = track("appliedTo") { def recur(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match { case arg :: args1 => @@ -997,7 +1020,7 @@ object Types { * +1 means: only covariant occurrences * 0 means: mixed or non-variant occurrences */ - def variances(include: TypeVar => Boolean)(implicit ctx: Context): VarianceMap = { + def variances(include: TypeVar => Boolean)(implicit ctx: Context): VarianceMap = track("variances") { val accu = new TypeAccumulator[VarianceMap] { def apply(vmap: VarianceMap, t: Type): VarianceMap = t match { case t: TypeVar if include(t) => diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 3216e8b74..05008ac1a 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -5,6 +5,7 @@ package typer import core._ import ast.{Trees, untpd, tpd, TreeInfo} import util.Positions._ +import util.Stats.track import Trees.Untyped import Mode.ImplicitsEnabled import Contexts._ @@ -447,8 +448,9 @@ trait Applications extends Compatibility { self: Typer => def treeToArg(arg: Tree): Tree = arg } - def typedApply(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = + def typedApply(app: untpd.Apply, fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = track("typedApply") { new ApplyToTyped(app, fun, methRef, args, resultType).result + } def typedApply(fun: Tree, methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context): Tree = typedApply(untpd.Apply(untpd.TypedSplice(fun), args), fun, methRef, args, resultType) @@ -458,7 +460,7 @@ trait Applications extends Compatibility { self: Typer => typedUnApply(tree, pt) else { - def realApply(implicit ctx: Context): Tree = { + def realApply(implicit ctx: Context): Tree = track("realApply") { val proto = new FunProto(tree.args, pt, this) val fun1 = typedExpr(tree.fun, proto) methPart(fun1).tpe match { @@ -473,7 +475,7 @@ trait Applications extends Compatibility { self: Typer => case Select(qual, name) => tryEither { implicit ctx => val qual1 = adapt(qual, new SelectionProto(name, proto)) - if (qual1.tpe.isError || (qual1 eq qual)) qual1 + if (qual1.tpe.isError || (qual1 eq qual)) qual1 else typedApply( cpy.Apply(tree, @@ -494,7 +496,7 @@ trait Applications extends Compatibility { self: Typer => } } - def typedOpAssign: Tree = { + def typedOpAssign: Tree = track("typedOpAssign") { val Apply(Select(lhs, name), rhss) = tree val lhs1 = typedExpr(lhs) val lifted = new mutable.ListBuffer[Tree] @@ -517,7 +519,7 @@ trait Applications extends Compatibility { self: Typer => } } - def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = { + def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = track("typedTypeApply") { val typedFn = typedExpr(tree.fun, PolyProto(tree.args.length, pt)) val typedArgs = tree.args mapconserve (typedType(_)) val ownType = typedFn.tpe.widen match { @@ -531,7 +533,7 @@ trait Applications extends Compatibility { self: Typer => cpy.TypeApply(tree, typedFn, typedArgs).withType(ownType) } - def typedUnApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { + def typedUnApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = track("typedUnApply") { val Apply(qual, args) = tree def unapplyArgs(unapplyResult: Type)(implicit ctx: Context): List[Type] = { @@ -662,7 +664,7 @@ trait Applications extends Compatibility { self: Typer => /** In a set of overloaded applicable alternatives, is `alt1` at least as good as * `alt2`? `alt1` and `alt2` are nonoverloaded references. */ - def isAsGood(alt1: TermRef, alt2: TermRef)(implicit ctx: Context): Boolean = { + def isAsGood(alt1: TermRef, alt2: TermRef)(implicit ctx: Context): Boolean = track("isAsGood") { /** Is class or module class `sym1` derived from class or module class `sym2`? */ def isDerived(sym1: Symbol, sym2: Symbol): Boolean = @@ -712,30 +714,32 @@ trait Applications extends Compatibility { self: Typer => else /* 1/9 */ winsType1 || /* 2/27 */ !winsType2 } - def narrowMostSpecific(alts: List[TermRef])(implicit ctx: Context): List[TermRef] = (alts: @unchecked) match { - case alt :: alts1 => - def winner(bestSoFar: TermRef, alts: List[TermRef]): TermRef = alts match { - case alt :: alts1 => - winner(if (isAsGood(alt, bestSoFar)) alt else bestSoFar, alts1) - case nil => - bestSoFar - } - val best = winner(alt, alts1) - def asGood(alts: List[TermRef]): List[TermRef] = alts match { - case alt :: alts1 => - if ((alt eq best) || !isAsGood(alt, best)) asGood(alts1) - else alt :: asGood(alts1) - case nil => - Nil - } - best :: asGood(alts1) + def narrowMostSpecific(alts: List[TermRef])(implicit ctx: Context): List[TermRef] = track("narrowMostSpecific") { + (alts: @unchecked) match { + case alt :: alts1 => + def winner(bestSoFar: TermRef, alts: List[TermRef]): TermRef = alts match { + case alt :: alts1 => + winner(if (isAsGood(alt, bestSoFar)) alt else bestSoFar, alts1) + case nil => + bestSoFar + } + val best = winner(alt, alts1) + def asGood(alts: List[TermRef]): List[TermRef] = alts match { + case alt :: alts1 => + if ((alt eq best) || !isAsGood(alt, best)) asGood(alts1) + else alt :: asGood(alts1) + case nil => + Nil + } + best :: asGood(alts1) + } } private lazy val dummyTree = untpd.Literal(Constant(null)) def dummyTreeOfType(tp: Type): Tree = dummyTree withTypeUnchecked tp /** Resolve overloaded alternative `alts`, given expected type `pt`. */ - def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = { + def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") { def isDetermined(alts: List[TermRef]) = alts.isEmpty || alts.tail.isEmpty diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 52b856864..98163a7f5 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -5,6 +5,7 @@ package typer import core._ import ast.{Trees, untpd, tpd, TreeInfo} import util.Positions._ +import util.Stats.track import Contexts._ import Types._ import Flags._ @@ -35,7 +36,7 @@ object Implicits { def refs: List[TermRef] /** Return those references in `refs` that are compatible with type `pt`. */ - protected def filterMatching(pt: Type)(implicit ctx: Context): List[TermRef] = { + protected def filterMatching(pt: Type)(implicit ctx: Context): List[TermRef] = track("filterMatching") { def result(implicit ctx: Context) = refs filter (ref => isCompatible(normalize(ref), pt)) result(ctx.fresh.withNewTyperState) // create a defensive copy of ctx to avoid constraint pollution @@ -180,7 +181,7 @@ trait ImplicitRunInfo { self: RunInfo => } // todo: compute implicits directly, without going via companionRefs - private def computeImplicitScope(tp: Type): OfTypeImplicits = { + private def computeImplicitScope(tp: Type): OfTypeImplicits = track("computeImplicicScope") { val comps = new TermRefSet tp match { case tp: NamedType => @@ -239,8 +240,9 @@ trait Implicits { self: Typer => /** Find an implicit conversion to apply to given tree `from` so that the * result is compatible with type `to`. */ - def inferView(from: tpd.Tree, to: Type)(implicit ctx: Context): SearchResult = + def inferView(from: tpd.Tree, to: Type)(implicit ctx: Context): SearchResult = track("inferView") { inferImplicit(to, from, from.pos) + } /** Find an implicit parameter or conversion. * @param pt The expected type of the parameter or conversion. @@ -248,17 +250,18 @@ trait Implicits { self: Typer => * it should be applied, EmptyTree otherwise. * @param pos The position where errors should be reported. */ - def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = + def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = track("inferImplicit") { ctx.traceIndented(s"search implicit $pt, arg = ${argument.show}", show = true) { - val isearch = - if (ctx.settings.explaintypes.value) new ExplainedImplicitSearch(pt, argument, pos) - else new ImplicitSearch(pt, argument, pos) - val result = isearch.bestImplicit - result match { - case success: SearchSuccess => success.tstate.commit() - case _ => + val isearch = + if (ctx.settings.explaintypes.value) new ExplainedImplicitSearch(pt, argument, pos) + else new ImplicitSearch(pt, argument, pos) + val result = isearch.bestImplicit + result match { + case success: SearchSuccess => success.tstate.commit() + case _ => + } + result } - result } /** An implicit search; parameters as in `inferImplicit` */ @@ -275,7 +278,7 @@ trait Implicits { self: Typer => ctx.typerState.checkConsistent // !!! DEBUG /** Try to typecheck an implicit reference */ - def typedImplicit(ref: TermRef)(implicit ctx: Context): SearchResult = { + def typedImplicit(ref: TermRef)(implicit ctx: Context): SearchResult = track("typedImplicit") { ctx.typerState.checkConsistent // !!! DEBUG val id = Ident(ref).withPos(pos) val tree = diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index c514699a3..6f78409d0 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -8,6 +8,7 @@ import Contexts._, Types._, Flags._, Denotations._, Names._, StdNames._, NameOps import Trees._ import annotation.unchecked import util.Positions._ +import util.Stats import Decorators._ import ErrorReporting.InfoString @@ -96,13 +97,15 @@ object Inferencing { * - converts non-dependent method types to the corresponding function types * - dereferences parameterless method types */ - def normalize(tp: Type)(implicit ctx: Context): Type = tp.widenSingleton match { - case pt: PolyType => normalize(ctx.track(pt).resultType) - case mt: MethodType if !mt.isDependent => - if (mt.isImplicit) mt.resultType - else defn.FunctionType(mt.paramTypes, mt.resultType) - case et: ExprType => et.resultType - case _ => tp + def normalize(tp: Type)(implicit ctx: Context): Type = Stats.track("normalize") { + tp.widenSingleton match { + case pt: PolyType => normalize(ctx.track(pt).resultType) + case mt: MethodType if !mt.isDependent => + if (mt.isImplicit) mt.resultType + else defn.FunctionType(mt.paramTypes, mt.resultType) + case et: ExprType => et.resultType + case _ => tp + } } /** Is type fully defined, meaning the type does not contain wildcard types @@ -188,7 +191,7 @@ object Inferencing { * approximate it by its lower bound. Otherwise, if it appears contravariantly * in type `tp` approximate it by its upper bound. */ - def interpolateUndetVars(tp: Type, pos: Position): Unit = { + def interpolateUndetVars(tp: Type, pos: Position): Unit = Stats.track("interpolateUndetVars") { val vs = tp.variances(tvar => (ctx.typerState.undetVars contains tvar) && (pos contains tvar.pos)) for ((tvar, v) <- vs) @@ -211,7 +214,7 @@ object Inferencing { * maximized and return None. If this is not possible, because a non-variant * typevar is not uniquely determined, return that typevar in a Some. */ - def maximizeType(tp: Type): Option[TypeVar] = { + def maximizeType(tp: Type): Option[TypeVar] = Stats.track("maximizeType") { val vs = tp.variances(tvar => ctx.typerState.undetVars contains tvar) var result: Option[TypeVar] = None for ((tvar, v) <- vs) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 224b3fcb1..e902864d6 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -27,6 +27,7 @@ import util.SourcePosition import collection.mutable import annotation.tailrec import Implicits._ +import util.Stats.track import language.implicitConversions trait TyperContextOps { ctx: Context => } @@ -151,7 +152,7 @@ class Typer extends Namer with Applications with Implicits { * (2) Change imported symbols to selections * */ - def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = { + def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = track("typedIdent") { val name = tree.name /** Method is necessary because error messages need to bind to @@ -334,19 +335,19 @@ class Typer extends Namer with Applications with Implicits { tree.withType(ownType.underlyingIfRepeated) } - def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { + def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") { val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt)) val ownType = checkedSelectionType(qual1, tree) checkValue(ownType, pt, tree.pos) cpy.Select(tree, qual1, tree.name).withType(ownType) } - def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = { + def typedThis(tree: untpd.This)(implicit ctx: Context): Tree = track("typedThis") { val cls = qualifyingClass(tree, tree.qual, packageOK = false) tree.withType(cls.thisType) } - def typedSuper(tree: untpd.Super)(implicit ctx: Context): Tree = { + def typedSuper(tree: untpd.Super)(implicit ctx: Context): Tree = track("typedSuper") { val mix = tree.mix val qual1 = typed(tree.qual) val cls = qual1.tpe.typeSymbol @@ -367,7 +368,7 @@ class Typer extends Namer with Applications with Implicits { cpy.Super(tree, qual1, mix).withType(SuperType(cls.thisType, owntype)) } - def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) = + def typedLiteral(tree: untpd.Literal)(implicit ctx: Context) = track("typedLiteral") { tree.withType { tree.const.tag match { case UnitTag => defn.UnitType @@ -375,21 +376,24 @@ class Typer extends Namer with Applications with Implicits { case _ => ConstantType(tree.const) } } + } - def typedNew(tree: untpd.New, pt: Type)(implicit ctx: Context) = tree.tpt match { - case templ: Template => - import untpd._ - val x = tpnme.ANON_CLASS - val clsDef = TypeDef(Modifiers(Final), x, templ) - typed(cpy.Block(tree, clsDef :: Nil, New(Ident(x), Nil)), pt) - case _ => - val tpt1 = typedType(tree.tpt) - val cls = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos) - // todo in a later phase: checkInstantiatable(cls, tpt1.pos) - cpy.New(tree, tpt1).withType(tpt1.tpe) + def typedNew(tree: untpd.New, pt: Type)(implicit ctx: Context) = track("typedNew") { + tree.tpt match { + case templ: Template => + import untpd._ + val x = tpnme.ANON_CLASS + val clsDef = TypeDef(Modifiers(Final), x, templ) + typed(cpy.Block(tree, clsDef :: Nil, New(Ident(x), Nil)), pt) + case _ => + val tpt1 = typedType(tree.tpt) + val cls = checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos) + // todo in a later phase: checkInstantiatable(cls, tpt1.pos) + cpy.New(tree, tpt1).withType(tpt1.tpe) + } } - def typedPair(tree: untpd.Pair, pt: Type)(implicit ctx: Context) = { + def typedPair(tree: untpd.Pair, pt: Type)(implicit ctx: Context) = track("typedPair") { val (leftProto, rightProto) = pt.typeArgs match { case l :: r :: Nil if pt isRef defn.PairClass => (l, r) case _ => (WildcardType, WildcardType) @@ -399,51 +403,55 @@ class Typer extends Namer with Applications with Implicits { cpy.Pair(tree, left1, right1).withType(defn.PairType.appliedTo(left1.tpe :: right1.tpe :: Nil)) } - def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = tree.expr match { - case id: Ident if (ctx.mode is Mode.Pattern) && isVarPattern(id) && id.name != nme.WILDCARD => - import untpd._ - typed(Bind(id.name, Typed(Ident(nme.WILDCARD), tree.tpt)).withPos(id.pos)) - case _ => - val tpt1 = typedType(tree.tpt) - val expr1 = typedExpr(tree.expr, tpt1.tpe) - cpy.Typed(tree, expr1, tpt1).withType(tpt1.tpe) + def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = track("typedTyped") { + tree.expr match { + case id: Ident if (ctx.mode is Mode.Pattern) && isVarPattern(id) && id.name != nme.WILDCARD => + import untpd._ + typed(Bind(id.name, Typed(Ident(nme.WILDCARD), tree.tpt)).withPos(id.pos)) + case _ => + val tpt1 = typedType(tree.tpt) + val expr1 = typedExpr(tree.expr, tpt1.tpe) + cpy.Typed(tree, expr1, tpt1).withType(tpt1.tpe) + } } - def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = { + def typedNamedArg(tree: untpd.NamedArg, pt: Type)(implicit ctx: Context) = track("typedNamedArg") { val arg1 = typed(tree.arg, pt) cpy.NamedArg(tree, tree.name, arg1).withType(arg1.tpe) } - def typedAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context) = tree.lhs match { - case lhs @ Apply(fn, args) => - typed(cpy.Apply(lhs, untpd.Select(fn, nme.update), args :+ tree.rhs), pt) - case lhs => - val lhs1 = typed(lhs) - def reassignmentToVal = - errorTree(cpy.Assign(tree, lhs1, typed(tree.rhs, lhs1.tpe.widen)), - "reassignment to val") - lhs1.tpe match { - case ref: TermRef if ref.symbol is Mutable => - cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info)).withType(defn.UnitType) - case ref: TermRef if ref.info.isParameterless => - val pre = ref.prefix - val setterName = ref.name.setterName - val setter = pre.member(setterName) - lhs1 match { - case lhs1: RefTree if setter.exists => - val setterTypeRaw = TermRef(pre, setterName).withDenot(setter) - val setterType = checkAccessible(setterTypeRaw, isSuperSelection(tree), tree.pos) - val lhs2 = lhs1.withName(setterName).withType(setterType) - typed(cpy.Apply(tree, untpd.TypedSplice(lhs2), tree.rhs :: Nil)) - case _ => - reassignmentToVal - } - case _ => - reassignmentToVal - } + def typedAssign(tree: untpd.Assign, pt: Type)(implicit ctx: Context) = track("typedAssign") { + tree.lhs match { + case lhs @ Apply(fn, args) => + typed(cpy.Apply(lhs, untpd.Select(fn, nme.update), args :+ tree.rhs), pt) + case lhs => + val lhs1 = typed(lhs) + def reassignmentToVal = + errorTree(cpy.Assign(tree, lhs1, typed(tree.rhs, lhs1.tpe.widen)), + "reassignment to val") + lhs1.tpe match { + case ref: TermRef if ref.symbol is Mutable => + cpy.Assign(tree, lhs1, typed(tree.rhs, ref.info)).withType(defn.UnitType) + case ref: TermRef if ref.info.isParameterless => + val pre = ref.prefix + val setterName = ref.name.setterName + val setter = pre.member(setterName) + lhs1 match { + case lhs1: RefTree if setter.exists => + val setterTypeRaw = TermRef(pre, setterName).withDenot(setter) + val setterType = checkAccessible(setterTypeRaw, isSuperSelection(tree), tree.pos) + val lhs2 = lhs1.withName(setterName).withType(setterType) + typed(cpy.Apply(tree, untpd.TypedSplice(lhs2), tree.rhs :: Nil)) + case _ => + reassignmentToVal + } + case _ => + reassignmentToVal + } + } } - def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = { + def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = track("typedBlock") { val exprCtx = index(tree.stats) val stats1 = typedStats(tree.stats, ctx.owner) val expr1 = typedExpr(tree.expr, pt)(exprCtx) @@ -457,14 +465,14 @@ class Typer extends Namer with Applications with Implicits { i"local definition of ${leaks.head.name} escapes as part of block's type ${result.tpe}") } - def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = { + def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = track("typedIf") { val cond1 = typed(tree.cond, defn.BooleanType) val thenp1 = typed(tree.thenp, pt) val elsep1 = typed(if (tree.elsep.isEmpty) unitLiteral else tree.elsep, pt) cpy.If(tree, cond1, thenp1, elsep1).withType(thenp1.tpe | elsep1.tpe) } - def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = { + def typedFunction(tree: untpd.Function, pt: Type)(implicit ctx: Context) = track("typedFunction") { val untpd.Function(args, body) = tree if (ctx.mode is Mode.Type) typed(cpy.AppliedTypeTree(tree, @@ -493,7 +501,7 @@ class Typer extends Namer with Applications with Implicits { } } - def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = { + def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context) = track("typedClosure") { val env1 = tree.env mapconserve (typed(_)) val meth1 = typedUnadapted(tree.meth) val ownType = meth1.tpe.widen match { @@ -507,56 +515,58 @@ class Typer extends Namer with Applications with Implicits { cpy.Closure(tree, env1, meth1, EmptyTree).withType(ownType) } - def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) = tree.selector match { - case EmptyTree => - typed(desugar.makeCaseLambda(tree.cases) withPos tree.pos, pt) - case _ => - val sel1 = typedExpr(tree.selector) - val selType = - if (isFullyDefined(sel1.tpe)) sel1.tpe - else errorType("internal error: type of pattern selector is not fully defined", tree.pos) + def typedMatch(tree: untpd.Match, pt: Type)(implicit ctx: Context) = track("typedMatch") { + tree.selector match { + case EmptyTree => + typed(desugar.makeCaseLambda(tree.cases) withPos tree.pos, pt) + case _ => + val sel1 = typedExpr(tree.selector) + val selType = + if (isFullyDefined(sel1.tpe)) sel1.tpe + else errorType("internal error: type of pattern selector is not fully defined", tree.pos) + + /** gadtSyms = "all type parameters of enclosing methods that appear + * non-variantly in the selector type + */ + val gadtSyms: Set[Symbol] = { + val accu = new TypeAccumulator[Set[Symbol]] { + def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = { + val tsyms1 = t match { + case tr: TypeRef if (tr.symbol is TypeParam) && tr.symbol.owner.isTerm && variance == 0 => + tsyms + tr.symbol + case _ => + tsyms + } + foldOver(tsyms1, t) + } + } + accu(Set.empty, selType) + } - /** gadtSyms = "all type parameters of enclosing methods that appear - * non-variantly in the selector type - */ - val gadtSyms: Set[Symbol] = { - val accu = new TypeAccumulator[Set[Symbol]] { - def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = { - val tsyms1 = t match { - case tr: TypeRef if (tr.symbol is TypeParam) && tr.symbol.owner.isTerm && variance == 0 => - tsyms + tr.symbol + def typedCase(tree: untpd.CaseDef): CaseDef = track("typedCase") { + def caseRest(pat: Tree)(implicit ctx: Context) = { + gadtSyms foreach (_.resetGADTFlexType) + foreachSubTreeOf(pat) { + case b: Bind => + if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol) + else ctx.error(i"duplicate pattern variable: ${b.name}", b.pos) case _ => - tsyms } - foldOver(tsyms1, t) + val guard1 = typedExpr(tree.guard, defn.BooleanType) + val body1 = typedExpr(tree.body, pt) + cpy.CaseDef(tree, pat, guard1, body1) withType body1.tpe } + val doCase: () => CaseDef = + () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.withNewScope) + (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))() } - accu(Set.empty, selType) - } - def typedCase(tree: untpd.CaseDef): CaseDef = { - def caseRest(pat: Tree)(implicit ctx: Context) = { - gadtSyms foreach (_.resetGADTFlexType) - foreachSubTreeOf(pat) { - case b: Bind => - if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol) - else ctx.error(i"duplicate pattern variable: ${b.name}", b.pos) - case _ => - } - val guard1 = typedExpr(tree.guard, defn.BooleanType) - val body1 = typedExpr(tree.body, pt) - cpy.CaseDef(tree, pat, guard1, body1) withType body1.tpe - } - val doCase: () => CaseDef = - () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.withNewScope) - (doCase /: gadtSyms) ((op, tsym) => tsym.withGADTFlexType(op)) () + val cases1 = tree.cases mapconserve typedCase + cpy.Match(tree, sel1, cases1).withType(ctx.typeComparer.lub(cases1.tpes)) } - - val cases1 = tree.cases mapconserve typedCase - cpy.Match(tree, sel1, cases1).withType(ctx.typeComparer.lub(cases1.tpes)) } - def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = { + def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") { def enclMethInfo(cx: Context): (Tree, Type) = if (cx == NoContext || cx.tree.isInstanceOf[Trees.TypeDef[_]]) { ctx.error("return outside method definition") @@ -582,7 +592,7 @@ class Typer extends Namer with Applications with Implicits { cpy.Return(tree, expr1, from) withType defn.NothingType } - def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = { + def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") { val expr1 = typed(tree.expr, pt) val handler1 = typed(tree.handler, defn.FunctionType(defn.ThrowableType :: Nil, pt)) val finalizer1 = typed(tree.finalizer, defn.UnitType) @@ -593,18 +603,18 @@ class Typer extends Namer with Applications with Implicits { cpy.Try(tree, expr1, handler1, finalizer1).withType(expr1.tpe | handlerResultType) } - def typedThrow(tree: untpd.Throw)(implicit ctx: Context): Throw = { + def typedThrow(tree: untpd.Throw)(implicit ctx: Context): Throw = track("typedThrow") { val expr1 = typed(tree.expr, defn.ThrowableType) cpy.Throw(tree, expr1) withType defn.NothingType } - def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = { + def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") { val proto1 = pt.elemType orElse WildcardType val elems1 = tree.elems mapconserve (typed(_, proto1)) cpy.SeqLiteral(tree, elems1) withType ctx.typeComparer.lub(elems1.tpes) } - def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = { + def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") { val (original1, ownType) = tree.original match { case untpd.EmptyTree => assert(isFullyDefined(pt)) @@ -620,30 +630,30 @@ class Typer extends Namer with Applications with Implicits { cpy.TypeTree(tree, original1) withType ownType } - def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = { + def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = track("typedSingletonTypeTree") { val ref1 = typedExpr(tree.ref) checkStable(ref1.qualifierType, tree.pos) cpy.SingletonTypeTree(tree, ref1) withType ref1.tpe } - def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = { + def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = track("typedSelectFromTypeTree") { val qual1 = typedType(tree.qualifier, selectionProto(tree.name, pt)) cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(checkedSelectionType(qual1, tree)) } - def typedAndTypeTree(tree: untpd.AndTypeTree)(implicit ctx: Context): AndTypeTree = { + def typedAndTypeTree(tree: untpd.AndTypeTree)(implicit ctx: Context): AndTypeTree = track("typedAndTypeTree") { val left1 = typed(tree.left) val right1 = typed(tree.right) cpy.AndTypeTree(tree, left1, right1) withType left1.tpe & right1.tpe } - def typedOrTypeTree(tree: untpd.OrTypeTree)(implicit ctx: Context): OrTypeTree = { + def typedOrTypeTree(tree: untpd.OrTypeTree)(implicit ctx: Context): OrTypeTree = track("typedOrTypeTree") { val left1 = typed(tree.left) val right1 = typed(tree.right) cpy.OrTypeTree(tree, left1, right1) withType left1.tpe | right1.tpe } - def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = { + def typedRefinedTypeTree(tree: untpd.RefinedTypeTree)(implicit ctx: Context): RefinedTypeTree = track("typedRefinedTypeTree") { val tpt1 = typedAheadType(tree.tpt) val refineClsDef = desugar.refinedTypeToClass(tree) val refineCls = createSymbol(refineClsDef).asClass @@ -664,7 +674,7 @@ class Typer extends Namer with Applications with Implicits { (tpt1.tpe /: refinements1)(addRefinement) } - def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): AppliedTypeTree = { + def typedAppliedTypeTree(tree: untpd.AppliedTypeTree)(implicit ctx: Context): AppliedTypeTree = track("typedAppliedTypeTree") { val tpt1 = typed(tree.tpt) val args1 = tree.args mapconserve (typed(_)) val tparams = tpt1.tpe.typeParams @@ -674,7 +684,7 @@ class Typer extends Namer with Applications with Implicits { cpy.AppliedTypeTree(tree, tpt1, args1) withType tpt1.tpe.appliedTo(args1.tpes) } - def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = { + def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = track("typedTypeBoundsTree") { val lo1 = typed(tree.lo) val hi1 = typed(tree.hi) if (!(lo1.tpe <:< hi1.tpe)) @@ -682,27 +692,28 @@ class Typer extends Namer with Applications with Implicits { cpy.TypeBoundsTree(tree, lo1, hi1) withType TypeBounds(lo1.tpe, hi1.tpe) } - def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = { + def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = track("typedBind") { val body1 = typed(tree.body, pt) val sym = ctx.newSymbol(ctx.owner, tree.name.asTermName, EmptyFlags, pt, coord = tree.pos) cpy.Bind(tree, tree.name, body1) withType TermRef.withSym(NoPrefix, sym) } - def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = { + def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = track("typedAlternative") { val trees1 = tree.trees mapconserve (typed(_, pt)) cpy.Alternative(tree, trees1) withType ctx.typeComparer.lub(trees1.tpes) } - def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = { + def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = track("typedModifiers") { val annotations1 = mods.annotations mapconserve typedAnnotation if (annotations1 eq mods.annotations) mods.asInstanceOf[Modifiers] else Modifiers(mods.flags, mods.privateWithin, annotations1) } - def typedAnnotation(annot: untpd.Tree)(implicit ctx: Context): Tree = + def typedAnnotation(annot: untpd.Tree)(implicit ctx: Context): Tree = track("typedAnnotation") { typed(annot, defn.AnnotationClass.typeConstructor) + } - def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context) = { + def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context) = track("typedValDef") { val ValDef(mods, name, tpt, rhs) = vdef val mods1 = typedModifiers(mods) val tpt1 = typedType(tpt) @@ -711,7 +722,7 @@ class Typer extends Namer with Applications with Implicits { cpy.ValDef(vdef, mods1, name, tpt1, rhs1).withType(refType) } - def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = { + def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") { val DefDef(mods, name, tparams, vparamss, tpt, rhs) = ddef val mods1 = typedModifiers(mods) val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef]) @@ -722,14 +733,14 @@ class Typer extends Namer with Applications with Implicits { //todo: make sure dependent method types do not depend on implicits or by-name params } - def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): TypeDef = { + def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): TypeDef = track("typedTypeDef") { val TypeDef(mods, name, rhs) = tdef val mods1 = typedModifiers(mods) val rhs1 = typedType(rhs) cpy.TypeDef(tdef, mods1, name, rhs1).withType(sym.symRef) } - def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = { + def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = track("typedClassDef") { val TypeDef(mods, name, impl @ Template(constr, parents, self, body)) = cdef val mods1 = typedModifiers(mods) val constr1 = typed(constr).asInstanceOf[DefDef] @@ -751,12 +762,12 @@ class Typer extends Namer with Applications with Implicits { // 4. Polymorphic type defs override nothing. } - def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = { + def typedImport(imp: untpd.Import, sym: Symbol)(implicit ctx: Context): Import = track("typedImport") { val expr1 = typedExpr(imp.expr, AnySelectionProto) cpy.Import(imp, expr1, imp.selectors).withType(sym.symRef) } - def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = { + def typedAnnotated(tree: untpd.Annotated, pt: Type)(implicit ctx: Context): Tree = track("typedAnnotated") { val annot1 = typed(tree.annot, defn.AnnotationClass.typeConstructor) val arg1 = typed(tree.arg, pt) val ownType = AnnotatedType(Annotation(annot1), arg1.tpe) @@ -766,7 +777,7 @@ class Typer extends Namer with Applications with Implicits { cpy.Typed(tree, arg1, TypeTree(ownType)) withType ownType } - def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = { + def typedPackageDef(tree: untpd.PackageDef)(implicit ctx: Context): Tree = track("typedPackageDef") { val pid1 = typedExpr(tree.pid, AnySelectionProto) val pkg = pid1.symbol val packageContext = @@ -953,7 +964,7 @@ class Typer extends Namer with Applications with Implicits { * (14) When in mode EXPRmode, apply a view * If all this fails, error */ - def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", show = false) { + def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = track("adapt") { ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", show = false) { assert(pt.exists) @@ -1085,5 +1096,5 @@ class Typer extends Namer with Applications with Implicits { } } } - } + }} } \ No newline at end of file diff --git a/src/dotty/tools/dotc/util/Stats.scala b/src/dotty/tools/dotc/util/Stats.scala index 68884fdbc..3aa6eb9b9 100644 --- a/src/dotty/tools/dotc/util/Stats.scala +++ b/src/dotty/tools/dotc/util/Stats.scala @@ -1,7 +1,48 @@ -package dotty.tools.dotc.util +package dotty.tools.dotc +package util + +import core.Contexts._ object Stats { final val enabled = true + /** The period in ms in which stack snapshots are displayed */ + final val HeartBeatPeriod = 250 + + @volatile private var stack: List[String] = Nil + + def track[T](fn: String)(op: => T) = { + stack = fn :: stack + try op + finally stack = stack.tail + } + + class HeartBeat extends Thread() { + @volatile private[Stats] var continue = true + + private def printStack(stack: List[String]): Unit = stack match { + case str :: rest => + printStack(rest) + print(s"-> $str ") + case Nil => + println() + print("|") + } + + override final def run() { + Thread.sleep(HeartBeatPeriod) + printStack(stack) + if (continue) run() + } + } + + def monitorHeartBeat[T](op: => T)(implicit ctx: Context) = { + if (ctx.settings.Yheartbeat.value) { + var hb = new HeartBeat() + hb.start() + try op + finally hb.continue = false + } else op + } } \ No newline at end of file -- cgit v1.2.3