aboutsummaryrefslogtreecommitdiff
path: root/compiler/src
diff options
context:
space:
mode:
authorEnno Runne <enno@runne.net>2017-03-02 22:17:12 +0100
committerEnno Runne <enno@runne.net>2017-03-02 22:17:12 +0100
commite1e13e92d276d76aa73aacc764f64166adbe306c (patch)
treebeb95075b7cdcf79142c066fb510380056e9dcde /compiler/src
parentce333b1fe852c2a6cb62486f31d336f4ecaac275 (diff)
parentfeaa0aeb691b24a407ccc9f371e7a1ae6545b33c (diff)
downloaddotty-e1e13e92d276d76aa73aacc764f64166adbe306c.tar.gz
dotty-e1e13e92d276d76aa73aacc764f64166adbe306c.tar.bz2
dotty-e1e13e92d276d76aa73aacc764f64166adbe306c.zip
Merge branch 'master' of https://github.com/lampepfl/dotty into ennru_RecursiveNeedsType
Diffstat (limited to 'compiler/src')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Contexts.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--compiler/src/dotty/tools/dotc/core/Symbols.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala19
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala44
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java1
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala20
-rw-r--r--compiler/src/dotty/tools/dotc/transform/MixinOps.scala10
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Applications.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Implicits.scala49
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/util/SourcePosition.scala8
14 files changed, 144 insertions, 42 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala
index 29629e505..6b7be12be 100644
--- a/compiler/src/dotty/tools/dotc/core/Contexts.scala
+++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala
@@ -202,7 +202,7 @@ object Contexts {
private[core] var pendingMemberSearches: List[Name] = Nil
/** The new implicit references that are introduced by this scope */
- private var implicitsCache: ContextualImplicits = null
+ protected var implicitsCache: ContextualImplicits = null
def implicits: ContextualImplicits = {
if (implicitsCache == null )
implicitsCache = {
@@ -469,6 +469,7 @@ object Contexts {
def setTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this }
def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) }
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
+ def setImplicits(implicits: ContextualImplicits): this.type = { this.implicitsCache = implicits; this }
def setRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
def setDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index 847177e2f..79e97becb 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -906,13 +906,6 @@ class Definitions {
/** The type of the boxed class corresponding to primitive value type `tp`. */
def boxedType(tp: Type)(implicit ctx: Context): TypeRef = boxedTypes(scalaClassName(tp))
- def wrapArrayMethodName(elemtp: Type): TermName = {
- val cls = elemtp.classSymbol
- if (cls.isPrimitiveValueClass) nme.wrapXArray(cls.name)
- else if (cls.derivesFrom(ObjectClass) && !cls.isPhantomClass) nme.wrapRefArray
- else nme.genericWrapArray
- }
-
type PrimitiveClassEnc = Int
val ByteEnc = 2
diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala
index c424c6182..1e36361f8 100644
--- a/compiler/src/dotty/tools/dotc/core/StdNames.scala
+++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala
@@ -130,6 +130,7 @@ object StdNames {
val COMPANION_CLASS_METHOD: N = "companion$class"
val TRAIT_SETTER_SEPARATOR: N = "$_setter_$"
val DIRECT_SUFFIX: N = "$direct"
+ val LAZY_IMPLICIT_PREFIX: N = "$lazy_implicit$"
// value types (and AnyRef) are all used as terms as well
// as (at least) arguments to the @specialize annotation.
diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala
index 5d0dd2123..c5e064478 100644
--- a/compiler/src/dotty/tools/dotc/core/Symbols.scala
+++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala
@@ -258,6 +258,10 @@ trait Symbols { this: Context =>
def newDefaultConstructor(cls: ClassSymbol) =
newConstructor(cls, EmptyFlags, Nil, Nil)
+ /** Create a synthetic lazy implicit value */
+ def newLazyImplicit(info: Type) =
+ newSymbol(owner, freshName(nme.LAZY_IMPLICIT_PREFIX).toTermName, Lazy, info)
+
/** Create a symbol representing a selftype declaration for class `cls`. */
def newSelfSym(cls: ClassSymbol, name: TermName = nme.WILDCARD, selfInfo: Type = NoType): TermSymbol =
ctx.newSymbol(cls, name, SelfSymFlags, selfInfo orElse cls.classInfo.selfType, coord = cls.coord)
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index c14108d2e..b27bff37a 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -1607,6 +1607,7 @@ object Parsers {
* LocalModifier ::= abstract | final | sealed | implicit | lazy
*/
def modifiers(allowed: BitSet = modifierTokens, start: Modifiers = Modifiers()): Modifiers = {
+ @tailrec
def loop(mods: Modifiers): Modifiers = {
if (allowed contains in.token) {
val isAccessMod = accessModifierTokens contains in.token
@@ -2057,7 +2058,7 @@ object Parsers {
val name = ident().toTypeName
val constr = atPos(in.lastOffset) {
val tparams = typeParamClauseOpt(ParamOwner.Class)
- val cmods = constrModsOpt()
+ val cmods = constrModsOpt(name)
val vparamss = paramClauses(name, mods is Case)
makeConstructor(tparams, vparamss).withMods(cmods)
@@ -2070,11 +2071,11 @@ object Parsers {
/** ConstrMods ::= AccessModifier
* | Annotation {Annotation} (AccessModifier | `this')
*/
- def constrModsOpt(): Modifiers = {
+ def constrModsOpt(owner: Name): Modifiers = {
val mods = modifiers(accessModifierTokens, annotsAsMods())
if (mods.hasAnnotations && !mods.hasFlags)
if (in.token == THIS) in.nextToken()
- else syntaxError("`private', `protected', or `this' expected")
+ else syntaxError(AnnotatedPrimaryConstructorRequiresModifierOrThis(owner), mods.annotations.last.pos)
mods
}
diff --git a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala
index 86f34e64d..e20f846ac 100644
--- a/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala
+++ b/compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala
@@ -6,6 +6,7 @@ import parsing.Tokens._
import scala.annotation.switch
import scala.collection.mutable.StringBuilder
import core.Contexts.Context
+import util.Chars.{ LF, FF, CR, SU }
import Highlighting.{Highlight, HighlightBuffer}
/** This object provides functions for syntax highlighting in the REPL */
@@ -26,7 +27,7 @@ object SyntaxHighlighting {
private def valDef(str: String) = ValDefColor + str + NoColor
private def operator(str: String) = TypeColor + str + NoColor
private def annotation(str: String) =
- if (str.trim == "@") str else AnnotationColor + str + NoColor
+ if (str.trim == "@") str else { AnnotationColor + str + NoColor }
private val tripleQs = Console.RED_B + "???" + NoColor
private val keywords: Seq[String] = for {
@@ -152,7 +153,11 @@ object SyntaxHighlighting {
var open = 1
while (open > 0 && remaining.nonEmpty) {
curr = takeChar()
- newBuf += curr
+ if (curr == '@') {
+ appendWhile('@', !typeEnders.contains(_), annotation)
+ newBuf append CommentColor
+ }
+ else newBuf += curr
if (curr == '*' && remaining.nonEmpty) {
curr = takeChar()
@@ -163,6 +168,11 @@ object SyntaxHighlighting {
newBuf += curr
if (curr == '*') open += 1
}
+
+ (curr: @switch) match {
+ case LF | FF | CR | SU => newBuf append CommentColor
+ case _ => ()
+ }
}
prev = curr
newBuf append NoColor
@@ -236,6 +246,11 @@ object SyntaxHighlighting {
newBuf += curr
closing = 0
}
+
+ (curr: @switch) match {
+ case LF | FF | CR | SU => newBuf append LiteralColor
+ case _ => ()
+ }
}
newBuf append NoColor
prev = curr
diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
index 190445d60..17eb8d39b 100644
--- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
@@ -5,9 +5,12 @@ package reporting
import core.Contexts.Context
import core.Decorators._
import printing.Highlighting.{Blue, Red}
+import printing.SyntaxHighlighting
import diagnostic.{ErrorMessageID, Message, MessageContainer, NoExplanation}
import diagnostic.messages._
import util.SourcePosition
+import util.Chars.{ LF, CR, FF, SU }
+import scala.annotation.switch
import scala.collection.mutable
@@ -38,20 +41,37 @@ trait MessageRendering {
*/
def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = {
var maxLen = Int.MinValue
- def render(xs: List[Int]) =
- xs.map(pos.source.offsetToLine(_))
- .map { lineNbr =>
- val prefix = s"${lineNbr + 1} |"
- maxLen = math.max(maxLen, prefix.length)
- (prefix, pos.lineContent(lineNbr).stripLineEnd)
- }
- .map { case (prefix, line) =>
- val lnum = Red(" " * math.max(0, maxLen - prefix.length) + prefix)
- hl"$lnum$line"
- }
+ def render(offsetAndLine: (Int, String)): String = {
+ val (offset, line) = offsetAndLine
+ val lineNbr = pos.source.offsetToLine(offset)
+ val prefix = s"${lineNbr + 1} |"
+ maxLen = math.max(maxLen, prefix.length)
+ val lnum = Red(" " * math.max(0, maxLen - prefix.length) + prefix).show
+ lnum + line.stripLineEnd
+ }
+
+ def linesFrom(arr: Array[Char]): List[String] = {
+ def pred(c: Char) = (c: @switch) match {
+ case LF | CR | FF | SU => true
+ case _ => false
+ }
+ val (line, rest0) = arr.span(!pred(_))
+ val (_, rest) = rest0.span(pred)
+ new String(line) :: { if (rest.isEmpty) Nil else linesFrom(rest) }
+ }
+ val syntax =
+ if (ctx.settings.color.value != "never")
+ SyntaxHighlighting(pos.linesSlice).toArray
+ else pos.linesSlice
+ val lines = linesFrom(syntax)
val (before, after) = pos.beforeAndAfterPoint
- (render(before), render(after), maxLen)
+
+ (
+ before.zip(lines).map(render),
+ after.zip(lines.drop(before.length)).map(render),
+ maxLen
+ )
}
/** The column markers aligned under the error */
diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java
index 75e1d4cb2..02869e752 100644
--- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java
+++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java
@@ -51,6 +51,7 @@ public enum ErrorMessageID {
ExpectedTokenButFoundID,
MixedLeftAndRightAssociativeOpsID,
CantInstantiateAbstractClassOrTraitID,
+ AnnotatedPrimaryConstructorRequiresModifierOrThisID,
OverloadedOrRecursiveMethodNeedsResultTypeID,
RecursiveValueNeedsResultTypeID,
CyclicReferenceInvolvingImplicitID,
diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
index 8d34d97ed..f2f69b6cc 100644
--- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala
@@ -1151,7 +1151,9 @@ object messages {
val kind = "Syntax"
val msg = hl"""overloaded or recursive method ${tree} needs result type"""
val explanation =
- hl"""""".stripMargin
+ hl"""
+ |
+ """.stripMargin
}
case class RecursiveValueNeedsResultType(tree: Names.TermName)(implicit ctx: Context)
@@ -1172,6 +1174,18 @@ object messages {
|""".stripMargin
}
-
-
+ case class AnnotatedPrimaryConstructorRequiresModifierOrThis(cls: Name)(implicit ctx: Context)
+ extends Message(AnnotatedPrimaryConstructorRequiresModifierOrThisID) {
+ val kind = "Syntax"
+ val msg = hl"""${"private"}, ${"protected"}, or ${"this"} expected for annotated primary constructor"""
+ val explanation =
+ hl"""|When using annotations with a primary constructor of a class,
+ |the annotation must be followed by an access modifier
+ |(${"private"} or ${"protected"}) or ${"this"}.
+ |
+ |For example:
+ | ${"class Sample @deprecated this(param: Parameter) { ..."}
+ | ^^^^
+ |""".stripMargin
+ }
}
diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala
index 25aa9ffaf..9f7ceeaed 100644
--- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala
+++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala
@@ -40,6 +40,12 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx:
def isCurrent(sym: Symbol) =
ctx.atPhase(thisTransform) { implicit ctx =>
cls.info.member(sym.name).hasAltWith(_.symbol == sym)
+ // this is a hot spot, where we spend several seconds while compiling stdlib
+ // unfortunately it will discard and recompute all the member chaches,
+ // both making itself slow and slowing down anything that runs after it
+ // because resolveSuper uses hacks with explicit adding to scopes through .enter
+ // this cannot be fixed by a smarter caching strategy. With current implementation
+ // we HAVE to discard caches here for correctness
}
/** Does `method` need a forwarder to in class `cls`
@@ -53,8 +59,8 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx:
def needsDisambiguation = competingMethods.exists(x=> !(x is Deferred)) // multiple implementations are available
def hasNonInterfaceDefinition = competingMethods.exists(!_.owner.is(Trait)) // there is a definition originating from class
meth.is(Method, butNot = PrivateOrAccessorOrDeferred) &&
- isCurrent(meth) &&
- (needsDisambiguation || hasNonInterfaceDefinition || meth.owner.is(Scala2x))
+ (meth.owner.is(Scala2x) || needsDisambiguation || hasNonInterfaceDefinition ) &&
+ isCurrent(meth)
}
/** Get `sym` of the method that needs a forwarder
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index de017961a..e9df12b42 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -450,7 +450,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
def typedArg(arg: Arg, formal: Type): Arg = arg
def addArg(arg: TypedArg, formal: Type) =
- ok = ok & isCompatible(argType(arg, formal), formal)
+ ok = ok & {
+ argType(arg, formal) match {
+ case ref: TermRef if ref.denot.isOverloaded =>
+ // in this case we could not resolve overloading because no alternative
+ // matches expected type
+ false
+ case argtpe =>
+ isCompatible(argtpe, formal)
+ }
+ }
def makeVarArg(n: Int, elemFormal: Type) = {}
def fail(msg: => Message, arg: Arg) =
ok = false
diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
index 48cf0cfac..d5afae90c 100644
--- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
@@ -29,6 +29,7 @@ import reporting.diagnostic.MessageContainer
import Inferencing.fullyDefinedType
import Trees._
import Hashable._
+import util.Property
import config.Config
import config.Printers.{implicits, implicitsDetailed, typr}
import collection.mutable
@@ -36,6 +37,11 @@ import collection.mutable
/** Implicit resolution */
object Implicits {
+ /** A reference to an implicit value to be made visible on the next nested call to
+ * inferImplicitArg with a by-name expected type.
+ */
+ val DelayedImplicit = new Property.Key[TermRef]
+
/** An eligible implicit candidate, consisting of an implicit reference and a nesting level */
case class Candidate(ref: TermRef, level: Int)
@@ -202,7 +208,7 @@ object Implicits {
}
override def toString = {
- val own = s"(implicits: ${refs mkString ","})"
+ val own = i"(implicits: $refs%, %)"
if (isOuterMost) own else own + "\n " + outerImplicits
}
@@ -537,27 +543,56 @@ trait Implicits { self: Typer =>
else EmptyTree
}
- inferImplicit(formal, EmptyTree, pos) match {
+ /** The context to be used when resolving a by-name implicit argument.
+ * This makes any implicit stored under `DelayedImplicit` visible and
+ * stores in turn the given `lazyImplicit` as new `DelayedImplicit`.
+ */
+ def lazyImplicitCtx(lazyImplicit: Symbol): Context = {
+ val lctx = ctx.fresh
+ for (delayedRef <- ctx.property(DelayedImplicit))
+ lctx.setImplicits(new ContextualImplicits(delayedRef :: Nil, ctx.implicits)(ctx))
+ lctx.setProperty(DelayedImplicit, lazyImplicit.termRef)
+ }
+
+ /** formalValue: The value type for which an implicit is searched
+ * lazyImplicit: An implicit symbol to install for nested by-name resolutions
+ * argCtx : The context to be used for searching the implicit argument
+ */
+ val (formalValue, lazyImplicit, argCtx) = formal match {
+ case ExprType(fv) =>
+ val lazyImplicit = ctx.newLazyImplicit(fv)
+ (fv, lazyImplicit, lazyImplicitCtx(lazyImplicit))
+ case _ => (formal, NoSymbol, ctx)
+ }
+
+ inferImplicit(formalValue, EmptyTree, pos)(argCtx) match {
case SearchSuccess(arg, _, _, _) =>
- arg
+ def refersToLazyImplicit = arg.existsSubTree {
+ case id: Ident => id.symbol == lazyImplicit
+ case _ => false
+ }
+ if (lazyImplicit.exists && refersToLazyImplicit)
+ Block(ValDef(lazyImplicit.asTerm, arg).withPos(pos) :: Nil, ref(lazyImplicit))
+ else
+ arg
case ambi: AmbiguousImplicits =>
error(where => s"ambiguous implicits: ${ambi.explanation} of $where")
EmptyTree
case failure: SearchFailure =>
- val arg = synthesizedClassTag(formal, pos)
+ val arg = synthesizedClassTag(formalValue, pos)
if (!arg.isEmpty) arg
else {
var msgFn = (where: String) =>
em"no implicit argument of type $formal found for $where" + failure.postscript
for {
- notFound <- formal.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot)
+ notFound <- formalValue.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot)
Trees.Literal(Constant(raw: String)) <- notFound.argument(0)
} {
msgFn = where =>
err.implicitNotFoundString(
raw,
- formal.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
- formal.argInfos)
+ formalValue.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
+ formalValue.argInfos)
}
error(msgFn)
EmptyTree
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 06200d3e4..33e320ce5 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1890,7 +1890,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def implicitArgError(msg: String => String) =
errors += (() => msg(em"parameter $pname of $methodStr"))
if (errors.nonEmpty) EmptyTree
- else inferImplicitArg(formal.widenExpr, implicitArgError, tree.pos.endPos)
+ else inferImplicitArg(formal, implicitArgError, tree.pos.endPos)
}
if (errors.nonEmpty) {
// If there are several arguments, some arguments might already
diff --git a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala
index aad4995d8..be5c46995 100644
--- a/compiler/src/dotty/tools/dotc/util/SourcePosition.scala
+++ b/compiler/src/dotty/tools/dotc/util/SourcePosition.scala
@@ -12,9 +12,14 @@ extends interfaces.SourcePosition {
def lineContent: String = source.lineContent(point)
def point: Int = pos.point
+
/** The line of the position, starting at 0 */
def line: Int = source.offsetToLine(point)
+ /** Extracts the lines from the underlying source file as `Array[Char]`*/
+ def linesSlice: Array[Char] =
+ source.content.slice(source.startOfLine(start), source.nextLine(end))
+
/** The lines of the position */
def lines: List[Int] =
List.range(source.offsetToLine(start), source.offsetToLine(end + 1)) match {
@@ -25,9 +30,6 @@ extends interfaces.SourcePosition {
def lineOffsets: List[Int] =
lines.map(source.lineToOffset(_))
- def lineContent(lineNumber: Int): String =
- source.lineContent(source.lineToOffset(lineNumber))
-
def beforeAndAfterPoint: (List[Int], List[Int]) =
lineOffsets.partition(_ <= point)