Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make indentation significant in old-style control syntax #7235

Merged
merged 8 commits into from
Sep 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2588,7 +2588,8 @@ class JSCodeGen()(implicit ctx: Context) {
sym.info.paramNamess.flatten.zip(sym.info.paramInfoss.flatten)

val wereRepeated = ctx.atPhase(ctx.elimRepeatedPhase) {
val list = for ((name, tpe) <- paramNamesAndTypes)
val list =
for ((name, tpe) <- paramNamesAndTypes)
yield (name -> tpe.isRepeatedParam)
list.toMap
}
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ScalaSettings extends Settings.SettingGroup {
val oldSyntax: Setting[Boolean] = BooleanSetting("-old-syntax", "Require `(...)` around conditions")
val indent: Setting[Boolean] = BooleanSetting("-indent", "allow significant indentation")
val noindent: Setting[Boolean] = BooleanSetting("-noindent", "require classical {...} syntax, indentation is not significant")
val YindentColons: Setting[Boolean] = BooleanSetting("-Yindent-colons", "allow colons at ends-of-lines to start indentation blocks")

/** Decompiler settings */
val printTasty: Setting[Boolean] = BooleanSetting("-print-tasty", "Prints the raw tasty.") withAbbreviation "--print-tasty"
Expand Down
21 changes: 12 additions & 9 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ object Parsers {
}
})
canRewrite &= (in.isAfterLineEnd || statCtdTokens.contains(in.token)) // test (5)
if (canRewrite) {
if (canRewrite && (!colonRequired || in.colonSyntax)) {
val openingPatchStr =
if (!colonRequired) ""
else if (testChar(startOpening - 1, Chars.isOperatorPart(_))) " :"
Expand Down Expand Up @@ -1218,7 +1218,7 @@ object Parsers {
}

def possibleTemplateStart(): Unit = {
in.observeIndented()
in.observeIndented(noIndentTemplateTokens, nme.derives)
newLineOptWhenFollowedBy(LBRACE)
}

Expand Down Expand Up @@ -1636,8 +1636,11 @@ object Parsers {
if (rewriteToOldSyntax()) revertToParens(t)
in.nextToken()
}
else if (rewriteToNewSyntax(t.span))
dropParensOrBraces(t.span.start, s"${tokenString(altToken)}")
else {
in.observeIndented(noIndentAfterConditionTokens)
if (rewriteToNewSyntax(t.span))
dropParensOrBraces(t.span.start, s"${tokenString(altToken)}")
}
t
}
else {
Expand Down Expand Up @@ -2296,6 +2299,7 @@ object Parsers {
dropParensOrBraces(start, if (in.token == YIELD || in.token == DO) "" else "do")
}
}
in.observeIndented(noIndentAfterEnumeratorTokens)
res
}
else {
Expand Down Expand Up @@ -3539,15 +3543,14 @@ object Parsers {

/** TemplateOpt = [Template]
*/
def templateOpt(constr: DefDef): Template =
possibleBracesStart()
def templateOpt(constr: DefDef): Template = {
possibleTemplateStart()
if (in.token == EXTENDS || isIdent(nme.derives))
template(constr)
else {
possibleTemplateStart()
else
if (in.isNestedStart) template(constr)
else Template(constr, Nil, Nil, EmptyValDef, Nil)
}
}

/** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
*/
Expand Down
22 changes: 14 additions & 8 deletions compiler/src/dotty/tools/dotc/parsing/Scanners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,15 @@ object Scanners {
val rewriteNoIndent = ctx.settings.noindent.value && rewrite

val noindentSyntax =
ctx.settings.noindent.value ||
ctx.settings.oldSyntax.value ||
isScala2Mode
ctx.settings.noindent.value
|| ctx.settings.oldSyntax.value
|| isScala2Mode
val indentSyntax =
(if (Config.defaultIndent) !noindentSyntax else ctx.settings.indent.value) ||
rewriteNoIndent
(if (Config.defaultIndent) !noindentSyntax else ctx.settings.indent.value)
|| rewriteNoIndent
val colonSyntax =
ctx.settings.YindentColons.value
|| rewriteNoIndent

if (rewrite) {
val s = ctx.settings
Expand Down Expand Up @@ -532,18 +535,21 @@ object Scanners {
}
}

def observeIndented(): Unit =
def observeIndented(unless: BitSet, unlessSoftKW: TermName = EmptyTermName): Unit =
if (indentSyntax && isAfterLineEnd && token != INDENT) {
val newLineInserted = token == NEWLINE || token == NEWLINES
val nextOffset = if (newLineInserted) next.offset else offset
val nextToken = if (newLineInserted) next.token else token
val nextWidth = indentWidth(nextOffset)
val lastWidth = currentRegion match {
case r: Indented => r.width
case r: InBraces => r.width
case _ => nextWidth
}

if (lastWidth < nextWidth) {
if (lastWidth < nextWidth
&& !unless.contains(nextToken)
&& (unlessSoftKW.isEmpty || token != IDENTIFIER || name != unlessSoftKW)) {
currentRegion = Indented(nextWidth, Set(), COLONEOL, currentRegion)
if (!newLineInserted) next.copyFrom(this)
offset = nextOffset
Expand Down Expand Up @@ -590,7 +596,7 @@ object Scanners {
lookahead()
val atEOL = isAfterLineEnd
reset()
if (atEOL) token = COLONEOL
if (colonSyntax && atEOL) token = COLONEOL
case EOF | RBRACE =>
currentRegion match {
case r: Indented if !r.isOutermost =>
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/parsing/Tokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ object Tokens extends TokensCommon {
*/
final val startParamOrGivenTypeTokens: BitSet = startParamTokens | BitSet(GIVEN, ERASED)

final val noIndentTemplateTokens = BitSet(EXTENDS)
final val noIndentAfterConditionTokens = BitSet(THEN, DO)
final val noIndentAfterEnumeratorTokens = BitSet(YIELD, DO)

final val scala3keywords = BitSet(ENUM, ERASED, GIVEN, IMPLIED)

final val softModifierNames = Set(nme.inline, nme.opaque)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2174,7 +2174,8 @@ object messages {
def symLocation(sym: Symbol) = {
val lineDesc =
if (sym.span.exists && sym.span != sym.owner.span)
s" at line ${sym.sourcePos.line + 1}" else ""
s" at line ${sym.sourcePos.line + 1}"
else ""
i"in ${sym.owner}${lineDesc}"
}
val clashDescription =
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>

def setters(mixin: ClassSymbol): List[Tree] =
for (setter <- mixin.info.decls.filter(setr => setr.isSetter && !wasOneOf(setr, Deferred)))
yield transformFollowing(DefDef(mkForwarderSym(setter.asTerm), unitLiteral.withSpan(cls.span)))
yield transformFollowing(DefDef(mkForwarderSym(setter.asTerm), unitLiteral.withSpan(cls.span)))

def mixinForwarders(mixin: ClassSymbol): List[Tree] =
for (meth <- mixin.info.decls.toList if needsMixinForwarder(meth))
Expand All @@ -263,7 +263,6 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
transformFollowing(polyDefDef(mkForwarderSym(meth.asTerm, Bridge), forwarderRhsFn(meth)))
}


cpy.Template(impl)(
constr =
if (cls.is(Trait)) cpy.DefDef(impl.constr)(vparamss = Nil :: Nil)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -890,8 +890,8 @@ trait Applications extends Compatibility {
case err: ErrorType => cpy.Apply(tree)(fun1, proto.unforcedTypedArgs).withType(err)
case TryDynamicCallType => typedDynamicApply(tree, pt)
case _ =>
if originalProto.isDropped then fun1
else if fun1.symbol == defn.Compiletime_summonFrom then
if (originalProto.isDropped) fun1
else if (fun1.symbol == defn.Compiletime_summonFrom)
// Special handling of `summonFrom { ... }`.
// We currently cannot use a macro for that since unlike other inline methods
// summonFrom needs to expand lazily. For instance, in
Expand Down
9 changes: 4 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
|""".stripMargin
ctx.error(msg, inlinedFrom.sourcePos)
EmptyTree
} else {
}
else {
val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx1)

val inlinedNormailizer = new TreeMap {
Expand All @@ -1270,10 +1271,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
/** Return the set of symbols that are refered at level -1 by the tree and defined in the current run.
* This corresponds to the symbols that will need to be interpreted.
*/
private def macroDependencies(tree: Tree)(implicit ctx: Context) = {
private def macroDependencies(tree: Tree)(implicit ctx: Context) =
new TreeAccumulator[Set[Symbol]] {
private[this] var level = -1
override def apply(syms: Set[Symbol], tree: tpd.Tree)(implicit ctx: Context): Set[Symbol] = {
override def apply(syms: Set[Symbol], tree: tpd.Tree)(implicit ctx: Context): Set[Symbol] =
if (level != -1) foldOver(syms, tree)
else tree match {
case tree: RefTree if level == -1 && tree.symbol.isDefinedInCurrentRun && !tree.symbol.isLocal =>
Expand All @@ -1289,8 +1290,6 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
case _ =>
foldOver(syms, tree)
}
}
}.apply(Set.empty, tree)
}
}

2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ trait QuotesAndSplices {
super.transform(tree)
case tdef: TypeDef if tdef.symbol.hasAnnotation(defn.InternalQuoted_patternBindHoleAnnot) =>
transformTypeBindingTypeDef(tdef, typePatBuf)
case tree @ AppliedTypeTree(tpt, args) =>
case tree @ AppliedTypeTree(tpt, args) =>
val args1: List[Tree] = args.zipWithConserve(tpt.tpe.typeParams.map(_.paramVariance)) { (arg, v) =>
arg.tpe match {
case _: TypeBounds => transform(arg)
Expand Down
3 changes: 2 additions & 1 deletion compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class CompilationTests extends ParallelTesting {
"tests/neg-custom-args/fatal-warnings/xfatalWarnings.scala",
defaultOptions.and("-nowarn", "-Xfatal-warnings")
),
compileFile("tests/pos-special/typeclass-scaling.scala", defaultOptions.and("-Xmax-inlines", "40"))
compileFile("tests/pos-special/typeclass-scaling.scala", defaultOptions.and("-Xmax-inlines", "40")),
compileFile("tests/pos-special/indent-colons.scala", defaultOptions.and("-Yindent-colons"))
).checkCompile()
}

Expand Down
28 changes: 11 additions & 17 deletions tests/neg/endmarkers.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
object Test

locally:
locally {
var x = 0
while x < 10 do x += 1
end while // error: end of statement expected but while found // error: not found: end
Expand All @@ -9,7 +9,8 @@ object Test
x += 1
x < 10
do ()
end while // error: misaligned end marker
end while // error: misaligned end marker // error: not found : end
} // error: ';' expected, but '}' found

def f(x: Int): Int =
val y =
Expand All @@ -23,22 +24,12 @@ object Test

val z = 22
x + y + z
end f // error: misaligned end marker
end f

def g = "!"

val xs = List(1, 2, 3)

xs.map:
x =>
val y = x * x
y * y

xs.map:
x =>
val y = x * x
y + y

println(f(2) + g)

(new Test2).foo
Expand All @@ -57,10 +48,11 @@ class Test2
def foo = 1

object x
new Test2:
new Test2 {
override def foo = 2
end new // error: end of statement expected but new found // error: not found: end
def bar = 2 // error: ';' expected, but unindent found
} // error: ';' expected, but '}' found
def bar = 2
end Test2 // error: misaligned end marker
end Test2

Expand Down Expand Up @@ -102,9 +94,11 @@ class Coder(words: List[String])
/** Invert the mnemonics map to give a map from chars 'A' ... 'Z' to '2' ... '9' */
private val charCode0: Map[Char, Char] =
mnemonics
.withFilter:
.withFilter {
case (digit, str) => true
case _ => false
.flatMap:
}
.flatMap {
case (digit, str) => str map (ltr => ltr -> digit)
}
end Coder // error: The start of this line does not match any of the previous indentation widths.
2 changes: 1 addition & 1 deletion tests/neg/i4373b.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ==> 05bef7805687ba94da37177f7568e3ba7da1f91c.scala <==
class x0 {
x1: // error
x0 | _
x0 | _ // error
// error
Loading