public Expression TypeCheck(MethodInvocation methodInvocation, Scope scope) { var position = methodInvocation.Position; var instance = methodInvocation.Instance; var methodName = methodInvocation.MethodName; var arguments = methodInvocation.Arguments; var typedInstance = TypeCheck(instance, scope); var instanceType = typedInstance.Type; var instanceNamedType = instanceType as NamedType; if (instanceNamedType == null) { LogError(CompilerError.AmbiguousMethodInvocation(position)); return(methodInvocation); } var typeMemberScope = new TypeMemberScope(typeRegistry.MembersOf(instanceNamedType)); //TODO: This block is suspiciously like Call type checking, but Callable/MethodName is evaluated in a special scope and the successful return is different. var Callable = methodName; //Attempt to treat this method invocation as an extension method, if we fail to find the method in the type member scope. if (!typeMemberScope.Contains(Callable.Identifier)) { var extensionMethodCall = TypeCheck(new Call(position, methodName, new[] { instance }.Concat(arguments)), scope); if (extensionMethodCall != null) { return(extensionMethodCall); } } var typedCallable = TypeCheck(Callable, typeMemberScope); var typedArguments = TypeCheck(arguments, scope); var calleeType = typedCallable.Type; var calleeFunctionType = calleeType as NamedType; if (calleeFunctionType == null || calleeFunctionType.Name != "System.Func") { LogError(CompilerError.ObjectNotCallable(position)); return(methodInvocation); } var returnType = calleeType.GenericArguments.Last(); var argumentTypes = typedArguments.Select(x => x.Type).ToVector(); Unify(position, calleeType, NamedType.Function(argumentTypes, returnType)); var callType = unifier.Normalize(returnType); var typedMethodName = (Name)typedCallable; return(new MethodInvocation(position, typedInstance, typedMethodName, typedArguments, callType)); }