Skip to content

Commit 07e8de5

Browse files
committed
Elaborate letrec terms
1 parent d2e1f7b commit 07e8de5

File tree

15 files changed

+307
-54
lines changed

15 files changed

+307
-54
lines changed

fathom/src/core.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,8 @@ pub enum Term<'arena> {
143143
/// Annotated expressions.
144144
Ann(Span, &'arena Term<'arena>, &'arena Term<'arena>),
145145
/// Let expressions.
146-
Let(
147-
Span,
148-
Option<StringId>,
149-
&'arena Term<'arena>,
150-
&'arena Term<'arena>,
151-
&'arena Term<'arena>,
152-
),
146+
Let(Span, &'arena LetDef<'arena>, &'arena Term<'arena>),
147+
Letrec(Span, &'arena [LetDef<'arena>], &'arena Term<'arena>),
153148

154149
/// The type of types.
155150
Universe(Span),
@@ -204,6 +199,13 @@ pub enum Term<'arena> {
204199
),
205200
}
206201

202+
#[derive(Debug, Clone)]
203+
pub struct LetDef<'arena> {
204+
pub name: Option<StringId>,
205+
pub r#type: Term<'arena>,
206+
pub expr: Term<'arena>,
207+
}
208+
207209
impl<'arena> Term<'arena> {
208210
/// Get the source span of the term.
209211
pub fn span(&self) -> Span {
@@ -213,7 +215,8 @@ impl<'arena> Term<'arena> {
213215
| Term::MetaVar(span, _)
214216
| Term::InsertedMeta(span, _, _)
215217
| Term::Ann(span, _, _)
216-
| Term::Let(span, _, _, _, _)
218+
| Term::Let(span, ..)
219+
| Term::Letrec(span, ..)
217220
| Term::Universe(span)
218221
| Term::FunType(span, ..)
219222
| Term::FunLit(span, ..)
@@ -243,11 +246,23 @@ impl<'arena> Term<'arena> {
243246
| Term::ConstLit(_, _) => false,
244247

245248
Term::Ann(_, expr, r#type) => expr.binds_local(var) || r#type.binds_local(var),
246-
Term::Let(_, _, def_type, def_expr, body_expr) => {
247-
def_type.binds_local(var)
248-
|| def_expr.binds_local(var)
249+
Term::Let(_, def, body_expr) => {
250+
def.r#type.binds_local(var)
251+
|| def.expr.binds_local(var)
249252
|| body_expr.binds_local(var.prev())
250253
}
254+
Term::Letrec(_, defs, body_expr) => {
255+
for _def in defs.iter() {
256+
var = var.prev();
257+
}
258+
259+
if (defs.iter()).any(|def| def.r#type.binds_local(var) || def.expr.binds_local(var))
260+
{
261+
return true;
262+
}
263+
264+
body_expr.binds_local(var)
265+
}
251266
Term::FunType(.., param_type, body_type) => {
252267
param_type.binds_local(var) || body_type.binds_local(var.prev())
253268
}

fathom/src/core/pretty.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use std::cell::RefCell;
3030

3131
use pretty::RcDoc;
3232

33-
use crate::core::{Item, Module, Plicity, Term};
33+
use crate::core::{Item, LetDef, Module, Plicity, Term};
3434
use crate::source::{StringId, StringInterner};
3535
use crate::surface::lexer::is_keyword;
3636

@@ -150,24 +150,33 @@ impl<'interner, 'arena> Context<'interner> {
150150
self.term_prec(Prec::Top, r#type),
151151
]),
152152
),
153-
Term::Let(_, def_pattern, def_type, def_expr, body_expr) => self.paren(
153+
Term::Let(_, def, body_expr) => self.paren(
154154
prec > Prec::Let,
155155
RcDoc::concat([
156156
RcDoc::concat([
157157
RcDoc::text("let"),
158158
RcDoc::space(),
159-
self.ann_pattern(Prec::Top, *def_pattern, def_type),
160-
RcDoc::space(),
161-
RcDoc::text("="),
162-
RcDoc::softline(),
163-
self.term_prec(Prec::Let, def_expr),
159+
self.let_def(def),
164160
RcDoc::text(";"),
165161
])
166162
.group(),
167163
RcDoc::line(),
168164
self.term_prec(Prec::Let, body_expr),
169165
]),
170166
),
167+
Term::Letrec(_, defs, body_expr) => self.paren(
168+
prec > Prec::Let,
169+
self.sequence(
170+
RcDoc::concat([RcDoc::text("let")]),
171+
defs.iter().map(|def| self.let_def(def)),
172+
RcDoc::text(","),
173+
RcDoc::concat([
174+
RcDoc::text(";"),
175+
RcDoc::line(),
176+
self.term_prec(Prec::Let, body_expr),
177+
]),
178+
),
179+
),
171180
Term::Universe(_) => RcDoc::text("Type"),
172181
Term::FunType(_, plicity, param_name, param_type, body_type) => self.paren(
173182
prec > Prec::Fun,
@@ -341,6 +350,16 @@ impl<'interner, 'arena> Context<'interner> {
341350
}
342351
}
343352

353+
fn let_def(&'arena self, def: &LetDef<'arena>) -> RcDoc {
354+
RcDoc::concat([
355+
self.ann_pattern(Prec::Top, def.name, &def.r#type),
356+
RcDoc::space(),
357+
RcDoc::text("="),
358+
RcDoc::softline(),
359+
self.term_prec(Prec::Let, &def.expr),
360+
])
361+
}
362+
344363
fn format_field(&'arena self, label: StringId, format: &Term<'arena>) -> RcDoc {
345364
RcDoc::concat([
346365
self.ident(label),

fathom/src/core/semantics.rs

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use std::sync::Arc;
77
use scoped_arena::Scope;
88

99
use crate::alloc::SliceVec;
10-
use crate::core::{prim, Const, LocalInfo, Plicity, Prim, Term};
11-
use crate::env::{EnvLen, Index, Level, SharedEnv, SliceEnv};
10+
use crate::core::*;
11+
use crate::env::{self, EnvLen, Index, Level, SharedEnv, SliceEnv};
1212
use crate::source::{Span, Spanned, StringId};
1313

1414
/// Atomically reference counted values. We use reference counting to increase
@@ -53,6 +53,8 @@ pub enum Value<'arena> {
5353
}
5454

5555
impl<'arena> Value<'arena> {
56+
pub const ERROR: Self = Self::Stuck(Head::Prim(Prim::ReportedError), Vec::new());
57+
5658
pub fn prim(prim: Prim, params: impl IntoIterator<Item = ArcValue<'arena>>) -> Value<'arena> {
5759
let params = params
5860
.into_iter()
@@ -299,13 +301,29 @@ impl<'arena, 'env> EvalEnv<'arena, 'env> {
299301
self.apply_local_infos(head_expr, local_infos)
300302
}
301303
Term::Ann(span, expr, _) => Spanned::merge(*span, self.eval(expr)),
302-
Term::Let(span, _, _, def_expr, body_expr) => {
303-
let def_expr = self.eval(def_expr);
304+
Term::Let(span, def, body_expr) => {
305+
let def_expr = self.eval(&def.expr);
304306
self.local_exprs.push(def_expr);
305307
let body_expr = self.eval(body_expr);
306308
self.local_exprs.pop();
307309
Spanned::merge(*span, body_expr)
308310
}
311+
Term::Letrec(span, defs, body_expr) => {
312+
let initial_len = self.local_exprs.len();
313+
314+
for _def in defs.iter() {
315+
// TODO: lazy evaluation?
316+
(self.local_exprs).push(Spanned::empty(Arc::new(Value::ERROR)));
317+
}
318+
for (level, def) in Iterator::zip(env::levels(), defs.iter()) {
319+
let def_expr = self.eval(&def.expr);
320+
self.local_exprs.set_level(level, def_expr);
321+
}
322+
323+
let body_expr = self.eval(body_expr);
324+
self.local_exprs.truncate(initial_len);
325+
Spanned::merge(*span, body_expr)
326+
}
309327

310328
Term::Universe(span) => Spanned::new(*span, Arc::new(Value::Universe)),
311329

@@ -879,13 +897,35 @@ impl<'arena, 'env> EvalEnv<'arena, 'env> {
879897
scope.to_scope(self.unfold_metas(scope, expr)),
880898
scope.to_scope(self.unfold_metas(scope, r#type)),
881899
),
882-
Term::Let(span, def_name, def_type, def_expr, body_expr) => Term::Let(
900+
Term::Let(span, def, body_expr) => Term::Let(
883901
*span,
884-
*def_name,
885-
scope.to_scope(self.unfold_metas(scope, def_type)),
886-
scope.to_scope(self.unfold_metas(scope, def_expr)),
902+
scope.to_scope(LetDef {
903+
name: def.name,
904+
r#type: self.unfold_metas(scope, &def.r#type),
905+
expr: self.unfold_metas(scope, &def.expr),
906+
}),
887907
self.unfold_bound_metas(scope, body_expr),
888908
),
909+
Term::Letrec(span, defs, body_expr) => {
910+
let initial_len = self.local_exprs.len();
911+
912+
for _def in defs.iter() {
913+
let var = Arc::new(Value::local_var(self.local_exprs.len().next_level()));
914+
self.local_exprs.push(Spanned::empty(var));
915+
}
916+
917+
let defs = scope.to_scope_from_iter(defs.iter().map(|def| {
918+
let name = def.name;
919+
let r#type = self.unfold_metas(scope, &def.r#type);
920+
let expr = self.unfold_metas(scope, &def.expr);
921+
LetDef { name, r#type, expr }
922+
}));
923+
924+
let body_expr = self.unfold_metas(scope, body_expr);
925+
self.local_exprs.truncate(initial_len);
926+
927+
Term::Letrec(*span, defs, scope.to_scope(body_expr))
928+
}
889929

890930
Term::Universe(span) => Term::Universe(*span),
891931

fathom/src/env.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,10 @@ impl<Entry> SharedEnv<Entry> {
337337
self.get_level(self.len().index_to_level(index)?)
338338
}
339339

340+
pub fn set_level(&mut self, level: Level, entry: Entry) {
341+
self.entries.set_mut(level.0 as usize, entry);
342+
}
343+
340344
/// Push an entry onto the environment.
341345
pub fn push(&mut self, entry: Entry) {
342346
assert!(self.entries.len() < usize::from(u16::MAX));

fathom/src/surface.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,15 @@ impl<Range: Clone> Pattern<Range> {
179179
}
180180
}
181181

182+
impl<Range> Pattern<Range> {
183+
pub fn name(&self) -> Option<StringId> {
184+
match self {
185+
Pattern::Name(_, name) => Some(*name),
186+
_ => None,
187+
}
188+
}
189+
}
190+
182191
/// Surface terms.
183192
#[derive(Debug, Clone)]
184193
pub enum Term<'arena, Range> {

fathom/src/surface/distillation.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,10 @@ impl<'interner, 'arena, 'env> Context<'interner, 'arena, 'env> {
380380
Term::Ann((), self.scope.to_scope(expr), self.scope.to_scope(r#type)),
381381
)
382382
}
383-
(core::Term::Let(_, name, r#type, expr, body), _) => {
384-
let r#type = self.term_prec(mode, Prec::Top, r#type);
385-
let expr = self.term_prec(mode, Prec::Let, expr);
386-
let name = self.freshen_name(*name, body);
383+
(core::Term::Let(_, def, body), _) => {
384+
let r#type = self.term_prec(mode, Prec::Top, &def.r#type);
385+
let expr = self.term_prec(mode, Prec::Let, &def.expr);
386+
let name = self.freshen_name(def.name, body);
387387
let name = self.push_local(name);
388388
let pattern = name_to_pattern(name);
389389
let body = self.term_prec(mode, Prec::Top, body);
@@ -402,6 +402,30 @@ impl<'interner, 'arena, 'env> Context<'interner, 'arena, 'env> {
402402
),
403403
)
404404
}
405+
(core::Term::Letrec(_, defs, body_expr), _) => {
406+
let initial_len = self.local_len();
407+
408+
// TODO: freshen names
409+
let def_names: Vec<_> = defs.iter().map(|def| self.push_local(def.name)).collect();
410+
411+
let defs = self.scope.to_scope_from_iter(
412+
Iterator::zip(def_names.iter(), defs.iter()).map(|(name, def)| {
413+
let r#type = self.check(&def.r#type);
414+
let expr = self.check(&def.expr);
415+
416+
LetDef {
417+
pattern: name_to_pattern(*name),
418+
r#type: Some(r#type),
419+
expr,
420+
}
421+
}),
422+
);
423+
424+
let body_expr = self.check(body_expr);
425+
self.truncate_local(initial_len);
426+
427+
Term::Letrec((), defs, self.scope.to_scope(body_expr))
428+
}
405429
(core::Term::Universe(_), _) => Term::Universe(()),
406430
(core::Term::FunType(..), _) => {
407431
let initial_local_len = self.local_len();

0 commit comments

Comments
 (0)