Skip to content

Commit 58f9d0a

Browse files
committed
Diff traces
1 parent 13409d6 commit 58f9d0a

File tree

11 files changed

+379
-162
lines changed

11 files changed

+379
-162
lines changed

src/analyses/compute_rules.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,15 @@ impl<'a> RenderableTypingRule<'a> {
478478
preconditions.len_ignoring_markup(),
479479
postconditions.len_ignoring_markup(),
480480
);
481-
let bar = "-".repeat(len);
481+
let bar = "-".repeat(len).to_display_tree(a);
482482
let name = self.name.display(self.options);
483483
DisplayTree::sep_by(
484484
a,
485485
"\n",
486486
[
487487
preconditions,
488-
DisplayTree::sep2_by(a, bar, " ", format!("\"{name}\"")).ignore_for_diff(),
488+
bar.sep_then(a, " ", format!("\"{name}\""))
489+
.ignore_for_diff(),
489490
postconditions,
490491
],
491492
)

src/ast/printer.rs

+43-22
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,39 @@ impl BindingMode {
106106
}
107107
}
108108

109+
/// TODO: Currently displayed as a single leaf.
110+
impl<'d> ToDisplayTree<'d> for Pattern<'_> {
111+
fn to_display_tree(&self, a: &'d Arenas<'d>) -> DisplayTree<'d> {
112+
match *self {
113+
Self::Tuple(pats) => DisplayTree::sep_by(a, ", ", pats.iter())
114+
.surrounded(a, "[", "]")
115+
.tag("pat_list"),
116+
Self::Ref(mutable, pat) => {
117+
let needs_parens = mutable == Mutability::Shared
118+
&& matches!(pat, Self::Binding(Mutability::Mutable, ..));
119+
let (before, after) = if needs_parens {
120+
(format!("&{mutable}("), ")")
121+
} else {
122+
(format!("&{mutable}"), "")
123+
};
124+
DisplayTree::sep_by(
125+
a,
126+
"",
127+
[
128+
before.to_display_tree(a),
129+
pat.to_display_tree(a),
130+
after.to_display_tree(a),
131+
],
132+
)
133+
}
134+
Self::Binding(mutable, mode, name) => {
135+
DisplayTree::sep_by(a, "", [&mutable.to_string(), &mode.to_string(), name])
136+
}
137+
Self::Abstract(name) => name.to_display_tree(a),
138+
}
139+
}
140+
}
141+
109142
impl<'d> ToDisplayTree<'d> for Type<'_> {
110143
fn to_display_tree(&self, a: &'d Arenas<'d>) -> DisplayTree<'d> {
111144
match self {
@@ -183,20 +216,24 @@ impl TypingResult<'_> {
183216

184217
impl<'a> TypingPredicate<'a> {
185218
/// Display as `let ...`.
186-
pub fn display_as_let(&self) -> String {
187-
format!("let {}: {} = {}", self.pat, self.expr.ty, self.expr)
219+
pub fn display_as_let<'d>(&self, a: &'d Arenas<'d>) -> DisplayTree<'d> {
220+
self.pat
221+
.to_display_tree(a)
222+
.sep_then(a, ": ", self.expr.ty)
223+
.sep_then(a, " = ", self.expr.to_string())
224+
.preceded(a, "let ")
188225
}
189226

190227
pub fn display(&self, style: PredicateStyle) -> String {
191228
let a = &Arenas::default();
192229
self.display_to_tree(a, style).to_string()
193230
}
194231

232+
/// Display according to the given predicate style.
195233
pub fn display_to_tree<'d>(&self, a: &'d Arenas<'d>, style: PredicateStyle) -> DisplayTree<'d> {
196234
match style {
197235
PredicateStyle::Expression => self
198236
.pat
199-
.to_string()
200237
.to_display_tree(a)
201238
.sep_then(a, " @ ", self.expr.to_string())
202239
.sep_then(a, ": ", self.expr.ty),
@@ -273,11 +310,7 @@ impl<'a> TypingPredicate<'a> {
273310
},
274311
},
275312
};
276-
let post_turnstile = self
277-
.pat
278-
.to_string()
279-
.to_display_tree(a)
280-
.sep_then(a, ": ", ty);
313+
let post_turnstile = self.pat.to_display_tree(a).sep_then(a, ": ", ty);
281314

282315
let parts: &[_] = if pre_turnstile.is_empty() {
283316
&[post_turnstile]
@@ -347,20 +380,8 @@ impl Display for BindingMode {
347380

348381
impl Display for Pattern<'_> {
349382
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350-
match *self {
351-
Self::Tuple(pats) => write!(f, "[{}]", pats.iter().format(", ")),
352-
Self::Ref(mutable, pat) => {
353-
let needs_parens = mutable == Mutability::Shared
354-
&& matches!(pat, Self::Binding(Mutability::Mutable, ..));
355-
if needs_parens {
356-
write!(f, "&{mutable}({pat})")
357-
} else {
358-
write!(f, "&{mutable}{pat}")
359-
}
360-
}
361-
Self::Binding(mutable, mode, name) => write!(f, "{mutable}{mode}{name}"),
362-
Self::Abstract(name) => write!(f, "{name}"),
363-
}
383+
let a = &Arenas::default();
384+
write!(f, "{}", self.to_display_tree(a))
364385
}
365386
}
366387

src/ast/printer/display_tree.rs

+76-50
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ use DisplayTreeKind::*;
1010
enum DisplayTreeKind<'a> {
1111
/// Leaf node.
1212
Leaf(&'a str),
13-
/// Separated node. Considered different if the separator is different or the lengths are
14-
/// different.
13+
/// Separated node. Considered different if the separator is different. If the lengths are
14+
/// different, different options are possible.
1515
Separated {
1616
/// The separator, intercalated between the children.
1717
sep: &'a str,
1818
/// The children.
1919
children: &'a [DisplayTree<'a>],
20+
/// If the lengths differ and this is `true`, the first elements are diffed together until
21+
/// exhaustion. If the lengths differ and this is `false`, we consider the whole subtree to
22+
/// differ.
23+
compare_common_prefix: bool,
2024
},
2125
}
2226

@@ -25,7 +29,7 @@ pub struct DisplayTree<'a> {
2529
kind: DisplayTreeKind<'a>,
2630
/// Identifies the kind of node. Two nodes with different tags are always considered different.
2731
tag: &'static str,
28-
/// Whether to this sub-tree unchanged for the purposes of diffing.
32+
/// Whether to consider this sub-tree unchanged for the purposes of diffing.
2933
ignore_for_diff: bool,
3034
}
3135

@@ -77,6 +81,14 @@ fn strip_markup(s: &str) -> String {
7781
}
7882

7983
impl<'a> DisplayTree<'a> {
84+
fn new_from_kind(kind: DisplayTreeKind<'a>) -> Self {
85+
Self {
86+
kind,
87+
tag: "",
88+
ignore_for_diff: false,
89+
}
90+
}
91+
8092
pub fn is_empty(&self) -> bool {
8193
match self.kind {
8294
Leaf(s) => s.is_empty(),
@@ -87,7 +99,7 @@ impl<'a> DisplayTree<'a> {
8799
pub fn len_ignoring_markup(&self) -> usize {
88100
match self.kind {
89101
Leaf(s) => len_ignoring_markup(s),
90-
Separated { sep, children } => {
102+
Separated { sep, children, .. } => {
91103
let sep_len = if children.len() <= 1 {
92104
0
93105
} else {
@@ -100,45 +112,44 @@ impl<'a> DisplayTree<'a> {
100112
}
101113

102114
pub fn leaf_noalloc(s: &'a str) -> Self {
103-
Self {
104-
kind: Leaf(s),
105-
tag: "",
106-
ignore_for_diff: false,
107-
}
115+
Self::new_from_kind(Leaf(s))
108116
}
109117

110118
pub fn leaf(a: &'a Arenas<'a>, s: &str) -> Self {
111119
Self::leaf_noalloc(a.alloc_str(s))
112120
}
113121

114-
pub fn sep_by(
122+
fn mk_separated(
115123
a: &'a Arenas<'a>,
116124
sep: &str,
117-
it: impl IntoIterator<Item: ToDisplayTree<'a>>,
125+
children: impl IntoIterator<Item: ToDisplayTree<'a>>,
126+
compare_common_prefix: bool,
118127
) -> Self {
119-
let children = it.into_iter().map(|x| x.to_display_tree(a)).collect_vec();
120-
Self {
121-
kind: Separated {
122-
sep: a.alloc_str(sep),
123-
children: a.bump.alloc_slice_copy(&children),
124-
},
125-
tag: "",
126-
ignore_for_diff: false,
127-
}
128+
let children = children
129+
.into_iter()
130+
.map(|x| x.to_display_tree(a))
131+
.collect_vec();
132+
Self::new_from_kind(Separated {
133+
sep: a.alloc_str(sep),
134+
children: a.bump.alloc_slice_copy(&children),
135+
compare_common_prefix,
136+
})
128137
}
129138

130-
/// Constructs `self` followed by `after`.
131-
pub fn then(&self, a: &'a Arenas<'a>, x: impl ToDisplayTree<'a>) -> Self {
132-
self.sep_then(a, "", x)
139+
pub fn sep_by(
140+
a: &'a Arenas<'a>,
141+
sep: &str,
142+
children: impl IntoIterator<Item: ToDisplayTree<'a>>,
143+
) -> Self {
144+
Self::mk_separated(a, sep, children, false)
133145
}
134146

135-
/// Constructs `self` surrounded by `before` and `after`.
136-
pub fn surrounded(&self, a: &'a Arenas<'a>, before: &'static str, after: &'static str) -> Self {
137-
Self::sep_by(
138-
a,
139-
"",
140-
[Self::leaf_noalloc(before), *self, Self::leaf_noalloc(after)],
141-
)
147+
pub fn sep_by_compare_prefix(
148+
a: &'a Arenas<'a>,
149+
sep: &str,
150+
children: impl IntoIterator<Item: ToDisplayTree<'a>>,
151+
) -> Self {
152+
Self::mk_separated(a, sep, children, true)
142153
}
143154

144155
/// Concatenates `self` and `x`, separated by `sep`.
@@ -148,17 +159,26 @@ impl<'a> DisplayTree<'a> {
148159
sep: &'static str,
149160
x: impl ToDisplayTree<'a>,
150161
) -> Self {
151-
Self::sep2_by(a, self, sep, x)
162+
Self::sep_by(a, sep, [self.to_display_tree(a), x.to_display_tree(a)])
152163
}
153164

154-
/// Concatenates `x` and `y`, separated by `sep`.
155-
pub fn sep2_by(
156-
a: &'a Arenas<'a>,
157-
x: impl ToDisplayTree<'a>,
158-
sep: &str,
159-
y: impl ToDisplayTree<'a>,
160-
) -> Self {
161-
Self::sep_by(a, sep, [x.to_display_tree(a), y.to_display_tree(a)])
165+
/// Constructs `self` followed by `after`.
166+
pub fn then(&self, a: &'a Arenas<'a>, x: impl ToDisplayTree<'a>) -> Self {
167+
self.sep_then(a, "", x)
168+
}
169+
170+
/// Constructs `self` surrounded by `before` and `after`.
171+
pub fn preceded(&self, a: &'a Arenas<'a>, before: &'static str) -> Self {
172+
Self::sep_by(a, "", [Self::leaf_noalloc(before), *self])
173+
}
174+
175+
/// Constructs `self` surrounded by `before` and `after`.
176+
pub fn surrounded(&self, a: &'a Arenas<'a>, before: &'static str, after: &'static str) -> Self {
177+
Self::sep_by(
178+
a,
179+
"",
180+
[Self::leaf_noalloc(before), *self, Self::leaf_noalloc(after)],
181+
)
162182
}
163183

164184
pub fn ignore_for_diff(mut self) -> Self {
@@ -212,20 +232,30 @@ impl<'a> DisplayTree<'a> {
212232
(Leaf(l), Leaf(r)) if strip_markup(l) == strip_markup(r) => all_same(left, right),
213233
// The non-trivial case: the trees differ partially.
214234
(
215-
Separated { sep, children: c1 },
235+
Separated {
236+
sep,
237+
children: c1,
238+
compare_common_prefix: ccp1,
239+
},
216240
Separated {
217241
sep: sep2,
218242
children: c2,
243+
compare_common_prefix: ccp2,
219244
},
220-
) if strip_markup(sep) == strip_markup(sep2) && c1.len() == c2.len() => {
245+
) if strip_markup(sep) == strip_markup(sep2)
246+
&& (c1.len() == c2.len() || ccp1 || ccp2) =>
247+
{
221248
let mut is_first = true;
222249
let mut any_diff = false;
223-
for (c1, c2) in c1.iter().zip(c2) {
224-
if !is_first {
250+
for either_or_both in c1.iter().copied().zip_longest(c2.iter().copied()) {
251+
if !is_first && !either_or_both.is_right() {
225252
write!(left, "{sep}")?;
253+
}
254+
if !is_first && !either_or_both.is_left() {
226255
write!(right, "{sep}")?;
227256
}
228-
any_diff |= c1.diff_display_inner(c2, left, right)?;
257+
let (c1, c2) = either_or_both.or_default();
258+
any_diff |= c1.diff_display_inner(&c2, left, right)?;
229259
is_first = false;
230260
}
231261
Ok(any_diff)
@@ -237,19 +267,15 @@ impl<'a> DisplayTree<'a> {
237267

238268
impl Default for DisplayTree<'_> {
239269
fn default() -> Self {
240-
Self {
241-
kind: Leaf(""),
242-
tag: "",
243-
ignore_for_diff: false,
244-
}
270+
Self::leaf_noalloc("")
245271
}
246272
}
247273

248274
impl<'a> Display for DisplayTree<'a> {
249275
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250276
match self.kind {
251277
Leaf(s) => write!(f, "{s}")?,
252-
Separated { sep, children } => {
278+
Separated { sep, children, .. } => {
253279
let mut is_first = true;
254280
for child in children {
255281
if !is_first {

0 commit comments

Comments
 (0)