Skip to content

Standardize -rewrite advertisements and suppress them in REPL #14955

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 2 commits into from
May 11, 2022
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
16 changes: 7 additions & 9 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -359,13 +359,11 @@ object Parsers {
recur(false, false)
end statSepOrEnd

def rewriteNotice(version: String = "3.0", additionalOption: String = "") = {
val optionStr = if (additionalOption.isEmpty) "" else " " ++ additionalOption
i"\nThis construct can be rewritten automatically under$optionStr -rewrite -source $version-migration."
}
def rewriteNotice(version: SourceVersion = `3.0-migration`, additionalOption: String = "") =
Message.rewriteNotice("This construct", version, additionalOption)

def syntaxVersionError(option: String, span: Span) =
syntaxError(em"""This construct is not allowed under $option.${rewriteNotice("3.0", option)}""", span)
syntaxError(em"""This construct is not allowed under $option.${rewriteNotice(`3.0-migration`, option)}""", span)

def rewriteToNewSyntax(span: Span = Span(in.offset)): Boolean = {
if (in.newSyntax) {
Expand Down Expand Up @@ -2084,7 +2082,7 @@ object Parsers {
in.nextToken()
if isVarargSplice then
report.errorOrMigrationWarning(
em"The syntax `x: _*` is no longer supported for vararg splices; use `x*` instead${rewriteNotice("future")}",
em"The syntax `x: _*` is no longer supported for vararg splices; use `x*` instead${rewriteNotice(`future-migration`)}",
in.sourcePos(uscoreStart),
future)
if sourceVersion == `future-migration` then
Expand Down Expand Up @@ -2160,7 +2158,7 @@ object Parsers {
val t =
if (in.token == COLON && location == Location.InBlock) {
report.errorOrMigrationWarning(
s"This syntax is no longer supported; parameter needs to be enclosed in (...)${rewriteNotice("future")}",
s"This syntax is no longer supported; parameter needs to be enclosed in (...)${rewriteNotice(`future-migration`)}",
source.atSpan(Span(start, in.lastOffset)),
from = future)
in.nextToken()
Expand Down Expand Up @@ -3186,7 +3184,7 @@ object Parsers {
def wildcardSelector() =
if in.token == USCORE && sourceVersion.isAtLeast(future) then
report.errorOrMigrationWarning(
em"`_` is no longer supported for a wildcard import; use `*` instead${rewriteNotice("future")}",
em"`_` is no longer supported for a wildcard import; use `*` instead${rewriteNotice(`future-migration`)}",
in.sourcePos(),
from = future)
patch(source, Span(in.offset, in.offset + 1), "*")
Expand All @@ -3205,7 +3203,7 @@ object Parsers {
if in.token == ARROW || isIdent(nme.as) then
if in.token == ARROW && sourceVersion.isAtLeast(future) then
report.errorOrMigrationWarning(
em"The import renaming `a => b` is no longer supported ; use `a as b` instead${rewriteNotice("future")}",
em"The import renaming `a => b` is no longer supported ; use `a as b` instead${rewriteNotice(`future-migration`)}",
in.sourcePos(),
from = future)
patch(source, Span(in.offset, in.offset + 2),
Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/printing/Formatting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,9 @@ object Formatting {
/** Explicit syntax highlighting */
def hl(s: String)(using Context): String =
SyntaxHighlighting.highlight(s)

/** Explicitly highlight a string with the same formatting as used for keywords */
def hlAsKeyword(str: String)(using Context): String =
if str.isEmpty || ctx.settings.color.value == "never" then str
else s"${SyntaxHighlighting.KeywordColor}$str${SyntaxHighlighting.NoColor}"
}
13 changes: 13 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/Message.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package dotty.tools
package dotc
package reporting

import core.Contexts.*, core.Decorators.*, core.Mode
import config.SourceVersion

import scala.language.unsafeNulls

import scala.annotation.threadUnsafe
Expand All @@ -15,6 +18,16 @@ object Message {
* see where old errors still exist
*/
implicit def toNoExplanation(str: => String): Message = NoExplanation(str)

def rewriteNotice(what: String, version: SourceVersion | Null = null, options: String = "")(using Context): String =
if !ctx.mode.is(Mode.Interactive) then
val sourceStr = if version != null then i"-source $version" else ""
val optionStr =
if options.isEmpty then sourceStr
else if sourceStr.isEmpty then options
else i"$sourceStr $options"
i"\n$what can be rewritten automatically under -rewrite $optionStr."
else ""
}

/** A `Message` contains all semantic information necessary to easily
Expand Down
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import transform.patmat.SpaceEngine.isIrrefutable
import config.Feature
import config.Feature.sourceVersion
import config.SourceVersion._
import printing.Formatting.hlAsKeyword
import transform.TypeUtils.*

import collection.mutable
Expand Down Expand Up @@ -834,11 +835,12 @@ trait Checking {
case NonConforming => sel.srcPos
case RefutableExtractor => pat.source.atSpan(pat.span union sel.span)
else pat.srcPos
def rewriteMsg = Message.rewriteNotice("This patch", `future-migration`)
report.warning(
em"""$message
|
|If $usage is intentional, this can be communicated by $fix,
|which $addendum.${err.rewriteNotice}""",
|which $addendum.$rewriteMsg""",
pos)
false
}
Expand Down Expand Up @@ -992,10 +994,10 @@ trait Checking {
("extractor", (n: Name) => s"prefix syntax $n(...)")
else
("method", (n: Name) => s"method syntax .$n(...)")
def rewriteMsg = Message.rewriteNotice("The latter", options = "-deprecation")
report.deprecationWarning(
i"""Alphanumeric $kind $name is not declared `infix`; it should not be used as infix operator.
|The operation can be rewritten automatically to `$name` under -deprecation -rewrite.
|Or rewrite to ${alternative(name)} manually.""",
i"""Alphanumeric $kind $name is not declared ${hlAsKeyword("infix")}; it should not be used as infix operator.
|Instead, use ${alternative(name)} or backticked identifier `$name`.$rewriteMsg""",
tree.op.srcPos)
if (ctx.settings.deprecation.value) {
patch(Span(tree.op.span.start, tree.op.span.start), "`")
Expand Down
13 changes: 4 additions & 9 deletions compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,6 @@ object ErrorReporting {
|
|The tests were made under $constraintText"""

/** Format `raw` implicitNotFound or implicitAmbiguous argument, replacing
* all occurrences of `${X}` where `X` is in `paramNames` with the
* corresponding shown type in `args`.
*/

def rewriteNotice: String =
if Feature.migrateTo3 then "\nThis patch can be inserted automatically under -rewrite."
else ""

def whyFailedStr(fail: FailedExtension) =
i""" failed with
|
Expand Down Expand Up @@ -285,6 +276,10 @@ class ImplicitSearchError(
}
}

/** Format `raw` implicitNotFound or implicitAmbiguous argument, replacing
* all occurrences of `${X}` where `X` is in `paramNames` with the
* corresponding shown type in `args`.
*/
private def userDefinedErrorString(raw: String, paramNames: List[String], args: List[Type]): String = {
def translate(name: String): Option[String] = {
val idx = paramNames.indexOf(name)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3452,10 +3452,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
if sourceVersion == `future-migration` && isContextBoundParams && pt.args.nonEmpty
then // Under future-migration, don't infer implicit arguments yet for parameters
// coming from context bounds. Issue a warning instead and offer a patch.
def rewriteMsg = Message.rewriteNotice("This code", `future-migration`)
report.migrationWarning(
em"""Context bounds will map to context parameters.
|A `using` clause is needed to pass explicit arguments to them.
|This code can be rewritten automatically using -rewrite""", tree.srcPos)
|A `using` clause is needed to pass explicit arguments to them.$rewriteMsg""", tree.srcPos)
patch(Span(pt.args.head.span.start), "using ")
tree
else
Expand Down
17 changes: 17 additions & 0 deletions compiler/test-resources/repl/rewrite-messages
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// scalac: -source:future-migration -deprecation -Werror
scala> import scala.util._
-- Error: ----------------------------------------------------------------------
1 | import scala.util._
| ^
| `_` is no longer supported for a wildcard import; use `*` instead

scala> extension (x: Int) def foo(y: Int) = x + y
def foo(x: Int)(y: Int): Int

scala> 2 foo 4
-- Error: ----------------------------------------------------------------------
1 | 2 foo 4
| ^^^
|Alphanumeric method foo is not declared infix; it should not be used as infix operator.
|Instead, use method syntax .foo(...) or backticked identifier `foo`.
1 error found
6 changes: 6 additions & 0 deletions tests/neg/refutable-pattern-binding-messages.check
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,44 @@
|
| If this usage is intentional, this can be communicated by adding the `case` keyword before the full pattern,
| which will result in a filtering for expression (using `withFilter`).
| This patch can be rewritten automatically under -rewrite -source future-migration.
-- Error: tests/neg/refutable-pattern-binding-messages.scala:11:11 -----------------------------------------------------
11 | for ((x: String) <- xs) do () // error: pattern type more specialized
| ^^^^^^
| pattern's type String is more specialized than the right hand side expression's type AnyRef
|
| If the narrowing is intentional, this can be communicated by adding the `case` keyword before the full pattern,
| which will result in a filtering for expression (using `withFilter`).
| This patch can be rewritten automatically under -rewrite -source future-migration.
-- Error: tests/neg/refutable-pattern-binding-messages.scala:15:13 -----------------------------------------------------
15 | for none @ None <- ys do () // error: pattern type does not match
| ^^^^
| pattern's type None.type does not match the right hand side expression's type (x$1 : Option[?])
|
| If the narrowing is intentional, this can be communicated by adding the `case` keyword before the full pattern,
| which will result in a filtering for expression (using `withFilter`).
| This patch can be rewritten automatically under -rewrite -source future-migration.
-- Error: tests/neg/refutable-pattern-binding-messages.scala:5:14 ------------------------------------------------------
5 | val Positive(p) = 5 // error: refutable extractor
| ^^^^^^^^^^^^^^^
| pattern binding uses refutable extractor `Test.Positive`
|
| If this usage is intentional, this can be communicated by adding `: @unchecked` after the expression,
| which may result in a MatchError at runtime.
| This patch can be rewritten automatically under -rewrite -source future-migration.
-- Error: tests/neg/refutable-pattern-binding-messages.scala:10:20 -----------------------------------------------------
10 | val i :: is = List(1, 2, 3) // error: pattern type more specialized
| ^^^^^^^^^^^^^
| pattern's type ::[Int] is more specialized than the right hand side expression's type List[Int]
|
| If the narrowing is intentional, this can be communicated by adding `: @unchecked` after the expression,
| which may result in a MatchError at runtime.
| This patch can be rewritten automatically under -rewrite -source future-migration.
-- Error: tests/neg/refutable-pattern-binding-messages.scala:16:10 -----------------------------------------------------
16 | val 1 = 2 // error: pattern type does not match
| ^
| pattern's type (1 : Int) does not match the right hand side expression's type (2 : Int)
|
| If the narrowing is intentional, this can be communicated by adding `: @unchecked` after the expression,
| which may result in a MatchError at runtime.
| This patch can be rewritten automatically under -rewrite -source future-migration.
11 changes: 11 additions & 0 deletions tests/neg/rewrite-messages.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Error: tests/neg/rewrite-messages.scala:3:18 ------------------------------------------------------------------------
3 |import scala.util._ // error
| ^
| `_` is no longer supported for a wildcard import; use `*` instead
| This construct can be rewritten automatically under -rewrite -source future-migration.
-- Error: tests/neg/rewrite-messages.scala:7:4 -------------------------------------------------------------------------
7 | 2 foo 4 // error
| ^^^
| Alphanumeric method foo is not declared infix; it should not be used as infix operator.
| Instead, use method syntax .foo(...) or backticked identifier `foo`.
| The latter can be rewritten automatically under -rewrite -deprecation.
8 changes: 8 additions & 0 deletions tests/neg/rewrite-messages.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// scalac: -source:future-migration -deprecation -Werror

import scala.util._ // error

object Test {
extension (x: Int) def foo(y: Int) = x + y
2 foo 4 // error
}