Skip to content

Commit

Permalink
feat: update bridge to account for actions
Browse files Browse the repository at this point in the history
  • Loading branch information
ckipp01 committed Jul 6, 2023
1 parent 666ad6c commit cde8150
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 22 deletions.
9 changes: 9 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/CodeAction.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dotty.tools.dotc.reporting

import dotty.tools.dotc.rewrites.Rewrites.ActionPatch

case class CodeAction(
title: String,
description: java.util.Optional[String],
patches: java.util.List[ActionPatch]
)
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/reporting/Message.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import printing.Formatting.hl
import config.SourceVersion

import scala.language.unsafeNulls

import scala.annotation.threadUnsafe

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

def actions(using Context): java.util.List[CodeAction] =
java.util.Collections.emptyList

override def toString = msg
}

Expand Down
19 changes: 18 additions & 1 deletion compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import transform.SymUtils._
import scala.util.matching.Regex
import java.util.regex.Matcher.quoteReplacement
import cc.CaptureSet.IdentityCaptRefMap
import dotty.tools.dotc.rewrites.Rewrites.ActionPatch
import dotty.tools.dotc.util.Spans.Span
import dotty.tools.dotc.util.SourcePosition

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

class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(using Context)
class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type, tree: untpd.PostfixOp)(using Context)
extends SyntaxMsg(OnlyFunctionsCanBeFollowedByUnderscoreID) {
def msg(using Context) = i"Only function types can be followed by ${hl("_")} but the current expression has type $tp"
def explain(using Context) =
i"""The syntax ${hl("x _")} is no longer supported if ${hl("x")} is not a function.
|To convert to a function value, you need to explicitly write ${hl("() => x")}"""

override def actions(using Context) =
val untpd.PostfixOp(qual, Ident(nme.WILDCARD)) = tree: @unchecked
import scala.language.unsafeNulls
import scala.jdk.CollectionConverters.*
List(
CodeAction(title = "Rewrite to function value",
description = java.util.Optional.empty(),
patches = List(
ActionPatch(SourcePosition(tree.source, Span(tree.span.start)), "(() => "),
ActionPatch(SourcePosition(tree.source, Span(qual.span.end, tree.span.end)), ")")
).asJava
)
).asJava
}

class MissingEmptyArgumentList(method: String)(using Context)
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import core.Contexts._
import collection.mutable
import scala.annotation.tailrec
import dotty.tools.dotc.reporting.Reporter
import dotty.tools.dotc.util.SourcePosition;

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

case class ActionPatch(srcPos: SourcePosition, replacement: String)

private class Patches(source: SourceFile) {
private[Rewrites] val pbuf = new mutable.ListBuffer[Patch]()

Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2941,7 +2941,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case closure(_, _, _) =>
case _ =>
val recovered = typed(qual)(using ctx.fresh.setExploreTyperState())
report.errorOrMigrationWarning(OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen), tree.srcPos, from = `3.0`)
report.errorOrMigrationWarning(
OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen, tree), tree.srcPos, from = `3.0`
)
if (migrateTo3) {
// Under -rewrite, patch `x _` to `(() => x)`
patch(Span(tree.span.start), "(() => ")
Expand Down
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ object Dependencies {
"com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % flexmarkVersion,
)

val newCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.8.0"
val newCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.9.0-RC3"
val oldCompilerInterface = "org.scala-sbt" % "compiler-interface" % "1.3.5"
}
28 changes: 28 additions & 0 deletions sbt-bridge/src/dotty/tools/xsbt/Action.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dotty.tools.xsbt;

import java.util.Optional;

final public class Action implements xsbti.Action {
private final String _title;
private final Optional<String> _description;
private final WorkspaceEdit _edit;

public Action(String title, Optional<String> description, WorkspaceEdit edit) {
super();
this._title = title;
this._description = description;
this._edit = edit;
}

public String title() {
return _title;
}

public Optional<String> description() {
return _description;
}

public WorkspaceEdit edit() {
return _edit;
}
}
6 changes: 5 additions & 1 deletion sbt-bridge/src/dotty/tools/xsbt/DelegatingReporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
*/
package dotty.tools.xsbt;

import java.util.List;

import scala.Tuple2;
import scala.collection.mutable.HashMap;

import dotty.tools.dotc.core.Contexts.Context;
import dotty.tools.dotc.reporting.AbstractReporter;
import dotty.tools.dotc.reporting.CodeAction;
import dotty.tools.dotc.reporting.Diagnostic;
import dotty.tools.dotc.reporting.Message;
import dotty.tools.dotc.util.SourceFile;
Expand Down Expand Up @@ -43,12 +46,13 @@ public void doReport(Diagnostic dia, Context ctx) {
messageBuilder.append(message.message());
String diagnosticCode = String.valueOf(message.errorId().errorNumber());
boolean shouldExplain = Diagnostic.shouldExplain(dia, ctx);
List<CodeAction> actions = message.actions(ctx);
if (shouldExplain && !message.explanation().isEmpty()) {
rendered.append(explanation(message, ctx));
messageBuilder.append(System.lineSeparator()).append(explanation(message, ctx));
}

delegate.log(new Problem(position, messageBuilder.toString(), severity, rendered.toString(), diagnosticCode));
delegate.log(new Problem(position, messageBuilder.toString(), severity, rendered.toString(), diagnosticCode, actions));
}

