Skip to content

Commit 35b4e04

Browse files
authored
Merge pull request #63 from metaborg/equiv-containerized
Ensure data equivalences can be delayed
2 parents 3605d47 + 0f1b2ea commit 35b4e04

File tree

7 files changed

+262
-185
lines changed

7 files changed

+262
-185
lines changed

scopegraphs/examples/overload/main.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn main() {
2+
println!("Hello from overload example!")
3+
}

scopegraphs/src/containers/env.rs

+155-93
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
use crate::future_wrapper::FutureWrapper;
2-
use crate::resolve::{Env, ResolvedPath};
2+
use crate::resolve::{DataEquivalence, Env, ResolvedPath};
33
use futures::future::Shared;
44
use std::hash::Hash;
55
use std::rc::Rc;
66

77
/// Interface for environment containers that support the operations required for query resolution.
8-
pub trait EnvContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>:
8+
pub trait EnvContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg>:
99
From<Env<'sg, LABEL, DATA>> + 'rslv
10+
where
11+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
1012
{
11-
/// Creates a new, container with an empty environment.
12-
fn empty() -> Self;
13+
/// Creates a new container with an empty environment.
14+
fn empty() -> Self {
15+
Self::from(Env::new())
16+
}
1317

14-
/// Creates a new environment that contains path when `data_ok` is `true`, and is empty otherwise.
15-
fn inject_if(data_ok: DWFO, path: ResolvedPath<'sg, LABEL, DATA>) -> Self;
18+
/// Creates a new container with a single path.
19+
fn single(path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
20+
Self::from(Env::single(path))
21+
}
1622

1723
/// Maps the current container to a new one, based a provided mapping of the underlying environment.
1824
fn flat_map(
@@ -21,23 +27,11 @@ pub trait EnvContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>:
2127
) -> Self;
2228
}
2329

24-
impl<'sg: 'rslv, 'rslv, LABEL: Eq, DATA: Eq> EnvContainer<'sg, 'rslv, LABEL, DATA, bool>
30+
impl<'sg: 'rslv, 'rslv, LABEL: Eq, DATA: Eq> EnvContainer<'sg, 'rslv, LABEL, DATA>
2531
for Env<'sg, LABEL, DATA>
2632
where
2733
ResolvedPath<'sg, LABEL, DATA>: Hash + Clone,
2834
{
29-
fn empty() -> Self {
30-
Self::new()
31-
}
32-
33-
fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
34-
if data_ok {
35-
Self::single(path)
36-
} else {
37-
Self::empty()
38-
}
39-
}
40-
4135
fn flat_map(
4236
&self,
4337
map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
@@ -46,25 +40,13 @@ where
4640
}
4741
}
4842

49-
impl<'sg: 'rslv, 'rslv, LABEL, DATA> EnvContainer<'sg, 'rslv, LABEL, DATA, bool>
43+
impl<'sg: 'rslv, 'rslv, LABEL, DATA> EnvContainer<'sg, 'rslv, LABEL, DATA>
5044
for Rc<Env<'sg, LABEL, DATA>>
5145
where
5246
ResolvedPath<'sg, LABEL, DATA>: Hash,
5347
LABEL: 'sg + Eq + Clone,
5448
DATA: 'sg + Eq,
5549
{
56-
fn empty() -> Self {
57-
Self::new(Env::empty())
58-
}
59-
60-
fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
61-
if data_ok {
62-
Env::single(path).into()
63-
} else {
64-
Self::empty()
65-
}
66-
}
67-
6850
fn flat_map(
6951
&self,
7052
map: impl for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
@@ -73,7 +55,6 @@ where
7355
}
7456
}
7557

76-
// Implementations for Results
7758
impl<'sg, LABEL: 'sg, DATA: 'sg, E> From<Env<'sg, LABEL, DATA>>
7859
for Result<Env<'sg, LABEL, DATA>, E>
7960
{
@@ -83,23 +64,11 @@ impl<'sg, LABEL: 'sg, DATA: 'sg, E> From<Env<'sg, LABEL, DATA>>
8364
}
8465

