Skip to content

Commit cde8150

Browse files
committed
feat: update bridge to account for actions
1 parent 666ad6c commit cde8150

File tree

13 files changed

+201
-22
lines changed

13 files changed

+201
-22
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package dotty.tools.dotc.reporting
2+
3+
import dotty.tools.dotc.rewrites.Rewrites.ActionPatch
4+
5+
case class CodeAction(
6+
title: String,
7+
description: java.util.Optional[String],
8+
patches: java.util.List[ActionPatch]
9+
)

compiler/src/dotty/tools/dotc/reporting/Message.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import printing.Formatting.hl
1010
import config.SourceVersion
1111

1212
import scala.language.unsafeNulls
13-
1413
import scala.annotation.threadUnsafe
1514

1615
/** ## Tips for error message generation
@@ -415,6 +414,9 @@ abstract class Message(val errorId: ErrorMessageID)(using Context) { self =>
415414
*/
416415
def showAlways = false
417416

417+
def actions(using Context): java.util.List[CodeAction] =
418+
java.util.Collections.emptyList
419+
418420
override def toString = msg
419421
}
420422

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import transform.SymUtils._
2929
import scala.util.matching.Regex
3030
import java.util.regex.Matcher.quoteReplacement
3131
import cc.CaptureSet.IdentityCaptRefMap
32+
import dotty.tools.dotc.rewrites.Rewrites.ActionPatch
33+
import dotty.tools.dotc.util.Spans.Span
34+
import dotty.tools.dotc.util.SourcePosition
3235

3336
/** Messages
3437
* ========
@@ -1846,12 +1849,26 @@ class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: L
18461849
|are only approximated in a best-effort way."""
18471850
}
18481851

1849-
class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(using Context)
1852+
class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type, tree: untpd.PostfixOp)(using Context)
18501853
extends SyntaxMsg(OnlyFunctionsCanBeFollowedByUnderscoreID) {
18511854
def msg(using Context) = i"Only function types can be followed by ${hl("_")} but the current expression has type $tp"
18521855
def explain(using Context) =
18531856
i"""The syntax ${hl("x _")} is no longer supported if ${hl("x")} is not a function.
18541857
|To convert to a function value, you need to explicitly write ${hl("() => x")}"""
1858+
1859+
override def actions(using Context) =
1860+
val untpd.PostfixOp(qual, Ident(nme.WILDCARD)) = tree: @unchecked
1861+
import scala.language.unsafeNulls
1862+
import scala.jdk.CollectionConverters.*
1863+
List(
1864+
CodeAction(title = "Rewrite to function value",
1865+
description = java.util.Optional.empty(),
1866+
patches = List(
1867+
ActionPatch(SourcePosition(tree.source, Span(tree.span.start)), "(() => "),
1868+
ActionPatch(SourcePosition(tree.source, Span(qual.span.end, tree.span.end)), ")")
1869+
).asJava
1870+
)
1871+
).asJava
18551872
}
18561873

18571874
class MissingEmptyArgumentList(method: String)(using Context)

compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import core.Contexts._
77
import collection.mutable
88
import scala.annotation.tailrec
99
import dotty.tools.dotc.reporting.Reporter
10+
import dotty.tools.dotc.util.SourcePosition;
1011

1112
import java.io.OutputStreamWriter
1213
import java.nio.charset.StandardCharsets.UTF_8
@@ -19,6 +20,8 @@ object Rewrites {
1920
def delta = replacement.length - (span.end - span.start)
2021
}
2122

23+
case class ActionPatch(srcPos: SourcePosition, replacement: String)
24+
2225
private class Patches(source: SourceFile) {
2326
private[Rewrites] val pbuf = new mutable.ListBuffer[Patch]()
2427

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2941,7 +2941,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
29412941
case closure(_, _, _) =>
29422942
case _ =>
29432943
val recovered = typed(qual)(using ctx.fresh.setExploreTyperState())
2944-
report.errorOrMigrationWarning(OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen), tree.srcPos, from = `3.0`)
2944+
report.errorOrMigrationWarning(
2945+
OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen, tree), tree.srcPos, from = `3.0`
2946+
)
29452947
if (migrateTo3) {
29462948
// Under -rewrite, patch `x _` to `(() => x)`
29472949
patch(Span(tree.span.start), "(() => ")

project/Dependencies.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ object Dependencies {
2828
"com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % flexmarkVersion,
2929
)
3030

31-
val newCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.8.0"
31+
val newCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.9.0-RC3"
3232
val oldCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.3.5"
3333
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dotty.tools.xsbt;
2+
3+
import java.util.Optional;
4+
5+
final public class Action implements xsbti.Action {
6+
private final String _title;
7+
private final Optional<String> _description;
8+
private final WorkspaceEdit _edit;
9+
10+
public Action(String title, Optional<String> description, WorkspaceEdit edit) {
11+
super();
12+
this._title = title;
13+
this._description = description;
14+
this._edit = edit;
15+
}
16+
17+
public String title() {
18+
return _title;
19+
}
20+
21+
public Optional<String> description() {
22+
return _description;
23+
}
24+
25+
public WorkspaceEdit edit() {
26+
return _edit;
27+
}
28+
}

sbt-bridge/src/dotty/tools/xsbt/DelegatingReporter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
*/
44
package dotty.tools.xsbt;
55

