Skip to content

Commit f456db6

Browse files
committed
front: Hide unused predicate state automatically
1 parent 0a971e3 commit f456db6

File tree

5 files changed

+129
-13
lines changed

5 files changed

+129
-13
lines changed

src/analyses/compute_rules.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,20 @@ pub enum TypeOfInterest {
170170
InMemory,
171171
}
172172

173+
impl TypeOfInterest {
174+
pub fn to_str(&self) -> String {
175+
format!("{self:?}")
176+
}
177+
178+
pub fn from_str(name: &str) -> anyhow::Result<Self> {
179+
Ok(match name {
180+
"UserVisible" => TypeOfInterest::UserVisible,
181+
"InMemory" => TypeOfInterest::InMemory,
182+
_ => anyhow::bail!("unknown type of interest `{name}`"),
183+
})
184+
}
185+
}
186+
173187
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)]
174188
pub enum PredicateStyle {
175189
/// `pattern @ expression : ty`
@@ -226,7 +240,7 @@ impl PredicateStyle {
226240
.find(|(n, _)| *n == name)
227241
{
228242
Some((_, style)) => Ok(*style),
229-
None => anyhow::bail!("unknown style {name}"),
243+
None => anyhow::bail!("unknown style `{name}`"),
230244
}
231245
}
232246

src/rulesets/mod.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,26 @@ impl RuleSet {
7171
}
7272

7373
/// List options that can be changed without affecting the current rules.
74-
pub fn irrelevant_options(self) -> &'static [&'static str] {
74+
pub fn irrelevant_options(&self) -> &'static [&'static str] {
7575
match self {
7676
RuleSet::TypeBased(o) => o.irrelevant_options(),
77-
RuleSet::BindingModeBased(c) => bm_based_irrelevant_options(c),
77+
RuleSet::BindingModeBased(c) => bm_based_irrelevant_options(*c),
78+
}
79+
}
80+
81+
/// Whether this ruleset cares about scrutinee mutability.
82+
pub fn tracks_scrut_mutability(&self) -> bool {
83+
match self {
84+
RuleSet::TypeBased(opts) => opts.tracks_scrut_mutability(),
85+
RuleSet::BindingModeBased(_) => true,
86+
}
87+
}
88+
89+
/// Whether this ruleset tracks some state related to inherited references/binding mode.
90+
pub fn tracks_reference_state(&self, ty: TypeOfInterest) -> bool {
91+
match self {
92+
RuleSet::TypeBased(opts) => opts.tracks_reference_state(ty),
93+
RuleSet::BindingModeBased(_) => true,
7894
}
7995
}
8096

src/rulesets/ty_based.rs

+49
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,55 @@ impl RuleOptions {
9797
}
9898
}
9999

