function as argument checks for the complete signature.
diff --git a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/validation/TypeInfoValidator.java b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/validation/TypeInfoValidator.java
index 07aabba..80645cc 100644
--- a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/validation/TypeInfoValidator.java
+++ b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/validation/TypeInfoValidator.java
@@ -1476,8 +1476,16 @@
 		private TypeCompatibility testArgumentType(IRType paramType,
 				IValueReference argument) {
 			if (argument != null && paramType != null) {
-				final IRType argumentType = JavaScriptValidations
+				final IRType argumentType;
+				if (argument.getAttribute(IReferenceAttributes.R_METHOD) != null) {
+					IRMethod method = (IRMethod) argument
+							.getAttribute(IReferenceAttributes.R_METHOD);
+					argumentType = RTypes.functionType(getContext(),
+							method.getParameters(), method.getType());
+				} else {
+					argumentType = JavaScriptValidations
 						.typeOf(argument);
+				}
 				if (argumentType != null) {
 					return paramType.isAssignableFrom(argumentType);
 				}
@@ -1552,6 +1560,11 @@
 						&& parameter.getType() instanceof IRRecordType) {
 					describeRecordTypeArgument(sb, argument,
 							(IRRecordType) parameter.getType());
+				} else if (argument.getAttribute(IReferenceAttributes.R_METHOD) != null) {
+					IRMethod method = (IRMethod) argument
+							.getAttribute(IReferenceAttributes.R_METHOD);
+					sb.append(RTypes.functionType(getContext(),
+							method.getParameters(), method.getType()).getName());
 				} else if (argument.getDeclaredType() != null) {
 					sb.append(argument.getDeclaredType().getName());
 				} else {
diff --git a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RFunctionType.java b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RFunctionType.java
index c78d80f..763e032 100644
--- a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RFunctionType.java
+++ b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RFunctionType.java
@@ -80,7 +80,54 @@
 		if (super.isAssignableFrom(type).ok()) {
 			return TypeCompatibility.TRUE;
 		} else if (type instanceof RFunctionType) {
-			return TypeCompatibility.TRUE;
+			RFunctionType funcType = (RFunctionType) type;
+			// if return type is null or it is a IRRecordType instance then it
+			// is always just fine.
+			// RecordType is hard to check, can be type defs with fluent typing.
+			TypeCompatibility returnType = (getReturnType() == null || getReturnType() instanceof IRRecordType) ? TypeCompatibility.TRUE
+					: TypeCompatibility.FALSE;
+			if (returnType == TypeCompatibility.FALSE
+					&& funcType.getReturnType() != null
+					&& getReturnType() != null) {
+				returnType = getReturnType().isAssignableFrom(
+						funcType.getReturnType());
+			}
+			TypeCompatibility paramsType = TypeCompatibility.TRUE;
+			if (returnType == TypeCompatibility.TRUE) {
+				paramsType = ((funcType.getParameters() == null || funcType
+						.getParameters().size() == 0) && (getParameters() == null || getParameters()
+						.size() == 0)) ? TypeCompatibility.TRUE
+						: TypeCompatibility.FALSE;
+				if ((funcType.getParameters() != null && funcType
+						.getParameters().size() > 0)
+						&& (getParameters() != null && getParameters().size() > 0)) {
+					paramsType = TypeCompatibility.TRUE;
+					for (int i = 0; i < getParameters().size(); i++) {
+						IRParameter parameter = getParameters().get(i);
+						if (parameter.getType() != null) {
+							if (i < funcType.getParameters().size()) {
+								IRParameter funcParam = funcType
+										.getParameters().get(i);
+								if (funcParam.getType() != null) {
+									if (funcParam.getType().isAssignableFrom(
+											parameter.getType()) == TypeCompatibility.FALSE) {
+										paramsType = TypeCompatibility.FALSE;
+										break;
+									}
+								} else {
+									paramsType = TypeCompatibility.FALSE;
+									break;
+								}
+							} else if (!parameter.isOptional()) {
+								paramsType = TypeCompatibility.FALSE;
+								break;
+							}
+						}
+					}
+				}
+			}
+			return (returnType == TypeCompatibility.TRUE && paramsType == TypeCompatibility.TRUE) ? TypeCompatibility.TRUE
+					: TypeCompatibility.FALSE;
 		} else if (type instanceof IRSimpleType) {
 			// TODO (alex) convert when creating type
 			return TypeCompatibility
diff --git a/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java b/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java
index 167ba33..d52498e 100644
--- a/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java
+++ b/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java
@@ -3489,5 +3489,136 @@
 		final List<IProblem> problems = validate(code.toString());
 		assertEquals(problems.toString(), 1, problems.size());
 	}
+	
+	public void testFunctionTypeExactParam() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number)} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number)} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 0, problems.size());
+	}
+	
+	public void testFunctionTypeObjectParam() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number)} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(Object,Object)} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 0, problems.size());
+	}
+	
+	public void testFunctionTypeObjectArgument() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(Object, Object)} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number)} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 1, problems.size());
+	}
+	
+	public void testFunctionTypeExactReturnType() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number):Boolean} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number):Boolean} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 0, problems.size());
+	}
+	
+	public void testFunctionTypeObjectReturnType() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number):Object} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number):Boolean} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 0, problems.size());
+	}
+	
+	public void testFunctionTypeObjectCallerReturnType() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number):Boolean} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number):Object} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 1, problems.size());
+	}
+
+	public void testFunctionTypeObjectNoReturnType() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number)} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number):Object} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 0, problems.size());
+	}
+	
+	public void testFunctionTypeObjectNoCallerReturnType() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number):Boolean} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number)} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 1, problems.size());
+	}
+
+	
+	public void testFunctionTypeOptionalParam() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number, String=):Boolean} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number):Boolean} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 0, problems.size());
+	}
+	public void testFunctionTypeOptionalArgument() {
+		final StringList code = new StringList();
+		code.add("/**");
+		code.add(" * @param {function(String, Number):Boolean} f");
+		code.add(" */");
+		code.add("function test(f) {}");
+		code.add("/** @type {function(String,Number,String=):Boolean} */");
+		code.add("var f = function(a,b){};");
+		code.add("test(f);");
+		final List<IProblem> problems = validate(code.toString());
+		assertEquals(problems.toString(), 0, problems.size());
+	}
+
 
 }