From 2e092d4822d044312317c502badd8ad5c2674b58 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 21 Jan 2012 11:22:28 +0100 Subject: Fix for problem in SBT that was caused by the too severe fix of type soundness problem t5120. --- .../scala/tools/nsc/typechecker/Typers.scala | 15 ++++++++++++- src/compiler/scala/tools/nsc/util/Statistics.scala | 4 +++- test/files/pos/t5120.scala | 26 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 test/files/pos/t5120.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b4221365be..f057d1e7be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2835,9 +2835,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def packSymbols(hidden: List[Symbol], tp: Type): Type = if (hidden.isEmpty) tp else existentialTransform(hidden, tp)(existentialAbstraction) + + def isReferencedFrom(ctx: Context, sym: Symbol): Boolean = + ctx.owner.isTerm && + (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || + { + var ctx1 = ctx.outer + while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer + (ctx1 != NoContext) && isReferencedFrom(ctx1, sym) + } def isCapturedExistential(sym: Symbol) = - sym hasAllFlags (EXISTENTIAL | CAPTURED) // todo refine this + (sym hasAllFlags (EXISTENTIAL | CAPTURED)) && { + val start = startTimer(isReferencedNanos) + try !isReferencedFrom(context, sym) + finally stopTimer(isReferencedNanos, start) + } def packCaptured(tpe: Type): Type = { val captured = mutable.Set[Symbol]() diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala index 27239b9b9f..f7c27dceb5 100644 --- a/src/compiler/scala/tools/nsc/util/Statistics.scala +++ b/src/compiler/scala/tools/nsc/util/Statistics.scala @@ -20,7 +20,7 @@ class Statistics extends scala.reflect.internal.util.Statistics { val typedSelectCount = new Counter val typerNanos = new Timer val classReadNanos = new Timer - + val failedApplyNanos = new Timer val failedOpEqNanos = new Timer val failedSilentNanos = new Timer @@ -48,6 +48,7 @@ class Statistics extends scala.reflect.internal.util.Statistics { val subtypeImprovCount = new SubCounter(subtypeCount) val subtypeETNanos = new Timer val matchesPtNanos = new Timer + val isReferencedNanos = new Timer val ctr1 = new Counter val ctr2 = new Counter val ctr3 = new Counter @@ -137,6 +138,7 @@ abstract class StatisticsInfo { inform("time spent in failed : "+showRelTyper(failedSilentNanos)) inform(" failed apply : "+showRelTyper(failedApplyNanos)) inform(" failed op= : "+showRelTyper(failedOpEqNanos)) + inform("time spent ref scanning : "+showRelTyper(isReferencedNanos)) inform("micros by tree node : "+showCounts(microsByType)) inform("#visits by tree node : "+showCounts(visitsByType)) val average = new ClassCounts diff --git a/test/files/pos/t5120.scala b/test/files/pos/t5120.scala new file mode 100644 index 0000000000..2c193d129d --- /dev/null +++ b/test/files/pos/t5120.scala @@ -0,0 +1,26 @@ +// An example extracted from SBT by Iulian +// that showed that the previous fix to t5120 +// was too strict. +class Test { + class ScopedKey[T] + class Value[T] + + class Compiled[T](val settings: Seq[Pair[T]]) + + case class Pair[T](k: ScopedKey[T], v: ScopedKey[T]) + + def transform[T](x: T) = x + + def test(compiledSettings: Seq[Compiled[_]]) = { + compiledSettings flatMap { cs => // cd: Compiled[_] in both versions + (cs.settings map { s => // cs.settings: Seq[Compiled[$1]] in trunk, Seq[Compiled[$1]] forSome $1 in 2.9.1 + // s: Pair[$1] in trunk, Pair[$1] in 2.9.1 + val t = transform(s.v) // t: ScopedKey[_] in trunk, ScopedKey[$1] in 2.9.1 + foo(s.k, t) + t + }) : Seq[ScopedKey[_]] + } + } + + def foo[T](x: ScopedKey[T], v: ScopedKey[T]) {} +} -- cgit v1.2.3