8566
impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv>
86-
EnvContainer<'sg, 'rslv, LABEL, DATA, bool> for Result<Env<'sg, LABEL, DATA>, E>
67+
EnvContainer<'sg, 'rslv, LABEL, DATA> for Result<Env<'sg, LABEL, DATA>, E>
8768
where
8869
ResolvedPath<'sg, LABEL, DATA>: Hash + Clone,
8970
E: Clone,
9071
{
91-
fn empty() -> Self {
92-
Ok(Env::empty())
93-
}
94-
95-
fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
96-
if data_ok {
97-
Env::single(path).into()
98-
} else {
99-
Env::empty().into()
100-
}
101-
}
102-
10372
fn flat_map(&self, map: impl for<'short> FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self {
10473
match self {
10574
Ok(env) => map(env),
@@ -108,45 +77,22 @@ where
10877
}
10978
}
11079

111-
impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv>
112-
EnvContainer<'sg, 'rslv, LABEL, DATA, Result<bool, E>> for Result<Env<'sg, LABEL, DATA>, E>
80+
impl<'sg: 'rslv, 'rslv, LABEL, DATA> From<Env<'sg, LABEL, DATA>>
81+
for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>>
11382
where
114-
ResolvedPath<'sg, LABEL, DATA>: Hash + Clone,
115-
E: Clone,
83+
LABEL: Clone,
11684
{
117-
fn empty() -> Self {
118-
Ok(Env::empty())
119-
}
120-
121-
fn inject_if(data_ok: Result<bool, E>, path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
122-
data_ok.map(|ok| if ok { Env::single(path) } else { Env::empty() })
123-
}
124-
125-
fn flat_map(&self, map: impl for<'short> FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self {
126-
match self {
127-
Ok(env) => map(env),
128-
Err(err) => Err(err.clone()),
129-
}
85+
fn from(value: Env<'sg, LABEL, DATA>) -> Self {
86+
FutureWrapper::new(std::future::ready(value))
13087
}
13188
}
132-
impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq> EnvContainer<'sg, 'rslv, LABEL, DATA, bool>
89+
90+
impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq> EnvContainer<'sg, 'rslv, LABEL, DATA>
13391
for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>>
13492
where
13593
ResolvedPath<'sg, LABEL, DATA>: Hash + Clone,
13694
LABEL: Clone,
13795
{
138-
fn empty() -> Self {
139-
FutureWrapper::new(std::future::ready(Env::empty()))
140-
}
141-
142-
fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
143-
if data_ok {
144-
Env::single(path).into()
145-
} else {
146-
Env::empty().into()
147-
}
148-
}
149-
15096
fn flat_map(
15197
&self,
15298
map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
@@ -159,17 +105,51 @@ where
159105
}
160106
}
161107

108+
// Injectable
109+
110+
/// Environment Container in which a path can be injected based on a condition.
111+
pub trait Injectable<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>:
112+
EnvContainer<'sg, 'rslv, LABEL, DATA>
113+
where
114+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
115+
{
116+
/// Creates a new environment that contains path when `data_ok` is `true`, and is empty otherwise.
117+
fn inject_if(data_ok: DWFO, path: ResolvedPath<'sg, LABEL, DATA>) -> Self;
118+
}
119+
120+
impl<'sg: 'rslv, 'rslv, LABEL: Eq + 'sg, DATA: Eq + 'sg, ENVC>
121+
Injectable<'sg, 'rslv, LABEL, DATA, bool> for ENVC
122+
where
123+
ENVC: EnvContainer<'sg, 'rslv, LABEL, DATA>,
124+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
125+
{
126+
fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
127+
if data_ok {
128+
Self::single(path)
129+
} else {
130+
Self::empty()
131+
}
132+
}
133+
}
134+
135+
impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv>
136+
Injectable<'sg, 'rslv, LABEL, DATA, Result<bool, E>> for Result<Env<'sg, LABEL, DATA>, E>
137+
where
138+
ResolvedPath<'sg, LABEL, DATA>: Hash + Clone,
139+
E: Clone,
140+
{
141+
fn inject_if(data_ok: Result<bool, E>, path: ResolvedPath<'sg, LABEL, DATA>) -> Self {
142+
data_ok.map(|ok| if ok { Env::single(path) } else { Env::empty() })
143+
}
144+
}
145+
162146
impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq>
163-
EnvContainer<'sg, 'rslv, LABEL, DATA, FutureWrapper<'rslv, bool>>
147+
Injectable<'sg, 'rslv, LABEL, DATA, FutureWrapper<'rslv, bool>>
164148
for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>>
165149
where
166150
ResolvedPath<'sg, LABEL, DATA>: Hash + Clone,
167151
LABEL: Clone,
168152
{
169-
fn empty() -> Self {
170-
FutureWrapper::new(std::future::ready(Env::empty()))
171-
}
172-
173153
fn inject_if(
174154
data_ok: FutureWrapper<'rslv, bool>,
175155
path: ResolvedPath<'sg, LABEL, DATA>,
@@ -183,25 +163,107 @@ where
183163
}
184164
})
185165
}
166+
}
186167

