Add unbound refs check

This commit is contained in:
Nicolas Abril 2024-05-31 18:30:25 +02:00
parent 6f6747ddc9
commit 3705094b6d
7 changed files with 70 additions and 1 deletions

View File

@ -1,3 +1,4 @@
pub mod set_entrypoint; pub mod set_entrypoint;
pub mod shared_names; pub mod shared_names;
pub mod unbound_refs;
pub mod unbound_vars; pub mod unbound_vars;

View File

@ -0,0 +1,37 @@
use crate::{
diagnostics::Diagnostics,
fun::{Ctx, Definitions, Name, Term},
maybe_grow,
};
use std::collections::HashSet;
impl Ctx<'_> {
pub fn check_unbound_refs(&mut self) -> Result<(), Diagnostics> {
self.info.start_pass();
for def in self.book.defs.values() {
let mut unbounds = HashSet::new();
for rule in def.rules.iter() {
rule.body.check_unbound_refs(&self.book.defs, &mut unbounds);
}
for unbound in unbounds {
self.info.add_rule_error(format!("Reference to undefined function '{unbound}'"), def.name.clone());
}
}
self.info.fatal(())
}
}
impl Term {
pub fn check_unbound_refs(&self, defs: &Definitions, unbounds: &mut HashSet<Name>) {
maybe_grow(|| {
if let Term::Ref { nam } = self {
if !defs.contains_key(nam) {
unbounds.insert(nam.clone());
}
}
for child in self.children() {
child.check_unbound_refs(defs, unbounds);
}
})
}
}

View File

@ -36,7 +36,7 @@ impl Ctx<'_> {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Book { pub struct Book {
/// The function definitions. /// The function definitions.
pub defs: IndexMap<Name, Definition>, pub defs: Definitions,
/// The algebraic datatypes defined by the program /// The algebraic datatypes defined by the program
pub adts: Adts, pub adts: Adts,
@ -48,6 +48,7 @@ pub struct Book {
pub entrypoint: Option<Name>, pub entrypoint: Option<Name>,
} }
pub type Definitions = IndexMap<Name, Definition>;
pub type Adts = IndexMap<Name, Adt>; pub type Adts = IndexMap<Name, Adt>;
pub type Constructors = IndexMap<Name, Name>; pub type Constructors = IndexMap<Name, Name>;

View File

@ -140,6 +140,8 @@ pub fn desugar_book(
ctx.book.float_combinators(MAX_NET_SIZE); ctx.book.float_combinators(MAX_NET_SIZE);
} }
ctx.check_unbound_refs()?;
ctx.prune(opts.prune); ctx.prune(opts.prune);
if opts.merge { if opts.merge {

View File

@ -0,0 +1,11 @@
# A net that expands inifinitely like church exponentiation
# Compiles to this net:
# a
# & ({(b c) (d b)} (c d)) ~ {(e a) e}
main =
let {a1 a2} =
@b
let {b1 b2} = b
let (c1, c2) = b2
((b1 c2), c1)
(a1 a2)

View File

@ -0,0 +1,10 @@
type Maybe = (Some x) | None
Maybe/bind val nxt = match val {
Maybe/Some: (nxt val.x)
Maybe/None: Maybe/None
}
main = with Maybe {
(wrap 1)
}

View File

@ -0,0 +1,7 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/run_file/unbound_wrap.bend
---
Errors:
In definition 'main':
Reference to undefined function 'Maybe/wrap'