diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2032ce36e..78adcb7e4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: nightly-2023-04-12 + toolchain: nightly-2023-08-25 components: rust-src, rustc-dev, llvm-tools-preview target: ${{ matrix.target }} profile: minimal diff --git a/Cargo.toml b/Cargo.toml index 042adeb9d..c54172a45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = ["crates/*"] exclude = ["ide/src/tests/mock_project"] +resolver = "2" [profile.bench] debug = true \ No newline at end of file diff --git a/README.md b/README.md index 4c2cd8878..d25fae98a 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,8 @@ The documentation is published here: https://willcrichton.net/flowistry/flowistr ## Usage -Note that the latest Flowistry has a [**Maximum** Supported Rust Version](https://github.com/cognitive-engineering-lab/rustc_plugin/tree/main#maximum-supported-rust-version) of **Rust 1.69**. -Flowistry is not guaranteed to work with features implemented after 1.69. +Note that the latest Flowistry has a [**Maximum** Supported Rust Version](https://github.com/cognitive-engineering-lab/rustc_plugin/tree/main#maximum-supported-rust-version) of **Rust 1.73**. +Flowistry is not guaranteed to work with features implemented after 1.73. ### Startup @@ -182,7 +182,7 @@ If rustup fails, especially with an error like "could not rename downloaded file To solve the issue, go to the command line and run: ``` -rustup toolchain install nightly-2023-04-12 -c rust-src -c rustc-dev -c llvm-tools-preview +rustup toolchain install nightly-2023-08-25 -c rust-src -c rustc-dev -c llvm-tools-preview ``` Then go back to VSCode and click "Continue" to let Flowistry continue installing. diff --git a/crates/flowistry/Cargo.toml b/crates/flowistry/Cargo.toml index a2beb93d6..4aed2265d 100644 --- a/crates/flowistry/Cargo.toml +++ b/crates/flowistry/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4" fluid-let = "1.0" cfg-if = "1.0" serde = {version = "1", features = ["derive"]} -rustc_utils = "0.6.3-nightly-2023-04-12" +rustc_utils = "0.7.0-nightly-2023-08-25" # For local debugging html-escape = {version = "0.2", optional = true} diff --git a/crates/flowistry/benches/main.rs b/crates/flowistry/benches/main.rs index fe083adf5..5a1cb5d31 100644 --- a/crates/flowistry/benches/main.rs +++ b/crates/flowistry/benches/main.rs @@ -13,7 +13,7 @@ use criterion::{ }; use flowistry::infoflow::Direction; use glob::glob; -use rustc_borrowck::BodyWithBorrowckFacts; +use rustc_borrowck::consumers::BodyWithBorrowckFacts; use rustc_hir::{BodyId, ItemKind}; use rustc_middle::{ mir::{Location, Place}, diff --git a/crates/flowistry/examples/example.rs b/crates/flowistry/examples/example.rs index c6362db6a..0efc3cd2f 100644 --- a/crates/flowistry/examples/example.rs +++ b/crates/flowistry/examples/example.rs @@ -25,7 +25,7 @@ extern crate rustc_span; use std::process::Command; use flowistry::{indexed::impls::LocationOrArg, infoflow::Direction}; -use rustc_borrowck::BodyWithBorrowckFacts; +use rustc_borrowck::consumers::BodyWithBorrowckFacts; use rustc_hir::{BodyId, ItemKind}; use rustc_middle::{ mir::{Local, Place}, diff --git a/crates/flowistry/src/indexed/mod.rs b/crates/flowistry/src/indexed/mod.rs index 1b26dfe79..f3c1e56a9 100644 --- a/crates/flowistry/src/indexed/mod.rs +++ b/crates/flowistry/src/indexed/mod.rs @@ -9,7 +9,7 @@ //! Therefore if we want to encode a set of locations (e.g. for the [`FlowDomain`](crate::infoflow::FlowDomain)), //! then we can assign each `Location` a numeric index and use a compact bit-set instead of, say, //! a hash set. Concretely, this means: -//! 1. Defining a type `LocationOrArgIndex` that implements the [`Idx`](rustc_index::vec::Idx) trait. +//! 1. Defining a type `LocationOrArgIndex` that implements the [`Idx`](rustc_index::Idx) trait. //! 2. Creating a mapping ("domain") from `Location`s to `LocationOrArgIndex`. //! 3. Constructing a `LocationSet` out of a [`BitSet`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_index/bit_set/struct.BitSet.html)``. //! @@ -35,10 +35,7 @@ use std::{ }; use rustc_data_structures::fx::FxHashMap as HashMap; -use rustc_index::{ - bit_set::BitSet, - vec::{Idx, IndexVec}, -}; +use rustc_index::{bit_set::BitSet, Idx, IndexVec}; use rustc_mir_dataflow::{fmt::DebugWithContext, JoinSemiLattice}; pub mod impls; diff --git a/crates/flowistry/src/infoflow/analysis.rs b/crates/flowistry/src/infoflow/analysis.rs index 0d1ec3ab3..890bb3fd6 100644 --- a/crates/flowistry/src/infoflow/analysis.rs +++ b/crates/flowistry/src/infoflow/analysis.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for FlowAnalysis<'a, 'tcx> { impl<'a, 'tcx> Analysis<'tcx> for FlowAnalysis<'a, 'tcx> { fn apply_statement_effect( - &self, + &mut self, state: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, @@ -245,30 +245,32 @@ impl<'a, 'tcx> Analysis<'tcx> for FlowAnalysis<'a, 'tcx> { .visit_statement(statement, location); } - fn apply_terminator_effect( - &self, + fn apply_terminator_effect<'mir>( + &mut self, state: &mut Self::Domain, - terminator: &Terminator<'tcx>, + terminator: &'mir Terminator<'tcx>, location: Location, - ) { + ) -> TerminatorEdges<'mir, 'tcx> { if matches!(terminator.kind, TerminatorKind::Call { .. }) && is_extension_active(|mode| mode.context_mode == ContextMode::Recurse) && self.recurse_into_call(state, &terminator.kind, location) { - return; + return terminator.edges(); } ModularMutationVisitor::new(&self.place_info, |_, mutations| { self.transfer_function(state, mutations, location) }) .visit_terminator(terminator, location); + + terminator.edges() } fn apply_call_return_effect( - &self, + &mut self, _state: &mut Self::Domain, _block: BasicBlock, - _return_places: rustc_mir_dataflow::CallReturnPlaces<'_, 'tcx>, + _return_places: CallReturnPlaces<'_, 'tcx>, ) { } } diff --git a/crates/flowistry/src/infoflow/mod.rs b/crates/flowistry/src/infoflow/mod.rs index e4480b37b..d18906feb 100644 --- a/crates/flowistry/src/infoflow/mod.rs +++ b/crates/flowistry/src/infoflow/mod.rs @@ -6,7 +6,7 @@ use std::cell::RefCell; use log::debug; -use rustc_borrowck::BodyWithBorrowckFacts; +use rustc_borrowck::consumers::BodyWithBorrowckFacts; use rustc_hir::BodyId; use rustc_middle::ty::TyCtxt; use rustc_utils::{block_timer, BodyExt}; diff --git a/crates/flowistry/src/infoflow/recursive.rs b/crates/flowistry/src/infoflow/recursive.rs index 62be72b01..1a51511e3 100644 --- a/crates/flowistry/src/infoflow/recursive.rs +++ b/crates/flowistry/src/infoflow/recursive.rs @@ -1,7 +1,7 @@ use log::{debug, info}; use rustc_middle::{ mir::*, - ty::{subst::GenericArgKind, ClosureKind, TyKind}, + ty::{ClosureKind, GenericArgKind, TyKind}, }; use rustc_mir_dataflow::JoinSemiLattice; use rustc_utils::{mir::borrowck_facts::get_body_with_borrowck_facts, PlaceExt}; diff --git a/crates/flowistry/src/mir/aliases.rs b/crates/flowistry/src/mir/aliases.rs index e4a0e7708..a2b219166 100644 --- a/crates/flowistry/src/mir/aliases.rs +++ b/crates/flowistry/src/mir/aliases.rs @@ -12,7 +12,7 @@ use rustc_data_structures::{ use rustc_hir::def_id::DefId; use rustc_index::{ bit_set::{HybridBitSet, SparseBitMatrix}, - vec::IndexVec, + IndexVec, }; use rustc_middle::{ mir::{visit::Visitor, *}, @@ -87,7 +87,7 @@ impl<'a, 'tcx> Aliases<'a, 'tcx> { let start = Instant::now(); let body = &body_with_facts.body; let static_region = RegionVid::from_usize(0); - let subset_base = &body_with_facts.input_facts.subset_base; + let subset_base = &body_with_facts.input_facts.as_ref().unwrap().subset_base; let all_pointers = body .local_decls() diff --git a/crates/flowistry/src/mir/engine.rs b/crates/flowistry/src/mir/engine.rs index 6751ce450..bd7bc1444 100644 --- a/crates/flowistry/src/mir/engine.rs +++ b/crates/flowistry/src/mir/engine.rs @@ -15,7 +15,7 @@ use std::rc::Rc; use either::Either; use rustc_data_structures::{graph::WithSuccessors, work_queue::WorkQueue}; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; use rustc_middle::{ mir::{traversal, Body, Location}, ty::TyCtxt, @@ -39,7 +39,7 @@ pub struct AnalysisResults<'tcx, A: Analysis<'tcx>> { impl<'tcx, A: Analysis<'tcx>> AnalysisResults<'tcx, A> { pub fn visit_reachable_with<'mir, V>(&self, body: &'mir Body<'tcx>, visitor: &mut V) where - V: ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, + V: ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, { for (block, data) in traversal::reachable(body) { for statement_index in 0 ..= data.statements.len() { @@ -51,17 +51,19 @@ impl<'tcx, A: Analysis<'tcx>> AnalysisResults<'tcx, A> { let state = &self.state[loc_index]; if statement_index == 0 { - visitor.visit_block_start(state, data, block); + visitor.visit_block_start(self, state, data, block); } if statement_index == data.statements.len() { visitor.visit_terminator_after_primary_effect( + self, state, data.terminator(), location, ) } else { visitor.visit_statement_after_primary_effect( + self, state, &data.statements[statement_index], location, @@ -85,7 +87,7 @@ pub fn iterate_to_fixpoint<'tcx, A: Analysis<'tcx>>( _tcx: TyCtxt<'tcx>, body: &Body<'tcx>, location_domain: Rc, - analysis: A, + mut analysis: A, ) -> AnalysisResults<'tcx, A> { let bottom_value = analysis.bottom_value(body); diff --git a/crates/flowistry/src/mir/placeinfo.rs b/crates/flowistry/src/mir/placeinfo.rs index b546c4c51..bb09ac721 100644 --- a/crates/flowistry/src/mir/placeinfo.rs +++ b/crates/flowistry/src/mir/placeinfo.rs @@ -144,9 +144,7 @@ impl<'a, 'tcx> PlaceInfo<'a, 'tcx> { fn collect_loans(&self, ty: Ty<'tcx>, mutability: Mutability) -> PlaceSet<'tcx> { let mut collector = LoanCollector { aliases: &self.aliases, - unknown_region: self - .tcx - .mk_region_from_kind(RegionKind::ReVar(UNKNOWN_REGION)), + unknown_region: Region::new_var(self.tcx, UNKNOWN_REGION), target_mutability: mutability, stack: vec![], loans: PlaceSet::default(), diff --git a/crates/flowistry/src/test_utils.rs b/crates/flowistry/src/test_utils.rs index dad04a165..069ca00c5 100644 --- a/crates/flowistry/src/test_utils.rs +++ b/crates/flowistry/src/test_utils.rs @@ -5,7 +5,7 @@ use std::{fs, io, panic, path::Path}; use anyhow::Result; use fluid_let::fluid_set; use log::info; -use rustc_borrowck::BodyWithBorrowckFacts; +use rustc_borrowck::consumers::BodyWithBorrowckFacts; use rustc_data_structures::fx::FxHashSet as HashSet; use rustc_hir::BodyId; use rustc_middle::ty::TyCtxt; @@ -14,7 +14,7 @@ pub use rustc_utils::test_utils::{compare_ranges, fmt_ranges, parse_ranges}; use rustc_utils::{ mir::borrowck_facts, source_map::{ - range::{ByteRange, ToSpan}, + range::{ByteRange, CharPos, ToSpan}, spanner::Spanner, }, test_utils, @@ -57,15 +57,18 @@ pub fn bless( [("`[", char_range.start), ("]`", char_range.end)] }) .collect::>(); - delims.sort_by_key(|(_, i)| i.0); + delims.sort_by_key(|(_, i)| (i.line, i.column)); let mut output = String::new(); - for (i, g) in contents.chars().enumerate() { - while delims.len() > 0 && delims[0].1 .0 == i { - let (delim, _) = delims.remove(0); - output.push_str(delim); + for (line, line_str) in contents.lines().enumerate() { + for (column, chr) in line_str.chars().enumerate() { + while delims.len() > 0 && delims[0].1 == (CharPos { line, column }) { + let (delim, _) = delims.remove(0); + output.push_str(delim); + } + output.push(chr); } - output.push(g); + output.push('\n'); } fs::write(path.with_extension("txt.expected"), output)?; diff --git a/crates/flowistry_ide/Cargo.toml b/crates/flowistry_ide/Cargo.toml index e535412bc..d72e6c91c 100644 --- a/crates/flowistry_ide/Cargo.toml +++ b/crates/flowistry_ide/Cargo.toml @@ -24,8 +24,8 @@ serde = {version = "1", features = ["derive"]} serde_json = "1" flate2 = "1" base64 = "0.21" -rustc_utils = {version = "0.6.3-nightly-2023-04-12", features = ["serde"]} -rustc_plugin = "0.6.3-nightly-2023-04-12" +rustc_utils = {version = "0.7.0-nightly-2023-08-25", features = ["serde"]} +rustc_plugin = "0.7.0-nightly-2023-08-25" # Decompose petgraph = {version = "0.6", default-features = false, optional = true} @@ -33,4 +33,4 @@ rayon = {version = "1.5", optional = true} # For binaries env_logger = {version = "0.9", default-features = false} -clap = {version = "4", default-features = false, features = ["std", "derive"]} \ No newline at end of file +clap = {version = "4.4", default-features = false, features = ["std", "derive"]} \ No newline at end of file diff --git a/crates/flowistry_ide/README.md b/crates/flowistry_ide/README.md index 4ff685568..1f6775d96 100644 --- a/crates/flowistry_ide/README.md +++ b/crates/flowistry_ide/README.md @@ -108,9 +108,9 @@ If rustup fails, especially with an error like "could not rename downloaded file To solve the issue, go to the command line and run: ``` -rustup toolchain install nightly-2023-04-12 -c rust-src -c rustc-dev -c llvm-tools-preview +rustup toolchain install nightly-2023-08-25 -c rust-src -c rustc-dev -c llvm-tools-preview ``` -> Note: double check the value of "channel" in `rust-toolchain.toml` if `nightly-2023-04-12` is no longer correct. +> Note: double check the value of "channel" in `rust-toolchain.toml` if `nightly-2023-08-25` is no longer correct. Then go back to VSCode and click "Continue" to let Flowistry continue installing. diff --git a/crates/flowistry_ide/src/focus/mod.rs b/crates/flowistry_ide/src/focus/mod.rs index 2bf5e9a45..bfa436771 100644 --- a/crates/flowistry_ide/src/focus/mod.rs +++ b/crates/flowistry_ide/src/focus/mod.rs @@ -93,6 +93,8 @@ pub fn focus(tcx: TyCtxt, body_id: BodyId) -> Result { .collect::>() }; + log::debug!("{:#?}", to_ranges(slice.clone())); + Some(PlaceInfo { range: CharRange::from_span(mir_span.span(), source_map).ok()?, ranges: to_ranges(vec![mir_span.span()]), diff --git a/crates/flowistry_ide/src/playground.rs b/crates/flowistry_ide/src/playground.rs index bdf476e18..4ef98e89d 100644 --- a/crates/flowistry_ide/src/playground.rs +++ b/crates/flowistry_ide/src/playground.rs @@ -17,9 +17,8 @@ pub fn playground(tcx: TyCtxt, body_id: BodyId) -> Result { let body = &body_with_facts.body; debug!("{}", body.to_string(tcx).unwrap()); - let outlives = body_with_facts - .input_facts - .subset_base + let subset_base = &body_with_facts.input_facts.as_ref().unwrap().subset_base; + let outlives = subset_base .iter() .map(|(sup, sub, _)| (format!("{sup:?}"), format!("{sub:?}"))) .collect::>(); diff --git a/crates/flowistry_ide/src/plugin.rs b/crates/flowistry_ide/src/plugin.rs index 3775b5837..0ebc7c238 100644 --- a/crates/flowistry_ide/src/plugin.rs +++ b/crates/flowistry_ide/src/plugin.rs @@ -18,6 +18,7 @@ use rustc_hir::BodyId; use rustc_interface::interface::Result as RustcResult; use rustc_middle::ty::TyCtxt; use rustc_plugin::{CrateFilter, RustcPlugin, RustcPluginArgs, Utf8Path}; +use rustc_span::ErrorGuaranteed; use rustc_utils::{ mir::borrowck_facts, source_map::{ @@ -53,7 +54,8 @@ enum FlowistryCommand { Focus { file: String, - pos: usize, + pos_line: usize, + pos_column: usize, }, Decompose { @@ -63,8 +65,10 @@ enum FlowistryCommand { Playground { file: String, - start: usize, - end: usize, + start_line: usize, + start_column: usize, + end_line: usize, + end_column: usize, }, Preload, @@ -141,11 +145,22 @@ impl RustcPlugin for FlowistryPlugin { match plugin_args.command { Spans { file, .. } => postprocess(crate::spans::spans(&compiler_args, file)), Playground { - file, start, end, .. + file, + start_line, + start_column, + end_line, + end_column, + .. } => { let compute_target = || CharRange { - start: CharPos(start), - end: CharPos(end), + start: CharPos { + line: start_line, + column: start_column, + }, + end: CharPos { + line: end_line, + column: end_column, + }, filename: Filename::intern(&file), }; postprocess(run( @@ -154,13 +169,23 @@ impl RustcPlugin for FlowistryPlugin { &compiler_args, )) } - Focus { file, pos, .. } => { + Focus { + file, + pos_line, + pos_column, + .. + } => { let compute_target = || { + let cpos = CharPos { + line: pos_line, + column: pos_column, + }; let range = CharRange { - start: CharPos(pos), - end: CharPos(pos), + start: cpos, + end: cpos, filename: Filename::intern(&file), }; + debug!("eyo WTF {range:?} {file}"); FunctionIdentifier::Range(range) }; postprocess(run(crate::focus::focus, compute_target, &compiler_args)) @@ -194,9 +219,7 @@ fn postprocess(result: FlowistryResult) -> RustcResult<()> { let result = match result { Ok(output) => Ok(output), Err(e) => match e { - FlowistryError::BuildError => { - return Err(rustc_errors::ErrorGuaranteed::unchecked_claim_error_was_emitted()); - } + FlowistryError::BuildError(e) => return Err(e), e => Err(e), }, }; @@ -225,7 +248,7 @@ pub fn run_with_callbacks( ); let compiler = rustc_driver::RunCompiler::new(&args, callbacks); - compiler.run().map_err(|_| FlowistryError::BuildError) + compiler.run().map_err(FlowistryError::BuildError) } fn run( @@ -257,7 +280,7 @@ fn run( #[derive(Debug, Serialize)] #[serde(tag = "type")] pub enum FlowistryError { - BuildError, + BuildError(#[serde(skip_serializing)] ErrorGuaranteed), AnalysisError { error: String }, FileNotFound, } @@ -312,6 +335,7 @@ impl T> rustc_driver::Callbacks let mut analysis = self.analysis.take().unwrap(); self.output = Some((|| { let target = (self.compute_target.take().unwrap())().to_span(tcx)?; + debug!("target span: {target:?}"); let mut bodies = find_enclosing_bodies(tcx, target); let body = bodies.next().context("Selection did not map to a body")?; analysis.analyze(tcx, body) diff --git a/crates/flowistry_ide/src/spans.rs b/crates/flowistry_ide/src/spans.rs index 4c33c5841..aa2a82e2d 100644 --- a/crates/flowistry_ide/src/spans.rs +++ b/crates/flowistry_ide/src/spans.rs @@ -1,5 +1,5 @@ use rustc_utils::source_map::{ - filename::Filename, find_bodies::find_bodies, range::ByteRange, + filename::Filename, find_bodies::find_bodies, range::CharRange, }; use serde::Serialize; @@ -7,7 +7,7 @@ use crate::plugin::{FlowistryError, FlowistryResult}; #[derive(Serialize)] pub struct SpansOutput { - spans: Vec, + spans: Vec, } unsafe impl Send for SpansOutput {} @@ -37,7 +37,7 @@ impl rustc_driver::Callbacks for Callbacks { .filter(|span| { source_map.lookup_source_file(span.lo()).name_hash == source_file.name_hash }) - .filter_map(|span| ByteRange::from_span(span, source_map).ok()) + .filter_map(|span| CharRange::from_span(span, source_map).ok()) .collect::>(); Ok(SpansOutput { spans }) })()); diff --git a/crates/flowistry_ifc/Cargo.toml b/crates/flowistry_ifc/Cargo.toml index 0e4aa328d..07dc26055 100644 --- a/crates/flowistry_ifc/Cargo.toml +++ b/crates/flowistry_ifc/Cargo.toml @@ -13,5 +13,5 @@ env_logger = "0.9" termcolor = "1.1" anyhow = "1" log = "0.4" -rustc_plugin = "0.6.3-nightly-2023-04-12" -rustc_utils = "0.6.3-nightly-2023-04-12" \ No newline at end of file +rustc_plugin = "0.7.0-nightly-2023-08-25" +rustc_utils = "0.7.0-nightly-2023-08-25" \ No newline at end of file diff --git a/ide/src/decorations.ts b/ide/src/decorations.ts index 8d404f176..8c99517e3 100644 --- a/ide/src/decorations.ts +++ b/ide/src/decorations.ts @@ -1,7 +1,13 @@ import _ from "lodash"; import * as vscode from "vscode"; -import { Range, to_vsc_range } from "./range"; +import { + Interval, + Range, + interval_to_range, + range_to_interval, + to_vsc_range, +} from "./range"; export let highlight_type = vscode.window.createTextEditorDecorationType({ backgroundColor: new vscode.ThemeColor("editor.symbolHighlightBackground"), @@ -33,38 +39,36 @@ export let select_type = vscode.window.createTextEditorDecorationType({ }, }); -export let invert_ranges = (container: Range, pieces: Range[]): Range[] => { +export let invert_ranges = ( + container: Range, + pieces: Range[], + doc: vscode.TextDocument +): Range[] => { + let icontainer = range_to_interval(container, doc); + let ipieces = pieces.map((piece) => range_to_interval(piece, doc)); + let filename = container.filename; - let pieces_sorted = _.sortBy(pieces, (r) => r.start).filter( - (r) => - container.start <= r.start && r.end <= container.end + let pieces_sorted = _.sortBy(ipieces, (r) => r[0]).filter( + (r) => icontainer[0] <= r[0] && r[1] <= icontainer[1] ); - let new_ranges: Range[] = []; - let start = container.start; + let new_ranges: Interval[] = []; + let start = icontainer[0]; pieces_sorted.forEach((r) => { - if (r.start < start) { - start = Math.max(r.end, start); + if (r[0] < start) { + start = Math.max(r[1], start); return; } - let end = r.start; - new_ranges.push({ - start: start, - end: end, - filename, - }); + let end = r[0]; + new_ranges.push([start, end]); - start = Math.max(start, r.end); + start = Math.max(start, r[1]); }); - new_ranges.push({ - start: start, - end: container.end, - filename, - }); + new_ranges.push([start, icontainer[1]]); - return new_ranges; + return new_ranges.map((intvl) => interval_to_range(intvl, filename, doc)); }; export let highlight_slice = ( @@ -76,7 +80,7 @@ export let highlight_slice = ( ) => { highlight_ranges(seeds, editor, select_type); let hide_ranges = containers - .map((container) => invert_ranges(container, slice)) + .map((container) => invert_ranges(container, slice, editor.document)) .flat(); highlight_ranges(hide_ranges, editor, hide_type); highlight_ranges(slice, editor, slice_type); @@ -90,7 +94,7 @@ export function highlight_ranges( ) { editor.setDecorations( type, - ranges.map((range) => to_vsc_range(range, editor.document)) + ranges.map((range) => to_vsc_range(range)) ); } diff --git a/ide/src/focus.ts b/ide/src/focus.ts index 325aab270..1d9cade51 100644 --- a/ide/src/focus.ts +++ b/ide/src/focus.ts @@ -29,11 +29,12 @@ class FocusBodyState { focus: Focus; places: RangeTree; - constructor(focus: Focus) { + constructor(focus: Focus, doc: vscode.TextDocument) { this.mark = null; this.focus = focus; this.places = new RangeTree( - focus.place_info.map((info) => ({ range: info.range, value: info })) + focus.place_info.map((info) => ({ range: info.range, value: info })), + doc ); } @@ -44,15 +45,17 @@ class FocusBodyState { let cmd = [ "focus", doc.fileName, - doc.offsetAt(selection.anchor).toString(), + selection.anchor.line.toString(), + selection.anchor.character.toString(), ]; let focus_res = await globals.call_flowistry(cmd); + console.log(focus_res); if (!is_ok(focus_res)) { return focus_res; } - return ok(new FocusBodyState(focus_res.value)); + return ok(new FocusBodyState(focus_res.value, doc)); }; private find_slice_at_selection = ( @@ -60,7 +63,6 @@ class FocusBodyState { doc: vscode.TextDocument ): { seeds: Range[]; slice: Range[]; direct_influence: Range[] } => { let query = this.places.selection_to_interval( - doc, this.mark || editor.selection ); let result = this.places.search(query); @@ -92,7 +94,7 @@ class FocusBodyState { if (seeds.length > 0) { if (select) { editor.selections = slice.map((range) => { - let vsc_range = to_vsc_range(range, doc); + let vsc_range = to_vsc_range(range); return new vscode.Selection(vsc_range.start, vsc_range.end); }); } else { @@ -131,9 +133,10 @@ class FocusDocumentState { // vscode.TextEditor to reduce API complexity. But those references were // seemingly invalidated after changing documents, so the editor must be // passed in anew each time. - constructor(spans: Spans) { + constructor(spans: Spans, doc: vscode.TextDocument) { this.bodies = new RangeTree( - spans.spans.map((range) => ({ range, value: new Cell(null) })) + spans.spans.map((range) => ({ range, value: new Cell(null) })), + doc ); } @@ -142,11 +145,12 @@ class FocusDocumentState { ): Promise> => { let cmd = ["spans", editor.document.fileName]; let spans = await globals.call_flowistry(cmd); + console.log("spans", spans); if (!is_ok(spans)) { return spans; } - return ok(new FocusDocumentState(spans.value)); + return ok(new FocusDocumentState(spans.value, editor.document)); }; on_change_selection = async ( @@ -171,7 +175,7 @@ class FocusDocumentState { ): Promise | null> => { // Find all bodies that contain the user's selection. let result = this.bodies.search( - this.bodies.selection_to_interval(editor.document, editor.selection) + this.bodies.selection_to_interval(editor.selection) ); // If the user hasn't selected a body, then return null @@ -346,7 +350,10 @@ export class FocusMode { } }; - private handle_analysis_result = async (result: FlowistryResult, userActivated: boolean = false) => { + private handle_analysis_result = async ( + result: FlowistryResult, + userActivated: boolean = false + ) => { if (!is_ok(result)) { if (userActivated) await show_error(result); this.set_mode("error"); diff --git a/ide/src/range.ts b/ide/src/range.ts index 2d614e2ab..e96c86054 100644 --- a/ide/src/range.ts +++ b/ide/src/range.ts @@ -2,22 +2,48 @@ import IntervalTree from "@flatten-js/interval-tree"; import _ from "lodash"; import vscode from "vscode"; +export interface CharPos { + line: number; + column: number; +} + export interface Range { - start: number; - end: number; + start: CharPos; + end: CharPos; filename: string; } -export let to_vsc_range = ( - range: Range, - doc: vscode.TextDocument -): vscode.Range => +export let to_vsc_range = (range: Range): vscode.Range => new vscode.Range( - doc.positionAt(range.start), - doc.positionAt(range.end) + range.start.line, + range.start.column, + range.end.line, + range.end.column ); -type Interval = [number, number]; +export let range_to_interval = ( + range: Range, + doc: vscode.TextDocument +): Interval => { + let vsc_range = to_vsc_range(range); + return [doc.offsetAt(vsc_range.start), doc.offsetAt(vsc_range.end)]; +}; + +export let interval_to_range = ( + interval: Interval, + filename: string, + doc: vscode.TextDocument +): Range => { + let start = doc.positionAt(interval[0]); + let end = doc.positionAt(interval[1]); + return { + start: { line: start.line, column: start.character }, + end: { line: end.line, column: end.character }, + filename, + }; +}; + +export type Interval = [number, number]; export type Ranged = { range: Range; @@ -31,27 +57,31 @@ export interface SearchResult { export class RangeTree { tree: IntervalTree; + filename: string; - constructor(entries: Ranged[] = []) { + constructor(entries: Ranged[] = [], readonly doc: vscode.TextDocument) { this.tree = new IntervalTree(); + this.filename = entries.length > 0 ? entries[0].range.filename : ""; entries.forEach(({ range, value }) => { this.insert(range, value); }); } - range_to_interval(range: Range): Interval { - return [range.start, range.end]; - } - - selection_to_interval( - doc: vscode.TextDocument, - selection: vscode.Selection - ): Interval { - return [doc.offsetAt(selection.start), doc.offsetAt(selection.end)]; + selection_to_interval(selection: vscode.Selection): Interval { + return [ + this.doc.offsetAt(selection.start), + this.doc.offsetAt(selection.end), + ]; } insert(range: Range, data: T) { - this.tree.insert(this.range_to_interval(range), data); + console.log( + "Inserting range", + range, + "at interval", + range_to_interval(range, this.doc) + ); + this.tree.insert(range_to_interval(range, this.doc), data); } search(query: Interval): SearchResult { @@ -70,11 +100,7 @@ export class RangeTree { }; result.forEach(([interval, value]) => { - let range = { - start: interval[0], - end: interval[1], - filename: "", - }; + let range = interval_to_range(interval, this.filename, this.doc); if (is_contained(interval, query)) { final.contained.push({ range, value }); } else if (is_contained(query, interval)) { @@ -86,12 +112,11 @@ export class RangeTree { ["contained", "containing", "overlapping"].forEach((k) => { let final_ = final as any; - final_[k] = _.sortBy( - final_[k], - ({ range }) => range.end - range.start - ); + final_[k] = _.sortBy(final_[k], ({ range }) => range.end - range.start); }); + console.log("Querying", query, "for result", final); + return final; } } diff --git a/ide/src/tests/commands/util/helpers.ts b/ide/src/tests/commands/util/helpers.ts index 8a190686d..0c824a160 100644 --- a/ide/src/tests/commands/util/helpers.ts +++ b/ide/src/tests/commands/util/helpers.ts @@ -119,9 +119,7 @@ export const get_command_selections = async ( const unique_ranges = _.uniqWith(output_data.ranges, _.isEqual); const sorted_ranges = _.sortBy(unique_ranges, (range) => [range.start]); - const vscode_ranges = sorted_ranges.map((range) => - to_vsc_range(range, vscode.window.activeTextEditor?.document!) - ); + const vscode_ranges = sorted_ranges.map((range) => to_vsc_range(range)); const merged_ranges = merge_ranges(vscode_ranges); const expected_selections = merged_ranges.map( (range) => new vscode.Selection(range.start, range.end) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a9dabd650..d9d396bd2 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-04-12" +channel = "nightly-2023-08-25" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] \ No newline at end of file