187-
fn flat_map(
188-
&self,
189-
map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self,
168+
// Filtering
169+
170+
/// Sub trait of [EnvContainer] that validates that filtering operations (for shadowing) can be applied on it.
171+
pub trait Filterable<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DEQO>:
172+
EnvContainer<'sg, 'rslv, LABEL, DATA>
173+
where
174+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
175+
{
176+
/// Implementation of the filter operation on this container.
177+
fn filter(
178+
base_env: &Env<'sg, LABEL, DATA>,
179+
sub_env: &Env<'sg, LABEL, DATA>,
180+
equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = DEQO>,
181+
) -> Self;
182+
}
183+
184+
impl<'sg: 'rslv, 'rslv, LABEL: 'sg, DATA: 'sg, ENVC> Filterable<'sg, 'rslv, LABEL, DATA, bool>
185+
for ENVC
186+
where
187+
ENVC: EnvContainer<'sg, 'rslv, LABEL, DATA>,
188+
Env<'sg, LABEL, DATA>: Clone,
189+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
190+
{
191+
fn filter(
192+
base_env: &Env<'sg, LABEL, DATA>,
193+
sub_env: &Env<'sg, LABEL, DATA>,
194+
equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = bool>,
190195
) -> Self {
191-
let fut = Shared::clone(&self.0);
192-
FutureWrapper::new(async move {
193-
let env = fut.await;
194-
map(&env).0.await
195-
})
196+
sub_env
197+
.iter()
198+
.filter(|p1| !base_env.iter().any(|p2| equiv.data_equiv(p1.data, p2.data)))
199+
.cloned()
200+
.collect::<Env<_, _>>()
201+
.into()
196202
}
197203
}
198204

199-
impl<'sg: 'rslv, 'rslv, LABEL, DATA> From<Env<'sg, LABEL, DATA>>
205+
impl<'sg: 'rslv, 'rslv, LABEL: Clone + Eq + 'sg, DATA: Eq + 'sg, E: Clone + 'rslv>
206+
Filterable<'sg, 'rslv, LABEL, DATA, Result<bool, E>> for Result<Env<'sg, LABEL, DATA>, E>
207+
where
208+
Env<'sg, LABEL, DATA>: Clone,
209+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
210+
{
211+
fn filter(
212+
base_env: &Env<'sg, LABEL, DATA>,
213+
sub_env: &Env<'sg, LABEL, DATA>,
214+
equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = Result<bool, E>>,
215+
) -> Self {
216+
let sub_env = sub_env.clone();
217+
sub_env.into_iter().try_fold(
218+
Env::new(),
219+
|mut filtered_env: Env<'sg, LABEL, DATA>, p1: ResolvedPath<'sg, LABEL, DATA>| {
220+
let shadowed = base_env.iter().try_fold(
221+
/* initially, not shadowed */ false,
222+
|previously_shadowed: bool, p2: &ResolvedPath<'sg, LABEL, DATA>| {
223+
if previously_shadowed {
224+
Ok(true) // if it was shadowed, it will be
225+
} else {
226+
// not yet shadowed, try if current path shadows
227+
equiv.data_equiv(p1.data, p2.data)
228+
}
229+
},
230+
)?;
231+
// p1 is not shadowed, so add it to accumulator
232+
if !shadowed {
233+
filtered_env.insert(p1);
234+
}
235+
236+
Ok(filtered_env)
237+
},
238+
)
239+
}
240+
}
241+
242+
impl<'sg: 'rslv, 'rslv, LABEL: Clone + Eq + 'sg, DATA: Eq + 'sg>
243+
Filterable<'sg, 'rslv, LABEL, DATA, FutureWrapper<'rslv, bool>>
200244
for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>>
201245
where
202-
LABEL: Clone,
246+
Env<'sg, LABEL, DATA>: Clone,
247+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
203248
{
204-
fn from(value: Env<'sg, LABEL, DATA>) -> Self {
205-
FutureWrapper::new(std::future::ready(value))
249+
fn filter(
250+
base_env: &Env<'sg, LABEL, DATA>,
251+
sub_env: &Env<'sg, LABEL, DATA>,
252+
equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = FutureWrapper<'rslv, bool>>,
253+
) -> Self {
254+
let base_env = base_env.clone();
255+
let sub_env = sub_env.clone();
256+
FutureWrapper::new(async move {
257+
let mut filtered_env = Env::new();
258+
'outer: for sub_path in sub_env {
259+
for base_path in &base_env {
260+
if equiv.data_equiv(sub_path.data, base_path.data).await {
261+
continue 'outer;
262+
}
263+
}
264+
filtered_env.insert(sub_path.clone());
265+
}
266+
filtered_env
267+
})
206268
}
207269
}

