summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/compiler/scala/tools/ant/templates/tool-unix.tmpl13
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala5
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala18
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala50
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala1
-rw-r--r--src/library/scala/concurrent/Future.scala2
-rw-r--r--src/library/scala/sys/process/Process.scala4
-rw-r--r--src/partest-extras/scala/tools/partest/IcodeComparison.scala9
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Chars.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Positions.scala9
-rw-r--r--src/reflect/scala/reflect/io/Streamable.scala8
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala1
-rw-r--r--src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala2
18 files changed, 102 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
index 6e91a2a202..5e6b3c041e 100755
--- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
+++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
@@ -67,6 +67,11 @@ if uname | grep -q ^MINGW; then
mingw="$(uname)"
fi
+unset msys
+if uname | grep -q ^MSYS; then
+ msys="$(uname)"
+fi
+
# Finding the root folder for this Scala distribution
SCALA_HOME="$(findScalaHome)"
SEP=":"
@@ -111,9 +116,9 @@ if [[ -n "$cygwin" ]]; then
TOOL_CLASSPATH="$(cygpath --path --$format "$TOOL_CLASSPATH")"
fi
-if [[ -n "$cygwin$mingw" ]]; then
+if [[ -n "$cygwin$mingw$msys" ]]; then
case "$TERM" in
- rxvt* | xterm*)
+ rxvt* | xterm* | cygwin*)
stty -icanon min 1 -echo
WINDOWS_OPT="-Djline.terminal=unix"
;;
@@ -182,10 +187,10 @@ fi
declare -a classpath_args
-# default to the boot classpath for speed, except on cygwin/mingw because
+# default to the boot classpath for speed, except on cygwin/mingw/msys because
# JLine on Windows requires a custom DLL to be loaded.
unset usebootcp
-if [[ -z "$cygwin$mingw" ]]; then
+if [[ -z "$cygwin$mingw$msys" ]]; then
usebootcp="true"
fi
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 5cb31c1b64..422e2080f0 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -1690,7 +1690,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
try {
val stream = new FileOutputStream(file)
printer.setWriter(new PrintWriter(stream, true))
- printer.printClass(cls)
+ try
+ printer.printClass(cls)
+ finally
+ stream.close()
informProgress(s"wrote $file")
} catch {
case e: IOException =>
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index f9e6a12241..dac3c7a285 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2692,7 +2692,10 @@ self =>
case t if t == SUPERTYPE || t == SUBTYPE || t == COMMA || t == RBRACE || isStatSep(t) =>
TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds())
case _ =>
- syntaxErrorOrIncompleteAnd("`=', `>:', or `<:' expected", skipIt = true)(EmptyTree)
+ syntaxErrorOrIncompleteAnd("`=', `>:', or `<:' expected", skipIt = true)(
+ // assume a dummy type def so as to have somewhere to stash the annotations
+ TypeDef(mods, tpnme.ERROR, Nil, EmptyTree)
+ )
}
}
}
@@ -2725,7 +2728,10 @@ self =>
case CASEOBJECT =>
objectDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on 'case' to 'object', thus take prev*/)))
case _ =>
- syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)(EmptyTree)
+ syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)(
+ // assume a class definition so as to have somewhere to stash the annotations
+ atPos(pos)(gen.mkClassDef(mods, tpnme.ERROR, Nil, Template(Nil, noSelfType, Nil)))
+ )
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
index ce2fe943e4..242171476a 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzerImpl.scala
@@ -459,4 +459,4 @@ class InitialProducerSourceInterpreter extends SourceInterpreter {
override def newExceptionValue(tryCatchBlockNode: TryCatchBlockNode, handlerFrame: Frame[_ <: Value], exceptionType: Type): SourceValue = {
new SourceValue(1, ExceptionProducer(handlerFrame))
}
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 57639a94c7..9d61dbbcae 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -475,13 +475,6 @@ abstract class UnCurry extends InfoTransform
withNeedLift(needLift = true) { super.transform(tree) }
else
super.transform(tree)
- case UnApply(fn, args) =>
- val fn1 = transform(fn)
- val args1 = fn.symbol.name match {
- case nme.unapplySeq => transformArgs(tree.pos, fn.symbol, args, patmat.alignPatterns(global.typer.context, tree).expectedTypes)
- case _ => args
- }
- treeCopy.UnApply(tree, fn1, args1)
case Apply(fn, args) =>
val needLift = needTryLift || !fn.symbol.isLabel // SI-6749, no need to lift in args to label jumps.
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala
index e84ccbf754..1916050dd8 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternExpander.scala
@@ -86,9 +86,25 @@ trait PatternExpander[Pattern, Type] {
* @param fixed The non-sequence types which are extracted
* @param repeated The sequence type which is extracted
*/
- final case class Extractor(whole: Type, fixed: List[Type], repeated: Repeated) {
+ final case class Extractor(whole: Type, fixed: List[Type], repeated: Repeated, typeOfSinglePattern: Type) {
require(whole != NoType, s"expandTypes($whole, $fixed, $repeated)")
+ /** A pattern with arity-1 that doesn't match the arity of the Product-like result of the `get` method,
+ * will match that result in its entirety. Example:
+ *
+ * {{{
+ * warning: there was one deprecation warning; re-run with -deprecation for details
+ * scala> object Extractor { def unapply(a: Any): Option[(Int, String)] = Some((1, "2")) }
+ * defined object Extractor
+ *
+ * scala> "" match { case Extractor(x: Int, y: String) => }
+ *
+ * scala> "" match { case Extractor(xy : (Int, String)) => }
+ * warning: there was one deprecation warning; re-run with -deprecation for details
+ * }}}
+ * */
+ def asSinglePattern: Extractor = copy(fixed = List(typeOfSinglePattern))
+
def productArity = fixed.length
def hasSeq = repeated.exists
def elementType = repeated.elementType
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
index b1783dc81f..d4f44303bb 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala
@@ -43,8 +43,9 @@ trait ScalacPatternExpanders {
orElse definitions.elementType(ArrayClass, seq)
)
}
- def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated): Extractor =
- logResult(s"newExtractor($whole, $fixed, $repeated")(Extractor(whole, fixed, repeated))
+ def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated, typeOfSinglePattern: Type): Extractor =
+ logResult(s"newExtractor($whole, $fixed, $repeated, $typeOfSinglePattern")(Extractor(whole, fixed, repeated, typeOfSinglePattern))
+ def newExtractor(whole: Type, fixed: List[Type], repeated: Repeated): Extractor = newExtractor(whole, fixed, repeated, tupleType(fixed))
// Turn Seq[A] into Repeated(Seq[A], A, A*)
def repeatedFromSeq(seqType: Type): Repeated = {
@@ -73,26 +74,27 @@ trait ScalacPatternExpanders {
* Unfortunately the MethodType does not carry the information of whether
* it was unapplySeq, so we have to funnel that information in separately.
*/
- def unapplyMethodTypes(whole: Type, result: Type, isSeq: Boolean): Extractor = {
- val expanded = (
- if (result =:= BooleanTpe) Nil
- else typeOfMemberNamedGet(result) match {
+ def unapplyMethodTypes(context: Context, whole: Type, result: Type, isSeq: Boolean): Extractor = {
+ if (result =:= BooleanTpe) newExtractor(whole, Nil, NoRepeated)
+ else {
+ val getResult = typeOfMemberNamedGet(result)
+ def noGetError() = {
+ val name = "unapply" + (if (isSeq) "Seq" else "")
+ context.error(context.tree.pos, s"The result type of an $name method must contain a member `get` to be used as an extractor pattern, no such member exists in ${result}")
+ }
+ val expanded = getResult match {
+ case global.NoType => noGetError(); Nil
case rawGet if !hasSelectors(rawGet) => rawGet :: Nil
case rawGet => typesOfSelectors(rawGet)
}
- )
- expanded match {
- case init :+ last if isSeq => newExtractor(whole, init, repeatedFromSeq(last))
- case tps => newExtractor(whole, tps, NoRepeated)
+ expanded match {
+ case init :+ last if isSeq => newExtractor(whole, init, repeatedFromSeq(last), getResult)
+ case tps => newExtractor(whole, tps, NoRepeated, getResult)
+ }
}
}
}
object alignPatterns extends ScalacPatternExpander {
- /** Converts a T => (A, B, C) extractor to a T => ((A, B, CC)) extractor.
- */
- def tupleExtractor(extractor: Extractor): Extractor =
- extractor.copy(fixed = tupleType(extractor.fixed) :: Nil)
-
private def validateAligned(context: Context, tree: Tree, aligned: Aligned): Aligned = {
import aligned._
@@ -129,8 +131,8 @@ trait ScalacPatternExpanders {
val isUnapply = sel.symbol.name == nme.unapply
val extractor = sel.symbol.name match {
- case nme.unapply => unapplyMethodTypes(firstParamType(fn.tpe), sel.tpe, isSeq = false)
- case nme.unapplySeq => unapplyMethodTypes(firstParamType(fn.tpe), sel.tpe, isSeq = true)
+ case nme.unapply => unapplyMethodTypes(context, firstParamType(fn.tpe), sel.tpe, isSeq = false)
+ case nme.unapplySeq => unapplyMethodTypes(context, firstParamType(fn.tpe), sel.tpe, isSeq = true)
case _ => applyMethodTypes(fn.tpe)
}
@@ -142,12 +144,14 @@ trait ScalacPatternExpanders {
def acceptMessage = if (extractor.isErroneous) "" else s" to hold ${extractor.offeringString}"
val requiresTupling = isUnapply && patterns.totalArity == 1 && productArity > 1
- if (requiresTupling && effectivePatternArity(args) == 1) {
- val sym = sel.symbol.owner
- currentRun.reporting.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)")
- }
-
- val normalizedExtractor = if (requiresTupling) tupleExtractor(extractor) else extractor
+ val normalizedExtractor = if (requiresTupling) {
+ val tupled = extractor.asSinglePattern
+ if (effectivePatternArity(args) == 1 && isTupleType(extractor.typeOfSinglePattern)) {
+ val sym = sel.symbol.owner
+ currentRun.reporting.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)")
+ }
+ tupled
+ } else extractor
validateAligned(context, fn, Aligned(patterns, normalizedExtractor))
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 3fe2f24818..cb4eab335b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -827,7 +827,12 @@ trait Contexts { self: Analyzer =>
case List() =>
List()
case List(ImportSelector(nme.WILDCARD, _, _, _)) =>
- collectImplicits(pre.implicitMembers, pre, imported = true)
+ // Using pre.implicitMembers seems to exposes a problem with out-dated symbols in the IDE,
+ // see the example in https://www.assembla.com/spaces/scala-ide/tickets/1002552#/activity/ticket
+ // I haven't been able to boil that down the an automated test yet.
+ // Looking up implicit members in the package, rather than package object, here is at least
+ // consistent with what is done just below for named imports.
+ collectImplicits(qual.tpe.implicitMembers, pre, imported = true)
case ImportSelector(from, _, to, _) :: sels1 =>
var impls = collect(sels1) filter (info => info.name != from)
if (to != nme.WILDCARD) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 533ef13574..26e04edcca 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3547,6 +3547,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def typedAnnotation(ann: Tree, mode: Mode = EXPRmode): AnnotationInfo = {
var hasError: Boolean = false
val pending = ListBuffer[AbsTypeError]()
+ def ErroneousAnnotation = new ErroneousAnnotation().setOriginal(ann)
def finish(res: AnnotationInfo): AnnotationInfo = {
if (hasError) {
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index 6304f35da9..c8ababbcab 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -610,7 +610,7 @@ object Future {
def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = {
in.foldLeft(successful(cbf(in))) {
(fr, fa) => for (r <- fr; a <- fa) yield (r += a)
- } map (_.result())
+ }.map(_.result())(InternalCallbackExecutor)
}
/** Asynchronously and non-blockingly returns a new `Future` to the result of the first future
diff --git a/src/library/scala/sys/process/Process.scala b/src/library/scala/sys/process/Process.scala
index c40838bb06..06b9967908 100644
--- a/src/library/scala/sys/process/Process.scala
+++ b/src/library/scala/sys/process/Process.scala
@@ -68,7 +68,7 @@ trait ProcessCreation {
/** Creates a [[scala.sys.process.ProcessBuilder]] with working dir set to `File` and extra
* environment variables.
*
- * @example {{{ apply("java", new java.ioFile("/opt/app"), "CLASSPATH" -> "library.jar") }}}
+ * @example {{{ apply("java", new java.io.File("/opt/app"), "CLASSPATH" -> "library.jar") }}}
*/
def apply(command: String, cwd: File, extraEnv: (String, String)*): ProcessBuilder =
apply(command, Some(cwd), extraEnv: _*)
@@ -76,7 +76,7 @@ trait ProcessCreation {
/** Creates a [[scala.sys.process.ProcessBuilder]] with working dir set to `File` and extra
* environment variables.
*
- * @example {{{ apply("java" :: javaArgs, new java.ioFile("/opt/app"), "CLASSPATH" -> "library.jar") }}}
+ * @example {{{ apply("java" :: javaArgs, new java.io.File("/opt/app"), "CLASSPATH" -> "library.jar") }}}
*/
def apply(command: Seq[String], cwd: File, extraEnv: (String, String)*): ProcessBuilder =
apply(command, Some(cwd), extraEnv: _*)
diff --git a/src/partest-extras/scala/tools/partest/IcodeComparison.scala b/src/partest-extras/scala/tools/partest/IcodeComparison.scala
index 7122703918..1430db886e 100644
--- a/src/partest-extras/scala/tools/partest/IcodeComparison.scala
+++ b/src/partest-extras/scala/tools/partest/IcodeComparison.scala
@@ -48,8 +48,13 @@ abstract class IcodeComparison extends DirectTest {
compile("-d" :: testOutput.path :: arg0 :: args.toList : _*)
val icodeFiles = testOutput.files.toList filter (_ hasExtension "icode")
- try icodeFiles sortBy (_.name) flatMap (f => f.lines.toList)
- finally icodeFiles foreach (f => f.delete())
+ // Some methods in scala.reflect.io.File leak an InputStream, leaving the underlying file open.
+ // Windows won't delete an open file, but we must ensure the files get deleted, since the logic
+ // here depends on it (collectIcode will be called multiple times, and we can't allow crosstalk
+ // between calls). So we are careful to use `slurp` which does call `close`, and careful to
+ // check that `delete` returns true indicating successful deletion.
+ try icodeFiles sortBy (_.name) flatMap (f => f.slurp().lines.toList)
+ finally icodeFiles foreach (f => require(f.delete()))
}
/** Collect icode at the default phase, `printIcodeAfterPhase`. */
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 6863cdfd82..b923541b56 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -404,7 +404,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil)
- object ErroneousAnnotation extends CompleteAnnotationInfo(ErrorType, Nil, Nil)
+ class ErroneousAnnotation() extends CompleteAnnotationInfo(ErrorType, Nil, Nil)
/** Extracts symbol of thrown exception from AnnotationInfo.
*
diff --git a/src/reflect/scala/reflect/internal/Chars.scala b/src/reflect/scala/reflect/internal/Chars.scala
index 0f532a4e57..74413fdaba 100644
--- a/src/reflect/scala/reflect/internal/Chars.scala
+++ b/src/reflect/scala/reflect/internal/Chars.scala
@@ -66,7 +66,7 @@ trait Chars {
'0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
/** Can character start an alphanumeric Scala identifier? */
- def isIdentifierStart(c: Char): Boolean =
+ def isIdentifierStart(c: Char): Boolean =
(c == '_') || (c == '$') || Character.isUnicodeIdentifierStart(c)
/** Can character form part of an alphanumeric Scala identifier? */
diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala
index 4d0e31b037..15d68bcdfe 100644
--- a/src/reflect/scala/reflect/internal/Positions.scala
+++ b/src/reflect/scala/reflect/internal/Positions.scala
@@ -252,7 +252,14 @@ trait Positions extends api.Positions { self: SymbolTable =>
super.traverse(t)
} else t match {
case mdef: MemberDef =>
- traverseTrees(mdef.mods.annotations)
+ val annTrees = mdef.mods.annotations match {
+ case Nil if mdef.symbol != null =>
+ // After typechecking, annotations are mvoed from the modifiers
+ // to the annotation on the symbol of the anotatee.
+ mdef.symbol.annotations.map(_.original)
+ case anns => anns
+ }
+ traverseTrees(annTrees)
case _ =>
}
}
diff --git a/src/reflect/scala/reflect/io/Streamable.scala b/src/reflect/scala/reflect/io/Streamable.scala
index aa47947672..99a14d1fb0 100644
--- a/src/reflect/scala/reflect/io/Streamable.scala
+++ b/src/reflect/scala/reflect/io/Streamable.scala
@@ -27,6 +27,10 @@ object Streamable {
* efficient method implementations.
*
* ''Note: This library is considered experimental and should not be used unless you know what you are doing.''
+ *
+ * Note that this code was not written with resource management in mind.
+ * Several methods (such as `chars` and `lines`) create InputStreams they
+ * don't close
*/
trait Bytes {
def inputStream(): InputStream
@@ -82,9 +86,13 @@ object Streamable {
*/
def creationCodec: Codec = implicitly[Codec]
+ /** Caller is responsible for closing the returned BufferedSource. */
def chars(codec: Codec): BufferedSource = Source.fromInputStream(inputStream())(codec)
+ /** Beware! Leaks an InputStream which will not be closed until it gets finalized. */
def lines(): Iterator[String] = lines(creationCodec)
+
+ /** Beware! Leaks an InputStream which will not be closed until it gets finalized. */
def lines(codec: Codec): Iterator[String] = chars(codec).getLines()
/** Obtains an InputStreamReader wrapped around a FileInputStream.
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index 278d081249..1e9a4fe8a5 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -106,7 +106,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.AnnotationInfo
this.Annotation
this.UnmappableAnnotation
- this.ErroneousAnnotation
this.ThrownException
this.typeNames
this.tpnme
diff --git a/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala b/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala
index d9dbd780d4..62e12f8703 100644
--- a/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala
+++ b/src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala
@@ -35,7 +35,7 @@ class PresentationCompilerCompleter(intp: IMain) extends Completion {
// secret handshakes
val slashPrint = """.*// *print *""".r
val slashTypeAt = """.*// *typeAt *(\d+) *(\d+) *""".r
- val Cursor = IMain.DummyCursorFragment
+ val Cursor = IMain.DummyCursorFragment + " "
def print(result: Result) = {
val offset = result.preambleLength