6+
import java.util.List;
7+
68
import scala.Tuple2;
79
import scala.collection.mutable.HashMap;
810

911
import dotty.tools.dotc.core.Contexts.Context;
1012
import dotty.tools.dotc.reporting.AbstractReporter;
13+
import dotty.tools.dotc.reporting.CodeAction;
1114
import dotty.tools.dotc.reporting.Diagnostic;
1215
import dotty.tools.dotc.reporting.Message;
1316
import dotty.tools.dotc.util.SourceFile;
@@ -43,12 +46,13 @@ public void doReport(Diagnostic dia, Context ctx) {
4346
messageBuilder.append(message.message());
4447
String diagnosticCode = String.valueOf(message.errorId().errorNumber());
4548
boolean shouldExplain = Diagnostic.shouldExplain(dia, ctx);
49+
List<CodeAction> actions = message.actions(ctx);
4650
if (shouldExplain && !message.explanation().isEmpty()) {
4751
rendered.append(explanation(message, ctx));
4852
messageBuilder.append(System.lineSeparator()).append(explanation(message, ctx));
4953
}
5054

51-
delegate.log(new Problem(position, messageBuilder.toString(), severity, rendered.toString(), diagnosticCode));
55+
delegate.log(new Problem(position, messageBuilder.toString(), severity, rendered.toString(), diagnosticCode, actions));
5256
}
5357

