Skip to content

Fix #9746: Require then in new conditional syntax #9859

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

Merged
merged 3 commits into from
Sep 24, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,8 @@ class CommunityBuildTest:
@Test def betterfiles = projects.betterfiles.run()
@Test def catsEffect2 = projects.catsEffect2.run()
@Test def catsEffect3 = projects.catsEffect3.run()
@Test def dottyCpsAsync = projects.dottyCpsAsync.run()
// Temporarily disabled until problem discovered in comments to #9449 is fixed
// @Test def dottyCpsAsync = projects.dottyCpsAsync.run()
@Test def effpi = projects.effpi.run()
@Test def endpoints4s = projects.endpoints4s.run()
@Test def fastparse = projects.fastparse.run()
Expand Down
55 changes: 21 additions & 34 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,6 @@ object Parsers {
offset
}

def reportMissing(expected: Token): Unit =
syntaxError(ExpectedTokenButFound(expected, in.token))

/** semi = nl {nl} | `;'
* nl = `\n' // where allowed
*/
Expand Down Expand Up @@ -1825,7 +1822,7 @@ object Parsers {
* the initially parsed (...) region?
*/
def toBeContinued(altToken: Token): Boolean =
if in.token == altToken || in.isNewLine || migrateTo3 then
if in.isNewLine || migrateTo3 then
false // a newline token means the expression is finished
else if !in.canStartStatTokens.contains(in.token)
|| in.isLeadingInfixOperator(inConditional = true)
Expand All @@ -1835,37 +1832,27 @@ object Parsers {
followedByToken(altToken) // scan ahead to see whether we find a `then` or `do`

def condExpr(altToken: Token): Tree =
if in.token == LPAREN then
var t: Tree = atSpan(in.offset) { Parens(inParens(exprInParens())) }
val enclosedInParens = !toBeContinued(altToken)
if !enclosedInParens then
t = inSepRegion(InCond) {
expr1Rest(postfixExprRest(simpleExprRest(t)), Location.ElseWhere)
}
if in.token == altToken then
if rewriteToOldSyntax() then revertToParens(t)
in.nextToken()
val t: Tree =
if in.token == LPAREN then
var t: Tree = atSpan(in.offset) { Parens(inParens(exprInParens())) }
if in.token != altToken then
if toBeContinued(altToken) then
t = inSepRegion(InCond) {
expr1Rest(postfixExprRest(simpleExprRest(t)), Location.ElseWhere)
}
else
if rewriteToNewSyntax(t.span) then
dropParensOrBraces(t.span.start, s"${tokenString(altToken)}")
in.observeIndented()
return t
t
else if in.isNestedStart then
try expr() finally newLinesOpt()
else
if (altToken == THEN || enclosedInParens) && in.isNewLine then
in.observeIndented()
if !enclosedInParens && in.token != INDENT then reportMissing(altToken)
if (rewriteToNewSyntax(t.span))
dropParensOrBraces(t.span.start, s"${tokenString(altToken)}")
t
else
val t =
if in.isNestedStart then
try expr() finally newLinesOpt()
else
inSepRegion(InCond)(expr())
if rewriteToOldSyntax(t.span.startPos) then
revertToParens(t)
if altToken == THEN && in.isNewLine then
// don't require a `then` at the end of a line
in.observeIndented()
if in.token != INDENT then accept(altToken)
t
end condExpr
inSepRegion(InCond)(expr())
if rewriteToOldSyntax(t.span.startPos) then revertToParens(t)
accept(altToken)
t

/** Expr ::= [`implicit'] FunParams (‘=>’ | ‘?=>’) Expr
* | Expr1
Expand Down
14 changes: 7 additions & 7 deletions compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ class ExtractSemanticDB extends Phase:

extension (sym: Symbol):
private def adjustIfCtorTyparam(using Context) =
if sym.isType && sym.owner.exists && sym.owner.isConstructor
if sym.isType && sym.owner.exists && sym.owner.isConstructor then
matchingMemberType(sym, sym.owner.owner)
else
sym
Expand All @@ -557,20 +557,20 @@ class ExtractSemanticDB extends Phase:
/**Necessary because not all of the eventual flags are propagated from the Tree to the symbol yet.
*/
private def symbolKinds(tree: NamedDefTree)(using Context): Set[SymbolKind] =
if tree.symbol.isSelfSym
if tree.symbol.isSelfSym then
Set.empty
else
val symkinds = mutable.HashSet.empty[SymbolKind]
tree match
case tree: ValDef =>
if !tree.symbol.is(Param)
if !tree.symbol.is(Param) then
symkinds += (if tree.mods is Mutable then SymbolKind.Var else SymbolKind.Val)
if tree.rhs.isEmpty && !tree.symbol.isOneOf(TermParam | CaseAccessor | ParamAccessor)
if tree.rhs.isEmpty && !tree.symbol.isOneOf(TermParam | CaseAccessor | ParamAccessor) then
symkinds += SymbolKind.Abstract
case tree: DefDef =>
if tree.isSetterDef
if tree.isSetterDef then
symkinds += SymbolKind.Setter
else if tree.rhs.isEmpty
else if tree.rhs.isEmpty then
symkinds += SymbolKind.Abstract
case tree: Bind =>
symkinds += SymbolKind.Val
Expand All @@ -584,7 +584,7 @@ class ExtractSemanticDB extends Phase:
vparams <- vparamss
vparam <- vparams
do
if !excludeSymbol(vparam.symbol)
if !excludeSymbol(vparam.symbol) then
traverseAnnotsOfDefinition(vparam.symbol)
val symkinds =
getters.get(vparam.name).fold(SymbolKind.emptySet)(getter =>
Expand Down
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/dotc/semanticdb/Scala3.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ object Scala3:
displaySymbol(symbol.owner)
else if symbol.is(ModuleClass) then
displaySymbol(symbol.sourceModule)
else if symbol == defn.RootPackage
else if symbol == defn.RootPackage then
RootPackageName
else if symbol.isEmptyPackage
else if symbol.isEmptyPackage then
EmptyPackageName
else
symbol.name.show
Expand Down Expand Up @@ -131,7 +131,7 @@ object Scala3:
def unapply(symbolInfo: SymbolInformation): Option[Int] = symbolInfo.symbol match
case locals(ints) =>
val bi = BigInt(ints)
if bi.isValidInt
if bi.isValidInt then
Some(bi.toInt)
else
None
Expand Down Expand Up @@ -242,14 +242,14 @@ object Scala3:
while i < len do
val a = o1.charAt(i)
val b = o2.charAt(i)
if a.isDigit && b.isDigit
if a.isDigit && b.isDigit then
val byDigit = Integer.compare(toDigit(o1, i), toDigit(o2, i))
if (byDigit != 0) return byDigit
else
i = seekNonDigit(o1, i)
else
val result = Character.compare(a, b)
if result != 0
if result != 0 then
return result
i += 1
end while
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ object Erasure {
if defn.specialErasure.contains(owner) then
assert(sym.isConstructor, s"${sym.showLocated}")
defn.specialErasure(owner)
else if defn.isSyntheticFunctionClass(owner)
else if defn.isSyntheticFunctionClass(owner) then
defn.erasedFunctionClass(owner)
else
owner
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,7 @@ trait Applications extends Compatibility {
case tp1: MethodType => // (1)
tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType]
|| {
if tp1.isVarArgsMethod
if tp1.isVarArgsMethod then
tp2.isVarArgsMethod
&& isApplicableMethodRef(alt2, tp1.paramInfos.map(_.repeatedToSingle), WildcardType)
else
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,7 @@ class Typer extends Namer
&& !cls.isAllOf(PrivateLocal)
&& effectiveOwner.is(Trait)
&& !effectiveOwner.derivesFrom(defn.ObjectClass)
then
report.error(i"$cls cannot be defined in universal $effectiveOwner", cdef.srcPos)

// Temporarily set the typed class def as root tree so that we have at least some
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class DottyLanguageServer extends LanguageServer
private[this] var myDependentProjects: mutable.Map[ProjectConfig, mutable.Set[ProjectConfig]] = _

def drivers: Map[ProjectConfig, InteractiveDriver] = thisServer.synchronized {
if myDrivers == null
if myDrivers == null then
assert(rootUri != null, "`drivers` cannot be called before `initialize`")
val configFile = new File(new URI(rootUri + '/' + IDE_CONFIG_FILE))
val configs: List[ProjectConfig] = (new ObjectMapper).readValue(configFile, classOf[Array[ProjectConfig]]).toList
Expand Down Expand Up @@ -102,12 +102,12 @@ class DottyLanguageServer extends LanguageServer
System.gc()
for ((_, driver, opened) <- driverConfigs; (uri, source) <- opened)
driver.run(uri, source)
if Memory.isCritical()
if Memory.isCritical() then
println(s"WARNING: Insufficient memory to run Scala language server on these projects.")
}

private def checkMemory() =
if Memory.isCritical()
if Memory.isCritical() then
CompletableFutures.computeAsync { _ => restart() }

/** The configuration of the project that owns `uri`. */
Expand Down Expand Up @@ -149,7 +149,7 @@ class DottyLanguageServer extends LanguageServer

/** A mapping from project `p` to the set of projects that transitively depend on `p`. */
def dependentProjects: Map[ProjectConfig, Set[ProjectConfig]] = thisServer.synchronized {
if myDependentProjects == null
if myDependentProjects == null then
val idToConfig = drivers.keys.map(k => k.id -> k).toMap
val allProjects = drivers.keySet

Expand Down Expand Up @@ -192,7 +192,7 @@ class DottyLanguageServer extends LanguageServer
throw ex
}
}
if synchronize
if synchronize then
thisServer.synchronized { computation() }
else
computation()
Expand Down Expand Up @@ -829,15 +829,15 @@ object DottyLanguageServer {
def completionItemKind(sym: Symbol)(implicit ctx: Context): lsp4j.CompletionItemKind = {
import lsp4j.{CompletionItemKind => CIK}

if sym.is(Package) || sym.is(Module)
if sym.is(Package) || sym.is(Module) then
CIK.Module // No CompletionItemKind.Package (https://github.com/Microsoft/language-server-protocol/issues/155)
else if sym.isConstructor
else if sym.isConstructor then
CIK.Constructor
else if sym.isClass
else if sym.isClass then
CIK.Class
else if sym.is(Mutable)
else if sym.is(Mutable) then
CIK.Variable
else if sym.is(Method)
else if sym.is(Method) then
CIK.Method
else
CIK.Field
Expand All @@ -861,7 +861,7 @@ object DottyLanguageServer {
}

def markupContent(content: String): lsp4j.MarkupContent = {
if content.isEmpty
if content.isEmpty then
null
else {
val markup = new lsp4j.MarkupContent
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i8731.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object test:
case _ => () // error: missing parameter type
end match

if 3 == 3
if 3 == 3 then
()
end if
else // error: illegal start of definition
Expand Down
4 changes: 2 additions & 2 deletions tests/pos/indent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ object Test:
println("world")
33
val y1 =
if x > 0
if x > 0 then
1
else
2
val y2 =
if (y > 0) && y < 0
if (y > 0) && y < 0 then
1
else
2
Expand Down