예제 #1
0
        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));
        }