-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Permit new with trivial end #24331
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
base: main
Are you sure you want to change the base?
Permit new with trivial end #24331
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -349,43 +349,45 @@ object Parsers { | |
| if in.isNewLine then in.nextToken() else accept(SEMI) | ||
|
|
||
| /** Parse statement separators and end markers. Ensure that there is at least | ||
| * one statement separator unless the next token terminates a statement´sequence. | ||
| * @param stats the statements parsed to far | ||
| * one statement separator unless the next token terminates a statement sequence. | ||
| * @param stats the statements parsed so far | ||
| * @param noPrevStat true if there was no immediately preceding statement parsed | ||
| * @param what a string indicating what kind of statement is parsed | ||
| * @param altEnd a token that is also considered as a terminator of the statement | ||
| * sequence (the default `EOF` already assumes to terminate a statement | ||
| * sequence (the default `EOF` is already assumed to terminate a statement | ||
| * sequence). | ||
| * @return true if the statement sequence continues, false if it terminates. | ||
| */ | ||
| def statSepOrEnd[T <: Tree](stats: ListBuffer[T], noPrevStat: Boolean = false, what: String = "statement", altEnd: Token = EOF): Boolean = | ||
| inline def stopping = false | ||
| inline def continuing = true | ||
| def recur(sepSeen: Boolean, endSeen: Boolean): Boolean = | ||
| if isStatSep then | ||
| in.nextToken() | ||
| recur(true, endSeen) | ||
| recur(sepSeen = true, endSeen) | ||
| else if in.token == END then | ||
| if endSeen then syntaxError(em"duplicate end marker") | ||
| checkEndMarker(stats) | ||
| recur(sepSeen, endSeen = true) | ||
| else if isStatSeqEnd || in.token == altEnd then | ||
| false | ||
| stopping | ||
| else if sepSeen || endSeen then | ||
| true | ||
| continuing | ||
| else | ||
| val found = in.token | ||
| val statFollows = mustStartStatTokens.contains(found) | ||
| syntaxError( | ||
| if noPrevStat then IllegalStartOfStatement(what, isModifier, statFollows) | ||
| else em"end of $what expected but ${showToken(found)} found") | ||
| if mustStartStatTokens.contains(found) then | ||
| false // it's a statement that might be legal in an outer context | ||
| if statFollows then | ||
| stopping // it's a statement that might be legal in an outer context | ||
| else | ||
| in.nextToken() // needed to ensure progress; otherwise we might cycle forever | ||
| skip() | ||
| true | ||
| continuing | ||
|
|
||
| in.observeOutdented() | ||
| recur(false, false) | ||
| recur(sepSeen = false, endSeen = false) | ||
| end statSepOrEnd | ||
|
|
||
| def rewriteNotice(version: SourceVersion = `3.0-migration`, additionalOption: String = "") = | ||
|
|
@@ -1566,15 +1568,23 @@ object Parsers { | |
| if MigrationVersion.Scala2to3.needsPatch then | ||
| patch(source, Span(in.offset), " ") | ||
|
|
||
| def possibleTemplateStart(isNew: Boolean = false): Unit = | ||
| def possibleTemplateStart(): Unit = | ||
| possiblyNewTemplateStart(): Unit | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ignores the boolean value |
||
|
|
||
| /** Return true on trivial end */ | ||
| def possiblyNewTemplateStart(): Boolean = | ||
| in.observeColonEOL(inTemplate = true) | ||
| if in.token == COLONeol then | ||
| if in.lookahead.token == END then in.token = NEWLINE | ||
| if in.lookahead.token == END then | ||
| in.token = NEWLINE | ||
| true | ||
| else | ||
| in.nextToken() | ||
| if in.token != LBRACE then acceptIndent() | ||
| false | ||
| else | ||
| newLineOptWhenFollowedBy(LBRACE) | ||
| false | ||
|
|
||
| def checkEndMarker[T <: Tree](stats: ListBuffer[T]): Unit = | ||
|
|
||
|
|
@@ -2915,15 +2925,22 @@ object Parsers { | |
| val parents = | ||
| if in.isNestedStart then Nil | ||
| else constrApps(exclude = COMMA) | ||
| possibleTemplateStart(isNew = true) | ||
| parents match { | ||
| case parent :: Nil if !in.isNestedStart => | ||
| reposition(if (parent.isType) ensureApplied(wrapNew(parent)) else parent) | ||
| case tkn if in.token == INDENT => | ||
| New(templateBodyOpt(emptyConstructor, parents, Nil)) | ||
| case _ => | ||
| New(reposition(templateBodyOpt(emptyConstructor, parents, Nil))) | ||
| } | ||
| val colonized = possiblyNewTemplateStart() | ||
| parents match | ||
| case parent :: Nil if !in.isNestedStart => | ||
| reposition: | ||
| if colonized then New(Template(emptyConstructor, parents, derived = Nil, self = EmptyValDef, body = Nil)) | ||
| else if parent.isType then ensureApplied(wrapNew(parent)) | ||
| else parent | ||
| case parents => | ||
| // With brace syntax, the last token consumed by a parser is }, but with indent syntax, | ||
| // the last token consumed by a parser is OUTDENT, which causes mismatching spans, so don't reposition. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. comment inlined from the previous PR |
||
| val indented = in.token == INDENT | ||
| val body = | ||
| val bo = templateBodyOpt(emptyConstructor, parents, derived = Nil) | ||
| if !indented then reposition(bo) else bo | ||
| New(body) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. preserves existing behavior, but what is the span of the result? |
||
| end newExpr | ||
|
|
||
| /** ExprsInParens ::= ExprInParens {`,' ExprInParens} | ||
| * | NamedExprInParens {‘,’ NamedExprInParens} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to break the habit of inserting an initial blank line in test sources? |
||
| class C | ||
| val cc = | ||
| new C | ||
| end new // error | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
|
|
||
| trait Foo | ||
| val foo = | ||
| new Foo: | ||
| // comment | ||
| end new | ||
| val foo2 = | ||
| new Foo: | ||
| end new | ||
| val foo3 = | ||
| new Foo { | ||
| } | ||
| end new | ||
|
|
||
| class C | ||
| val c = | ||
| new C: | ||
| end new | ||
| val c2 = | ||
| new C { | ||
| } | ||
|
|
||
| class D: | ||
| end D | ||
| val d = | ||
| new D: | ||
| def more = ??? | ||
| end new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isNewwas never used