5458
private static Severity severityOf(int level) {

sbt-bridge/src/dotty/tools/xsbt/Problem.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package dotty.tools.xsbt;
22

3+
import java.util.List;
34
import java.util.Optional;
5+
import static java.util.stream.Collectors.toList;
6+
7+
import dotty.tools.dotc.reporting.CodeAction;
8+
import dotty.tools.dotc.rewrites.Rewrites.ActionPatch;
9+
import dotty.tools.dotc.util.SourcePosition;
10+
411
import xsbti.Position;
512
import xsbti.Severity;
613

@@ -10,14 +17,16 @@ final public class Problem implements xsbti.Problem {
1017
private final Severity _severity;
1118
private final Optional<String> _rendered;
1219
private final String _diagnosticCode;
20+
private final List<CodeAction> _actions;
1321

14-
public Problem(Position position, String message, Severity severity, String rendered, String diagnosticCode) {
22+
public Problem(Position position, String message, Severity severity, String rendered, String diagnosticCode, List<CodeAction> actions) {
1523
super();
1624
this._position = position;
1725
this._message = message;
1826
this._severity = severity;
1927
this._rendered = Optional.of(rendered);
2028
this._diagnosticCode = diagnosticCode;
29+
this._actions = actions;
2130
}
2231

2332
public String category() {
@@ -56,6 +65,34 @@ public Optional<xsbti.DiagnosticCode> diagnosticCode() {
5665
}
5766
}
5867

68+
public List<xsbti.Action> actions() {
69+
if (_actions.isEmpty()) {
70+
return java.util.Collections.emptyList();
71+
} else {
72+
return _actions
73+
.stream()
74+
.map(action -> new Action(action.title(), action.description(), toWorkspaceEdit(action.patches())))
75+
.collect(toList());
76+
}
77+
}
78+
79+
private static WorkspaceEdit toWorkspaceEdit(List<ActionPatch> patches) {
80+
return new WorkspaceEdit(
81+
patches
82+
.stream()
83+
.map(patch -> new TextEdit(positionOf(patch.srcPos()), patch.replacement()))
84+
.collect(toList())
85+
);
86+
}
87+
88+
private static Position positionOf(SourcePosition pos) {
89+
if (pos.exists()){
90+
return new PositionBridge(pos, pos.source());
91+
} else {
92+
return PositionBridge.noPosition;
93+
}
94+
}
95+
5996
@Override
6097
public String toString() {
6198
return "Problem(" + _position + ", " + _message + ", " + _severity + ", " + _rendered + ", " + _diagnosticCode + ")";
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dotty.tools.xsbt;
2+
3+
import xsbti.Position;
4+
5+
final public class TextEdit implements xsbti.TextEdit {
6+
private final Position _position;
7+
private final String _newText;
8+
9+
public TextEdit(Position position, String newText) {
10+
super();
11+
this._position = position;
12+
this._newText = newText;
13+
}
14+
15+
public Position position() {
16+
return _position;
17+
}
18+
19+
public String newText() {
20+
return _newText;
21+
}
22+
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package dotty.tools.xsbt;
2+
3+
import java.util.List;
4+
5+
import xsbti.TextEdit;
6+
7+
final public class WorkspaceEdit implements xsbti.WorkspaceEdit {
8+
9+
private final List<TextEdit> _changes;
10+
11+
public WorkspaceEdit(List<TextEdit> changes) {
12+
super();
13+
this._changes = changes;
14+
}
15+
16+
public List<TextEdit> changes() {
17+
return _changes;
18+
}
19+
20+
}

sbt-test/compilerReporter/simple/Source.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ trait Wr {
77

88
object Er {
99
val a = er1
10-
}
10+
11+
def f: Int = 1
12+
val x = f _
13+
}

sbt-test/compilerReporter/simple/project/Reporter.scala

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,58 @@ object Reporter {
2727
check := (Compile / compile).failure.map(_ => {
2828
val problems = reporter.problems
2929
println(problems.toList)
30-
assert(problems.size == 1)
3130

32-
// make sure position reported by zinc are proper
33-
val mainProblem = problems.head
31+
problems match {
32+
case Array(err, warning) =>
33+
// Checking the error reported
34+
val eline = err.position().line()
35+
assert(eline.isPresent() == true)
36+
assert(eline.get() == 9)
3437

35-
val line = mainProblem.position().line()
36-
assert(line.isPresent() == true)
37-
assert(line.get() == 9)
38+
val ediagnosticCode = err.diagnosticCode()
39+
assert(ediagnosticCode.isPresent() == true)
40+
val ecode = ediagnosticCode.get().code()
41+
assert(ecode == "6")
3842

39-
val diagnosticCode = mainProblem.diagnosticCode()
40-
assert(diagnosticCode.isPresent() == true)
41-
val code = diagnosticCode.get()
42-
assert(diagnosticCode.get().code() == "6")
43+
val epointer = err.position().pointer()
44+
assert(epointer.isPresent() == true)
45+
assert(epointer.get() == 10)
4346

44-
val pointer = mainProblem.position().pointer()
45-
assert(pointer.isPresent() == true)
46-
assert(pointer.get() == 10)
47+
assert(err.position.offset.isPresent)
4748

48-
assert(problems.forall(_.position.offset.isPresent))
49+
assert(err.severity == Severity.Error) // not found: er1,
4950

50-
assert(problems.count(_.severity == Severity.Error) == 1) // not found: er1,
51+
// Checking the warning reported
52+
53+
val wline = warning.position().line()
54+
assert(wline.isPresent() == true)
55+
assert(wline.get() == 12)
56+
57+
val wdiagnosticCode = warning.diagnosticCode()
58+
assert(wdiagnosticCode.isPresent() == true)
59+
val wcode = wdiagnosticCode.get().code()
60+
assert(wcode == "99")
61+
62+
val wpointer = warning.position().pointer()
63+
assert(wpointer.isPresent() == true)
64+
assert(wpointer.get() == 12)
65+
66+
assert(warning.position.offset.isPresent)
67+
68+
assert(warning.severity == Severity.Warn) // Only function types can be followed by _ but the current expression has type Int
69+
70+
//val actions = warning.actions()
71+
72+
//assert(actions.size == 1)
73+
74+
//val action = actions.head
75+
76+
//assert(action.title() == "wrong")
77+
78+
case somethingElse =>
79+
assert(false, s"Only expected to have a single error and a single warning, but instead got: ${somethingElse.toString}")
80+
81+
}
5182
}).value
5283
)
5384
}

0 commit comments

Comments
 (0)