From 97d87da8905703241c21a05b0d3582aa74693523 Mon Sep 17 00:00:00 2001 From: Zack Grannan Date: Tue, 10 Feb 2026 11:18:14 -0800 Subject: [PATCH 1/5] Update two-phase borrow activation logic --- src/borrow_pcg/graph/mod.rs | 24 ++-- src/borrow_pcg/state/mod.rs | 13 ++ src/pcg/domain/pcg.rs | 6 +- src/pcg/visitor/mod.rs | 22 +-- src/pcg/visitor/obtain.rs | 6 +- src/pcg/visitor/upgrade.rs | 40 +++--- test-files/219_twophase.rs | 16 +++ visualization/src/components/PCGNavigator.tsx | 128 +++++++++--------- 8 files changed, 153 insertions(+), 102 deletions(-) create mode 100644 test-files/219_twophase.rs diff --git a/src/borrow_pcg/graph/mod.rs b/src/borrow_pcg/graph/mod.rs index 13993b4c6..857a2fa9d 100644 --- a/src/borrow_pcg/graph/mod.rs +++ b/src/borrow_pcg/graph/mod.rs @@ -164,6 +164,18 @@ impl<'tcx, EdgeKind, VC> BorrowsGraph<'tcx, EdgeKind, VC> { }) .collect() } + + pub(crate) fn edges_blocking<'slf, Ctxt: Copy + DebugCtxt, P: PcgNodeComponent>( + &'slf self, + node: BlockedNode<'tcx, P>, + ctxt: Ctxt, + ) -> impl Iterator> + where + EdgeKind: EdgeData<'tcx, Ctxt, P> + std::hash::Hash + Eq, + { + self.edges() + .filter(move |edge| edge.kind.blocks_node(node, ctxt)) + } } impl<'tcx, P: PcgNodeComponent, VC> BorrowsGraph<'tcx, BorrowPcgEdgeKind<'tcx, P>, VC> { @@ -233,18 +245,6 @@ impl<'tcx, P: PcgNodeComponent, VC> BorrowsGraph<'tcx, BorrowPcgEdgeKind<'tcx, P .all(|place| nodes.contains(&place.to_pcg_node(ctxt)))) } - pub(crate) fn edges_blocking<'slf, Ctxt: Copy + DebugCtxt>( - &'slf self, - node: BlockedNode<'tcx, P>, - ctxt: Ctxt, - ) -> impl Iterator, VC>> - where - BorrowPcgEdgeKind<'tcx, P>: EdgeData<'tcx, Ctxt, P>, - { - self.edges() - .filter(move |edge| edge.kind.blocks_node(node, ctxt)) - } - pub fn edges_blocked_by<'graph, Ctxt: Copy + DebugCtxt>( &'graph self, node: LocalNode<'tcx, P>, diff --git a/src/borrow_pcg/state/mod.rs b/src/borrow_pcg/state/mod.rs index dfa6a8850..60d178340 100644 --- a/src/borrow_pcg/state/mod.rs +++ b/src/borrow_pcg/state/mod.rs @@ -349,6 +349,19 @@ pub(crate) trait BorrowsStateLike<'tcx, EdgeKind = BorrowPcgEdgeKind<'tcx>, VC = }; Ok(result) } + + fn edges_blocking<'slf, Ctxt: Copy + DebugCtxt>( + &'slf self, + node: BlockedNode<'tcx>, + ctxt: Ctxt, + ) -> impl Iterator> + where + EdgeKind: EdgeData<'tcx, Ctxt, Place<'tcx>> + std::hash::Hash + Eq + 'slf, + VC: 'slf, + 'tcx: 'slf, + { + self.graph().edges_blocking(node, ctxt) + } } impl<'pcg, 'tcx: 'pcg> BorrowsStateLike<'tcx> for BorrowStateMutRef<'pcg, 'tcx> { diff --git a/src/pcg/domain/pcg.rs b/src/pcg/domain/pcg.rs index 0a1743737..cf6d13681 100644 --- a/src/pcg/domain/pcg.rs +++ b/src/pcg/domain/pcg.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use crate::{ DebugLines, Weaken, borrow_pcg::{ - edge::kind::BorrowPcgEdgeKind, + edge::{borrow::BorrowEdge, kind::BorrowPcgEdgeKind}, graph::{BorrowsGraph, join::JoinBorrowsArgs}, state::{BorrowStateMutRef, BorrowStateRef, BorrowsState, BorrowsStateLike}, }, @@ -327,6 +327,10 @@ impl<'a, 'tcx: 'a> Pcg<'a, 'tcx> { &self.owned } + pub(crate) fn borrow_created_at(&self, location: mir::Location) -> Option<&BorrowEdge<'tcx>> { + self.borrow.graph().borrow_created_at(location) + } + #[must_use] pub fn borrow_pcg(&self) -> &BorrowsState<'a, 'tcx> { &self.borrow diff --git a/src/pcg/visitor/mod.rs b/src/pcg/visitor/mod.rs index bf0fafae7..8b6fb5c49 100644 --- a/src/pcg/visitor/mod.rs +++ b/src/pcg/visitor/mod.rs @@ -15,9 +15,10 @@ use crate::{ obtain::{PlaceCollapser, PlaceObtainer, expand::PlaceExpander}, place_capabilities::{PlaceCapabilitiesInterface, PlaceCapabilitiesReader}, triple::TripleWalker, + visitor::upgrade::AdjustCapabilityReason, }, rustc_interface::middle::mir::{self, Location, Operand, Rvalue, Statement, Terminator}, - utils::{PlaceLike, data_structures::HashSet, display::DisplayWithCompilerCtxt}, + utils::{data_structures::HashSet, display::DisplayWithCompilerCtxt}, }; use crate::utils::{ @@ -418,21 +419,20 @@ impl<'a, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx>> PcgVisitor<'_, 'a, 'tcx, Ctxt> &mut self, created_location: Location, ) -> Result<(), PcgError<'tcx>> { - let Some(borrow) = self.pcg.borrow.graph().borrow_created_at(created_location) else { + let Some(borrow) = self.pcg.borrow_created_at(created_location) else { return Ok(()); }; - tracing::debug!( - "activate twophase borrow: {}", + tracing::info!( + "{:?} activate twophase borrow: {}", + self.location(), borrow.display_string(self.ctxt.bc_ctxt()) ); let blocked_place = borrow.blocked_place.place(); - if !blocked_place.is_owned(self.ctxt) { - self.place_obtainer() - .remove_read_permission_upwards_and_label_rps( - blocked_place, - "Activate twophase borrow", - )?; - } + self.place_obtainer() + .remove_read_permission_upwards_and_label_rps( + blocked_place, + AdjustCapabilityReason::TwoPhaseBorrowActivation, + )?; Ok(()) } } diff --git a/src/pcg/visitor/obtain.rs b/src/pcg/visitor/obtain.rs index 83e4f3d5d..d4d392c22 100644 --- a/src/pcg/visitor/obtain.rs +++ b/src/pcg/visitor/obtain.rs @@ -25,6 +25,7 @@ use crate::{ BlockType, PlaceCapabilitiesInterface, PlaceCapabilitiesReader, SymbolicPlaceCapabilities, }, + visitor::upgrade::AdjustCapabilityReason, }, pcg_validity_assert, rustc_interface::middle::mir, @@ -420,7 +421,10 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx>> )?; self.remove_read_permission_downwards(place)?; if let Some(parent) = place.parent_place() { - self.remove_read_permission_upwards_and_label_rps(parent, "Upgrade read to exclusive")?; + self.remove_read_permission_upwards_and_label_rps( + parent, + AdjustCapabilityReason::UpgradeReadToExclusive, + )?; } Ok(()) } diff --git a/src/pcg/visitor/upgrade.rs b/src/pcg/visitor/upgrade.rs index c6bd0df16..15b4658e3 100644 --- a/src/pcg/visitor/upgrade.rs +++ b/src/pcg/visitor/upgrade.rs @@ -16,7 +16,7 @@ use crate::{ pcg::{ CapabilityKind, PcgNode, PcgRefLike, obtain::{HasSnapshotLocation, PlaceObtainer}, - place_capabilities::{BlockType, PlaceCapabilitiesReader}, + place_capabilities::BlockType, }, utils::{ DataflowCtxt, DebugCtxt, Place, PlaceLike, data_structures::HashSet, @@ -27,12 +27,12 @@ use crate::{ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> PlaceObtainer<'state, 'a, 'tcx, Ctxt> { - fn weaken_place_from_read_upwards( + fn weaken_capability_from_read( &mut self, place: Place<'tcx>, - debug_ctxt: &str, + reason: AdjustCapabilityReason, ) -> Result<(), PcgError<'tcx>> { - if place.is_mut_ref(self.ctxt) { + if place.is_mut_ref(self.ctxt) && reason == AdjustCapabilityReason::UpgradeReadToExclusive { // We've reached an indirection (e.g from **s to *s), we // downgrade the ref from R to W // We need to continue: `s` would previously have capability R, which @@ -43,8 +43,8 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> CapabilityKind::Read, BlockType::DerefMutRefForExclusive.blocked_place_maximum_retained_capability(), format!( - "{}: remove read permission upwards from base place {} (downgrade R to W for mut ref)", - debug_ctxt, + "{:?}: remove read permission upwards from base place {} (downgrade R to W for mut ref)", + reason, place.display_string(self.ctxt.bc_ctxt()), ) ) @@ -57,8 +57,8 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> CapabilityKind::Read, None, format!( - "{}: remove read permission upwards from base place {}", - debug_ctxt, + "{:?}: remove read permission upwards from base place {}", + reason, place.display_string(self.ctxt.bc_ctxt()), ), ) @@ -75,13 +75,16 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> pub(crate) fn remove_read_permission_upwards_and_label_rps( &mut self, place: Place<'tcx>, - debug_ctxt: &str, + reason: AdjustCapabilityReason, ) -> Result<(), PcgError<'tcx>> { let place_regions = place.regions(self.ctxt); let mut prev = None; let mut current = place; - while self.pcg.capabilities.get(current, self.ctxt) == Some(CapabilityKind::Read.into()) { - self.weaken_place_from_read_upwards(current, debug_ctxt)?; + while self + .pcg + .place_capability_equals(current, CapabilityKind::Read) + { + self.weaken_capability_from_read(current, reason)?; let leaf_nodes = self.pcg.borrow.leaf_nodes(self.ctxt.bc_ctxt()); for place in self.pcg.borrow.graph.places(self.ctxt.bc_ctxt()) { if prev != Some(place) @@ -97,8 +100,8 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> place, CapabilityKind::Exclusive, format!( - "{}: remove_read_permission_upwards_and_label_rps: restore exclusive cap for leaf place {}", - debug_ctxt, + "{:?}: remove_read_permission_upwards_and_label_rps: restore exclusive cap for leaf place {}", + reason, place.display_string(self.ctxt.bc_ctxt()) ), ) @@ -123,7 +126,6 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> let edges_blocking_current_rp = self .pcg .borrow - .graph .edges_blocking(current_rp.into(), self.ctxt.bc_ctxt()) .collect::>(); if !edges_blocking_current_rp.is_empty() { @@ -154,8 +156,8 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> LabelNodePredicate::equals_lifetime_projection(current_rp.into()), Some(self.prev_snapshot_location().into()), format!( - "{}: remove_read_permission_upwards_and_label_rps: label current lifetime projection {} with previous snapshot location {:?}", - debug_ctxt, + "{:?}: remove_read_permission_upwards_and_label_rps: label current lifetime projection {} with previous snapshot location {:?}", + reason, current_rp.display_string(self.ctxt.bc_ctxt()), self.prev_snapshot_location() ), @@ -220,3 +222,9 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> Ok(()) } } + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub(crate) enum AdjustCapabilityReason { + TwoPhaseBorrowActivation, + UpgradeReadToExclusive, +} diff --git a/test-files/219_twophase.rs b/test-files/219_twophase.rs new file mode 100644 index 000000000..417571897 --- /dev/null +++ b/test-files/219_twophase.rs @@ -0,0 +1,16 @@ +struct Tmp {} + +impl Tmp { + fn read(&self) -> Self { + Tmp {} + } + + fn write (&mut self, x: Self) { + + } +} + +fn foo() { + let mut x = Tmp {}; + x.write(x.read()); +} diff --git a/visualization/src/components/PCGNavigator.tsx b/visualization/src/components/PCGNavigator.tsx index 82efd8f51..9f8277186 100644 --- a/visualization/src/components/PCGNavigator.tsx +++ b/visualization/src/components/PCGNavigator.tsx @@ -286,69 +286,75 @@ export default function PCGNavigator({ // Render navigation items in order const renderItems = () => { return navigationItems.map((item, idx) => { - if (item.type === "iteration") { - const isSelected = - selectedPoint?.type === "iteration" && - selectedPoint.name === item.name; - return ( -
{ - onSelectPoint({ type: "iteration", name: item.name }); - }} - > - {item.name} -
- ); - } else { - // action - const isSelected = - selectedPoint?.type === "action" && - selectedPoint.phase === item.phase && - selectedPoint.index === item.index; - const action = - item.phase === "successor" ? item.action : item.action.action; - let hoverText = action.data.debug_context || ""; - const itemContent = actionLine(action.data.kind); - if (item.phase !== "successor") { - if (!hoverText) { - hoverText = item.action.result.change_summary; - } else { - hoverText += " " + item.action.result.change_summary; + try { + if (item.type === "iteration") { + const isSelected = + selectedPoint?.type === "iteration" && + selectedPoint.name === item.name; + return ( +
{ + onSelectPoint({ type: "iteration", name: item.name }); + }} + > + {item.name} +
+ ); + } else { + // action + const isSelected = + selectedPoint?.type === "action" && + selectedPoint.phase === item.phase && + selectedPoint.index === item.index; + const action = + item.phase === "successor" ? item.action : item.action.action; + let hoverText = action.data.debug_context || ""; + const itemContent = actionLine(action.data.kind); + if (item.phase !== "successor") { + if (!hoverText) { + hoverText = item.action.result.change_summary; + } else { + hoverText += " " + item.action.result.change_summary; + } } + return ( +
{ + onSelectPoint({ + type: "action", + phase: item.phase, + index: item.index, + }); + }} + title={hoverText || undefined} + > + {itemContent} +
+ ); } - return ( -
{ - onSelectPoint({ - type: "action", - phase: item.phase, - index: item.index, - }); - }} - title={hoverText || undefined} - > - {itemContent} -
- ); + } catch (error) { + console.error("Error rendering item %O:", item, error); + const errorMessage = error instanceof Error ? error.message : String(error); +
{errorMessage}
} }); }; From 486e17d13872e96ddfe2ccf2536cee05d2f7812a Mon Sep 17 00:00:00 2001 From: Zack Grannan Date: Tue, 10 Feb 2026 11:43:34 -0800 Subject: [PATCH 2/5] Fix ssmall issues --- src/pcg/visitor/upgrade.rs | 22 +++++++++++++++++++++- src/utils/mod.rs | 6 +++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/pcg/visitor/upgrade.rs b/src/pcg/visitor/upgrade.rs index 15b4658e3..11dd9ba19 100644 --- a/src/pcg/visitor/upgrade.rs +++ b/src/pcg/visitor/upgrade.rs @@ -32,7 +32,7 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> place: Place<'tcx>, reason: AdjustCapabilityReason, ) -> Result<(), PcgError<'tcx>> { - if place.is_mut_ref(self.ctxt) && reason == AdjustCapabilityReason::UpgradeReadToExclusive { + if place.is_mut_ref(self.ctxt) { // We've reached an indirection (e.g from **s to *s), we // downgrade the ref from R to W // We need to continue: `s` would previously have capability R, which @@ -223,8 +223,28 @@ impl<'state, 'a: 'state, 'tcx: 'a, Ctxt: DataflowCtxt<'a, 'tcx> + DebugCtxt> } } +/// The reason for performing in-place updates on the PCG capabilities. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub(crate) enum AdjustCapabilityReason { + /// Just prior to activating a two-phase borrow, the capability of the + /// blocked place is R. The PCG evaluates the two-phase borrow by removing + /// this capability and adjusting the capabilities of the parents of the + /// blocked place as well as their related places. In particular, if the + /// blocked place's parent place also has capability R, it should be removed + /// as well. TwoPhaseBorrowActivation, + + /// Currently, there are situations in the analysis that require obtaining + /// capability E to a place with capability R. In particular, consider the following code: + /// ```rust + /// let mut pair = (String::new(), String::new()); + /// let fst = &pair.0; + /// let snd = pair.1; + /// ``` + /// For the assignment to `fst`, the PCG will weaken `pair` to capability + /// `R`, and then unpack it. Therefore, `pair.1` will have capability `R`. + /// The assignment to `snd` requires obtaining capability `E` to `pair.1`, + /// To handle this case, we would remove capability from `pair` and upgrade + /// `pair.1` to `E`. UpgradeReadToExclusive, } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index a8cdfed4d..36654f9d4 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -228,7 +228,11 @@ impl PcgSettings { tracing::info!("Using user path for {var_name}: {:?}", user_path); match user_path.canonicalize() { Ok(path) => tracing::info!("Absolute path: {:?}", path), - Err(e) => tracing::error!("User path cannot be canonicalized: {e}"), + Err(e) => tracing::error!( + "User path {} cannot be canonicalized from current directory {}: {e}", + user_path.display(), + std::env::current_dir().unwrap().display() + ), } user_path } else { From ab48d10e7f241fe4e7a59e417b3a2dcb620ced43 Mon Sep 17 00:00:00 2001 From: Zack Grannan Date: Tue, 10 Feb 2026 11:45:44 -0800 Subject: [PATCH 3/5] Add annotation --- test-files/219_twophase.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-files/219_twophase.rs b/test-files/219_twophase.rs index 417571897..8d6b2069d 100644 --- a/test-files/219_twophase.rs +++ b/test-files/219_twophase.rs @@ -13,4 +13,6 @@ impl Tmp { fn foo() { let mut x = Tmp {}; x.write(x.read()); + // PCG: bb1[1] pre_operands: Weaken x from R to None + // `x`'s capability should be removed when the two-phase borrow is activated } From 32d41894a927c8db17b82b4f8cfcf07fee501f0d Mon Sep 17 00:00:00 2001 From: Zack Grannan Date: Tue, 10 Feb 2026 15:08:50 -0800 Subject: [PATCH 4/5] WIP --- .github/workflows/test.yml | 15 ++++++++++ type-export/Cargo.lock | 29 +++++++++++++++++-- visualization/src/components/PCGNavigator.tsx | 8 +++-- visualization/src/generated/types.ts | 10 +++---- visualization/src/types.ts | 6 ++-- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eafe24876..0eeee639d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -164,6 +164,21 @@ jobs: working-directory: flowistry/crates/flowistry run: cargo test + check_generated_types: + runs-on: ${{ vars.RUNNER || 'ubuntu-latest' }} + container: ${{ fromJSON(vars.CONTAINER || 'null') }} + steps: + - uses: actions/checkout@v4 + - name: Generate TypeScript types + run: cargo run --manifest-path type-export/Cargo.toml --bin generate_types + - name: Check generated types are up-to-date + run: | + if ! git diff --exit-code visualization/src/generated/types.ts; then + echo "ERROR: Generated TypeScript types are out of date." + echo "Run 'cargo run --manifest-path type-export/Cargo.toml --bin generate_types' to update." + exit 1 + fi + build_visualization: runs-on: ubuntu-latest steps: diff --git a/type-export/Cargo.lock b/type-export/Cargo.lock index 3e555b0b0..bdad6f3d4 100644 --- a/type-export/Cargo.lock +++ b/type-export/Cargo.lock @@ -25,9 +25,15 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cfg-if" @@ -197,10 +203,11 @@ version = "0.1.0" dependencies = [ "bit-set", "bumpalo", + "bytes", "derive_more", "dot", "itertools", - "lazy_static", + "pcg-macros", "petgraph", "rustversion", "serde", @@ -212,6 +219,16 @@ dependencies = [ "strum_macros", "tracing", "tracing-subscriber", + "union-find", +] + +[[package]] +name = "pcg-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -477,6 +494,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "union-find" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039142448432983c34b64739f8526f8f233a1eec7a66e61b6ab29acfa781194e" + [[package]] name = "valuable" version = "0.1.1" diff --git a/visualization/src/components/PCGNavigator.tsx b/visualization/src/components/PCGNavigator.tsx index 9f8277186..ee937a998 100644 --- a/visualization/src/components/PCGNavigator.tsx +++ b/visualization/src/components/PCGNavigator.tsx @@ -287,6 +287,7 @@ export default function PCGNavigator({ const renderItems = () => { return navigationItems.map((item, idx) => { try { + console.log(item); if (item.type === "iteration") { const isSelected = selectedPoint?.type === "iteration" && @@ -317,7 +318,7 @@ export default function PCGNavigator({ selectedPoint.index === item.index; const action = item.phase === "successor" ? item.action : item.action.action; - let hoverText = action.data.debug_context || ""; + let hoverText = action.data.debug_info || ""; const itemContent = actionLine(action.data.kind); if (item.phase !== "successor") { if (!hoverText) { @@ -353,8 +354,9 @@ export default function PCGNavigator({ } } catch (error) { console.error("Error rendering item %O:", item, error); - const errorMessage = error instanceof Error ? error.message : String(error); -
{errorMessage}
+ const errorMessage = + error instanceof Error ? error.message : String(error); +
{errorMessage}
; } }); }; diff --git a/visualization/src/generated/types.ts b/visualization/src/generated/types.ts index 5f01c8b8c..202a7a174 100644 --- a/visualization/src/generated/types.ts +++ b/visualization/src/generated/types.ts @@ -5,7 +5,7 @@ import type { StringOf } from "../generated_type_deps.ts"; * A pair of a PCG action and a debug context (indicating the source of the * action and possibly its effects). */ -export type ActionKindWithDebugCtxt = { kind: T; debug_context: Ctxt }; +export type ActionKindWithDebugInfo = { kind: T; debug_info: DebugInfo }; export type AppliedAction = { action: Action; result: Result; _marker: null }; @@ -100,9 +100,9 @@ export type PathToDotFile = string; export type PcgBlockVisualizationData = { statements: PcgStmtVisualizationData[]; successors: { [key in BasicBlock]: PcgSuccessorVisualizationData } }; -export type PcgStmtVisualizationData = { actions: EvalStmtData<(AppliedAction, ActionKindWithDebugCtxt, string | null>>, ApplyActionResult>)[]>; graphs: StmtGraphs> }; +export type PcgStmtVisualizationData = { actions: EvalStmtData<(AppliedAction, ActionKindWithDebugInfo, string | null>>, ApplyActionResult>)[]>; graphs: StmtGraphs> }; -export type PcgSuccessorVisualizationData = { actions: (GenericPcgAction, ActionKindWithDebugCtxt, string | null>>)[] }; +export type PcgSuccessorVisualizationData = { actions: (GenericPcgAction, ActionKindWithDebugInfo, string | null>>)[] }; export type PcgVisualizationData = { [key in BasicBlock]: PcgBlockVisualizationData }; @@ -114,7 +114,7 @@ export type RepackExpand = { from: Place; guide: Guide | null; cap export type RepackOp = /** - * Rust will sometimes join two BasicBlocks where a local is live in one and dead in the other. + * Rust will sometimes join two `BasicBlocks` where a local is live in one and dead in the other. * Our analysis will join these two into a state where the local is dead, and this Op marks the * edge from where it was live. * @@ -130,7 +130,7 @@ export type RepackOp = */ { type: "StorageDead"; data: Local } | /** - * This Op only appears within a BasicBlock and is attached to a + * This Op only appears within a `BasicBlock` and is attached to a * [`mir::StatementKind::StorageDead`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.StatementKind.html#variant.StorageDead) * statement. We emit it for any such statement where the local may already be dead. We * guarantee to have inserted a [`RepackOp::StorageDead`] before this Op so that one can diff --git a/visualization/src/types.ts b/visualization/src/types.ts index dbe473652..0cf7f5d86 100644 --- a/visualization/src/types.ts +++ b/visualization/src/types.ts @@ -62,8 +62,8 @@ export type ReactFlowNodeData = BasicBlockData & { }; export type PcgAction = GenericPcgAction< - ActionKindWithDebugCtxt, - ActionKindWithDebugCtxt, string | null> + ActionKindWithDebugInfo, + ActionKindWithDebugInfo, string | null> >; export type PcgActions = PcgAction[]; @@ -84,7 +84,7 @@ export type FunctionSlug = Branded; export type FunctionName = Branded; import type { - ActionKindWithDebugCtxt, + ActionKindWithDebugInfo, BorrowPcgActionKindDebugRepr, EvalStmtPhase, FunctionMetadata, From a121c7a817c512c40d7c4c0339a540c312ec0d78 Mon Sep 17 00:00:00 2001 From: Zack Grannan Date: Tue, 10 Feb 2026 15:10:49 -0800 Subject: [PATCH 5/5] Update CI --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0eeee639d..0a6d72791 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -169,11 +169,13 @@ jobs: container: ${{ fromJSON(vars.CONTAINER || 'null') }} steps: - uses: actions/checkout@v4 + - name: Save current generated types + run: cp visualization/src/generated/types.ts /tmp/types.ts.before - name: Generate TypeScript types run: cargo run --manifest-path type-export/Cargo.toml --bin generate_types - name: Check generated types are up-to-date run: | - if ! git diff --exit-code visualization/src/generated/types.ts; then + if ! diff /tmp/types.ts.before visualization/src/generated/types.ts; then echo "ERROR: Generated TypeScript types are out of date." echo "Run 'cargo run --manifest-path type-export/Cargo.toml --bin generate_types' to update." exit 1