Skip to content

Commit

Permalink
fix(check): Don't guess a record type when the field list is empty
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Apr 9, 2017
1 parent 130a6ec commit 9db233a
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 18 deletions.
13 changes: 10 additions & 3 deletions check/src/typecheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,16 @@ impl<'a> Typecheck<'a> {
}

fn find_record(&self, fields: &[Symbol]) -> TcResult<(ArcType, ArcType)> {
self.environment
.find_record(fields)
.ok_or(TypeError::UndefinedRecord { fields: fields.to_owned() })
// If fields is empty it is going to match any record which means this function probably
// returns the wron record as the record we expect can still contain type fields.
// Just return an error so that inference continues without any guessed record type.
if fields.is_empty() {
Err(TypeError::UndefinedRecord { fields: fields.to_owned() })
} else {
self.environment
.find_record(fields)
.ok_or(TypeError::UndefinedRecord { fields: fields.to_owned() })
}
}

fn find_type_info(&self, id: &Symbol) -> TcResult<&Alias<Symbol, ArcType>> {
Expand Down
14 changes: 13 additions & 1 deletion check/tests/pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,6 @@ type Bar = Test Foo
assert!(result.is_ok(), "{}", result.unwrap_err());
}


/// Check that after typechecking, the resulting types are `Alias`, not `Ident`. This is necessary
/// so that when the type is later propagated it knows what its internal representation are without
/// any extra information
Expand All @@ -912,6 +911,18 @@ Test 0
ref typ => panic!("Expected alias, got {:?}", typ),
}
}
#[test]
fn dont_guess_a_record_when_the_construction_has_no_fields() {
let _ = ::env_logger::init();
let text = r#"
type Test = { x : Int }
type Test2 = Int
{ Test2 }
"#;
let result = support::typecheck(text);
assert!(result.is_ok(), "{}", result.unwrap_err());
}

#[test]
fn simple_tuple_type() {
Expand Down Expand Up @@ -975,3 +986,4 @@ match () with

assert_eq!(result, Ok(Type::unit()));
}

24 changes: 14 additions & 10 deletions examples/http.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#[macro_use]
extern crate gluon_base as base;
#[macro_use]
extern crate gluon_vm as vm;
Expand Down Expand Up @@ -59,7 +58,11 @@ impl<'vm> Pushable<'vm> for Wrap<Method> {
Get => 0,
Post => 1,
Delete => 2,
_ => return Err(VmError::Message(format!("Method `{:?}` does not exist in gluon", self.0)).into()),
_ => {
return Err(VmError::Message(format!("Method `{:?}` does not exist in gluon",
self.0))
.into())
}
}));
Ok(())
}
Expand All @@ -78,7 +81,7 @@ fn listen(port: i32, value: WithVM<OpaqueValue<RootedThread, Handler<Response>>>
use self::hyper::server::Response as HyperResponse;

let server = Server::http(("localhost", port as u16)).unwrap();
type ListenFn = fn (OpaqueValue<RootedThread, Handler<Response>>, Request) -> IO<Response>;
type ListenFn = fn(OpaqueValue<RootedThread, Handler<Response>>, Request) -> IO<Response>;
let handle: Function<RootedThread, ListenFn> = thread.get_global("std.http.handle")
.unwrap_or_else(|err| panic!("{}", err));
let result = server.handle(move |request: HyperRequest, response: HyperResponse<_>| {
Expand All @@ -96,12 +99,13 @@ fn listen(port: i32, value: WithVM<OpaqueValue<RootedThread, Handler<Response>>>
});
match result {
Ok(_) => IO::Value(()),
Err(err) => IO::Exception(err.to_string())
Err(err) => IO::Exception(err.to_string()),
}
}

pub fn load(vm: &Thread) -> Result<()> {
vm.define_global("http_prim", record! {
vm.define_global("http_prim",
record! {
listen => primitive!(2 listen)
})?;
Ok(())
Expand All @@ -111,14 +115,14 @@ fn main() {
let port = env::args().nth(1).map(|port| port.parse::<i32>().expect("port")).unwrap_or(80);

let expr = r#"
let prelude = import "std/prelude.glu"
let prelude = import! "std/prelude.glu"
let { show } = prelude.show_Int
let string = import "std/string.glu"
let string = import! "std/string.glu"
let { (<>) } = prelude.make_Monoid string.monoid
let { (*>) } = prelude.make_Applicative prelude.applicative_IO
let { handle, get, applicative } = import "std/http.glu"
let { handle, get, applicative } = import! "std/http.glu"
let { (*>), pure } = prelude.make_Applicative applicative
let handler = get (pure { body = "Hello World" })
Expand All @@ -129,14 +133,14 @@ fn main() {
"#;
let thread = new_vm();
Compiler::new()
.run_expr::<()>(&thread, "", r#"let _ = import "std/http.glu" in () "#)
.run_expr::<()>(&thread, "", r#"let _ = import! "std/http.glu" in () "#)
.unwrap_or_else(|err| panic!("{}", err));
load(&thread).unwrap();

let (mut listen, _) = Compiler::new()
.run_expr::<FunctionRef<fn(i32) -> IO<()>>>(&thread, "http_test", expr)
.unwrap_or_else(|err| panic!("{}", err));

listen.call(port)
.unwrap_or_else(|err| panic!("{}", err));
}
3 changes: 0 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
extern crate log;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate collect_mac;

extern crate futures;

#[macro_use]
Expand Down
2 changes: 1 addition & 1 deletion std/http.glu
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let prelude = import "std/prelude.glu"
let prelude = import! "std/prelude.glu"
let { Functor, Applicative, Alternative, Monad } = prelude
let { (<<), id } = prelude.make_Category prelude.category_Function
let { pure } = prelude.applicative_IO
Expand Down

0 comments on commit 9db233a

Please sign in to comment.