Skip to content

Commit

Permalink
fix: Don't panic when compiling partially compiled constructors
Browse files Browse the repository at this point in the history
Ideally partially applied constructors should be compiled into an automatically generated lambda but until then we should at least not panic when encountering one.

Fixes #202
  • Loading branch information
Marwes committed Nov 26, 2016
1 parent ca734e4 commit 6fb552e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 18 deletions.
50 changes: 39 additions & 11 deletions tests/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,15 @@ pure 123
value.0);
}

#[test]
fn dont_panic_on_partially_applied_constructor() {
let _ = ::env_logger::init();
let vm = make_vm();

let result = Compiler::new().run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "test", "Some");
assert!(result.is_err());
}

#[test]
fn stacktrace() {
use gluon::vm::stack::StacktraceFrame;
Expand All @@ -740,17 +749,36 @@ g 10
let f = stacktrace.frames[1].as_ref().unwrap().name.clone();
let end = stacktrace.frames[6].as_ref().unwrap().name.clone();
assert_eq!(stacktrace.frames,
vec![
// Removed due to being a tail call
// Some(StacktraceFrame { name: f.clone(), line: 9 }),
Some(StacktraceFrame { name: g.clone(), line: 7.into() }),
Some(StacktraceFrame { name: f.clone(), line: 6.into() }),
Some(StacktraceFrame { name: g.clone(), line: 7.into() }),
Some(StacktraceFrame { name: f.clone(), line: 6.into() }),
Some(StacktraceFrame { name: g.clone(), line: 7.into() }),
Some(StacktraceFrame { name: f.clone(), line: 4.into() }),
Some(StacktraceFrame { name: end.clone(), line: 1.into() }),
]);
vec![// Removed due to being a tail call
// Some(StacktraceFrame { name: f.clone(), line: 9 }),
Some(StacktraceFrame {
name: g.clone(),
line: 7.into(),
}),
Some(StacktraceFrame {
name: f.clone(),
line: 6.into(),
}),
Some(StacktraceFrame {
name: g.clone(),
line: 7.into(),
}),
Some(StacktraceFrame {
name: f.clone(),
line: 6.into(),
}),
Some(StacktraceFrame {
name: g.clone(),
line: 7.into(),
}),
Some(StacktraceFrame {
name: f.clone(),
line: 4.into(),
}),
Some(StacktraceFrame {
name: end.clone(),
line: 1.into(),
})]);
}
Err(err) => panic!("Unexpected error `{}`", err),
Ok(_) => panic!("Expected an error"),
Expand Down
17 changes: 10 additions & 7 deletions vm/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use vm::GlobalVmState;
use source_map::SourceMap;
use self::Variable::*;

use Result;
use {Error, Result};

pub type CExpr = SpannedExpr<Symbol>;

Expand Down Expand Up @@ -440,7 +440,7 @@ impl<'a> Compiler<'a> {
Ok(function)
}

fn load_identifier(&self, id: &Symbol, function: &mut FunctionEnvs) {
fn load_identifier(&self, id: &Symbol, function: &mut FunctionEnvs) -> Result<()> {
match self.find(id, function)
.unwrap_or_else(|| panic!("Undefined variable {}", self.symbols.string(&id))) {
Stack(index) => function.emit(Push(index)),
Expand All @@ -453,8 +453,11 @@ impl<'a> Compiler<'a> {
args: 0,
})
}
Constructor(..) => panic!("Constructor {:?} is not fully applied", id),
Constructor(..) => {
return Err(Error::Message(format!("Constructor `{}` is not fully applied", id)))
}
}
Ok(())
}

fn compile(&mut self,
Expand Down Expand Up @@ -504,7 +507,7 @@ impl<'a> Compiler<'a> {
Literal::Char(c) => function.emit(PushInt(c as isize)),
}
}
Expr::Ident(ref id) => self.load_identifier(&id.name, function),
Expr::Ident(ref id) => self.load_identifier(&id.name, function)?,
Expr::IfElse(ref pred, ref if_true, ref if_false) => {
self.compile(&**pred, function, false)?;
let jump_index = function.function.instructions.len();
Expand Down Expand Up @@ -570,7 +573,7 @@ impl<'a> Compiler<'a> {
"#Float<" => FloatLT,
"#Float==" => FloatEQ,
_ => {
self.load_identifier(&op.name, function);
self.load_identifier(&op.name, function)?;
Call(2)
}
};
Expand Down Expand Up @@ -689,7 +692,7 @@ impl<'a> Compiler<'a> {
// Create a catch all to prevent us from running into undefined behaviour
if !catch_all {
let error_fn = self.symbols.symbol("#error");
self.load_identifier(&error_fn, function);
self.load_identifier(&error_fn, function)?;
function.emit_string(self.intern("Non-exhaustive pattern")?);
function.emit(Call(1));
// The stack has been increased by 1 here but it should not affect compiling the
Expand Down Expand Up @@ -759,7 +762,7 @@ impl<'a> Compiler<'a> {
for field in fields {
match field.1 {
Some(ref field_expr) => self.compile(field_expr, function, false)?,
None => self.load_identifier(&field.0, function),
None => self.load_identifier(&field.0, function)?,
}
}
let index =
Expand Down

0 comments on commit 6fb552e

Please sign in to comment.