Add API for dataflow errors (#1422)

This commit is contained in:
Dmitry Bushev 2021-01-25 17:41:20 +03:00 committed by GitHub
parent 4770e72734
commit 2515721799
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1938 additions and 266 deletions

1
.gitignore vendored
View File

@ -19,7 +19,6 @@ target/
## Rust ##
##########
Cargo.lock
**/*.rs.bk
wasm-pack.log
generated/

1454
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@ transport formats, please look [here](./protocol-architecture).
- [`MethodPointer`](#methodpointer)
- [`ExpressionValueUpdate`](#expressionvalueupdate)
- [`ExpressionUpdate`](#expressionupdate)
- [`ExpressionUpdatePayload`](#expressionupdatepayload)
- [`ProfilingInfo`](#profilinginfo)
- [`VisualisationConfiguration`](#visualisationconfiguration)
- [`SuggestionEntryArgument`](#suggestionentryargument)
@ -277,13 +278,10 @@ interface ExecutionTime {
### `ExpressionUpdate`
```typescript
type ExpressionUpdate = Computed | Failed | Poisoned;
An update about the computed expression.
/**
* An update about computed expression.
*/
interface Computed {
```typescript
interface ExpressionUpdate {
/**
* The id of updated expression.
*/
@ -298,36 +296,70 @@ interface Computed {
* The updated pointer to the method call.
*/
methodPointer?: SuggestionId;
/**
* Profiling information about the expression.
*/
profilingInfo: ProfilingInfo[];
/**
* Wether or not the expression's value came from the cache.
*/
fromCache: bool;
/**
* An extra information about the computed value.
*/
payload: ExpressionUpdatePayload;
}
```
### `ExpressionUpdatePayload`
An information about the computed value.
```typescript
type ExpressionUpdatePayload = Value | DatafalowError | RuntimeError | Poisoned;
/**
* An empty payload. Indicates that the expression was computed to a value.
*/
interface Value {}
/**
* Indicates that the expression was computed to an error.
*/
interface DataflowError {
/**
* The list of expressions leading to the root error.
*/
trace: ExpressionId[];
}
/**
* An update about failed expression.
* Indicates that the expression failed with the runtime exception.
*/
interface Failed {
/**
* The id of updated expression.
*/
expressionId: ExpressionId;
interface RuntimeError {
/**
* The error message.
*/
message: String;
/**
* The stack trace.
*/
trace: ExpressionId[];
}
/**
* An update about expression not executed due to the failed dependency.
* Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*/
interface Poisoned {
/**
* The id of updated expression.
* The list of expressions leading to the root expression that failed.
*/
expressionId: ExpressionId;
/**
* The failed expression that prevents the execution of this expression.
*/
failedExpressionId: ExpressionId;
trace: ExpressionId[];
}
```
@ -887,6 +919,11 @@ interface Diagnostic {
*/
location?: Range;
/**
* The id of related expression.
*/
expressionId?: ExpressionId;
/**
* The stack trace.
*/

View File

@ -104,43 +104,19 @@ final class ContextEventsListener(
sessionRouter ! DeliverToJsonController(rpcSession.clientId, payload)
case RunExpressionUpdates if expressionUpdates.nonEmpty =>
val updates = Vector.newBuilder[ContextRegistryProtocol.ExpressionUpdate]
val computedExpressions =
Vector.newBuilder[Api.ExpressionUpdate.ExpressionComputed]
expressionUpdates.foreach {
case m: Api.ExpressionUpdate.ExpressionComputed =>
computedExpressions += m
case m: Api.ExpressionUpdate.ExpressionFailed =>
updates += ContextRegistryProtocol.ExpressionUpdate
.ExpressionFailed(m.expressionId, m.message)
case m: Api.ExpressionUpdate.ExpressionPoisoned =>
updates += ContextRegistryProtocol.ExpressionUpdate
.ExpressionPoisoned(m.expressionId, m.failedExpressionId)
}
val notification = ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
updates.result(),
None
)
if (notification.updates.nonEmpty) {
sessionRouter ! DeliverToJsonController(
rpcSession.clientId,
notification
)
}
runExpressionComputed(computedExpressions.result())
runExpressionUpdates(expressionUpdates)
context.become(withState(Vector()))
case RunExpressionUpdates if expressionUpdates.isEmpty =>
}
/** Process `ExpressionComputed` notifications.
/** Process `ExpressionUpdate` notifications.
*
* Function resolves method pointers to the corresponding suggestion ids in
* the suggestions database, and creates the API updates.
*/
private def runExpressionComputed(
expressionUpdates: Vector[Api.ExpressionUpdate.ExpressionComputed]
private def runExpressionUpdates(
expressionUpdates: Vector[Api.ExpressionUpdate]
): Unit = {
def toMethodPointer(call: Api.MethodPointer): (String, String, String) =
(call.module, call.definedOnType, call.name)
@ -163,7 +139,7 @@ final class ContextEventsListener(
}
.toMap
val computedExpressions = expressionUpdates.map { update =>
ContextRegistryProtocol.ExpressionUpdate.ExpressionComputed(
ContextRegistryProtocol.ExpressionUpdate(
update.expressionId,
update.expressionType,
update.methodCall.flatMap { call =>
@ -175,16 +151,16 @@ final class ContextEventsListener(
None
}
},
update.profilingInfo.map { case Api.ProfilingInfo.ExecutionTime(t) =>
ProfilingInfo.ExecutionTime(t)
},
update.fromCache
update.profilingInfo.map(toProtocolProfilingInfo),
update.fromCache,
toProtocolPayload(update.payload)
)
}
val valueUpdates = computedExpressions.collect(toExpressionValueUpdate)
val payload = ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
computedExpressions,
Some(computedExpressions.map(toExpressionValueUpdate))
Option.when(valueUpdates.nonEmpty)(valueUpdates)
)
DeliverToJsonController(rpcSession.clientId, payload)
@ -193,16 +169,56 @@ final class ContextEventsListener(
}
/** Conversion between the new and the old expression update message. */
private def toExpressionValueUpdate(
m: ContextRegistryProtocol.ExpressionUpdate.ExpressionComputed
): ExpressionValueUpdate =
ExpressionValueUpdate(
m.expressionId,
m.`type`,
m.methodPointer,
m.profilingInfo,
m.fromCache
)
private def toExpressionValueUpdate: PartialFunction[
ContextRegistryProtocol.ExpressionUpdate,
ExpressionValueUpdate
] = {
case m: ContextRegistryProtocol.ExpressionUpdate
if m.payload == ContextRegistryProtocol.ExpressionUpdate.Payload.Value =>
ExpressionValueUpdate(
m.expressionId,
m.`type`,
m.methodPointer,
m.profilingInfo,
m.fromCache
)
}
/** Convert the runtime expression update payload to the context registry
* protocol representation.
*
* @param payload the runtime payload
* @return the registry protocol representation of the payload message
*/
private def toProtocolPayload(
payload: Api.ExpressionUpdate.Payload
): ContextRegistryProtocol.ExpressionUpdate.Payload =
payload match {
case Api.ExpressionUpdate.Payload.Value() =>
ContextRegistryProtocol.ExpressionUpdate.Payload.Value
case Api.ExpressionUpdate.Payload.DataflowError(trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload.DataflowError(trace)
case Api.ExpressionUpdate.Payload.RuntimeError(message, trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload
.RuntimeError(message, trace)
case Api.ExpressionUpdate.Payload.Poisoned(trace) =>
ContextRegistryProtocol.ExpressionUpdate.Payload.Poisoned(trace)
}
/** Convert the runtime profiling info to the context registry protocol
* representation.
*
* @param info the profiling info
* @return the registry protocol representation of the profiling info
*/
private def toProtocolProfilingInfo(info: Api.ProfilingInfo): ProfilingInfo =
info match {
case Api.ProfilingInfo.ExecutionTime(t) =>
ProfilingInfo.ExecutionTime(t)
}
/** Convert the runtime failure message to the context registry protocol
* representation.

View File

@ -107,96 +107,114 @@ object ContextRegistryProtocol {
updatesOld: Option[Vector[ExpressionValueUpdate]]
)
sealed trait ExpressionUpdate
/** An update about computed expression.
*
* @param expressionId the id of updated expression
* @param `type` the updated type of expression
* @param methodPointer the suggestion id of the updated method pointer
* @param profilingInfo profiling information about the expression
* @param fromCache whether or not the expression's value came from the cache
* @param payload an extra information about the computed value
*/
case class ExpressionUpdate(
expressionId: UUID,
`type`: Option[String],
methodPointer: Option[Long],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean,
payload: ExpressionUpdate.Payload
)
object ExpressionUpdate {
/** An update about computed expression.
*
* @param expressionId the id of updated expression
* @param `type` the updated type of expression
* @param methodPointer the suggestion id of the updated method pointer
* @param profilingInfo profiling information about the expression
* @param fromCache whether or not the expression's value came from the cache
*/
case class ExpressionComputed(
expressionId: UUID,
`type`: Option[String],
methodPointer: Option[Long],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean
) extends ExpressionUpdate
sealed trait Payload
object Payload {
/** An update about failed expression.
*
* @param expressionId the expression id
* @param message the error message
*/
case class ExpressionFailed(
expressionId: UUID,
message: String
) extends ExpressionUpdate
/** An information about computed expression. */
case object Value extends Payload
/** An update about expression not executed due to the failed dependency.
*
* @param expressionId the expression id
* @param failedExpressionId failed expression that blocks the execution
* of this expression
*/
case class ExpressionPoisoned(
expressionId: UUID,
failedExpressionId: UUID
) extends ExpressionUpdate
/** Indicates that the expression was computed to an error.
*
* @param trace the list of expressions leading to the root error.
*/
case class DataflowError(trace: Seq[UUID]) extends Payload
private object CodecField {
/** Indicates that the expression failed with the runtime exception.
*
* @param message the error message
* @param trace the stack trace
*/
case class RuntimeError(
message: String,
trace: Seq[UUID]
) extends Payload
val Type = "type"
}
/** Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*
* @param trace the list of expressions leading to the root error.
*/
case class Poisoned(trace: Seq[UUID]) extends Payload
private object ExpressionUpdateType {
val Computed = "Computed"
private object CodecField {
val Failed = "Failed"
val Poisoned = "Poisoned"
}
implicit val encoder: Encoder[ExpressionUpdate] =
Encoder.instance[ExpressionUpdate] {
case m: ExpressionUpdate.ExpressionComputed =>
Encoder[ExpressionUpdate.ExpressionComputed]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> ExpressionUpdateType.Computed.asJson)
)
case m: ExpressionUpdate.ExpressionFailed =>
Encoder[ExpressionUpdate.ExpressionFailed]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> ExpressionUpdateType.Failed.asJson)
)
case m: ExpressionUpdate.ExpressionPoisoned =>
Encoder[ExpressionUpdate.ExpressionPoisoned]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> ExpressionUpdateType.Poisoned.asJson)
)
val Type = "type"
}
implicit val decoder: Decoder[ExpressionUpdate] =
Decoder.instance { cursor =>
cursor.downField(CodecField.Type).as[String].flatMap {
case ExpressionUpdateType.Computed =>
Decoder[ExpressionUpdate.ExpressionComputed].tryDecode(cursor)
private object PayloadType {
case ExpressionUpdateType.Failed =>
Decoder[ExpressionUpdate.ExpressionFailed].tryDecode(cursor)
val Value = "Value"
case ExpressionUpdateType.Poisoned =>
Decoder[ExpressionUpdate.ExpressionFailed].tryDecode(cursor)
val DataflowError = "DataflowError"
val RuntimeError = "RuntimeError"
val Poisoned = "Poisoned"
}
implicit val encoder: Encoder[Payload] =
Encoder.instance[Payload] {
case Payload.Value =>
Json.obj(CodecField.Type -> PayloadType.Value.asJson)
case m: Payload.DataflowError =>
Encoder[Payload.DataflowError]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> PayloadType.DataflowError.asJson)
)
case m: Payload.RuntimeError =>
Encoder[Payload.RuntimeError]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> PayloadType.RuntimeError.asJson)
)
case m: Payload.Poisoned =>
Encoder[Payload.Poisoned]
.apply(m)
.deepMerge(
Json.obj(CodecField.Type -> PayloadType.Poisoned.asJson)
)
}
}
implicit val decoder: Decoder[Payload] =
Decoder.instance { cursor =>
cursor.downField(CodecField.Type).as[String].flatMap {
case PayloadType.Value =>
Right(Payload.Value)
case PayloadType.DataflowError =>
Decoder[Payload.DataflowError].tryDecode(cursor)
case PayloadType.RuntimeError =>
Decoder[Payload.RuntimeError].tryDecode(cursor)
case PayloadType.Poisoned =>
Decoder[Payload.Poisoned].tryDecode(cursor)
}
}
}
}
/** Signals that user doesn't have access to the requested context.

View File

@ -82,18 +82,19 @@ class ContextEventsListenerSpec
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Suggestions.method.externalId.get,
Some(Suggestions.method.returnType),
Some(
Api.MethodPointer(
Suggestions.method.module,
Suggestions.method.selfType,
Suggestions.method.name,
Suggestions.method.name
)
),
Vector(),
false
false,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -104,12 +105,13 @@ class ContextEventsListenerSpec
ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
Vector(
ContextRegistryProtocol.ExpressionUpdate.ExpressionComputed(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.method.externalId.get,
Some(Suggestions.method.returnType),
Some(suggestionIds(1).get),
Vector(),
false
false,
ContextRegistryProtocol.ExpressionUpdate.Payload.Value
)
),
Some(
@ -128,14 +130,20 @@ class ContextEventsListenerSpec
)
}
"send failure updates" taggedAs Retry in withDb {
"send dataflow error updates" taggedAs Retry in withDb {
(clientId, contextId, _, router, listener) =>
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionFailed(
Api.ExpressionUpdate(
Suggestions.method.externalId.get,
"Method failure"
None,
None,
Vector(),
false,
Api.ExpressionUpdate.Payload.DataflowError(
Seq(Suggestions.function.externalId.get)
)
)
)
)
@ -146,9 +154,14 @@ class ContextEventsListenerSpec
ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
Vector(
ContextRegistryProtocol.ExpressionUpdate.ExpressionFailed(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.method.externalId.get,
"Method failure"
None,
None,
Vector(),
false,
ContextRegistryProtocol.ExpressionUpdate.Payload
.DataflowError(Seq(Suggestions.function.externalId.get))
)
),
None
@ -157,14 +170,18 @@ class ContextEventsListenerSpec
)
}
"send poisoning updates" taggedAs Retry in withDb {
"send runtime error updates" taggedAs Retry in withDb {
(clientId, contextId, _, router, listener) =>
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionPoisoned(
Suggestions.local.externalId.get,
Suggestions.method.externalId.get
Api.ExpressionUpdate(
Suggestions.method.externalId.get,
None,
None,
Vector(),
false,
Api.ExpressionUpdate.Payload.RuntimeError("Method failure", Seq())
)
)
)
@ -175,9 +192,54 @@ class ContextEventsListenerSpec
ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
Vector(
ContextRegistryProtocol.ExpressionUpdate.ExpressionPoisoned(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.method.externalId.get,
None,
None,
Vector(),
false,
ContextRegistryProtocol.ExpressionUpdate.Payload
.RuntimeError("Method failure", Seq())
)
),
None
)
)
)
}
"send poisoning error updates" taggedAs Retry in withDb {
(clientId, contextId, _, router, listener) =>
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate(
Suggestions.local.externalId.get,
None,
None,
Vector(),
false,
Api.ExpressionUpdate.Payload.Poisoned(
Seq(Suggestions.method.externalId.get)
)
)
)
)
router.expectMsg(
DeliverToJsonController(
clientId,
ContextRegistryProtocol.ExpressionUpdatesNotification(
contextId,
Vector(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.local.externalId.get,
Suggestions.method.externalId.get
None,
None,
Vector(),
false,
ContextRegistryProtocol.ExpressionUpdate.Payload
.Poisoned(Seq(Suggestions.method.externalId.get))
)
),
None
@ -203,12 +265,13 @@ class ContextEventsListenerSpec
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Suggestions.method.externalId.get,
None,
None,
Vector(),
false
false,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -216,12 +279,13 @@ class ContextEventsListenerSpec
listener ! Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Suggestions.local.externalId.get,
None,
None,
Vector(),
false
false,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -234,19 +298,21 @@ class ContextEventsListenerSpec
ExpressionUpdatesNotification(
contextId,
Vector(
ContextRegistryProtocol.ExpressionUpdate.ExpressionComputed(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.method.externalId.get,
None,
None,
Vector(),
false
false,
ContextRegistryProtocol.ExpressionUpdate.Payload.Value
),
ContextRegistryProtocol.ExpressionUpdate.ExpressionComputed(
ContextRegistryProtocol.ExpressionUpdate(
Suggestions.local.externalId.get,
None,
None,
Vector(),
false
false,
ContextRegistryProtocol.ExpressionUpdate.Payload.Value
)
),
Some(

View File

@ -269,65 +269,80 @@ object Runtime {
fromCache: Boolean
)
/** Base trait for expression updates. */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(
Array(
new JsonSubTypes.Type(
value = classOf[ExpressionUpdate.ExpressionComputed],
name = "expressionUpdateComputed"
),
new JsonSubTypes.Type(
value = classOf[ExpressionUpdate.ExpressionFailed],
name = "expressionUpdateFailed"
),
new JsonSubTypes.Type(
value = classOf[ExpressionUpdate.ExpressionPoisoned],
name = "expressionUpdatePoisoned"
)
)
/** An update about the computed expression.
*
* @param expressionId the expression id
* @param expressionType the type of expression
* @param methodCall the pointer to a method definition
* @param profilingInfo profiling information about the execution of this
* expression
* @param fromCache whether or not the value for this expression came
* from the cache
* @param payload an extra information about the computed value
*/
case class ExpressionUpdate(
expressionId: ExpressionId,
expressionType: Option[String],
methodCall: Option[MethodPointer],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean,
payload: ExpressionUpdate.Payload
)
sealed trait ExpressionUpdate
object ExpressionUpdate {
/** An update about computed expression.
*
* @param expressionId the expression id
* @param expressionType the type of expression
* @param methodCall the pointer to a method definithin
* @param profilingInfo profiling information about the execution of this
* expression
* @param fromCache whether or not the value for this expression came
* from the cache
*/
case class ExpressionComputed(
expressionId: ExpressionId,
expressionType: Option[String],
methodCall: Option[MethodPointer],
profilingInfo: Vector[ProfilingInfo],
fromCache: Boolean
) extends ExpressionUpdate
/** Base trait for expression payloads. */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(
Array(
new JsonSubTypes.Type(
value = classOf[Payload.Value],
name = "expressionUpdatePayloadValue"
),
new JsonSubTypes.Type(
value = classOf[Payload.DataflowError],
name = "expressionUpdatePayloadDataflowError"
),
new JsonSubTypes.Type(
value = classOf[Payload.RuntimeError],
name = "expressionUpdatePayloadRuntimeError"
),
new JsonSubTypes.Type(
value = classOf[Payload.Poisoned],
name = "expressionUpdatePayloadPoisoned"
)
)
)
sealed trait Payload
object Payload {
/** An update about failed expression.
*
* @param expressionId the expression id
* @param message the error message
*/
case class ExpressionFailed(
expressionId: ExpressionId,
message: String
) extends ExpressionUpdate
/** An empty payload. Indicates that the expression was computed to a
* value.
*/
case class Value() extends Payload
/** An update about expression not executed due to a failed dependency.
*
* @param expressionId the expression id
* @param failedExpressionId failed expression that blocks the execution
* of this expression
*/
case class ExpressionPoisoned(
expressionId: ExpressionId,
failedExpressionId: ExpressionId
) extends ExpressionUpdate
/** Indicates that the expression was computed to an error.
*
* @param trace the list of expressions leading to the root error.
*/
case class DataflowError(trace: Seq[ExpressionId]) extends Payload
/** Indicates that the expression failed with the runtime exception.
*
* @param message the error message
* @param trace the stack trace
*/
case class RuntimeError(
message: String,
trace: Seq[ExpressionId]
) extends Payload
/** Indicates that the expression was not computed due to a dependency,
* that failed with the runtime exception.
*
* @param trace the list of expressions leading to the root error.
*/
case class Poisoned(trace: Seq[ExpressionId]) extends Payload
}
}
/** An object representing profiling information about an executed

View File

@ -35,13 +35,26 @@ object ErrorResolver {
val poisoned: Set[Api.ExpressionUpdate] = meta
.getExternal(toDataflowDependencyType(expressionId))
.getOrElse(Set())
.map(
Api.ExpressionUpdate
.ExpressionPoisoned(_, expressionId.externalId)
)
.map { id =>
Api.ExpressionUpdate(
id,
None,
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
Api.ExpressionUpdate.Payload.Poisoned(Seq())
)
}
val failed =
Api.ExpressionUpdate
.ExpressionFailed(expressionId.externalId, error.getMessage)
Api.ExpressionUpdate(
expressionId.externalId,
None,
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
Api.ExpressionUpdate.Payload
.RuntimeError(error.getMessage, Seq())
)
poisoned + failed
}
.getOrElse(Set())
@ -84,4 +97,6 @@ object ErrorResolver {
DataflowAnalysis.DependencyInfo.Type
.Static(id.internalId, Some(id.externalId))
val DependencyFailed: String =
"Dependency failed."
}

View File

@ -269,14 +269,14 @@ class EnsureCompiledJob(protected val files: Iterable[File])
private def runCompilationDiagnostics(module: Module)(implicit
ctx: RuntimeContext
): CompilationStatus = {
val errors = GatherDiagnostics
val pass = GatherDiagnostics
.runModule(module.getIr, ModuleContext(module))
.unsafeGetMetadata(
GatherDiagnostics,
"No diagnostics metadata right after the gathering pass."
)
.diagnostics
val diagnostics = errors.collect {
val diagnostics = pass.collect {
case warn: IR.Warning =>
createDiagnostic(Api.DiagnosticType.Warning(), module, warn)
case error: IR.Error =>

View File

@ -410,14 +410,15 @@ trait ProgramExecutionSupport {
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
value.getExpressionId,
Option(value.getType),
methodPointer,
value.getProfilingInfo.map { case e: ExecutionTime =>
Api.ProfilingInfo.ExecutionTime(e.getNanoTimeElapsed)
}.toVector,
value.wasCached()
value.wasCached(),
Api.ExpressionUpdate.Payload.Value()
)
)
)

View File

@ -11,7 +11,6 @@ import org.graalvm.polyglot.io.MessageEndpoint
import org.scalatest.BeforeAndAfterEach
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import java.io.{ByteArrayOutputStream, File}
import java.nio.ByteBuffer
import java.nio.file.Files
@ -102,6 +101,38 @@ class ExpressionErrorsTest
Api.Response(Api.ExecutionComplete(contextId))
}
object Update {
def error(
expressionId: UUID,
payload: Api.ExpressionUpdate.Payload
): Api.ExpressionUpdate =
Api.ExpressionUpdate(
expressionId,
None,
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
payload
)
def runtimeError(
expressionId: UUID,
message: String
): Api.ExpressionUpdate =
Api.ExpressionUpdate(
expressionId,
None,
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
Api.ExpressionUpdate.Payload.RuntimeError(message, Seq())
)
def poisonedError(expressionId: UUID): Api.ExpressionUpdate =
error(expressionId, Api.ExpressionUpdate.Payload.Poisoned(Seq()))
}
def contentsVersion(content: String): ContentVersion =
Sha3_224VersionCalculator.evalVersion(content)
@ -177,12 +208,12 @@ class ExpressionErrorsTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionFailed(
Update.runtimeError(
xId,
"Compile_Error Variable `undefined` is not defined."
),
Api.ExpressionUpdate.ExpressionPoisoned(yId, xId),
Api.ExpressionUpdate.ExpressionPoisoned(mainResId, xId)
Update.poisonedError(yId),
Update.poisonedError(mainResId)
)
)
),

View File

@ -132,7 +132,14 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(expressionId, None, None, Vector(Api.ProfilingInfo.ExecutionTime(0)), false)
Api.ExpressionUpdate(
expressionId,
None,
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false,
Api.ExpressionUpdate.Payload.Value()
)
)
)
)
@ -146,12 +153,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
expressionId,
Some(expressionType),
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false
false,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -176,12 +184,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
expressionId,
Some(expressionType),
Some(methodPointer),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache
fromCache,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -194,7 +203,15 @@ class RuntimeServerTest
Api.Response(
Api.ExpressionValuesComputed(
contextId,
Vector(Api.ExpressionValueUpdate(expressionId, None, None, Vector(Api.ProfilingInfo.ExecutionTime(0)), false))
Vector(
Api.ExpressionValueUpdate(
expressionId,
None,
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false
)
)
)
)
@ -286,12 +303,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Main.idMainX,
Some(Constants.INTEGER),
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache
fromCache,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -302,18 +320,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Main.idMainY,
Some(Constants.INTEGER),
Some(
Api.MethodPointer(
"Test.Main",
Constants.NUMBER,
"foo"
)
),
Some(Api.MethodPointer("Test.Main", Constants.NUMBER, "foo")),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache
fromCache,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -324,12 +337,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Main.idMainZ,
Some(Constants.INTEGER),
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache
fromCache,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -340,12 +354,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Main.idFooY,
Some(Constants.INTEGER),
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache
fromCache,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -356,12 +371,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
Main.idFooZ,
Some(Constants.INTEGER),
None,
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache
fromCache,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -491,12 +507,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
idMainY,
Some(Constants.INTEGER),
Some(Api.MethodPointer("Test.Main", "Test.Main", "foo")),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false
false,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -507,12 +524,13 @@ class RuntimeServerTest
Api.ExpressionUpdates(
contextId,
Set(
Api.ExpressionUpdate.ExpressionComputed(
Api.ExpressionUpdate(
idMainZ,
Some(Constants.INTEGER),
Some(Api.MethodPointer("Test.Main", "Test.Main", "bar")),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
false
false,
Api.ExpressionUpdate.Payload.Value()
)
)
)
@ -660,7 +678,7 @@ class RuntimeServerTest
context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PopContextResponse(contextId)),
context.Main.UpdateOld.mainY(contextId, fromCache = true),
context.Main.Update.mainY(contextId, fromCache = true),
context.Main.Update.mainY(contextId, fromCache = true),
context.executionComplete(contextId)
)
@ -1689,7 +1707,7 @@ class RuntimeServerTest
context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PopContextResponse(contextId)),
context.Main.UpdateOld.mainY(contextId, fromCache = true),
context.Main.Update.mainY(contextId, fromCache = true),
context.Main.Update.mainY(contextId, fromCache = true),
context.executionComplete(contextId)
)
@ -2954,7 +2972,7 @@ class RuntimeServerTest
context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PopContextResponse(contextId)),
context.Main.UpdateOld.mainY(contextId, fromCache = true),
context.Main.Update.mainY(contextId, fromCache = true),
context.Main.Update.mainY(contextId, fromCache = true),
context.executionComplete(contextId)
)
@ -5189,7 +5207,9 @@ class RuntimeServerTest
// open file
context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, isIndexed = true))
Api.Request(
Api.OpenFileNotification(mainFile, contents, isIndexed = true)
)
)
context.receiveNone shouldEqual None