scopegraphs/src/containers/path.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use futures::future::join_all;
44
use std::fmt::Debug;
55
use std::hash::Hash;
66

7-
use super::EnvContainer;
7+
use super::{Filterable, Injectable};
88

99
/// Interface for path containers that support the operations required for query resolution.
1010
pub trait PathContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg>: Debug + 'rslv {
@@ -19,19 +19,25 @@ pub trait PathContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg>: Debug + 'rslv {
1919
}
2020

2121
/// Trait that is auto-implemented for any [PathContainer] implementation that yields a valid [EnvContainer].
22-
pub trait PathContainerWf<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>:
22+
pub trait PathContainerWf<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO, DEQO>:
2323
PathContainer<'sg, 'rslv, LABEL, DATA, EnvContainer = Self::EnvContainerWf>
24+
where
25+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
2426
{
2527
/// Witness that ```Self::EnvContainer``` is a valid environment container.
26-
type EnvContainerWf: EnvContainer<'sg, 'rslv, LABEL, DATA, DWFO>;
28+
type EnvContainerWf: Injectable<'sg, 'rslv, LABEL, DATA, DWFO>
29+
+ Filterable<'sg, 'rslv, LABEL, DATA, DEQO>;
2730
}
2831

29-
impl<'sg, 'rslv, LABEL, DATA, DWFO, T> PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO> for T
32+
impl<'sg, 'rslv, LABEL, DATA, DWFO, DEQO, T> PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DEQO>
33+
for T
3034
where
3135
LABEL: Debug + 'sg,
3236
DATA: 'sg,
3337
T: PathContainer<'sg, 'rslv, LABEL, DATA>,
34-
Self::EnvContainer: EnvContainer<'sg, 'rslv, LABEL, DATA, DWFO>,
38+
Self::EnvContainer:
39+
Injectable<'sg, 'rslv, LABEL, DATA, DWFO> + Filterable<'sg, 'rslv, LABEL, DATA, DEQO>,
40+
ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone,
3541
{
3642
type EnvContainerWf = Self::EnvContainer;
3743
}

0 commit comments

Comments
 (0)