Skip to content

Commit

Permalink
fix: Error on undefined variables in type bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Oct 14, 2017
1 parent 21e23f8 commit ed44211
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 5 deletions.
35 changes: 33 additions & 2 deletions check/src/typecheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use itertools::Itertools;

use base::scoped_map::ScopedMap;
use base::ast::{DisplayEnv, Expr, Literal, MutVisitor, Pattern, PatternField, SpannedExpr};
use base::ast::{SpannedIdent, SpannedPattern, TypeBinding, ValueBinding};
use base::ast::{AstType, SpannedIdent, SpannedPattern, TypeBinding, ValueBinding};
use base::error::Errors;
use base::fnv::{FnvMap, FnvSet};
use base::resolve;
Expand Down Expand Up @@ -1230,7 +1230,38 @@ impl<'a> Typecheck<'a> {
// Rename the aliase's name to its global name
bind.alias.value.name = new;

resolved_aliases.push(types::translate_alias(&self.type_cache, &bind.alias.value));
fn check_undefined_variables(
self_: &mut Typecheck,
args: &[Generic<Symbol>],
typ: &AstType<Symbol>,
) {
use base::pos::HasSpan;
match **typ {
Type::Generic(ref id) => if args.iter().all(|arg| arg.id != id.id) {
self_.error(
typ.span(),
TypeError::UndefinedVariable(id.id.clone()).into(),
);
},
Type::Record(_) => {
// Inside records variables are bound implicitly to the closest field
// so variables are allowed to be undefined/implicit
}
_ => {
types::walk_move_type_opt(
typ,
&mut types::ControlVisitation(|typ: &AstType<_>| {
check_undefined_variables(self_, args, typ);
None
}),
);
}
}
}
check_undefined_variables(self, &bind.alias.value.args, bind.alias.value.unresolved_type());

let alias = types::translate_alias(&self.type_cache, &bind.alias.value);
resolved_aliases.push(alias);
}

for alias in &mut resolved_aliases {
Expand Down
30 changes: 27 additions & 3 deletions check/tests/fail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ macro_rules! assert_multi_unify_err {
}
None => {
assert!(false,
"Found less errors than expected at {}.\nErrors:\n{}\nbut expected {}",
"Found less errors than expected at {}.\n\
Errors:\n{}\nbut expected {}",
i,
error,
stringify!($id)
Expand All @@ -99,7 +100,8 @@ macro_rules! assert_multi_unify_err {
error);
}
_ => assert!(false,
"Found errors at {}:\n{}\nbut expected an unification error",
"Found errors at {}:\n\
{}\nbut expected an unification error",
i,
error)
}
Expand Down Expand Up @@ -561,4 +563,26 @@ fn record_base_not_record() {
"#;
let result = support::typecheck(text);
assert_unify_err!(result, TypeMismatch(..));
}
}

#[test]
fn undefined_type_variable() {
let _ = ::env_logger::init();
let text = r#"
type Test = a
()
"#;
let result = support::typecheck(text);
assert_err!(result, UndefinedVariable(..));
}

#[test]
fn undefined_type_variable_in_enum() {
let _ = ::env_logger::init();
let text = r#"
type Test = | Test a
()
"#;
let result = support::typecheck(text);
assert_err!(result, UndefinedVariable(..));
}
13 changes: 13 additions & 0 deletions check/tests/pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,3 +1148,16 @@ let record = { x = 1 }
))
);
}

#[test]
fn undefined_type_variable_in_record() {
let _ = ::env_logger::init();
let text = r#"
type Test = {
x: a
}
()
"#;
let result = support::typecheck(text);
assert!(result.is_ok(), "{}", result.unwrap_err());
}

0 comments on commit ed44211

Please sign in to comment.