Skip to content

Commit d349af7

Browse files
committed
Enable significant indentation inside braces.
Also: - Make indentation opt in, controlled by -indent. indent is set as a default option when testing. - Allow rewritings under constructs that could not be rewritten - More systematic checking of conflicting rewrite options - Don't insert an <outdent> where a statement is logically continued The last item fixes a case observed in SJSCodeGen, which was basically like this: ```scala if (x) { ... } else /* bla bla } else */ { ``` The problem is that the commented out `}` in front of the uncommented `{` caused an <outdent> to be inserte between `else` and `{`.
1 parent cbc4bbd commit d349af7

File tree

10 files changed

+321
-223
lines changed

10 files changed

+321
-223
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ object Config {
157157
*/
158158
final val simplifyApplications = true
159159

160-
/** Always assume -indent */
161-
final val allowIndent = true
160+
/** Assume -indent by default */
161+
final val defaultIndent = true
162162

163163
/** If set, prints a trace of all symbol completions */
164164
final val showCompletions = false

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,6 @@ object Parsers {
581581
*/
582582
var possibleColonOffset: Int = -1
583583

584-
/** A list of pending patches, to be issued if we can rewrite all enclosing braces to
585-
* indentation regions.
586-
*/
587-
var pendingPatches: List[() => Unit] = Nil
588-
589584
def testChar(idx: Int, p: Char => Boolean): Boolean = {
590585
val txt = source.content
591586
idx < txt.length && p(txt(idx))
@@ -606,7 +601,8 @@ object Parsers {
606601

607602
/** Parse indentation region `body` and rewrite it to be in braces instead */
608603
def indentedToBraces[T](body: => T): T = {
609-
val indentWidth = in.indent.enclosing.width
604+
val enclRegion = in.currentRegion.enclosing
605+
def indentWidth = enclRegion.indentWidth
610606
val followsColon = testChar(in.lastOffset - 1, ':')
611607
val startOpening =
612608
if (followsColon)
@@ -701,10 +697,12 @@ object Parsers {
701697
def bracesToIndented[T](body: => T): T = {
702698
val colonRequired = possibleColonOffset == in.lastOffset
703699
val (startOpening, endOpening) = startingElimRegion(colonRequired)
704-
val isOuterMost = in.sepRegions.isEmpty
705-
val savedPending = pendingPatches
706-
var canRewrite =
707-
in.sepRegions.forall(token => token == RBRACE || token == OUTDENT) && // test (1)
700+
val isOutermost = in.currentRegion.isOutermost
701+
def allBraces(r: Region): Boolean = r match {
702+
case r: InBraces => allBraces(r.enclosing)
703+
case _ => r.isOutermost
704+
}
705+
var canRewrite = allBraces(in.currentRegion) && // test (1)
708706
!testChars(in.lastOffset - 3, " =>") // test(6)
709707
val t = enclosed(LBRACE, {
710708
canRewrite &= in.isAfterLineEnd // test (2)
@@ -721,17 +719,9 @@ object Parsers {
721719
else if (testChar(startOpening - 1, Chars.isOperatorPart(_))) " :"
722720
else ":"
723721
val (startClosing, endClosing) = closingElimRegion()
724-
val applyPatch = () => {
725-
patch(source, Span(startOpening, endOpening), openingPatchStr)
726-
patch(source, Span(startClosing, endClosing), "")
727-
}
728-
pendingPatches = applyPatch :: pendingPatches
729-
if (isOuterMost) {
730-
pendingPatches.reverse.foreach(_())
731-
pendingPatches = Nil
732-
}
722+
patch(source, Span(startOpening, endOpening), openingPatchStr)
723+
patch(source, Span(startClosing, endClosing), "")
733724
}
734-
else pendingPatches = savedPending // can't rewrite, cancel all nested patches.
735725
t
736726
}
737727

@@ -1168,7 +1158,7 @@ object Parsers {
11681158
}
11691159

11701160
def indentRegion[T](tag: EndMarkerTag)(op: => T): T = {
1171-
val iw = in.indent.width
1161+
val iw = in.currentRegion.indentWidth
11721162
val t = op
11731163
in.consumeEndMarker(tag, iw)
11741164
t
@@ -1282,6 +1272,7 @@ object Parsers {
12821272
}
12831273
else { accept(TLARROW); typ() }
12841274
}
1275+
else if (in.token == INDENT) enclosed(INDENT, typ())
12851276
else infixType()
12861277

12871278
in.token match {
@@ -2152,8 +2143,15 @@ object Parsers {
21522143
def block(): Tree = {
21532144
val stats = blockStatSeq()
21542145
def isExpr(stat: Tree) = !(stat.isDef || stat.isInstanceOf[Import])
2155-
if (stats.nonEmpty && isExpr(stats.last)) Block(stats.init, stats.last)
2156-
else Block(stats, EmptyTree)
2146+
stats match {
2147+
case (stat : Block) :: Nil =>
2148+
stat // A typical case where this happens is creating a block around a region
2149+
// hat is already indented, e.g. something following a =>.
2150+
case _ :: stats1 if isExpr(stats.last) =>
2151+
Block(stats.init, stats.last)
2152+
case _ =>
2153+
Block(stats, EmptyTree)
2154+
}
21572155
}
21582156

21592157
/** Guard ::= if PostfixExpr
@@ -2192,7 +2190,7 @@ object Parsers {
21922190
/** Generator ::= [‘case’] Pattern `<-' Expr
21932191
*/
21942192
def generator(): Tree = {
2195-
val casePat = if (in.token == CASE) { in.skipCASE(); true } else false
2193+
val casePat = if (in.token == CASE) { in.nextToken(); true } else false
21962194
generatorRest(pattern1(), casePat)
21972195
}
21982196

@@ -2302,15 +2300,21 @@ object Parsers {
23022300
* ImplicitCaseClause ::= ‘case’ PatVar [Ascription] [Guard] `=>' Block
23032301
*/
23042302
val caseClause: () => CaseDef = () => atSpan(in.offset) {
2305-
accept(CASE)
2306-
CaseDef(pattern(), guard(), atSpan(accept(ARROW)) { block() })
2303+
val (pat, grd) = inSepRegion(LPAREN, RPAREN) {
2304+
accept(CASE)
2305+
(pattern(), guard())
2306+
}
2307+
CaseDef(pat, grd, atSpan(accept(ARROW)) { block() })
23072308
}
23082309

23092310
/** TypeCaseClause ::= ‘case’ InfixType ‘=>’ Type [nl]
23102311
*/
23112312
val typeCaseClause: () => CaseDef = () => atSpan(in.offset) {
2312-
accept(CASE)
2313-
CaseDef(infixType(), EmptyTree, atSpan(accept(ARROW)) {
2313+
val pat = inSepRegion(LPAREN, RPAREN) {
2314+
accept(CASE)
2315+
infixType()
2316+
}
2317+
CaseDef(pat, EmptyTree, atSpan(accept(ARROW)) {
23142318
val t = typ()
23152319
if (isStatSep) in.nextToken()
23162320
t
@@ -3246,7 +3250,7 @@ object Parsers {
32463250
*/
32473251
def enumCase(start: Offset, mods: Modifiers): DefTree = {
32483252
val mods1 = mods | EnumCase
3249-
in.skipCASE()
3253+
accept(CASE)
32503254

32513255
atSpan(start, nameStart) {
32523256
val id = termIdent()
@@ -3349,9 +3353,8 @@ object Parsers {
33493353
case _ => false
33503354
}
33513355

3352-
def givenArgs(t: Tree): Tree = {
3356+
def givenArgs(t: Tree): Tree =
33533357
if (in.token == GIVEN) givenArgs(applyGiven(t, prefixExpr)) else t
3354-
}
33553358

33563359
if (in.token == LPAREN)
33573360
inParens {

0 commit comments

Comments
 (0)