diff options
-rw-r--r-- | .mailmap | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/ClassPath.scala | 12 | ||||
-rw-r--r-- | src/library/scala/concurrent/Future.scala | 11 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/HasFlags.scala | 3 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/tpe/TypeMaps.scala | 2 | ||||
-rw-r--r-- | test/files/pos/t7815.scala | 30 | ||||
-rw-r--r-- | test/files/run/future-flatmap-exec-count.check | 6 | ||||
-rw-r--r-- | test/files/run/future-flatmap-exec-count.scala | 61 | ||||
-rw-r--r-- | test/files/run/t7398.scala | 6 | ||||
-rw-r--r-- | test/files/run/t7825.scala | 34 |
13 files changed, 162 insertions, 19 deletions
@@ -27,6 +27,7 @@ Erik Stenman <stenman@epfl.ch> Eugene Burmako <xeno.by@gmail.com> Eugene Burmako <xeno.by@gmail.com> <burmako@epfl.ch> Eugene Vigdorchik <eugenevigdorchik@epfl.ch> <eugene.vigdorchik@gmail.com> +François Garillot <francois@garillot.net> Geoff Reedy <geoff@programmer-monk.net> <gereedy@sandia.gov> Ilya Sergei <ilyas@epfl.ch> Ingo Maier <ingo.maier@epfl.ch> diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 6f27eb8660..8b739958ff 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -164,10 +164,17 @@ abstract class SymbolLoaders { if (settings.verbose) inform("[symloader] no class, picked up source file for " + src.path) enterToplevelsFromSource(owner, classRep.name, src) case (Some(bin), _) => - enterClassAndModule(owner, classRep.name, new ClassfileLoader(bin)) + enterClassAndModule(owner, classRep.name, newClassLoader(bin)) } } + /** Create a new loader from a binary classfile. + * This is intented as a hook allowing to support loading symbols from + * files other than .class files. + */ + protected def newClassLoader(bin: AbstractFile): SymbolLoader = + new ClassfileLoader(bin) + /** * A lazy type that completes itself by calling parameter doComplete. * Any linked modules/classes or module classes are also initialized. diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 0ac81af56f..f3aed66bc5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -411,7 +411,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans overrideError("cannot be used here - classes can only override abstract types") } else if (other.isEffectivelyFinal) { // (1.2) overrideError("cannot override final member") - } else if (!other.isDeferred && !other.hasFlag(DEFAULTMETHOD) && !member.isAnyOverride && !member.isSynthetic) { // (*) + } else if (!other.isDeferredOrDefault && !other.hasFlag(DEFAULTMETHOD) && !member.isAnyOverride && !member.isSynthetic) { // (*) // (*) Synthetic exclusion for (at least) default getters, fixes SI-5178. We cannot assign the OVERRIDE flag to // the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket. if (isNeitherInClass && !(other.owner isSubClass member.owner)) @@ -596,7 +596,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def checkNoAbstractMembers(): Unit = { // Avoid spurious duplicates: first gather any missing members. def memberList = clazz.info.nonPrivateMembersAdmitting(VBRIDGE) - val (missing, rest) = memberList partition (m => m.isDeferred && !ignoreDeferred(m)) + val (missing, rest) = memberList partition (m => m.isDeferredNotDefault && !ignoreDeferred(m)) // Group missing members by the name of the underlying symbol, // to consolidate getters and setters. val grouped = missing groupBy (sym => analyzer.underlyingSymbol(sym).name) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 906a575d90..c63d7f6820 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -96,6 +96,12 @@ object ClassPath { */ def isValidName(name: String): Boolean = true + /** Filters for assessing validity of various entities. + */ + def validClassFile(name: String) = endsClass(name) && isValidName(name) + def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.charAt(0) != '.') + def validSourceFile(name: String) = endsScala(name) || endsJava(name) + /** From the representation to its identifier. */ def toBinaryName(rep: T): String @@ -208,9 +214,9 @@ abstract class ClassPath[T] { /** Filters for assessing validity of various entities. */ - def validClassFile(name: String) = endsClass(name) && context.isValidName(name) - def validPackage(name: String) = (name != "META-INF") && (name != "") && (name.charAt(0) != '.') - def validSourceFile(name: String) = endsScala(name) || endsJava(name) + def validClassFile(name: String) = context.validClassFile(name) + def validPackage(name: String) = context.validPackage(name) + def validSourceFile(name: String) = context.validSourceFile(name) /** * Find a ClassRep given a class name of the form "package.subpackage.ClassName". diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 4e3f3c6c81..b9f73c2872 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -96,11 +96,8 @@ trait Future[+T] extends Awaitable[T] { // of the Future trait. Note that this will // (modulo bugs) _never_ execute a callback // other than those below in this same file. - // As a nice side benefit, having this implicit - // here forces an ambiguity in those methods - // that also have an executor parameter, which - // keeps us from accidentally forgetting to use - // the executor parameter. + // + // See the documentation on `InternalCallbackExecutor` for more details. private def internalExecutor = Future.InternalCallbackExecutor /* Callbacks */ @@ -254,7 +251,7 @@ trait Future[+T] extends Awaitable[T] { case Success(v) => try f(v) match { // If possible, link DefaultPromises to avoid space leaks case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p) - case fut => fut onComplete p.complete + case fut => fut.onComplete(p.complete)(internalExecutor) } catch { case NonFatal(t) => p failure t } } p.future @@ -344,7 +341,7 @@ trait Future[+T] extends Awaitable[T] { def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = { val p = Promise[U]() onComplete { - case Failure(t) => try pf.applyOrElse(t, (_: Throwable) => this) onComplete p.complete catch { case NonFatal(t) => p failure t } + case Failure(t) => try pf.applyOrElse(t, (_: Throwable) => this).onComplete(p.complete)(internalExecutor) catch { case NonFatal(t) => p failure t } case other => p complete other } p.future diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index 922353ee2e..4e12998ac7 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -116,6 +116,9 @@ trait HasFlags { def isSynthetic = hasFlag(SYNTHETIC) def isTrait = hasFlag(TRAIT) && !hasFlag(PARAM) + def isDeferredOrDefault = hasFlag(DEFERRED | DEFAULTMETHOD) + def isDeferredNotDefault = isDeferred && !hasFlag(DEFAULTMETHOD) + def flagBitsToString(bits: Long): String = { // Fast path for common case if (bits == 0L) "" else { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index dd6917814e..77f4b1b70c 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -2553,7 +2553,7 @@ trait Types private var isdepmeth: ThreeValue = UNKNOWN override def isDependentMethodType: Boolean = { - if (isdepmeth == UNKNOWN) isdepmeth = fromBoolean(IsDependentCollector.collect(resultType)) + if (isdepmeth == UNKNOWN) isdepmeth = fromBoolean(IsDependentCollector.collect(resultType.dealias)) toBoolean(isdepmeth) } diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index be61c45041..d6310c8cec 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -841,7 +841,7 @@ private[internal] trait TypeMaps { object IsDependentCollector extends TypeCollector(false) { def traverse(tp: Type) { if (tp.isImmediatelyDependent) result = true - else if (!result) mapOver(tp) + else if (!result) mapOver(tp.dealias) } } diff --git a/test/files/pos/t7815.scala b/test/files/pos/t7815.scala new file mode 100644 index 0000000000..12a434c5b0 --- /dev/null +++ b/test/files/pos/t7815.scala @@ -0,0 +1,30 @@ +import language.higherKinds + +trait Foo[A <: AnyRef] { + type Repr + def f(a: A): Repr + def g(a: A): Option[Repr] + + type M[X] + def m(a: A): M[a.type] + + type Id[X] = X + def n(a: A): Id[(Repr, M[a.type])] + +} + +object Foo { + type Aux[A <: AnyRef, B] = Foo[A] { type Repr = B; type M[X] = Int } + +} + +object Main extends App { + def mapWithFoo[A <: AnyRef, B](as: List[A])(implicit foo: Foo.Aux[A, B]) = { + // Should be Eta expandable because the result type of `f` is not + // dependant on the value, it is just `B`. + as map foo.f + as map foo.g + as map foo.m + as map foo.n + } +} diff --git a/test/files/run/future-flatmap-exec-count.check b/test/files/run/future-flatmap-exec-count.check new file mode 100644 index 0000000000..dd9dce64ed --- /dev/null +++ b/test/files/run/future-flatmap-exec-count.check @@ -0,0 +1,6 @@ +mapping +execute() +flatmapping +execute() +recovering +execute() diff --git a/test/files/run/future-flatmap-exec-count.scala b/test/files/run/future-flatmap-exec-count.scala new file mode 100644 index 0000000000..86c37be938 --- /dev/null +++ b/test/files/run/future-flatmap-exec-count.scala @@ -0,0 +1,61 @@ +import scala.concurrent._ +import java.util.concurrent.atomic.AtomicInteger + +object Test { + def main(args: Array[String]) { + test() + } + + def test() = { + def await(f: Future[Any]) = + Await.result(f, duration.Duration.Inf) + + val ec = new TestExecutionContext(ExecutionContext.Implicits.global) + + { + val p = Promise[Int]() + val fp = p.future + println("mapping") + val mapped = fp.map(x => x)(ec) + p.success(0) + await(mapped) + } + + { + println("flatmapping") + val p = Promise[Int]() + val fp = p.future + val flatMapped = fp.flatMap({ (x: Int) => + Future.successful(2 * x) + })(ec) + p.success(0) + await(flatMapped) + } + + { + println("recovering") + val recovered = Future.failed(new Throwable()).recoverWith { + case _ => Future.successful(2) + }(ec) + await(recovered) + } + } + + class TestExecutionContext(delegate: ExecutionContext) extends ExecutionContext { + def execute(runnable: Runnable): Unit = ??? + + def reportFailure(t: Throwable): Unit = ??? + + override def prepare(): ExecutionContext = { + val preparedDelegate = delegate.prepare() + return new ExecutionContext { + def execute(runnable: Runnable): Unit = { + println("execute()") + preparedDelegate.execute(runnable) + } + + def reportFailure(t: Throwable): Unit = ??? + } + } + } +} diff --git a/test/files/run/t7398.scala b/test/files/run/t7398.scala index dd59697b71..493c4dcf40 100644 --- a/test/files/run/t7398.scala +++ b/test/files/run/t7398.scala @@ -3,11 +3,9 @@ import scala.tools.partest._ object Test extends CompilerTest { import global._ - // This way we auto-pass on non-java8 since there's nothing to check - override lazy val units: List[CompilationUnit] = testUnderJavaAtLeast("1.8") { + override lazy val units: List[CompilationUnit] = { + // This test itself does not depend on JDK8. javaCompilationUnits(global)(defaultMethodSource) - } otherwise { - Nil } private def defaultMethodSource = """ diff --git a/test/files/run/t7825.scala b/test/files/run/t7825.scala new file mode 100644 index 0000000000..65ca06fdfc --- /dev/null +++ b/test/files/run/t7825.scala @@ -0,0 +1,34 @@ +import scala.tools.partest._ + +object Test extends CompilerTest { + import global._ + + override lazy val units: List[CompilationUnit] = { + // We can test this on JDK6. + javaCompilationUnits(global)(defaultMethodSource) ++ compilationUnits(global)(scalaExtendsDefault) + } + + private def defaultMethodSource = """ +public interface Iterator<E> { + boolean hasNext(); + E next(); + default void remove() { + throw new UnsupportedOperationException("remove"); + } +} + """ + + private def scalaExtendsDefault = """ +object Test { + object X extends Iterator[String] { + def hasNext = true + def next = "!" + } +} + """ + + // We're only checking we that the Scala compilation unit passes refchecks + // No further checks are needed here. + def check(source: String, unit: global.CompilationUnit): Unit = { + } +} |