Skip to content

Commit

Permalink
Intern types, replace projections, Mini-buffer info area
Browse files Browse the repository at this point in the history
* Intern types while serializing

* Move DynCtxt to separate module

* Show projected types instead of their paths

* Clean up transmutes

* Add comment on type projections

* Add mini-buffer for full type information

* Add mini-buffer pinning, clean up icons and projection replacement
  • Loading branch information
gavinleroy authored Jul 3, 2024
1 parent fbf02cf commit 5e3742f
Show file tree
Hide file tree
Showing 49 changed files with 3,676 additions and 3,617 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/argus-ext/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub trait TyExt<'tcx> {

fn is_local(&self) -> bool;

fn is_alias(&self) -> bool;

fn base_ty(&self) -> ty::Ty<'tcx>;
}

Expand Down
4 changes: 4 additions & 0 deletions crates/argus-ext/src/ty/impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ impl<'tcx> TyExt<'tcx> for Ty<'tcx> {
matches!(self.kind(), ty::TyKind::Error(..))
}

fn is_alias(&self) -> bool {
matches!(self.kind(), ty::TyKind::Alias(..))
}

fn is_local(&self) -> bool {
match self.kind() {
ty::TyKind::Ref(_, ty, _) | ty::TyKind::RawPtr(ty, ..) => ty.is_local(),
Expand Down
1 change: 1 addition & 0 deletions crates/argus-ser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ serde.workspace = true
serde_json.workspace = true
smallvec = "1.11.2"
ts-rs = { version = "7.1.1", features = ["indexmap-impl"], optional = true }
index_vec = { version = "0.1.3", features = ["serde"] }

[dev-dependencies]
argus-ser = { path = ".", features = ["testing"] }
Expand Down
133 changes: 67 additions & 66 deletions crates/argus-ser/src/const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,32 +173,33 @@ enum UnevaluatedConstDef<'tcx> {

impl<'tcx> UnevaluatedConstDef<'tcx> {
fn new(value: &UnevaluatedConst<'tcx>) -> Self {
let infcx = get_dynamic_ctx();
let UnevaluatedConst { def, args } = value;
match infcx.tcx.def_kind(def) {
DefKind::Const | DefKind::AssocConst => Self::ValuePath {
data: path::ValuePathWithArgs::new(*def, args),
},
DefKind::AnonConst => {
if def.is_local()
&& let span = infcx.tcx.def_span(def)
&& let Ok(snip) = infcx.tcx.sess.source_map().span_to_snippet(span)
{
Self::AnonSnippet { data: snip }
} else {
// Do not call `print_value_path` as if a parent of this anon const is an impl it will
// attempt to print out the impl trait ref i.e. `<T as Trait>::{constant#0}`. This would
// cause printing to enter an infinite recursion if the anon const is in the self type i.e.
// `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {`
// where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}`
Self::AnonLocation {
krate: infcx.tcx.crate_name(def.krate),
path: path::BasicPathNoArgs::new(*def),
InferCtxt::access(|infcx| {
let UnevaluatedConst { def, args } = value;
match infcx.tcx.def_kind(def) {
DefKind::Const | DefKind::AssocConst => Self::ValuePath {
data: path::ValuePathWithArgs::new(*def, args),
},
DefKind::AnonConst => {
if def.is_local()
&& let span = infcx.tcx.def_span(def)
&& let Ok(snip) = infcx.tcx.sess.source_map().span_to_snippet(span)
{
Self::AnonSnippet { data: snip }
} else {
// Do not call `print_value_path` as if a parent of this anon const is an impl it will
// attempt to print out the impl trait ref i.e. `<T as Trait>::{constant#0}`. This would
// cause printing to enter an infinite recursion if the anon const is in the self type i.e.
// `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {`
// where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}`
Self::AnonLocation {
krate: infcx.tcx.crate_name(def.krate),
path: path::BasicPathNoArgs::new(*def),
}
}
}
defkind => panic!("unexpected defkind {defkind:?} {value:?}"),
}
defkind => panic!("unexpected defkind {defkind:?} {value:?}"),
}
})
}

pub fn serialize<S>(
Expand Down Expand Up @@ -237,56 +238,56 @@ pub enum ConstScalarIntDef {

impl<'tcx> ConstScalarIntDef {
pub fn new(int: ScalarInt, ty: Ty<'tcx>) -> Self {
let infcx = get_dynamic_ctx();
let tcx = infcx.tcx;

match ty.kind() {
Bool if int == ScalarInt::FALSE => Self::False,
Bool if int == ScalarInt::TRUE => Self::True,
Float(FloatTy::F32) => {
let val = Single::try_from(int).unwrap();
Self::Float {
data: format!("{val}"),
is_finite: val.is_finite(),
}
}
Float(FloatTy::F64) => {
let val = Double::try_from(int).unwrap();
Self::Float {
data: format!("{val}"),
is_finite: val.is_finite(),
InferCtxt::access(|infcx| {
let tcx = infcx.tcx;
match ty.kind() {
Bool if int == ScalarInt::FALSE => Self::False,
Bool if int == ScalarInt::TRUE => Self::True,
Float(FloatTy::F32) => {
let val = Single::try_from(int).unwrap();
Self::Float {
data: format!("{val}"),
is_finite: val.is_finite(),
}
}
}
Uint(_) | Int(_) => {
let int = ConstInt::new(
int,
matches!(ty.kind(), Int(_)),
ty.is_ptr_sized_integral(),
);
Self::Int {
data: format!("{int:?}"),
Float(FloatTy::F64) => {
let val = Double::try_from(int).unwrap();
Self::Float {
data: format!("{val}"),
is_finite: val.is_finite(),
}
}
}
Char if char::try_from(int).is_ok() => Self::Char {
data: format!("{}", char::try_from(int).is_ok()),
},
Ref(..) | RawPtr(..) | FnPtr(_) => {
let data = int.assert_bits(tcx.data_layout.pointer_size);
Self::Misc {
data: format!("0x{data:x}"),
Uint(_) | Int(_) => {
let int = ConstInt::new(
int,
matches!(ty.kind(), Int(_)),
ty.is_ptr_sized_integral(),
);
Self::Int {
data: format!("{int:?}"),
}
}
}
_ => {
if int.size() == Size::ZERO {
Char if char::try_from(int).is_ok() => Self::Char {
data: format!("{}", char::try_from(int).is_ok()),
},
Ref(..) | RawPtr(..) | FnPtr(_) => {
let data = int.assert_bits(tcx.data_layout.pointer_size);
Self::Misc {
data: "transmute(())".to_string(),
data: format!("0x{data:x}"),
}
} else {
Self::Misc {
data: format!("transmute(0x{int:x})"),
}
_ => {
if int.size() == Size::ZERO {
Self::Misc {
data: "transmute(())".to_string(),
}
} else {
Self::Misc {
data: format!("transmute(0x{int:x})"),
}
}
}
}
}
})
}
}
68 changes: 68 additions & 0 deletions crates/argus-ser/src/dyn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use rustc_infer::infer::InferCtxt;

// These types are safe for dependents to use.
use crate::interner::TyInterner;

pub trait DynCtxt<'tcx>
where
Self: 'tcx,
{
type Static: 'static;
type Dynamic: 'tcx;

fn tls() -> &'static fluid_let::DynamicVariable<&'static Self::Static>;

fn invoke_in<'a, T>(v: &'a Self::Dynamic, f: impl FnOnce() -> T) -> T
where
'tcx: 'a,
{
log::trace!(
"Setting dynamic ctx {:?}",
std::any::TypeId::of::<Self::Static>()
);

let cell = Self::tls();
let vstat: &'static Self::Static = unsafe { std::mem::transmute(v) };

cell.set(vstat, f)
}

fn access<T>(f: impl for<'a> FnOnce(&'a Self::Dynamic) -> T) -> T {
log::trace!(
"Accessing dynamic ctx {:?}",
std::any::TypeId::of::<Self::Static>()
);

let cell = Self::tls();
cell.get(|v_opt| {
let v: &'static Self::Static = v_opt.expect("no dynamic context set");
let vdyn: &Self::Dynamic = unsafe { std::mem::transmute(v) };

f(vdyn)
})
}
}

// NOTE: setting the dynamic TCX should *only* happen
// before calling the serialize function, it must guarantee
// that the 'tcx lifetime is the same as that of the serialized item.
fluid_let::fluid_let! {static INFCX: &'static InferCtxt<'static>}
fluid_let::fluid_let! {static TY_BUF: &'static TyInterner<'static>}

impl<'tcx> DynCtxt<'tcx> for InferCtxt<'tcx> {
type Static = InferCtxt<'static>;
type Dynamic = InferCtxt<'tcx>;

fn tls() -> &'static fluid_let::DynamicVariable<&'static Self::Static> {
&INFCX
}
}

impl<'tcx> DynCtxt<'tcx> for TyInterner<'tcx> {
type Static = TyInterner<'static>;
type Dynamic = TyInterner<'tcx>;

fn tls() -> &'static fluid_let::DynamicVariable<&'static Self::Static> {
&TY_BUF
}
}
64 changes: 64 additions & 0 deletions crates/argus-ser/src/interner.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::collections::HashMap; // FIXME: change back to above
use std::{
cell::RefCell,
cmp::{Eq, PartialEq},
hash::Hash,
};

use index_vec::{Idx, IndexVec};
// use rustc_data_structures::fx::FxHashMap as HashMap;
use rustc_middle::ty;

crate::define_idx! {
usize,
TyIdx
}

pub type TyInterner<'tcx> =
RefCell<Interner<ty::Ty<'tcx>, TyIdx, serde_json::Value>>;

pub struct Interner<K: PartialEq + Eq + Hash, I: Idx, D> {
values: IndexVec<I, D>,
keys: HashMap<K, I>,
}

impl<K, I, D> Default for Interner<K, I, D>
where
K: PartialEq + Eq + Hash,
I: Idx,
{
fn default() -> Self {
Self {
values: IndexVec::with_capacity(1_000_000),
keys: HashMap::with_capacity(1_000_000),
}
}
}

impl<K, I, D> Interner<K, I, D>
where
K: PartialEq + Eq + Hash,
I: Idx,
{
pub fn get_idx(&self, key: &K) -> Option<I> {
self.keys.get(key).copied()
}

pub fn get_data(&self, key: &I) -> Option<&D> {
self.values.get(*key)
}

pub fn insert(&mut self, k: K, d: D) -> I {
let idx = self.values.push(d);
self.keys.insert(k, idx);
idx
}

pub fn insert_no_key(&mut self, d: D) -> I {
self.values.push(d)
}

pub fn consume(self) -> IndexVec<I, D> {
self.values
}
}
Loading

0 comments on commit 5e3742f

Please sign in to comment.