100+
/// Whether this ruleset cares about scrutinee mutability.
101+
/// Warning: will cause `IncompatibleStyle` crashes if incorrect.
102+
pub fn tracks_scrut_mutability(&self) -> bool {
103+
self.downgrade_mut_inside_shared
104+
}
105+
106+
/// Whether this ruleset tracks some state related to inherited references/binding mode.
107+
/// Warning: will cause `IncompatibleStyle` crashes if incorrect.
108+
pub fn tracks_reference_state(&self, ty: TypeOfInterest) -> bool {
109+
match ty {
110+
// We always inspect the binding mode. More work would be needed to be able
111+
// to represent rulesets that handle the binding mode generically.
112+
TypeOfInterest::InMemory => true,
113+
// We carefully inspect each rule to see if it inspects the expression. If
114+
// it only inspects the type, that doesn't count as extra state.
115+
TypeOfInterest::UserVisible => {
116+
let RuleOptions {
117+
match_constructor_through_ref,
118+
eat_inherited_ref_alone,
119+
inherited_ref_on_ref,
120+
fallback_to_outer: _,
121+
allow_ref_pat_on_ref_mut: _,
122+
simplify_deref_mut: _,
123+
downgrade_mut_inside_shared: _,
124+
eat_mut_inside_shared: _,
125+
ref_binding_on_inherited,
126+
mut_binding_on_inherited,
127+
} = *self;
128+
if !match_constructor_through_ref {
129+
false
130+
} else if matches!(inherited_ref_on_ref, InheritedRefOnRefBehavior::EatOuter)
131+
&& matches!(
132+
ref_binding_on_inherited,
133+
RefBindingOnInheritedBehavior::AllocTemporary
134+
)
135+
&& matches!(
136+
mut_binding_on_inherited,
137+
MutBindingOnInheritedBehavior::Keep
138+
)
139+
&& eat_inherited_ref_alone
140+
{
141+
false
142+
} else {
143+
true
144+
}
145+
}
146+
}
147+
}
148+
100149
pub fn to_map(&self) -> serde_json::Map<String, serde_json::Value> {
101150
let serde_json::Value::Object(map) = serde_json::to_value(self).unwrap() else {
102151
panic!()

src/wasm.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,32 @@ pub struct PredicateStyleJs(PredicateStyle);
176176

177177
#[wasm_bindgen]
178178
impl PredicateStyleJs {
179-
pub fn from_name(name: &str) -> Option<PredicateStyleJs> {
180-
Some(PredicateStyleJs(PredicateStyle::from_name(name).ok()?))
179+
pub fn from_name_and_option(name: &str, ruleset: &RuleSetJs) -> Option<PredicateStyleJs> {
180+
// Silly but DRY
181+
Self::from_name_and_options(name, ruleset, ruleset)
182+
}
183+
184+
/// Constructs a sequent-style style based on the given name (reflecting the type of interest)
185+
/// and the passed rulesets (reflecting )
186+
pub fn from_name_and_options(
187+
name: &str,
188+
left: &RuleSetJs,
189+
right: &RuleSetJs,
190+
) -> Option<PredicateStyleJs> {
191+
let ty = TypeOfInterest::from_str(name).ok()?;
192+
let left = left.as_ruleset();
193+
let right = right.as_ruleset();
194+
let style = PredicateStyle::Sequent {
195+
ty,
196+
show_reference_state: left.tracks_reference_state(ty)
197+
|| right.tracks_reference_state(ty),
198+
show_scrut_access: left.tracks_scrut_mutability() || right.tracks_scrut_mutability(),
199+
};
200+
Some(PredicateStyleJs(style))
181201
}
182202

183203
pub fn to_name(&self) -> String {
184-
self.0.to_name().unwrap().to_string()
204+
self.0.type_of_interest().to_str()
185205
}
186206

187207
pub fn doc(&self) -> String {

web/src/components/Solver.jsx

+24-7
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ export function Help({show, setShow, style}) {
9595
</>
9696
}
9797

98-
const availableStyles = ['Sequent', 'SequentBindingMode'];
98+
const availableStyles = ['UserVisible', 'InMemory'];
9999

100-
export function MainNavBar({compare, setCompare, style, setStyle}) {
100+
export function MainNavBar({compare, setCompare, style, setStyleName, styleMap}) {
101101
const navigate = useNavigate()
102102
const [searchParams, setSearchParams] = useSearchParams();
103103
function resetSearchParams() {
@@ -114,11 +114,11 @@ export function MainNavBar({compare, setCompare, style, setStyle}) {
114114

115115
const currentStyle = style;
116116
const styles = availableStyles.map(style_name => {
117-
let style = PredicateStyleJs.from_name(style_name);
117+
let style = styleMap[style_name];
118118
return <OverlayTrigger key={style_name} placement="bottom" overlay={<Tooltip>{style.doc()}</Tooltip>}>
119119
<Button
120120
active={currentStyle.to_name() == style_name}
121-
onClick={() => setStyle(style)}
121+
onClick={() => setStyleName(style_name)}
122122
dangerouslySetInnerHTML={{__html: style.display_generic_predicate()}}
123123
></Button>
124124
</OverlayTrigger>
@@ -399,17 +399,34 @@ export default function Solver() {
399399
const [searchParams, setSearchParams] = useSearchParams();
400400
const sp = {searchParams, setSearchParams};
401401
const [compare, setCompare] = useStateInParams(sp, 'compare', false, (x) => x == 'true');
402-
const defaultStyle = PredicateStyleJs.from_name('Sequent');
403-
const [style, setStyle] = useStateInParams(sp, 'style', defaultStyle, PredicateStyleJs.from_name, (style) => style.to_name());
404402
const [optionsLeft, setOptionsLeft] = useStateInParams(sp, 'opts1', RuleSetJs.from_bundle_name('nadri', 'stable'), RuleSetJs.decode, (o) => o.encode());
405403
const [optionsRight, setOptionsRight] = useStateInParams(sp, 'opts2', RuleSetJs.from_bundle_name('rfc3627', 'rfc3627'), RuleSetJs.decode, (o) => o.encode());
406404
const [inputQuery, setInputQuery] = useStateInParams(sp, 'q', "[&x]: &mut [&T]");
407405
const [mode, setMode] = useStateInParams(sp, 'mode', 'typechecker', validateIn(['typechecker', 'rules', 'compare']));
406+
const [styleName, setStyleName] = useStateInParams(sp, 'style', 'UserVisible', validateIn(['UserVisible', 'InMemory', 'Sequent', 'SequentBindingMode']));
407+
408+
// Map from style name to predicate style. Takes into account the selected
409+
// options to hide parts of the predicate we don't care about.
410+
const styleMap = useMemo(() => {
411+
var map = availableStyles.reduce(function(map, style_name) {
412+
if(compare) {
413+
map[style_name] = PredicateStyleJs.from_name_and_options(style_name, optionsLeft, optionsRight);
414+
} else {
415+
map[style_name] = PredicateStyleJs.from_name_and_option(style_name, optionsLeft);
416+
}
417+
return map;
418+
}, {});
419+
// Back-compat with permalinks that used the old style names.
420+
map['Sequent'] = map['UserVisible'];
421+
map['SequentBindingMode'] = map['InMemory'];
422+
return map;
423+
}, [compare, optionsLeft, optionsRight]);
424+
const style = styleMap[styleName];
408425

409426
return (
410427
<>
411428
<div className="sticky-top">
412-
<MainNavBar {...{compare, setCompare, style, setStyle}}/>
429+
<MainNavBar {...{compare, setCompare, style, setStyleName, styleMap}}/>
413430
<SolverOptions options={optionsLeft} setOptions={setOptionsLeft} title={compare ? <>Left&nbsp;&nbsp;&nbsp;</> : null}/>
414431
{compare ? <SolverOptions options={optionsRight} setOptions={setOptionsRight} title="Right"/> : null}
415432
</div>

0 commit comments

Comments
 (0)