Skip to content

Commit 6406d8a

Browse files
committed
Missing file 🤦
1 parent f9db125 commit 6406d8a

File tree

1 file changed

+356
-0
lines changed

1 file changed

+356
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
use std::{cell::RefCell, future::Future, rc::Rc};
2+
3+
use async_recursion::async_recursion;
4+
use scopegraphs::{
5+
add_scope,
6+
completeness::{FutureCompleteness, ScopeExtPerm},
7+
future_wrapper::FutureWrapper,
8+
label_order, query_regex,
9+
render::{RenderScopeData, RenderScopeLabel, RenderSettings},
10+
resolve::Resolve,
11+
Label, Scope, ScopeGraph, Storage,
12+
};
13+
use smol::LocalExecutor;
14+
15+
use crate::{union_find::UnionFind, Expr, Function, PartialType, Program, Type};
16+
17+
#[derive(Debug, Label, Copy, Clone, Hash, PartialEq, Eq)]
18+
enum SgLabel {
19+
Fun,
20+
Var,
21+
Lex,
22+
}
23+
24+
impl RenderScopeLabel for SgLabel {
25+
fn render(&self) -> String {
26+
match self {
27+
SgLabel::Fun => "FUN".into(),
28+
SgLabel::Var => "VAR".into(),
29+
SgLabel::Lex => "LEX".into(),
30+
}
31+
}
32+
}
33+
34+
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
35+
struct FunType {
36+
args: Vec<PartialType>,
37+
return_type: PartialType,
38+
}
39+
40+
#[derive(Debug, Default, Hash, Eq, PartialEq, Clone)]
41+
enum SgData {
42+
VarDecl {
43+
name: String,
44+
ty: PartialType,
45+
},
46+
FunDecl {
47+
name: String,
48+
ty: FunType,
49+
},
50+
51+
#[default]
52+
Nothing,
53+
}
54+
55+
impl RenderScopeData for SgData {
56+
fn render_node(&self) -> Option<String> {
57+
match self {
58+
SgData::VarDecl { name, ty } => Some(format!("var {name}: {ty:?}")),
59+
SgData::FunDecl { name, ty } => {
60+
let args = &ty.args;
61+
let return_type = &ty.return_type;
62+
Some(format!("fun {name}({args:?}) : {return_type:?}"))
63+
}
64+
SgData::Nothing => None,
65+
}
66+
}
67+
}
68+
69+
impl SgData {
70+
pub fn expect_var_decl(&self) -> &PartialType {
71+
match self {
72+
SgData::VarDecl { ty, .. } => ty,
73+
_ => panic!("expected var decl, got {:?}", &self),
74+
}
75+
}
76+
77+
pub fn expect_fun_decl(&self) -> &FunType {
78+
match self {
79+
SgData::FunDecl { ty, .. } => ty,
80+
_ => panic!("expected type decl, got {:?}", &self),
81+
}
82+
}
83+
}
84+
85+
type OverloadScopegraph<'sg> = ScopeGraph<'sg, SgLabel, SgData, FutureCompleteness<SgLabel>>;
86+
type SgScopeExt<'sg> = ScopeExtPerm<'sg, SgLabel, SgData, FutureCompleteness<SgLabel>>;
87+
88+
struct TypeChecker<'sg, 'ex> {
89+
sg: &'sg OverloadScopegraph<'sg>,
90+
uf: RefCell<UnionFind>,
91+
ex: LocalExecutor<'ex>,
92+
}
93+
94+
async fn resolve_var<'sg>(
95+
sg: &'sg OverloadScopegraph<'sg>,
96+
scope: Scope,
97+
ref_name: &str,
98+
) -> PartialType {
99+
let ref_name: String = ref_name.into();
100+
let query = sg
101+
.query()
102+
.with_path_wellformedness(query_regex!(SgLabel: Lex* Var))
103+
.with_data_wellformedness(move |decl: &SgData| {
104+
let ref_name: String = ref_name.clone();
105+
let decl = decl.clone();
106+
FutureWrapper::new(async move {
107+
match decl {
108+
SgData::VarDecl {
109+
name: decl_name,
110+
ty,
111+
} => *decl_name == ref_name,
112+
_ => false,
113+
};
114+
todo!()
115+
})
116+
})
117+
.with_label_order(label_order!(SgLabel: Var < Lex));
118+
119+
let env = query.resolve(scope).await;
120+
// how to teach Rust that after the await, everything is released?
121+
122+
let result = env
123+
.get_only_item()
124+
.expect("variable did not resolve properly")
125+
.data()
126+
.expect_var_decl()
127+
.clone();
128+
129+
return result;
130+
}
131+
132+
async fn resolve_fun<'sg>(
133+
sg: &'sg OverloadScopegraph<'sg>,
134+
scope: Scope,
135+
ref_name: &str,
136+
arg_types: Vec<PartialType>, // used to select correct overload
137+
expected_return: PartialType, // used to select correct overload
138+
) -> FunType {
139+
let ref_name: String = ref_name.into();
140+
let query = sg
141+
.query()
142+
.with_path_wellformedness(query_regex!(SgLabel: Lex* Fun))
143+
.with_data_wellformedness(move |decl: &SgData| {
144+
let ref_name: String = ref_name.clone();
145+
let arg_types = arg_types.clone();
146+
let decl = decl.clone();
147+
FutureWrapper::new(async move {
148+
let result: bool = match decl {
149+
SgData::FunDecl {
150+
name: decl_name,
151+
ty,
152+
} => *decl_name == ref_name && ty.args.len() == arg_types.len(),
153+
_ => false,
154+
};
155+
result
156+
})
157+
})
158+
.with_data_equivalence(|d1: &SgData, d2: &SgData| {
159+
let d1_type = d1.expect_fun_decl();
160+
let d2_type = d2.expect_fun_decl();
161+
FutureWrapper::new(async move {
162+
// do all the proper scheduling
163+
// take care that incompatible types can occur, due to later refinements; those should have lowest priority
164+
false
165+
})
166+
})
167+
.with_label_order(label_order!(SgLabel: Var < Lex));
168+
169+
let env = query.resolve(scope).await;
170+
// how to teach Rust that after the await, everything is released?
171+
172+
let result = env
173+
.get_only_item()
174+
.expect("variable did not resolve properly")
175+
.data()
176+
.expect_fun_decl()
177+
.clone();
178+
179+
return result;
180+
}
181+
182+
impl<'sg, 'ex> TypeChecker<'sg, 'ex>
183+
where
184+
'sg: 'ex,
185+
{
186+
fn spawn<F, T>(self: &Rc<Self>, f: impl FnOnce(Rc<Self>) -> F)
187+
where
188+
F: Future<Output = T> + 'ex,
189+
T: 'ex,
190+
{
191+
self.ex.spawn(f(self.clone())).detach()
192+
}
193+
194+
fn to_partial_type(self: &Rc<Self>, type_opt: Option<Type>) -> PartialType {
195+
type_opt
196+
.map(PartialType::Type)
197+
.unwrap_or_else(|| PartialType::Variable(self.uf.borrow_mut().fresh()))
198+
}
199+
200+
async fn typecheck_fun(self: Rc<Self>, function: &Function, fun_ext: &SgScopeExt<'sg>) {
201+
let arg_vars = function
202+
.args
203+
.iter()
204+
.map(|arg| (arg.name.clone(), self.to_partial_type(arg.type_ann.clone())))
205+
.collect::<Vec<_>>();
206+
self.sg
207+
.ext_decl(
208+
fun_ext,
209+
SgData::FunDecl {
210+
name: function.name.clone(),
211+
ty: FunType {
212+
args: arg_vars.iter().map(|(_, tp)| tp).cloned().collect(),
213+
return_type: self.to_partial_type(function.return_type.clone()),
214+
},
215+
},
216+
)
217+
.expect("why can this function even have an error??")
218+
}
219+
220+
#[async_recursion(?Send)]
221+
async fn typecheck_expr(
222+
self: Rc<Self>,
223+
expr: &'ex Expr,
224+
scope: Scope,
225+
expected_type: PartialType,
226+
) {
227+
match expr {
228+
Expr::IntLit(_) => self
229+
.uf
230+
.borrow_mut()
231+
.unify(expected_type, PartialType::Type(Type::IntT)),
232+
Expr::BoolLit(_) => self
233+
.uf
234+
.borrow_mut()
235+
.unify(expected_type, PartialType::Type(Type::BoolT)),
236+
Expr::Ident(name) => {
237+
let decl_type = resolve_var(self.sg, scope, &name).await;
238+
self.uf.borrow_mut().unify(expected_type, decl_type);
239+
}
240+
Expr::Plus(lhs, rhs) => {
241+
self.uf
242+
.borrow_mut()
243+
.unify(expected_type, PartialType::Type(Type::IntT));
244+
self.clone()
245+
.typecheck_expr(lhs, scope, PartialType::Type(Type::IntT));
246+
self.typecheck_expr(rhs, scope, PartialType::Type(Type::IntT));
247+
}
248+
Expr::Lt(lhs, rhs) => {
249+
self.uf
250+
.borrow_mut()
251+
.unify(expected_type, PartialType::Type(Type::BoolT));
252+
self.clone()
253+
.typecheck_expr(lhs, scope, PartialType::Type(Type::IntT));
254+
self.typecheck_expr(rhs, scope, PartialType::Type(Type::IntT));
255+
}
256+
Expr::IfThenElse(condition, if_branch, then_branch) => {
257+
self.clone()
258+
.typecheck_expr(condition, scope, PartialType::Type(Type::BoolT));
259+
self.clone()
260+
.typecheck_expr(if_branch, scope, expected_type.clone());
261+
self.typecheck_expr(then_branch, scope, expected_type);
262+
}
263+
Expr::FunCall(name, args) => {
264+
// we do not yet know which direction inference will flow, so create vars for all arguments
265+
let vars = args
266+
.iter()
267+
.map(|_| PartialType::Variable(self.uf.borrow_mut().fresh()))
268+
.collect::<Vec<_>>();
269+
270+
// type check all arguments
271+
args.iter().zip(vars.clone()).for_each(|(arg, ty)| {
272+
self.spawn(|this| this.typecheck_expr(arg, scope, ty));
273+
});
274+
275+
// spawn task that resolves function
276+
self.spawn(|this| {
277+
FutureWrapper::new(async move {
278+
// resolve function
279+
let fun =
280+
resolve_fun(this.sg, scope, &name, vars.clone(), expected_type.clone())
281+
.await;
282+
283+
// check return type
284+
this.uf.borrow_mut().unify(expected_type, fun.return_type);
285+
286+
// check argument types
287+
fun.args.into_iter().zip(vars).for_each(|(formal, actual)| {
288+
this.uf.borrow_mut().unify(formal, actual);
289+
});
290+
})
291+
});
292+
}
293+
Expr::Ascribe(expr, ty) => {
294+
let ty = PartialType::Type(ty.clone());
295+
self.uf.borrow_mut().unify(expected_type, ty.clone());
296+
self.clone().typecheck_expr(expr, scope, ty);
297+
}
298+
}
299+
}
300+
}
301+
302+
fn typecheck(ast: &Program) -> Option<Type> {
303+
let storage = Storage::new();
304+
let sg = OverloadScopegraph::new(&storage, FutureCompleteness::default());
305+
let uf = RefCell::new(UnionFind::default());
306+
let local = LocalExecutor::new();
307+
308+
let tc = Rc::new(TypeChecker {
309+
sg: &sg,
310+
uf,
311+
ex: local,
312+
});
313+
314+
// INLINED add_scope!(...) macro for debugging purposes
315+
let (global_scope, ext_fun) = add_scope!(&tc.sg, [SgLabel::Fun]);
316+
317+
// typecheck all the type definitions somewhere in the future
318+
for item in &ast.functions {
319+
// TODO: spawn task for type checking functions
320+
}
321+
322+
// We can close for function definitions since the scopes for this are synchronously
323+
// made even before the future is returned and spawned. so, at this point,
324+
// no new type definitions are made.
325+
// FIXME: does this work when type-checking functions is spawned in a task?
326+
ext_fun.close(); // required, otherwise it will be dropped only after the type checking process is finished, which is too late
327+
328+
// init variable for main type
329+
let main_ty = PartialType::Variable(tc.uf.borrow_mut().fresh());
330+
331+
// typecheck the main expression
332+
let res = tc.ex.spawn(
333+
tc.clone()
334+
.typecheck_expr(&ast.main, global_scope, main_ty.clone()),
335+
);
336+
337+
// extract result from task
338+
smol::block_on(async {
339+
while !tc.ex.is_empty() {
340+
tc.ex.tick().await;
341+
}
342+
343+
res.await
344+
});
345+
346+
tc.sg
347+
.render_to(
348+
"overload-sg.dot",
349+
RenderSettings::default().with_name("example with overloading"),
350+
)
351+
.unwrap();
352+
println!("Unifier: {:?}", tc.uf.borrow());
353+
354+
let resolved_main_ty = tc.uf.borrow_mut().type_of_partial_type(main_ty);
355+
resolved_main_ty
356+
}

0 commit comments

Comments
 (0)