diff --git a/sieve/errors/match-type-errors.sieve b/sieve/errors/match-type-errors.sieve
deleted file mode 100644
index f2b08be9f81f13c9c538e007f7e23aed7690d7c6..0000000000000000000000000000000000000000
--- a/sieve/errors/match-type-errors.sieve
+++ /dev/null
@@ -1,16 +0,0 @@
-require "comparator-i;ascii-numeric";
-
-if address :contains :is :comparator "i;ascii-casemap" :localpart "from" "STEPHAN" {
-	discard;
-
-	if address :contains :domain :comparator "i;octet" :matches "from" "drunksnipers.com" {
-		keep;
-	}
-	stop;
-}
-
-if header :contains :comparator "i;ascii-numeric" "from" "drunksnipers.com" {
-    keep;
-}
-
-keep;
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index f8c8deaa3ad2bc463de633e1a1fe6a500c49f495..5dba8dd295cd4fa18580ce0d2b1fdbd4d2a1b3e6 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -280,7 +280,8 @@ static bool tst_envelope_validate
 		return FALSE;
 
 	/* Validate the key argument to a specified match type */
-	return sieve_match_type_validate(validator, tst, arg);
+	return sieve_match_type_validate
+		(validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator);
 }
 
 /*
diff --git a/src/lib-sieve/plugins/body/tst-body.c b/src/lib-sieve/plugins/body/tst-body.c
index 1d58e30f1de0fa0313bab4c0be0c1322f2d01c82..5ea705450f64e317cb23b4ed214bca91eebe0972 100644
--- a/src/lib-sieve/plugins/body/tst-body.c
+++ b/src/lib-sieve/plugins/body/tst-body.c
@@ -207,7 +207,8 @@ static bool tst_body_validate
 		return FALSE;
 
 	/* Validate the key argument to a specified match type */
-	return sieve_match_type_validate(validator, tst, arg);
+	return sieve_match_type_validate
+		(validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator);
 }
 
 /*
diff --git a/src/lib-sieve/plugins/imapflags/tst-hasflag.c b/src/lib-sieve/plugins/imapflags/tst-hasflag.c
index cf1115149d54e108898908ef52bd6c6e531c874d..54afc918470a44307b07185808998e1f5d10dc6e 100644
--- a/src/lib-sieve/plugins/imapflags/tst-hasflag.c
+++ b/src/lib-sieve/plugins/imapflags/tst-hasflag.c
@@ -103,7 +103,8 @@ static bool tst_hasflag_validate
 	}
 	
 	/* Validate the key argument to a specified match type */
