Improve display of KCL backtrace (#7582)
* Improve display of KCL backtrace * Fix circular dep
This commit is contained in:
@ -265,6 +265,8 @@ middle(0)
|
||||
})
|
||||
await expect(
|
||||
page.getByText(`assert failed: Expected 0 to be greater than 0 but it wasn't
|
||||
|
||||
Backtrace:
|
||||
assert()
|
||||
check()
|
||||
middle()`)
|
||||
|
@ -27,7 +27,8 @@ import { getConstraintInfoKw } from '@src/lang/std/sketch'
|
||||
import type { ConstrainInfo } from '@src/lang/std/stdTypes'
|
||||
import { topLevelRange } from '@src/lang/util'
|
||||
import type { CallExpressionKw, Expr, PathToNode } from '@src/lang/wasm'
|
||||
import { defaultSourceRange, parse, recast, resultIsOk } from '@src/lang/wasm'
|
||||
import { parse, recast, resultIsOk } from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/sourceRange'
|
||||
import { cameraMouseDragGuards } from '@src/lib/cameraControls'
|
||||
import {
|
||||
codeManager,
|
||||
|
@ -144,14 +144,13 @@ import type { SegmentInputs } from '@src/lang/std/stdTypes'
|
||||
import { crossProduct, topLevelRange } from '@src/lang/util'
|
||||
import type { PathToNode, VariableMap } from '@src/lang/wasm'
|
||||
import {
|
||||
defaultSourceRange,
|
||||
getTangentialArcToInfo,
|
||||
parse,
|
||||
recast,
|
||||
resultIsOk,
|
||||
sketchFromKclValue,
|
||||
sourceRangeFromRust,
|
||||
} from '@src/lang/wasm'
|
||||
import { defaultSourceRange, sourceRangeFromRust } from '@src/lang/sourceRange'
|
||||
import { EXECUTION_TYPE_MOCK } from '@src/lib/constants'
|
||||
import {
|
||||
getRectangleCallExpressions,
|
||||
|
@ -5,7 +5,7 @@ import { getNodeFromPath } from '@src/lang/queryAst'
|
||||
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
|
||||
import { codeRefFromRange } from '@src/lang/std/artifactGraph'
|
||||
import { topLevelRange } from '@src/lang/util'
|
||||
import { defaultSourceRange } from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/sourceRange'
|
||||
import { codeToIdSelections } from '@src/lib/selections'
|
||||
import { editorManager, kclManager } from '@src/lib/singletons'
|
||||
import { trap } from '@src/lib/trap'
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
codeRefFromRange,
|
||||
getArtifactFromRange,
|
||||
} from '@src/lang/std/artifactGraph'
|
||||
import { sourceRangeFromRust } from '@src/lang/wasm'
|
||||
import { sourceRangeFromRust } from '@src/lang/sourceRange'
|
||||
import {
|
||||
filterOperations,
|
||||
getOperationIcon,
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
} from '@src/lang/std/artifactGraph'
|
||||
import { isTopLevelModule } from '@src/lang/util'
|
||||
import type { CallExpressionKw, PathToNode } from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/sourceRange'
|
||||
import type { DefaultPlaneStr } from '@src/lib/planes'
|
||||
import { getEventForSelectWithPoint } from '@src/lib/selections'
|
||||
import {
|
||||
|
@ -16,8 +16,9 @@ import type { Operation } from '@rust/kcl-lib/bindings/Operation'
|
||||
import type { SourceRange } from '@rust/kcl-lib/bindings/SourceRange'
|
||||
import { defaultArtifactGraph } from '@src/lang/std/artifactGraph'
|
||||
import { isTopLevelModule } from '@src/lang/util'
|
||||
import type { ArtifactGraph } from '@src/lang/wasm'
|
||||
import { type ArtifactGraph } from '@src/lang/wasm'
|
||||
import type { BacktraceItem } from '@rust/kcl-lib/bindings/BacktraceItem'
|
||||
import { sourceRangeContains } from '@src/lang/sourceRange'
|
||||
|
||||
type ExtractKind<T> = T extends { kind: infer K } ? K : never
|
||||
export class KCLError extends Error {
|
||||
@ -377,13 +378,13 @@ export function kclErrorsToDiagnostics(
|
||||
let message = err.msg
|
||||
if (err.kclBacktrace.length > 0) {
|
||||
// Show the backtrace in the error message.
|
||||
const backtraceLines: Array<string> = []
|
||||
for (let i = 0; i < err.kclBacktrace.length; i++) {
|
||||
const item = err.kclBacktrace[i]
|
||||
if (
|
||||
i > 0 &&
|
||||
isTopLevelModule(item.sourceRange) &&
|
||||
item.sourceRange[0] !== err.sourceRange[0] &&
|
||||
item.sourceRange[1] !== err.sourceRange[1]
|
||||
!sourceRangeContains(item.sourceRange, err.sourceRange)
|
||||
) {
|
||||
diagnostics.push({
|
||||
from: toUtf16(item.sourceRange[0], sourceCode),
|
||||
@ -397,7 +398,11 @@ export function kclErrorsToDiagnostics(
|
||||
break
|
||||
}
|
||||
const name = item.fnName ? `${item.fnName}()` : '(anonymous)'
|
||||
message += `\n${name}`
|
||||
backtraceLines.push(name)
|
||||
}
|
||||
// If the backtrace is only one line, it's not helpful to show.
|
||||
if (backtraceLines.length > 1) {
|
||||
message += `\n\nBacktrace:\n${backtraceLines.join('\n')}`
|
||||
}
|
||||
}
|
||||
if (err.nonFatal.length > 0) {
|
||||
|
28
src/lang/sourceRange.ts
Normal file
28
src/lang/sourceRange.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import type { SourceRange } from '@rust/kcl-lib/bindings/SourceRange'
|
||||
|
||||
/**
|
||||
* Convert a SourceRange as used inside the KCL interpreter into the above one for use in the
|
||||
* frontend (essentially we're eagerly checking whether the frontend should care about the SourceRange
|
||||
* so as not to expose details of the interpreter's current representation of module ids throughout
|
||||
* the frontend).
|
||||
*/
|
||||
export function sourceRangeFromRust(s: SourceRange): SourceRange {
|
||||
return [s[0], s[1], s[2]]
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default SourceRange for testing or as a placeholder.
|
||||
*/
|
||||
export function defaultSourceRange(): SourceRange {
|
||||
return [0, 0, 0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the first range is equal to or contains the second range.
|
||||
*/
|
||||
export function sourceRangeContains(
|
||||
outer: SourceRange,
|
||||
inner: SourceRange
|
||||
): boolean {
|
||||
return outer[0] <= inner[0] && outer[1] >= inner[1] && outer[2] === inner[2]
|
||||
}
|
@ -12,7 +12,7 @@ import type { EngineCommand, ResponseMap } from '@src/lang/std/artifactGraph'
|
||||
import type { CommandLog } from '@src/lang/std/commandLog'
|
||||
import { CommandLogType } from '@src/lang/std/commandLog'
|
||||
import type { SourceRange } from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/sourceRange'
|
||||
import { EXECUTE_AST_INTERRUPT_ERROR_MESSAGE } from '@src/lib/constants'
|
||||
import { markOnce } from '@src/lib/performance'
|
||||
import type RustContext from '@src/lib/rustContext'
|
||||
|
@ -67,6 +67,7 @@ import {
|
||||
} from '@src/lang/queryAstConstants'
|
||||
import type { NumericType } from '@rust/kcl-lib/bindings/NumericType'
|
||||
import { isTopLevelModule } from '@src/lang/util'
|
||||
import { defaultSourceRange, sourceRangeFromRust } from '@src/lang/sourceRange'
|
||||
|
||||
export type { ArrayExpression } from '@rust/kcl-lib/bindings/ArrayExpression'
|
||||
export type {
|
||||
@ -137,23 +138,6 @@ export type { Path } from '@rust/kcl-lib/bindings/Path'
|
||||
export type { Sketch } from '@rust/kcl-lib/bindings/Sketch'
|
||||
export type { Solid } from '@rust/kcl-lib/bindings/Solid'
|
||||
|
||||
/**
|
||||
* Convert a SourceRange as used inside the KCL interpreter into the above one for use in the
|
||||
* frontend (essentially we're eagerly checking whether the frontend should care about the SourceRange
|
||||
* so as not to expose details of the interpreter's current representation of module ids throughout
|
||||
* the frontend).
|
||||
*/
|
||||
export function sourceRangeFromRust(s: SourceRange): SourceRange {
|
||||
return [s[0], s[1], s[2]]
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default SourceRange for testing or as a placeholder.
|
||||
*/
|
||||
export function defaultSourceRange(): SourceRange {
|
||||
return [0, 0, 0]
|
||||
}
|
||||
|
||||
function bestSourceRange(error: RustKclError): SourceRange {
|
||||
if (error.details.sourceRanges.length === 0) {
|
||||
return defaultSourceRange()
|
||||
|
@ -1,11 +1,11 @@
|
||||
import type { NodePath } from '@rust/kcl-lib/bindings/NodePath'
|
||||
import type { Operation } from '@rust/kcl-lib/bindings/Operation'
|
||||
import { defaultSourceRange } from '@src/lang/sourceRange'
|
||||
import { topLevelRange } from '@src/lang/util'
|
||||
|
||||
import {
|
||||
assertParse,
|
||||
defaultNodePath,
|
||||
defaultSourceRange,
|
||||
nodePathFromRange,
|
||||
type SourceRange,
|
||||
} from '@src/lang/wasm'
|
||||
|
@ -24,7 +24,7 @@ import type {
|
||||
Program,
|
||||
SourceRange,
|
||||
} from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/wasm'
|
||||
import { defaultSourceRange } from '@src/lang/sourceRange'
|
||||
import type { ArtifactEntry, ArtifactIndex } from '@src/lib/artifactIndex'
|
||||
import type { CommandArgument } from '@src/lib/commandTypes'
|
||||
import type { DefaultPlaneStr } from '@src/lib/planes'
|
||||
|
Reference in New Issue
Block a user