From 9db233a06dd712eabefdcbb67e07550718bdd998 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sat, 17 Dec 2016 00:11:21 +0100 Subject: [PATCH] fix(check): Don't guess a record type when the field list is empty --- check/src/typecheck.rs | 13 ++++++++++--- check/tests/pass.rs | 14 +++++++++++++- examples/http.rs | 24 ++++++++++++++---------- src/lib.rs | 3 --- std/http.glu | 2 +- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs index 2aa4f23cbe..449c6a817d 100644 --- a/check/src/typecheck.rs +++ b/check/src/typecheck.rs @@ -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> { diff --git a/check/tests/pass.rs b/check/tests/pass.rs index e5b7d594a9..25ee43bfc5 100644 --- a/check/tests/pass.rs +++ b/check/tests/pass.rs @@ -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 @@ -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() { @@ -975,3 +986,4 @@ match () with assert_eq!(result, Ok(Type::unit())); } + diff --git a/examples/http.rs b/examples/http.rs index 1a93cd5d13..6b2d92c065 100644 --- a/examples/http.rs +++ b/examples/http.rs @@ -1,4 +1,3 @@ -#[macro_use] extern crate gluon_base as base; #[macro_use] extern crate gluon_vm as vm; @@ -59,7 +58,11 @@ impl<'vm> Pushable<'vm> for Wrap { 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(()) } @@ -78,7 +81,7 @@ fn listen(port: i32, value: WithVM>> use self::hyper::server::Response as HyperResponse; let server = Server::http(("localhost", port as u16)).unwrap(); - type ListenFn = fn (OpaqueValue>, Request) -> IO; + type ListenFn = fn(OpaqueValue>, Request) -> IO; let handle: Function = thread.get_global("std.http.handle") .unwrap_or_else(|err| panic!("{}", err)); let result = server.handle(move |request: HyperRequest, response: HyperResponse<_>| { @@ -96,12 +99,13 @@ fn listen(port: i32, value: WithVM>> }); 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(()) @@ -111,14 +115,14 @@ fn main() { let port = env::args().nth(1).map(|port| port.parse::().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" }) @@ -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:: IO<()>>>(&thread, "http_test", expr) .unwrap_or_else(|err| panic!("{}", err)); - + listen.call(port) .unwrap_or_else(|err| panic!("{}", err)); } diff --git a/src/lib.rs b/src/lib.rs index c238d21dfe..0bd10c6bc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,9 +8,6 @@ extern crate log; #[macro_use] extern crate quick_error; -#[macro_use] -extern crate collect_mac; - extern crate futures; #[macro_use] diff --git a/std/http.glu b/std/http.glu index 08b76870a9..860ebbf07f 100644 --- a/std/http.glu +++ b/std/http.glu @@ -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