-	return sieve_match_type_validate(validator, tst, keys);
+	return sieve_match_type_validate
+		(validator, tst, keys, &is_match_type, &i_ascii_casemap_comparator);
 }
 
 /*
diff --git a/src/lib-sieve/plugins/regex/mcht-regex.c b/src/lib-sieve/plugins/regex/mcht-regex.c
index d38ba333815ee5c9bd3c5cb42ee745e648543d74..a7935c2f1750df58c4d943c58eea880abde91ed3 100644
--- a/src/lib-sieve/plugins/regex/mcht-regex.c
+++ b/src/lib-sieve/plugins/regex/mcht-regex.c
@@ -127,18 +127,15 @@ bool mcht_regex_validate_context
 (struct sieve_validator *validator, struct sieve_ast_argument *arg ATTR_UNUSED,
 	struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg)
 {
+	const struct sieve_comparator *cmp = ctx->comparator;
 	int cflags = REG_EXTENDED | REG_NOSUB;
 	struct _regex_key_context keyctx;
-	struct sieve_ast_argument *cmp_arg;
 	struct sieve_ast_argument *kitem;
 
-	cmp_arg = sieve_command_find_argument(ctx->command_ctx, &comparator_tag);	
-	if ( cmp_arg != NULL ) { 
-		/* FIXME: new commands might use incompatible default comparator */
-		
-		if ( sieve_comparator_tag_is(cmp_arg, &i_ascii_casemap_comparator) )
+	if ( cmp != NULL ) { 
+		if ( cmp == &i_ascii_casemap_comparator )
 			cflags =  REG_EXTENDED | REG_NOSUB | REG_ICASE;
-		else if ( sieve_comparator_tag_is(cmp_arg, &i_octet_comparator) )
+		else if ( cmp == &i_octet_comparator )
 			cflags =  REG_EXTENDED | REG_NOSUB;
 		else {
 			sieve_command_validate_error(validator, ctx->command_ctx, 
@@ -150,14 +147,14 @@ bool mcht_regex_validate_context
 
 	/* Validate regular expression keys */
 
-    keyctx.valdtr = validator;
+	keyctx.valdtr = validator;
 	keyctx.mctx = ctx;
 	keyctx.cflags = cflags;
 
 	kitem = key_arg;
-    if ( !sieve_ast_stringlist_map(&kitem, (void *) &keyctx,
+	if ( !sieve_ast_stringlist_map(&kitem, (void *) &keyctx,
 		mcht_regex_validate_key_argument) )
-        return FALSE;
+		return FALSE;
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/variables/tst-string.c b/src/lib-sieve/plugins/variables/tst-string.c
index a80eabd3c7d3f070cc9096ff8ea8cceb9bb39b0e..04c05b73fd9e73c5e1c62932471e82a81c9d9608 100644
--- a/src/lib-sieve/plugins/variables/tst-string.c
+++ b/src/lib-sieve/plugins/variables/tst-string.c
@@ -110,7 +110,8 @@ static bool tst_string_validate
 		return FALSE;
 
 	/* Validate the key argument to a specified match type */
-	return sieve_match_type_validate(validator, tst, arg);
+	return sieve_match_type_validate
+		(validator, tst, arg, &is_match_type, &i_octet_comparator);
 }
 
 /* 
diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h
index 76fa69beb81cb2d6826156feeba57bea32577e3d..c3adb7199c97509a094fd55f0ee78ac0eb559f6b 100644
--- a/src/lib-sieve/sieve-comparators.h
+++ b/src/lib-sieve/sieve-comparators.h
@@ -5,8 +5,9 @@
 #define __SIEVE_COMPARATORS_H
 
 #include "sieve-common.h"
-#include "sieve-objects.h"
 #include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-objects.h"
 #include "sieve-code.h"
 
 /* 
@@ -63,6 +64,12 @@ struct sieve_comparator {
  
 extern const struct sieve_argument comparator_tag;
 
+static inline bool sieve_argument_is_comparator
+	(struct sieve_ast_argument *arg) 
+{
+	return arg->argument == &comparator_tag;
+}
+
 void sieve_comparators_link_tag
 	(struct sieve_validator *validator, 
 		struct sieve_command_registration *cmd_reg,	int id_code);
diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c
index 1153a4901ab256d4dedbe27a94137f65042f8a23..be1af4c64efe6d3b71534eb86bc457744e95699c 100644
--- a/src/lib-sieve/sieve-match-types.c
+++ b/src/lib-sieve/sieve-match-types.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file
+ */
+ 
 #include <stdio.h>
 
 #include "lib.h"
@@ -362,6 +365,7 @@ static bool tag_match_type_is_instance_of
 	mtctx = p_new(sieve_command_pool(cmd), struct sieve_match_type_context, 1);
 	mtctx->match_type = mtch;
 	mtctx->command_ctx = cmd;
+	mtctx->comparator = NULL; /* Can be filled in later */
 	
 	arg->context = (void *) mtctx;
 	
@@ -406,52 +410,69 @@ static bool tag_match_type_generate
 	return TRUE;
 }
 
-bool sieve_match_type_validate_argument
-(struct sieve_validator *validator, struct sieve_ast_argument *arg,
-	struct sieve_ast_argument *key_arg )
-{
-	struct sieve_match_type_context *mtctx = 
-		(struct sieve_match_type_context *) arg->context;
-
-	i_assert(arg->argument == &match_type_tag);
-
-	/* Check whether this match type requires additional validation. 
-	 * Additional validation can override the match type recorded in the context 
-	 * for later code generation. 
-	 */
-	if ( mtctx != NULL && mtctx->match_type != NULL &&
-		mtctx->match_type->validate_context != NULL ) {
-		return mtctx->match_type->validate_context(validator, arg, mtctx, key_arg);
-	}
-	
-	return TRUE;
+void sieve_match_types_link_tags
+	(struct sieve_validator *validator, 
+		struct sieve_command_registration *cmd_reg, int id_code) 
+{	
+	sieve_validator_register_tag
+		(validator, cmd_reg, &match_type_tag, id_code); 	
 }
 
+/*
+ * Validation
+ */
+
 bool sieve_match_type_validate
 (struct sieve_validator *validator, struct sieve_command_context *cmd,
-	struct sieve_ast_argument *key_arg )
+	struct sieve_ast_argument *key_arg, 
+	const struct sieve_match_type *mcht_default, 
+	const struct sieve_comparator *cmp_default)
 {
 	struct sieve_ast_argument *arg = sieve_command_first_argument(cmd);
+	struct sieve_ast_argument *mt_arg = NULL;
+	struct sieve_match_type_context *mtctx;
+	const struct sieve_match_type *mcht = NULL;
+	const struct sieve_comparator *cmp = NULL;
 
+	/* Find match type and comparator among the arguments */
 	while ( arg != NULL && arg != cmd->first_positional ) {
-		if ( arg->argument == &match_type_tag ) {
-			if ( !sieve_match_type_validate_argument(validator, arg, key_arg) ) 
-				return FALSE;
+		if ( sieve_argument_is_comparator(arg) ) {
+			cmp = sieve_comparator_tag_get(arg);
+			if ( mt_arg != NULL ) break;
+		}
+
+		if ( sieve_argument_is_match_type(arg) ) {
+			mt_arg = arg;
+			if ( cmp != NULL ) break;
 		}
 		arg = sieve_ast_argument_next(arg);
 	}
+	
+	/* Verify using the default comparator if none is specified explicitly */
+	if ( cmp == NULL )
+		cmp = cmp_default;
+	
+	/* Verify the default match type if none is specified explicitly */
+	if ( mt_arg == NULL || mt_arg->context == NULL ) {
+		mtctx = NULL;
+		mcht = mcht_default;
+	} else {
+		mtctx = (struct sieve_match_type_context *) mt_arg->context;
+		mcht = mtctx->match_type;
+		mtctx->comparator = cmp;
+	}
 
+	/* Check whether this match type requires additional validation. 
+	 * Additional validation can override the match type recorded in the context 
+	 * for later code generation. 
+	 */
+	if ( mcht != NULL && mcht->validate_context != NULL ) {
+		return mcht->validate_context(validator, mt_arg, mtctx, key_arg);
+	}
+	
 	return TRUE;	
 }
 
-void sieve_match_types_link_tags
-	(struct sieve_validator *validator, 
-		struct sieve_command_registration *cmd_reg, int id_code) 
-{	
-	sieve_validator_register_tag
-		(validator, cmd_reg, &match_type_tag, id_code); 	
-}
-
 /*
  * Match-type operand
  */
@@ -471,35 +492,27 @@ const struct sieve_operand match_type_operand = {
 };
 
 /*
- * Matching
+ * Common validation implementation
  */
 
 bool sieve_match_substring_validate_context
-(struct sieve_validator *validator, struct sieve_ast_argument *arg,
-    struct sieve_match_type_context *ctx, 
+(struct sieve_validator *validator, struct sieve_ast_argument *arg ATTR_UNUSED,
+	struct sieve_match_type_context *ctx,
 	struct sieve_ast_argument *key_arg ATTR_UNUSED)
 {
-	struct sieve_ast_argument *carg =
-		sieve_command_first_argument(ctx->command_ctx);
-
-    while ( carg != NULL && carg != ctx->command_ctx->first_positional ) {
-		if ( carg != arg && carg->argument == &comparator_tag ) {
-			const struct sieve_comparator *cmp =
-				sieve_comparator_tag_get(carg);
+	const struct sieve_comparator *cmp = ctx->comparator;
+		
+	if ( cmp == NULL )
+		return TRUE;
 			
-			if ( (cmp->flags & SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH) == 0 ) {
-				sieve_command_validate_error(validator, ctx->command_ctx,
-					"the specified %s comparator does not support "
-					"sub-string matching as required by the :%s match type",
-					cmp->object.identifier, ctx->match_type->object.identifier );
-
-				return FALSE;
-			}
-			return TRUE;
-		}
+	if ( (cmp->flags & SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH) == 0 ) {
+		sieve_command_validate_error(validator, ctx->command_ctx,
+			"the specified %s comparator does not support "
+			"sub-string matching as required by the :%s match type",
+			cmp->object.identifier, ctx->match_type->object.identifier );
 
-		carg = sieve_ast_argument_next(carg);
+		return FALSE;
 	}
-
+	
 	return TRUE;
 } 
diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h
index 87da2a3edccd0232bae6b9e3ce1479e0a0b8b5b1..775d67a6bce48de43a3e5602a26b4888342f42e5 100644
--- a/src/lib-sieve/sieve-match-types.h
+++ b/src/lib-sieve/sieve-match-types.h
@@ -1,11 +1,21 @@
+/* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file
+ */
+ 
 #ifndef __SIEVE_MATCH_TYPES_H
 #define __SIEVE_MATCH_TYPES_H
 
 #include "sieve-common.h"
 #include "sieve-extensions.h"
+#include "sieve-commands.h"
 #include "sieve-code.h"
 #include "sieve-objects.h"
 
+/*
+ * Types
+ */
+
+struct sieve_match_type_context;
+
 /*
  * Core match types 
  */
@@ -21,9 +31,10 @@ extern const struct sieve_match_type is_match_type;
 extern const struct sieve_match_type contains_match_type;
 extern const struct sieve_match_type matches_match_type;
 
-struct sieve_match_type;
-struct sieve_match_type_context;
-
+/*
+ * Match type object
+ */
+ 
 struct sieve_match_type {
 	struct sieve_object object;
 
@@ -50,11 +61,11 @@ struct sieve_match_type {
 
 	void (*match_init)(struct sieve_match_context *mctx);
 
-	/* WARNING: some tests may pass a val == NULL parameter indicating that the passed
-	 * value has no significance. For string-type matches this should map to the empty
-	 * string "", but for match types that consider the passed values as objects rather
-	 * than strings (e.g. :count) this means that the passed value should be skipped.
-	 * This is currently only used by string test of the variables extension.
+	/* WARNING: some tests may pass a val == NULL parameter indicating that the 
+	 * passed value has no significance. For string-type matches this should map 
+	 * to the empty string "", but for match types that consider the passed values 
+	 * as objects rather than strings (e.g. :count) this means that the passed 
+	 * value should be skipped. 
 	 */
 	int (*match)
 		(struct sieve_match_context *mctx, const char *val, size_t val_size, 
@@ -66,6 +77,9 @@ struct sieve_match_type_context {
 	struct sieve_command_context *command_ctx;
 	const struct sieve_match_type *match_type;
 	
+	/* Only filled in when match_type->validate_context() is called */
+	const struct sieve_comparator *comparator;
+	
 	/* Context data could be used in the future to pass data between validator and
 	 * generator in match types that use extra parameters. Currently not 
 	 * necessary, not even for the relational extension.
@@ -73,7 +87,18 @@ struct sieve_match_type_context {
 	void *ctx_data;
 };
 
-/* Match values */
+/*
+ * Match type registration
+ */
+
+void sieve_match_type_register
+	(struct sieve_validator *validator, const struct sieve_match_type *mcht);
+const struct sieve_match_type *sieve_match_type_find
+	(struct sieve_validator *validator, const char *identifier);
+
+/* 
+ * Match values 
+ */
 
 struct sieve_match_values;
 
@@ -98,29 +123,34 @@ void sieve_match_values_commit
 void sieve_match_values_abort
 	(struct sieve_match_values **mvalues);
 	
-	
 void sieve_match_values_get
 	(struct sieve_interpreter *interp, unsigned int index, string_t **value_r);
 
-/* ... */
+/*
+ * Match type tagged argument 
+ */
+
+extern const struct sieve_argument match_type_tag;
+
+static inline bool sieve_argument_is_match_type
+	(struct sieve_ast_argument *arg)
+{
+	return ( arg->argument == &match_type_tag );
+}
 
 void sieve_match_types_link_tags
 	(struct sieve_validator *validator, 
 		struct sieve_command_registration *cmd_reg, int id_code);
-bool sieve_match_type_validate_argument
-(struct sieve_validator *validator, struct sieve_ast_argument *arg,
-	struct sieve_ast_argument *key_arg);
-bool sieve_match_type_validate
-(struct sieve_validator *validator, struct sieve_command_context *cmd,
-	struct sieve_ast_argument *key_arg);
-		
-void sieve_match_type_register
-	(struct sieve_validator *validator, 
-	const struct sieve_match_type *addrp);
-const struct sieve_match_type *sieve_match_type_find
-	(struct sieve_validator *validator, const char *identifier);
 
-extern const struct sieve_argument match_type_tag;
+/*
+ * Validation
+ */
+
+bool sieve_match_type_validate
+	(struct sieve_validator *validator, struct sieve_command_context *cmd,
+		struct sieve_ast_argument *key_arg, 
+		const struct sieve_match_type *mcht_default, 
+		const struct sieve_comparator *cmp_default);
 
 /*
  * Match type operand
@@ -159,11 +189,11 @@ static inline bool sieve_opr_match_type_dump
 		(denv, &sieve_match_type_operand_class, address, NULL);
 }
 
-/* Match Utility */
+/* Common validation implementation */
 
 bool sieve_match_substring_validate_context
-(struct sieve_validator *validator, struct sieve_ast_argument *arg,
-    struct sieve_match_type_context *ctx, 
-	struct sieve_ast_argument *key_arg);
+	(struct sieve_validator *validator, struct sieve_ast_argument *arg,
+		struct sieve_match_type_context *ctx, 
+		struct sieve_ast_argument *key_arg);
 
 #endif /* __SIEVE_MATCH_TYPES_H */
diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c
index 2cf3685ef8e91eac46275ba3e548492f459b4f09..afbe9ec75dd50a1187072794826e5f513fb7cdc3 100644
--- a/src/lib-sieve/tst-address.c
+++ b/src/lib-sieve/tst-address.c
@@ -168,7 +168,8 @@ static bool tst_address_validate
 		return FALSE;
 	
 	/* Validate the key argument to a specified match type */
-	return sieve_match_type_validate(validator, tst, arg);
+	return sieve_match_type_validate
+		(validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator); 
 }
 
 /* 
diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c
index 4335aab70cc6d14449889ba81b5a25dcd2eb5648..934d5996403410561b1f0d1671290d9501d5c0bb 100644
--- a/src/lib-sieve/tst-header.c
+++ b/src/lib-sieve/tst-header.c
@@ -99,7 +99,8 @@ static bool tst_header_validate
 		return FALSE;
 
 	/* Validate the key argument to a specified match type */
-	return sieve_match_type_validate(validator, tst, arg);
+	return sieve_match_type_validate
+		(validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator);
 }
 
 /*
diff --git a/src/testsuite/tst-test-error.c b/src/testsuite/tst-test-error.c
index 07a8811808c7dceddb48ed53a12fffcdbe9b45d1..772787f4b199628fb4c0da950b931d473e9fe10c 100644
--- a/src/testsuite/tst-test-error.c
+++ b/src/testsuite/tst-test-error.c
@@ -143,7 +143,8 @@ static bool tst_test_error_validate
         return FALSE;
 
     /* Validate the key argument to a specified match type */
-    return sieve_match_type_validate(valdtr, tst, arg);
+    return sieve_match_type_validate
+		(valdtr, tst, arg, &is_match_type, &i_octet_comparator);
 }
 
 /* 
diff --git a/tests/compile/errors.svtest b/tests/compile/errors.svtest
index bcc5a44bf25edc28402e4948e8b7342213abd7aa..af68e17e808cd82f494a0d345720c0a5ce2ead29 100644
--- a/tests/compile/errors.svtest
+++ b/tests/compile/errors.svtest
@@ -256,6 +256,20 @@ test "ADDRESS-PART errors (FIXME: count only)" {
     }
 }
 
+/*
+ * MATCH-TYPE errors
+ */
+
+test "MATCH-TYPE errors (FIXME: count only)" {
+    if test_compile "errors/match-type.sieve" {
+        test_fail "compile should have failed.";
+    }
+
+    if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+        test_fail "wrong number of errors reported";
+    }
+}
+
 /*
  * Encoded-character errors
  */
diff --git a/tests/compile/errors/match-type.sieve b/tests/compile/errors/match-type.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..4df4564054b9101262551a0078141ad61a33bd29
--- /dev/null
+++ b/tests/compile/errors/match-type.sieve
@@ -0,0 +1,7 @@
+require "comparator-i;ascii-numeric";
+
+if header :contains :comparator "i;ascii-numeric" "from" "drunksnipers.com" {
+    keep;
+}
+
+keep;