diff options
8 files changed, 87 insertions, 42 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index e36df22435..f7c5c5d724 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -402,7 +402,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory else if (bSym.isAliasType) Some(new NonTemplateMemberImpl(bSym, inTpl) with HigherKindedImpl with AliasType { override def isAliasType = true - def alias = makeType(appliedType(sym.tpe, sym.info.typeParams map {_.tpe}).normalize, inTpl, sym) + def alias = makeType(sym.tpe.dealias, inTpl, sym) }) else if (bSym.isPackage) inTpl match { case inPkg: PackageImpl => makePackage(bSym, inPkg) } @@ -536,8 +536,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory nameBuffer append " {...}" // TODO: actually print the refinement } /* Polymorphic types */ - case PolyType(tparams, result) if (!tparams.isEmpty) => - throw new Error("Polymorphic type '" + tpe + "' cannot be printed as a type") + case PolyType(tparams, result) if tparams nonEmpty => +// throw new Error("Polymorphic type '" + tpe + "' cannot be printed as a type") + def typeParamsToString(tps: List[Symbol]): String = if(tps isEmpty) "" else + tps.map{tparam => + tparam.varianceString + tparam.name + typeParamsToString(tparam.typeParams) + }.mkString("[", ", ", "]") + nameBuffer append typeParamsToString(tparams) + appendType0(result) case PolyType(tparams, result) if (tparams.isEmpty) => nameBuffer append '⇒' appendType0(result) diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index 1772f6f722..0ae137b23b 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -91,7 +91,7 @@ trait CompilerControl { self: Global => /** Make sure a set of compilation units is loaded and parsed. * Return () to syncvar `result` on completion. */ - def askReload(sources: List[SourceFile], result: Response[Unit]) = + def askReload(sources: Seq[SourceFile], result: Response[Unit]) = scheduler postWorkItem new WorkItem { def apply() = reload(sources, result) override def toString = "reload "+sources diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 59221eb348..e47c511260 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -33,7 +33,7 @@ self => * All units in firsts are typechecked before any unit not in this list * Modified by askToDoFirst, reload, typeAtTree. */ - var firsts: List[SourceFile] = List() + var firsts: Seq[SourceFile] = Seq() /** A map of all loaded files to the rich compilation units that correspond to them. */ @@ -210,9 +210,11 @@ self => /** The current presentation compiler runner */ private var compileRunner = newRunnerThread + private var threadId = 1 + /** Create a new presentation compiler runner. */ - def newRunnerThread: Thread = new Thread("Scala Presentation Compiler") { + def newRunnerThread: Thread = new Thread("Scala Presentation Compiler V"+threadId) { override def run() { try { while (true) { @@ -240,6 +242,7 @@ self => } } } + threadId += 1 start() } @@ -254,7 +257,7 @@ self => val prefix = firsts map unitOf - val units = prefix ::: (unitOfFile.values.toList diff prefix) filter (!_.isUpToDate) + val units = prefix ++ (unitOfFile.values.toSeq diff prefix) filter (!_.isUpToDate) recompile(units) @@ -284,7 +287,7 @@ self => /** Make sure symbol and type attributes are reset and recompile units. */ - def recompile(units: List[RichCompilationUnit]) { + def recompile(units: Seq[RichCompilationUnit]) { for (unit <- units) { reset(unit) if (debugIDE) inform("parsing: "+unit) @@ -295,7 +298,7 @@ self => activeLocks = 0 currentTyperRun.typeCheck(unit) unit.status = currentRunId - syncTopLevelSyms(unit) + if (!unit.isJava) syncTopLevelSyms(unit) } } @@ -311,8 +314,8 @@ self => } /** Move list of files to front of firsts */ - def moveToFront(fs: List[SourceFile]) { - firsts = fs ::: (firsts diff fs) + def moveToFront(fs: Seq[SourceFile]) { + firsts = fs ++ (firsts diff fs) } // ----------------- Implementations of client commands ----------------------- @@ -348,7 +351,7 @@ self => } /** Make sure a set of compilation units is loaded and parsed */ - def reloadSources(sources: List[SourceFile]) { + def reloadSources(sources: Seq[SourceFile]) { currentTyperRun = newTyperRun for (source <- sources) { val unit = new RichCompilationUnit(source) @@ -359,7 +362,7 @@ self => } /** Make sure a set of compilation units is loaded and parsed */ - def reload(sources: List[SourceFile], response: Response[Unit]) { + def reload(sources: Seq[SourceFile], response: Response[Unit]) { respond(response)(reloadSources(sources)) if (outOfDate) throw FreshRunReq // cancel background compile else outOfDate = true // proceed normally and enable new background compile diff --git a/src/compiler/scala/tools/nsc/interactive/Response.scala b/src/compiler/scala/tools/nsc/interactive/Response.scala index 96e474a34a..56a48e44cd 100644 --- a/src/compiler/scala/tools/nsc/interactive/Response.scala +++ b/src/compiler/scala/tools/nsc/interactive/Response.scala @@ -1,8 +1,6 @@ package scala.tools.nsc package interactive -import scala.concurrent.SyncVar - /** Typical interaction, given a predicate <user-input>, a function <display>, * and an exception handler <handle>: * @@ -19,49 +17,80 @@ import scala.concurrent.SyncVar */ class Response[T] { - private val data = new SyncVar[Either[T, Throwable]] + private var data: Option[Either[T, Throwable]] = None private var complete = false private var cancelled = false /** Set provisional data, more to come */ - def setProvisionally(x: T) = - data.set(Left(x)) + def setProvisionally(x: T) = synchronized { + data = Some(Left(x)) + } - /** Set final data, and mark resposne as complete. + /** Set final data, and mark response as complete. */ - def set(x: T) = data.synchronized { - data.set(Left(x)) + def set(x: T) = synchronized { + data = Some(Left(x)) complete = true + notifyAll() } - def raise(exc: Throwable) = data.synchronized { - data.set(Right(exc)) + /** Store raised exception in data, and mark response as complete. + */ + def raise(exc: Throwable) = synchronized { + data = Some(Right(exc)) complete = true + notifyAll() } - /** Get data, wait as long as necessary + /** Get final data, wait as long as necessary. + * When interrupted will return with Right(InterruptedException) */ - def get: Either[T, Throwable] = data.get + def get: Either[T, Throwable] = synchronized { + while (!complete) { + try { + wait() + } catch { + case exc: InterruptedException => raise(exc) + } + } + data.get + } /** Optionally get data within `timeout` milliseconds. + * When interrupted will return with Some(Right(InterruptedException)) + * When timeout ends, will return last stored provisional result, + * or else None if no provisional result was stored. */ - def get(timeout: Long): Option[Either[T, Throwable]] = data.get(timeout) + def get(timeout: Long): Option[Either[T, Throwable]] = { + val start = System.currentTimeMillis + var current = start + while (!complete && start + timeout > current) { + try { + wait(timeout - (current - start)) + } catch { + case exc: InterruptedException => raise(exc) + } + current = System.currentTimeMillis + } + data + } /** Final data set was stored */ - def isComplete = data.synchronized { complete } + def isComplete = synchronized { complete } - /** Cancel action computing this response + /** Cancel action computing this response (Only the + * party that calls get on a response may cancel). */ - def cancel() = data.synchronized { cancelled = true } + def cancel() = synchronized { cancelled = true } /** A cancel request for this response has been issued */ - def isCancelled = data.synchronized { cancelled } + def isCancelled = synchronized { cancelled } - def clear() = data.synchronized { - data.unset() + def clear() = synchronized { + data = None complete = false cancelled = false } diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 32db64679d..a05bedc97a 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -218,6 +218,8 @@ trait Definitions extends reflect.generic.StandardDefinitions { lazy val Array_clone = getMember(ArrayClass, nme.clone_) lazy val ArrayModule = getModule("scala.Array") + def isArray_Apply(sym: Symbol): Boolean = sym.owner == ArrayModule.moduleClass && sym.name == nme.apply + // reflection / structural types lazy val SoftReferenceClass = getClass("java.lang.ref.SoftReference") lazy val WeakReferenceClass = getClass("java.lang.ref.WeakReference") diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 392223e1e2..ad39736ba3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -789,7 +789,7 @@ self: Analyzer => * reflect.Manifest for type 'tp'. An EmptyTree is returned if * no manifest is found. todo: make this instantiate take type params as well? */ - private def manifestOfType(tp: Type, full: Boolean): Tree = { + private def manifestOfType(tp: Type, full: Boolean): SearchResult = { /** Creates a tree that calls the factory method called constructor in object reflect.Manifest */ def manifestFactoryCall(constructor: String, tparg: Type, args: Tree*): Tree = @@ -814,8 +814,10 @@ self: Analyzer => inferImplicit(tree, appliedType(manifestClass.typeConstructor, List(tp)), true, false, context).tree def findSubManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else OptManifestClass) + def mot(tp0: Type)(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = { + implicit def wrapResult(tree: Tree): SearchResult = + if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to)) - def mot(tp0: Type): Tree = { val tp1 = tp0.normalize tp1 match { case ThisType(_) | SingleType(_, _) if !(tp1 exists {tp => tp.typeSymbol.isExistentiallyBound}) => // can't generate a reference to a value that's abstracted over by an existential @@ -849,7 +851,7 @@ self: Analyzer => manifestFactoryCall("wildcardType", tp, findManifest(tp.bounds.lo), findManifest(tp.bounds.hi)) } else if(undetParams contains sym) { // looking for a manifest of a type parameter that hasn't been inferred by now, can't do much, but let's not fail - mot(NothingClass.tpe) // TODO: should we include the mapping from sym -> NothingClass.tpe in the SearchResult? (it'll get instantiated to nothing anyway, I think) + mot(NothingClass.tpe)(sym :: from, NothingClass.tpe :: to) // #3859: need to include the mapping from sym -> NothingClass.tpe in the SearchResult } else { EmptyTree // a manifest should have been found by normal searchImplicit } @@ -875,13 +877,12 @@ self: Analyzer => */ private def implicitManifestOrOfExpectedType(pt: Type): SearchResult = pt.dealias match { case TypeRef(_, FullManifestClass, List(arg)) => - wrapResult(manifestOfType(arg, true)) + manifestOfType(arg, true) case TypeRef(_, PartialManifestClass, List(arg)) => - wrapResult(manifestOfType(arg, false)) + manifestOfType(arg, false) case TypeRef(_, OptManifestClass, List(arg)) => - val itree = manifestOfType(arg, false) - wrapResult(if (itree == EmptyTree) gen.mkAttributedRef(NoManifest) - else itree) + val res = manifestOfType(arg, false) + if (res == SearchFailure) wrapResult(gen.mkAttributedRef(NoManifest)) else res case TypeRef(_, tsym, _) if (tsym.isAbstractType) => implicitManifestOrOfExpectedType(pt.bounds.lo) case _ => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d58f881200..9efe53d96a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2658,7 +2658,7 @@ trait Typers { self: Analyzer => // and Array.apply(x: Int, xs: Int*): Array[Int] (and similar) case Apply(fun, args) => val typedFun = typed(fun, funMode(mode), WildcardType) - if (typedFun.symbol.owner == ArrayModule.moduleClass && typedFun.symbol.name == nme.apply) + if (isArray_Apply(typedFun.symbol)) pt match { case TypeRef(_, ArrayClass, targ :: _) => trees2ConstArg(args, targ) @@ -3384,7 +3384,7 @@ trait Typers { self: Analyzer => res.tpe = res.tpe.notNull } */ - if (fun2.symbol == Array_apply) { + if (isArray_Apply(fun2.symbol)) { val checked = gen.mkCheckInit(res) // this check is needed to avoid infinite recursion in Duplicators // (calling typed1 more than once for the same tree) diff --git a/test/files/pos/t3859.scala b/test/files/pos/t3859.scala new file mode 100644 index 0000000000..83d4c37b29 --- /dev/null +++ b/test/files/pos/t3859.scala @@ -0,0 +1,4 @@ +class Test { + def foo: Unit = bar(Array(): _*) + def bar(values: AnyRef*): Unit = () +}
\ No newline at end of file |