From 248387d9c8d8121ab0f25645f79f7a47aeedfb25 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Tue, 3 Dec 2019 19:52:58 +0100 Subject: [PATCH] fix(check): Reject programs which misspecifies the number of patterns ... in a constructor Fixes #807 --- check/src/typecheck.rs | 26 ++++++++++++++++++-------- check/src/typecheck/error.rs | 15 ++++++++++++--- check/tests/fail.rs | 11 +++++++++++ 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs index 4b262ae251..1fea58afb4 100644 --- a/check/src/typecheck.rs +++ b/check/src/typecheck.rs @@ -403,7 +403,10 @@ impl<'a> Typecheck<'a> { | Message(_) => (), NotAFunction(ref mut typ) | UndefinedField(ref mut typ, _) - | PatternError(ref mut typ, _) + | PatternError { + constructor_type: ref mut typ, + .. + } | InvalidProjection(ref mut typ) | TypeConstructorReturnsWrongType { actual: ref mut typ, @@ -1721,16 +1724,23 @@ impl<'a> Typecheck<'a> { fn typecheck_pattern_rec( &mut self, args: &mut [SpannedPattern], - mut typ: &RcType, + typ: &RcType, ) -> TcResult { - let len = args.len(); - for arg_pattern in args { - match typ.as_function() { - Some((arg, ret)) => { + let pattern_args = args.len(); + let mut pattern_iter = args.iter_mut(); + let mut type_iter = typ.arg_iter(); + loop { + match (pattern_iter.next(), type_iter.next()) { + (Some(arg_pattern), Some(arg)) => { self.typecheck_pattern(arg_pattern, ModType::wobbly(arg.clone()), arg.clone()); - typ = ret; } - None => return Err(TypeError::PatternError(typ.clone(), len)), + (None, Some(_)) | (Some(_), None) => { + return Err(TypeError::PatternError { + constructor_type: typ.clone(), + pattern_args, + }) + } + (None, None) => break, } } Ok(typ.clone()) diff --git a/check/src/typecheck/error.rs b/check/src/typecheck/error.rs index ec5fd0ca3f..f32f24391f 100644 --- a/check/src/typecheck/error.rs +++ b/check/src/typecheck/error.rs @@ -30,7 +30,10 @@ pub enum TypeError { /// Type were expected to have a certain field UndefinedField(T, I), /// Constructor type was found in a pattern but did not have the expected number of arguments - PatternError(T, usize), + PatternError { + constructor_type: T, + pattern_args: usize, + }, /// Errors found when trying to unify two types Unification(T, T, Vec>), /// Error were found when trying to unify the kinds of two types @@ -176,8 +179,14 @@ where } write!(f, "{}", errors.last().unwrap()) } - PatternError(typ, expected_len) => { - write!(f, "Type {} has {} to few arguments", typ, expected_len) + PatternError { constructor_type, pattern_args } => { + write!( + f, + "Matching on constructor `{}` requires `{}` arguments but the pattern specifies `{}`", + constructor_type, + constructor_type.arg_iter().count(), + pattern_args + ) } KindError(err) => kindcheck::fmt_kind_error(err, f), RecursionCheck(err) => write!(f, "{}", err), diff --git a/check/tests/fail.rs b/check/tests/fail.rs index a41aaebeb7..685131a2e6 100644 --- a/check/tests/fail.rs +++ b/check/tests/fail.rs @@ -836,3 +836,14 @@ let alternative : Alternative (Eff (HttpEffect r)) = alt.alternative "#, UndefinedField(..) } + +test_check_err! { + issue_807_pattern_match_arg_mismatch, + r#" +type Test = | Test Int + +match Test 0 with +| Test -> () +"#, +PatternError { .. } +}