microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/compiler/qsc/src/interpret/debug.rs

112lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#[cfg(test)]
5mod tests;
6
7use qsc_data_structures::line_column::{Encoding, Position};
8use qsc_eval::debug::Frame;
9use qsc_fir::fir::{Global, PackageStoreLookup, StoreItemId};
10use qsc_frontend::compile::PackageStore;
11use qsc_hir::hir;
12use qsc_hir::hir::{Item, ItemKind};
13use qsc_lowerer::map_fir_package_to_hir;
14use std::fmt::Write;
15use std::rc::Rc;
16
17#[must_use]
18pub(crate) fn format_call_stack(
19 store: &PackageStore,
20 globals: &impl PackageStoreLookup,
21 frames: Vec<Frame>,
22 error: &dyn std::error::Error,
23) -> String {
24 let mut trace = String::new();
25 writeln!(trace, "Error: {error}").expect("writing to string should succeed");
26 trace.push_str("Call stack:\n");
27
28 let mut frames = frames;
29 frames.reverse();
30
31 for frame in frames {
32 let Some(Global::Callable(call)) = globals.get_global(frame.id) else {
33 panic!("missing global");
34 };
35
36 trace.push_str(" at ");
37 if frame.functor.adjoint {
38 trace.push_str("Adjoint ");
39 }
40 if frame.functor.controlled > 0 {
41 write!(trace, "Controlled({}) ", frame.functor.controlled)
42 .expect("writing to string should succeed");
43 }
44 if let Some(item) = get_item_parent(store, frame.id)
45 && let Some(ns) = get_ns_name(&item)
46 {
47 write!(trace, "{ns}.").expect("writing to string should succeed");
48 }
49 write!(trace, "{}", call.name.name).expect("writing to string should succeed");
50
51 let name = get_item_file_name(store, frame.id);
52 let pos = get_position(&frame, store);
53 write!(
54 trace,
55 " in {}:{}:{}",
56 name.unwrap_or("<expression>".to_string()),
57 pos.line + 1,
58 pos.column + 1,
59 )
60 .expect("writing to string should succeed");
61
62 trace.push('\n');
63 }
64 trace
65}
66
67#[must_use]
68fn get_item_parent(store: &PackageStore, id: StoreItemId) -> Option<Item> {
69 let package = map_fir_package_to_hir(id.package);
70 let item = hir::LocalItemId::from(usize::from(id.item));
71 store.get(package).and_then(|unit| {
72 let item = unit.package.items.get(item)?;
73 if let Some(parent) = item.parent {
74 let parent = unit.package.items.get(parent)?;
75 Some(parent.clone())
76 } else {
77 None
78 }
79 })
80}
81
82#[must_use]
83fn get_item_file_name(store: &PackageStore, id: StoreItemId) -> Option<String> {
84 let package = map_fir_package_to_hir(id.package);
85 let item = hir::LocalItemId::from(usize::from(id.item));
86 store.get(package).and_then(|unit| {
87 let item = unit.package.items.get(item)?;
88 let source = unit.sources.find_by_offset(item.span.lo);
89 source.map(|s| s.name.to_string())
90 })
91}
92
93#[must_use]
94fn get_ns_name(item: &Item) -> Option<Rc<str>> {
95 let ItemKind::Namespace(ns, _) = &item.kind else {
96 return None;
97 };
98 Some(ns.name())
99}
100
101/// Converts the [`Span`] of [`Frame`] into a [`Position`].
102fn get_position(frame: &Frame, store: &PackageStore) -> Position {
103 let filename = get_item_file_name(store, frame.id).expect("file should exist");
104 let package_id = map_fir_package_to_hir(frame.id.package);
105 let unit = store.get(package_id).expect("package should exist");
106 let source = unit
107 .sources
108 .find_by_name(&filename)
109 .expect("source should exist");
110 let contents = &source.contents;
111 Position::from_utf8_byte_offset(Encoding::Utf8, contents, frame.span.lo - source.offset)
112}
113