From f28c069266137d6dda16be6c503151374aa6e019 Mon Sep 17 00:00:00 2001 From: gavinleroy Date: Fri, 16 Aug 2024 09:35:06 -0400 Subject: [PATCH] Add impl candidates for each proof node idx --- crates/argus/src/aadebug/mod.rs | 9 ---- crates/argus/src/aadebug/tree.rs | 45 +------------------ crates/argus/src/proof_tree/interners.rs | 6 ++- crates/argus/src/proof_tree/mod.rs | 4 ++ crates/argus/src/proof_tree/serialize.rs | 34 +++++++++++++- ide/packages/common/src/TreeInfo.ts | 5 +-- .../panoptes/src/TreeView/TopDown.tsx | 2 + .../panoptes/src/TreeView/Wrappers.tsx | 9 ++-- 8 files changed, 49 insertions(+), 65 deletions(-) diff --git a/crates/argus/src/aadebug/mod.rs b/crates/argus/src/aadebug/mod.rs index d37665c..6d198d3 100644 --- a/crates/argus/src/aadebug/mod.rs +++ b/crates/argus/src/aadebug/mod.rs @@ -6,12 +6,10 @@ use std::time::Instant; use anyhow::Result; use argus_ext::ty::EvaluationResultExt; use index_vec::IndexVec; -use rustc_data_structures::fx::FxHashMap as HashMap; use rustc_infer::traits::solve::GoalSource; use rustc_trait_selection::solve::inspect::{InspectCandidate, InspectGoal}; use rustc_utils::timer; use serde::Serialize; -use serde_json as json; #[cfg(feature = "testing")] use ts_rs::TS; @@ -28,12 +26,6 @@ pub struct Storage<'tcx> { #[cfg_attr(feature = "testing", ts(export))] pub struct AnalysisResults { pub problematic_sets: Vec, - - #[cfg_attr( - feature = "testing", - ts(type = "Record") - )] - pub impl_candidates: HashMap>, } impl<'tcx> Storage<'tcx> { @@ -126,7 +118,6 @@ impl<'tcx> Storage<'tcx> { AnalysisResults { problematic_sets: sets, - impl_candidates: tree.reportable_impl_candidates(), } } } diff --git a/crates/argus/src/aadebug/tree.rs b/crates/argus/src/aadebug/tree.rs index 54a6267..63a39a2 100644 --- a/crates/argus/src/aadebug/tree.rs +++ b/crates/argus/src/aadebug/tree.rs @@ -1,12 +1,7 @@ use std::{cell::RefCell, ops::Deref, time::Instant}; -use argus_ext::{ - rustc::InferCtxtExt, - ty::{EvaluationResultExt, PredicateExt, TyCtxtExt, TyExt}, -}; -use argus_ser as ser; +use argus_ext::ty::{EvaluationResultExt, TyCtxtExt, TyExt}; use index_vec::IndexVec; -use rustc_data_structures::fx::FxHashMap as HashMap; use rustc_infer::infer::InferCtxt; use rustc_middle::{ traits::solve::{CandidateSource, Goal as RGoal}, @@ -22,7 +17,6 @@ use super::dnf::{And, Dnf}; use crate::{ analysis::EvaluationResult, proof_tree::{topology::TreeTopology, ProofNodeIdx}, - tls, }; pub type I = ProofNodeIdx; @@ -487,43 +481,6 @@ impl<'a, 'tcx: 'a> T<'a, 'tcx> { goals, } } - - pub fn reportable_impl_candidates( - &self, - ) -> HashMap> { - let mut indices = Vec::default(); - self.for_correction_set(|and| indices.extend(and.iter().copied())); - - let goals_only = indices.iter().filter_map(|&idx| self.goal(idx)); - - let trait_goals = goals_only.filter(|g| { - matches!( - g.analyze().kind, - GoalKind::Trait { .. } | GoalKind::FnToTrait { .. } - ) - }); - - trait_goals - .filter_map(|g| { - g.predicate().as_trait_predicate().map(|tp| { - let candidates = g - .infcx - .find_similar_impl_candidates(tp) - .into_iter() - .filter_map(|can| { - let header = - ser::argus::get_opt_impl_header(g.infcx.tcx, can.impl_def_id)?; - Some(tls::unsafe_access_interner(|ty_interner| { - ser::to_value_expect(g.infcx, ty_interner, &header) - })) - }) - .collect(); - - (g.idx, candidates) - }) - }) - .collect() - } } // ------------------ diff --git a/crates/argus/src/proof_tree/interners.rs b/crates/argus/src/proof_tree/interners.rs index f2b4e9b..55d25ee 100644 --- a/crates/argus/src/proof_tree/interners.rs +++ b/crates/argus/src/proof_tree/interners.rs @@ -183,7 +183,11 @@ impl Interners { .insert(CanKey::ParamEnv(idx), CandidateData::ParamEnv(idx)) } - fn intern_impl(&mut self, infcx: &InferCtxt, def_id: DefId) -> CandidateIdx { + pub(super) fn intern_impl( + &mut self, + infcx: &InferCtxt, + def_id: DefId, + ) -> CandidateIdx { if let Some(i) = self.candidates.get_idx(&CanKey::Impl(def_id)) { return i; } diff --git a/crates/argus/src/proof_tree/mod.rs b/crates/argus/src/proof_tree/mod.rs index 26c579c..8f71fc6 100644 --- a/crates/argus/src/proof_tree/mod.rs +++ b/crates/argus/src/proof_tree/mod.rs @@ -110,9 +110,13 @@ pub struct SerializedTree { pub projection_values: HashMap, + pub all_impl_candidates: HashMap>, + pub topology: TreeTopology, + #[serde(skip_serializing_if = "Option::is_none")] pub cycle: Option, + pub analysis: aadebug::AnalysisResults, } diff --git a/crates/argus/src/proof_tree/serialize.rs b/crates/argus/src/proof_tree/serialize.rs index fd7b062..ad2c880 100644 --- a/crates/argus/src/proof_tree/serialize.rs +++ b/crates/argus/src/proof_tree/serialize.rs @@ -1,5 +1,8 @@ use anyhow::{bail, Result}; -use argus_ext::ty::{EvaluationResultExt, TyExt}; +use argus_ext::{ + rustc::InferCtxtExt, + ty::{EvaluationResultExt, PredicateExt, TyExt}, +}; use index_vec::IndexVec; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; @@ -22,6 +25,7 @@ pub struct SerializedTreeVisitor<'tcx> { pub topology: TreeTopology, pub cycle: Option, pub projection_values: HashMap, + pub all_impl_candidates: HashMap>, deferred_leafs: Vec<(ProofNodeIdx, EvaluationResult)>, interners: Interners, @@ -37,6 +41,7 @@ impl SerializedTreeVisitor<'_> { topology: TreeTopology::new(), cycle: None, projection_values: HashMap::default(), + all_impl_candidates: HashMap::default(), deferred_leafs: Vec::default(), interners: Interners::default(), @@ -117,6 +122,7 @@ impl SerializedTreeVisitor<'_> { mut interners, aadebug, deferred_leafs, + all_impl_candidates, .. } = self else { @@ -143,6 +149,7 @@ impl SerializedTreeVisitor<'_> { results, tys, projection_values, + all_impl_candidates, topology, cycle, analysis, @@ -154,7 +161,7 @@ impl SerializedTreeVisitor<'_> { // interned keys does essentially). We should wait until the new trait solver // has some mechanism for detecting cycles and piggy back off that. // FIXME: this is currently dissabled but we should check for cycles again... - #[allow(dead_code)] + #[allow(dead_code, unused)] fn check_for_cycle_from(&mut self, from: ProofNodeIdx) { if self.cycle.is_some() { return; @@ -226,6 +233,25 @@ impl<'tcx> SerializedTreeVisitor<'tcx> { } } } + + fn record_all_impls( + &mut self, + idx: ProofNodeIdx, + goal: &InspectGoal<'_, 'tcx>, + ) { + // If the Goal is a TraitPredicate we will cache *all* possible implementors + if let Some(tp) = goal.goal().predicate.as_trait_predicate() { + let infcx = goal.infcx(); + for can in infcx.find_similar_impl_candidates(tp) { + let can_idx = self.interners.intern_impl(infcx, can.impl_def_id); + self + .all_impl_candidates + .entry(idx) + .or_default() + .push(can_idx); + } + } + } } impl<'tcx> ProofTreeVisitor<'tcx> for SerializedTreeVisitor<'tcx> { @@ -240,6 +266,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for SerializedTreeVisitor<'tcx> { let here_node = self.interners.mk_goal_node(goal); let here_idx = self.nodes.push(here_node); + + // Record all the possible candidate impls for this goal. + self.record_all_impls(here_idx, goal); + // Push node into the analysis tree. self.aadebug.push_goal(here_idx, goal).unwrap(); diff --git a/ide/packages/common/src/TreeInfo.ts b/ide/packages/common/src/TreeInfo.ts index feaef1d..ce6cffe 100644 --- a/ide/packages/common/src/TreeInfo.ts +++ b/ide/packages/common/src/TreeInfo.ts @@ -6,7 +6,6 @@ import type { EvaluationResult, GoalIdx, GoalKind, - ImplHeader, ProofNodeIdx, ResultIdx, SerializedTree, @@ -443,8 +442,8 @@ export class TreeInfo { return _.min(_.map(hs, TreeInfo.setInertia)) ?? 10_000; } - public implCandidates(idx: ProofNodeIdx): ImplHeader[] | undefined { - return this.tree.analysis.implCandidates[idx]; + public implCandidates(idx: ProofNodeIdx): CandidateIdx[] | undefined { + return this.tree.allImplCandidates[idx]; } } diff --git a/ide/packages/panoptes/src/TreeView/TopDown.tsx b/ide/packages/panoptes/src/TreeView/TopDown.tsx index d35a8d4..328fef5 100644 --- a/ide/packages/panoptes/src/TreeView/TopDown.tsx +++ b/ide/packages/panoptes/src/TreeView/TopDown.tsx @@ -6,6 +6,7 @@ import _ from "lodash"; import React, { useContext } from "react"; import { DirRecursive } from "./Directory"; +import { WrapImplCandidates } from "./Wrappers"; const TopDown = ({ start }: { start?: ProofNodeIdx }) => { const tree = useContext(TreeAppContext.TreeContext)!; @@ -64,6 +65,7 @@ const TopDown = ({ start }: { start?: ProofNodeIdx }) => { })(); const renderParams: TreeRenderParams = { + Wrappers: [WrapImplCandidates], styleEdges: true, ...ops }; diff --git a/ide/packages/panoptes/src/TreeView/Wrappers.tsx b/ide/packages/panoptes/src/TreeView/Wrappers.tsx index 3a9d1e1..a4d7290 100644 --- a/ide/packages/panoptes/src/TreeView/Wrappers.tsx +++ b/ide/packages/panoptes/src/TreeView/Wrappers.tsx @@ -6,7 +6,6 @@ import type { import { TreeAppContext } from "@argus/common/context"; import { arrUpdate } from "@argus/common/func"; import { IcoListUL, IcoTreeDown } from "@argus/print/Icons"; -import { PrintImplHeader } from "@argus/print/lib"; import { FloatingArrow, FloatingFocusManager, @@ -23,6 +22,7 @@ import classNames from "classnames"; import _ from "lodash"; import React, { type ReactElement, useState, useContext, useRef } from "react"; import Graph from "./Graph"; +import { Candidate } from "./Node"; import "./Wrappers.css"; @@ -140,10 +140,7 @@ export const WrapTreeIco = ({ n, reportActive }: InfoWrapperProps) => ( export const WrapImplCandidates = ({ n, reportActive }: InfoWrapperProps) => { const tree = useContext(TreeAppContext.TreeContext)!; const candidates = tree.implCandidates(n); - - if (candidates === undefined || candidates.length === 0) { - return null; - } + if (candidates === undefined || candidates.length === 0) return null; return ( }> @@ -151,7 +148,7 @@ export const WrapImplCandidates = ({ n, reportActive }: InfoWrapperProps) => {
{_.map(candidates, (c, i) => (
- +
))}