private static Severity severityOf(int level) {
Expand Down
39 changes: 38 additions & 1 deletion sbt-bridge/src/dotty/tools/xsbt/Problem.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package dotty.tools.xsbt;

import java.util.List;
import java.util.Optional;
import static java.util.stream.Collectors.toList;

import dotty.tools.dotc.reporting.CodeAction;
import dotty.tools.dotc.rewrites.Rewrites.ActionPatch;
import dotty.tools.dotc.util.SourcePosition;

import xsbti.Position;
import xsbti.Severity;

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

public Problem(Position position, String message, Severity severity, String rendered, String diagnosticCode) {
public Problem(Position position, String message, Severity severity, String rendered, String diagnosticCode, List<CodeAction> actions) {
super();
this._position = position;
this._message = message;
this._severity = severity;
this._rendered = Optional.of(rendered);
this._diagnosticCode = diagnosticCode;
this._actions = actions;
}

public String category() {
Expand Down Expand Up @@ -56,6 +65,34 @@ public Optional<xsbti.DiagnosticCode> diagnosticCode() {
}
}

public List<xsbti.Action> actions() {
if (_actions.isEmpty()) {
return java.util.Collections.emptyList();
} else {
return _actions
.stream()
.map(action -> new Action(action.title(), action.description(), toWorkspaceEdit(action.patches())))
.collect(toList());
}
}

private static WorkspaceEdit toWorkspaceEdit(List<ActionPatch> patches) {
return new WorkspaceEdit(
patches
.stream()
.map(patch -> new TextEdit(positionOf(patch.srcPos()), patch.replacement()))
.collect(toList())
);
}

private static Position positionOf(SourcePosition pos) {
if (pos.exists()){
return new PositionBridge(pos, pos.source());
} else {
return PositionBridge.noPosition;
}
}

@Override
public String toString() {
return "Problem(" + _position + ", " + _message + ", " + _severity + ", " + _rendered + ", " + _diagnosticCode + ")";
Expand Down
23 changes: 23 additions & 0 deletions sbt-bridge/src/dotty/tools/xsbt/TextEdit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dotty.tools.xsbt;

import xsbti.Position;

final public class TextEdit implements xsbti.TextEdit {
private final Position _position;
private final String _newText;

public TextEdit(Position position, String newText) {
super();
this._position = position;
this._newText = newText;
}

public Position position() {
return _position;
}

public String newText() {
return _newText;
}

}
20 changes: 20 additions & 0 deletions sbt-bridge/src/dotty/tools/xsbt/WorkspaceEdit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package dotty.tools.xsbt;

import java.util.List;

import xsbti.TextEdit;

final public class WorkspaceEdit implements xsbti.WorkspaceEdit {

private final List<TextEdit> _changes;

public WorkspaceEdit(List<TextEdit> changes) {
super();
this._changes = changes;
}

public List<TextEdit> changes() {
return _changes;
}

}
5 changes: 4 additions & 1 deletion sbt-test/compilerReporter/simple/Source.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ trait Wr {

object Er {
val a = er1
}

def f: Int = 1
val x = f _
}
61 changes: 46 additions & 15 deletions sbt-test/compilerReporter/simple/project/Reporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,58 @@ object Reporter {
check := (Compile / compile).failure.map(_ => {
val problems = reporter.problems
println(problems.toList)
assert(problems.size == 1)

// make sure position reported by zinc are proper
val mainProblem = problems.head
problems match {
case Array(err, warning) =>
// Checking the error reported
val eline = err.position().line()
assert(eline.isPresent() == true)
assert(eline.get() == 9)

val line = mainProblem.position().line()
assert(line.isPresent() == true)
assert(line.get() == 9)
val ediagnosticCode = err.diagnosticCode()
assert(ediagnosticCode.isPresent() == true)
val ecode = ediagnosticCode.get().code()
assert(ecode == "6")

val diagnosticCode = mainProblem.diagnosticCode()
assert(diagnosticCode.isPresent() == true)
val code = diagnosticCode.get()
assert(diagnosticCode.get().code() == "6")
val epointer = err.position().pointer()
assert(epointer.isPresent() == true)
assert(epointer.get() == 10)

val pointer = mainProblem.position().pointer()
assert(pointer.isPresent() == true)
assert(pointer.get() == 10)
assert(err.position.offset.isPresent)

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

assert(problems.count(_.severity == Severity.Error) == 1) // not found: er1,
// Checking the warning reported

val wline = warning.position().line()
assert(wline.isPresent() == true)
assert(wline.get() == 12)

val wdiagnosticCode = warning.diagnosticCode()
assert(wdiagnosticCode.isPresent() == true)
val wcode = wdiagnosticCode.get().code()
assert(wcode == "99")

val wpointer = warning.position().pointer()
assert(wpointer.isPresent() == true)
assert(wpointer.get() == 12)

assert(warning.position.offset.isPresent)

assert(warning.severity == Severity.Warn) // Only function types can be followed by _ but the current expression has type Int

//val actions = warning.actions()

//assert(actions.size == 1)

//val action = actions.head

//assert(action.title() == "wrong")

case somethingElse =>
assert(false, s"Only expected to have a single error and a single warning, but instead got: ${somethingElse.toString}")

}
}).value
)
}

0 comments on commit cde8150

Please sign in to comment.