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(
|
await expect(
|
||||||
page.getByText(`assert failed: Expected 0 to be greater than 0 but it wasn't
|
page.getByText(`assert failed: Expected 0 to be greater than 0 but it wasn't
|
||||||
|
|
||||||
|
Backtrace:
|
||||||
assert()
|
assert()
|
||||||
check()
|
check()
|
||||||
middle()`)
|
middle()`)
|
||||||
|
|||||||
@ -27,7 +27,8 @@ import { getConstraintInfoKw } from '@src/lang/std/sketch'
|
|||||||
import type { ConstrainInfo } from '@src/lang/std/stdTypes'
|
import type { ConstrainInfo } from '@src/lang/std/stdTypes'
|
||||||
import { topLevelRange } from '@src/lang/util'
|
import { topLevelRange } from '@src/lang/util'
|
||||||
import type { CallExpressionKw, Expr, PathToNode } from '@src/lang/wasm'
|
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 { cameraMouseDragGuards } from '@src/lib/cameraControls'
|
||||||
import {
|
import {
|
||||||
codeManager,
|
codeManager,
|
||||||
|
|||||||
@ -144,14 +144,13 @@ import type { SegmentInputs } from '@src/lang/std/stdTypes'
|
|||||||
import { crossProduct, topLevelRange } from '@src/lang/util'
|
import { crossProduct, topLevelRange } from '@src/lang/util'
|
||||||
import type { PathToNode, VariableMap } from '@src/lang/wasm'
|
import type { PathToNode, VariableMap } from '@src/lang/wasm'
|
||||||
import {
|
import {
|
||||||
defaultSourceRange,
|
|
||||||
getTangentialArcToInfo,
|
getTangentialArcToInfo,
|
||||||
parse,
|
parse,
|
||||||
recast,
|
recast,
|
||||||
resultIsOk,
|
resultIsOk,
|
||||||
sketchFromKclValue,
|
sketchFromKclValue,
|
||||||
sourceRangeFromRust,
|
|
||||||
} from '@src/lang/wasm'
|
} from '@src/lang/wasm'
|
||||||
|
import { defaultSourceRange, sourceRangeFromRust } from '@src/lang/sourceRange'
|
||||||
import { EXECUTION_TYPE_MOCK } from '@src/lib/constants'
|
import { EXECUTION_TYPE_MOCK } from '@src/lib/constants'
|
||||||
import {
|
import {
|
||||||
getRectangleCallExpressions,
|
getRectangleCallExpressions,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { getNodeFromPath } from '@src/lang/queryAst'
|
|||||||
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
|
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
|
||||||
import { codeRefFromRange } from '@src/lang/std/artifactGraph'
|
import { codeRefFromRange } from '@src/lang/std/artifactGraph'
|
||||||
import { topLevelRange } from '@src/lang/util'
|
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 { codeToIdSelections } from '@src/lib/selections'
|
||||||
import { editorManager, kclManager } from '@src/lib/singletons'
|
import { editorManager, kclManager } from '@src/lib/singletons'
|
||||||
import { trap } from '@src/lib/trap'
|
import { trap } from '@src/lib/trap'
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
codeRefFromRange,
|
codeRefFromRange,
|
||||||
getArtifactFromRange,
|
getArtifactFromRange,
|
||||||
} from '@src/lang/std/artifactGraph'
|
} from '@src/lang/std/artifactGraph'
|
||||||
import { sourceRangeFromRust } from '@src/lang/wasm'
|
import { sourceRangeFromRust } from '@src/lang/sourceRange'
|
||||||
import {
|
import {
|
||||||
filterOperations,
|
filterOperations,
|
||||||
getOperationIcon,
|
getOperationIcon,
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
} from '@src/lang/std/artifactGraph'
|
} from '@src/lang/std/artifactGraph'
|
||||||
import { isTopLevelModule } from '@src/lang/util'
|
import { isTopLevelModule } from '@src/lang/util'
|
||||||
import type { CallExpressionKw, PathToNode } from '@src/lang/wasm'
|
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 type { DefaultPlaneStr } from '@src/lib/planes'
|
||||||
import { getEventForSelectWithPoint } from '@src/lib/selections'
|
import { getEventForSelectWithPoint } from '@src/lib/selections'
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -16,8 +16,9 @@ import type { Operation } from '@rust/kcl-lib/bindings/Operation'
|
|||||||
import type { SourceRange } from '@rust/kcl-lib/bindings/SourceRange'
|
import type { SourceRange } from '@rust/kcl-lib/bindings/SourceRange'
|
||||||
import { defaultArtifactGraph } from '@src/lang/std/artifactGraph'
|
import { defaultArtifactGraph } from '@src/lang/std/artifactGraph'
|
||||||
import { isTopLevelModule } from '@src/lang/util'
|
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 type { BacktraceItem } from '@rust/kcl-lib/bindings/BacktraceItem'
|
||||||
|
import { sourceRangeContains } from '@src/lang/sourceRange'
|
||||||
|
|
||||||
type ExtractKind<T> = T extends { kind: infer K } ? K : never
|
type ExtractKind<T> = T extends { kind: infer K } ? K : never
|
||||||
export class KCLError extends Error {
|
export class KCLError extends Error {
|
||||||
@ -377,13 +378,13 @@ export function kclErrorsToDiagnostics(
|
|||||||
let message = err.msg
|
let message = err.msg
|
||||||
if (err.kclBacktrace.length > 0) {
|
if (err.kclBacktrace.length > 0) {
|
||||||
// Show the backtrace in the error message.
|
// Show the backtrace in the error message.
|
||||||
|
const backtraceLines: Array<string> = []
|
||||||
for (let i = 0; i < err.kclBacktrace.length; i++) {
|
for (let i = 0; i < err.kclBacktrace.length; i++) {
|
||||||
const item = err.kclBacktrace[i]
|
const item = err.kclBacktrace[i]
|
||||||
if (
|
if (
|
||||||
i > 0 &&
|
i > 0 &&
|
||||||
isTopLevelModule(item.sourceRange) &&
|
isTopLevelModule(item.sourceRange) &&
|
||||||
item.sourceRange[0] !== err.sourceRange[0] &&
|
!sourceRangeContains(item.sourceRange, err.sourceRange)
|
||||||
item.sourceRange[1] !== err.sourceRange[1]
|
|
||||||
) {
|
) {
|
||||||
diagnostics.push({
|
diagnostics.push({
|
||||||
from: toUtf16(item.sourceRange[0], sourceCode),
|
from: toUtf16(item.sourceRange[0], sourceCode),
|
||||||
@ -397,7 +398,11 @@ export function kclErrorsToDiagnostics(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
const name = item.fnName ? `${item.fnName}()` : '(anonymous)'
|
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) {
|
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 type { CommandLog } from '@src/lang/std/commandLog'
|
||||||
import { CommandLogType } from '@src/lang/std/commandLog'
|
import { CommandLogType } from '@src/lang/std/commandLog'
|
||||||
import type { SourceRange } from '@src/lang/wasm'
|
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 { EXECUTE_AST_INTERRUPT_ERROR_MESSAGE } from '@src/lib/constants'
|
||||||
import { markOnce } from '@src/lib/performance'
|
import { markOnce } from '@src/lib/performance'
|
||||||
import type RustContext from '@src/lib/rustContext'
|
import type RustContext from '@src/lib/rustContext'
|
||||||
|
|||||||
@ -67,6 +67,7 @@ import {
|
|||||||
} from '@src/lang/queryAstConstants'
|
} from '@src/lang/queryAstConstants'
|
||||||
import type { NumericType } from '@rust/kcl-lib/bindings/NumericType'
|
import type { NumericType } from '@rust/kcl-lib/bindings/NumericType'
|
||||||
import { isTopLevelModule } from '@src/lang/util'
|
import { isTopLevelModule } from '@src/lang/util'
|
||||||
|
import { defaultSourceRange, sourceRangeFromRust } from '@src/lang/sourceRange'
|
||||||
|
|
||||||
export type { ArrayExpression } from '@rust/kcl-lib/bindings/ArrayExpression'
|
export type { ArrayExpression } from '@rust/kcl-lib/bindings/ArrayExpression'
|
||||||
export type {
|
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 { Sketch } from '@rust/kcl-lib/bindings/Sketch'
|
||||||
export type { Solid } from '@rust/kcl-lib/bindings/Solid'
|
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 {
|
function bestSourceRange(error: RustKclError): SourceRange {
|
||||||
if (error.details.sourceRanges.length === 0) {
|
if (error.details.sourceRanges.length === 0) {
|
||||||
return defaultSourceRange()
|
return defaultSourceRange()
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import type { NodePath } from '@rust/kcl-lib/bindings/NodePath'
|
import type { NodePath } from '@rust/kcl-lib/bindings/NodePath'
|
||||||
import type { Operation } from '@rust/kcl-lib/bindings/Operation'
|
import type { Operation } from '@rust/kcl-lib/bindings/Operation'
|
||||||
|
import { defaultSourceRange } from '@src/lang/sourceRange'
|
||||||
import { topLevelRange } from '@src/lang/util'
|
import { topLevelRange } from '@src/lang/util'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
assertParse,
|
assertParse,
|
||||||
defaultNodePath,
|
defaultNodePath,
|
||||||
defaultSourceRange,
|
|
||||||
nodePathFromRange,
|
nodePathFromRange,
|
||||||
type SourceRange,
|
type SourceRange,
|
||||||
} from '@src/lang/wasm'
|
} from '@src/lang/wasm'
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import type {
|
|||||||
Program,
|
Program,
|
||||||
SourceRange,
|
SourceRange,
|
||||||
} from '@src/lang/wasm'
|
} 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 { ArtifactEntry, ArtifactIndex } from '@src/lib/artifactIndex'
|
||||||
import type { CommandArgument } from '@src/lib/commandTypes'
|
import type { CommandArgument } from '@src/lib/commandTypes'
|
||||||
import type { DefaultPlaneStr } from '@src/lib/planes'
|
import type { DefaultPlaneStr } from '@src/lib/planes'
|
||||||
|
|||||||
Reference in New Issue
Block a user