コード例 #1
0
 private bool fixTypeVariable(TypeVariableInfo info) {
     info.fixedType = getFixedType(context.TypeSystem, info.bounds);
     return info.fixedType != null;
 }
コード例 #2
0
        MethodInfo resolveMethod(Iterable<MethodInfo> methods, Iterable<ExpressionNode> arguments,
                TypeInfo returnType, bool extensionMethods) {
            var candidates = new ArrayList<CandidateMethodInfo>();
            var hasLambda = false;
            
            foreach (var method in methods) {
                var parameterCount = method.Parameters.count();
                var argumentCount = arguments.count();
                if (method.IsVarargs) {
                    if (argumentCount < parameterCount - 1) {
                        continue;
                    }
                } else if (argumentCount != parameterCount) {
                    continue;
                }
                var fixedArgumentCount = (method.IsVarargs) ? parameterCount - 1 : parameterCount;
                var isCompatible = true;
                var parameterTypes = new TypeInfo[argumentCount];
                var expandedForm = method.IsVarargs;

                if (!method.IsClosed) {
                    var typeVariableInfos = new HashMap<TypeInfo, TypeVariableInfo>();
                    foreach (var t in method.GenericArguments) {
                        typeVariableInfos[t] = new TypeVariableInfo(t);
                    }
                    
                    // Inference phase 1
                    var nit = arguments.iterator();
                    var pit = method.Parameters.iterator();
                    bool closedParams = true;
                    for (int i = 0; i < fixedArgumentCount; i++) {
                        var paramType = pit.next().Type;
                        var argNode = nit.next();
                        if (paramType.IsClosed) {
                            if (!isArgumentCompatible(argNode, paramType)) {
                                goto continueLookup;
                            }
                        } else {
                            closedParams = false;
                            if (argNode.ExpressionKind == ExpressionKind.Lambda) {
                                hasLambda = true;
                                makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos);
                            } else {
                                var argInfo = argNode.getUserData(typeof(ExpressionInfo));
                                if (argInfo == null) {
                                    continue;
                                }
                                if (BytecodeHelper.isDelegateType(paramType) || BytecodeHelper.isExpressionTreeType(paramType)) {
                                    makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos);
                                } else {
                                    ValidationHelper.getType(context, argNode);
                                    makeOutputTypeInference(argNode, paramType, typeVariableInfos);
                                }
                            }
                        }
                    }
                    if (method.IsVarargs) {
                        var paramType = pit.next().Type.ElementType;
                        var isClosedParam = paramType.IsClosed;
                        var first = true;
                        while (nit.hasNext()) {
                            var argNode = nit.next();
                            if (isClosedParam) {
                                switch (isVarargCompatible(argNode, paramType, first)) {
                                case False:
                                    goto continueLookup;
                                case True:
                                    expandedForm = false;
                                    if (nit.hasNext()) {
                                        goto continueLookup;
                                    }
                                    break;
                                }
                            } else {
                                closedParams = false;
                                if (argNode.ExpressionKind == ExpressionKind.Lambda) {
                                    hasLambda = true;
                                    makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos);
                                } else {
                                    var argInfo = argNode.getUserData(typeof(ExpressionInfo));
                                    if (argInfo == null) {
                                        continue;
                                    }
                                    if (BytecodeHelper.isDelegateType(paramType) || BytecodeHelper.isExpressionTreeType(paramType)) {
                                        makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos);
                                    } else if (paramType != ValidationHelper.getType(context, argNode)
                                            && !ValidationHelper.isAssignable(context, paramType, argNode)
                                            && first
                                            && ValidationHelper.isAssignable(context, paramType.getArrayType(), argNode)) {
                                        expandedForm = false;
                                        makeOutputTypeInference(argNode, paramType.getArrayType(), typeVariableInfos);
                                    } else {
                                        makeOutputTypeInference(argNode, paramType, typeVariableInfos);
                                    }
                                }
                            }
                            first = false;
                        }
                    }

                    if (closedParams && returnType != null && returnType != context.TypeSystem.VoidType) {
                        makeLowerBoundInference(returnType, method.ReturnType, typeVariableInfos);
                    }
                    
                    // Inference phase 2
                    for (;;) {
                        var varFixed = false;
                        var hasUnfixed = false;
                        foreach (var e in typeVariableInfos.entrySet()) {
                            if (e.Value.fixedType != null) {
                                continue;
                            }
                            if (!containsUnfixedVariables(e.getValue().dependencies, typeVariableInfos)) {
                                if (fixTypeVariable(e.getValue())) {
                                    varFixed = true;
                                    continue;
                                }
                            }
                            hasUnfixed = true;
                        }
                        if (!varFixed) {
                            varFixed = false;
                            foreach (var e in typeVariableInfos.entrySet()) {
                                if (e.Value.fixedType != null) {
                                    continue;
                                }
                                if (hasUnfixedTypeVariablesDependingOn(e.Key, typeVariableInfos, new HashSet<TypeInfo>())) {
                                    if (!e.Value.bounds.isEmpty()) {
                                        if (fixTypeVariable(e.Value)) {
                                            varFixed = true;
                                            continue;
                                        }
                                    }
                                }
                                hasUnfixed = true;
                            }
                        }
                        if (!varFixed && hasUnfixed) {
                            goto continueLookup;
                        }
                        if (!hasUnfixed) {
                            break;
                        }
                        var mit = method.Parameters.iterator();
                        TypeInfo paramType = null;
                        foreach (var e in arguments) {
                            if (mit.hasNext()) {
                                paramType = mit.next().Type;
                            }
                            if (e.ExpressionKind != ExpressionKind.Lambda) {
                                if (!BytecodeHelper.isDelegateType(paramType) && !BytecodeHelper.isExpressionTreeType(paramType)) {
                                    continue;
                                }
                            }
                            var m = getInvokeMethod(paramType);
                            if (hasUnfixedTypeVariables(m.ReturnType, typeVariableInfos)) {
                                hasUnfixed = false;
                                foreach (var p in m.Parameters) {
                                    if (hasUnfixedTypeVariables(p.Type, typeVariableInfos)) {
                                        hasUnfixed = true;
                                        break;
                                    }
                                }
                                if (!hasUnfixed) {
                                    makeOutputTypeInference(e, paramType, typeVariableInfos);
                                }
                            }
                        }
                    }

                    var typeArguments = new ArrayList<TypeInfo>();
                    foreach (var t in method.GenericArguments) {
                        typeArguments.add(typeVariableInfos[t].fixedType);
                    }
                    method = context.TypeSystem.getGenericMethod(method, typeArguments);
                }

                var it1 = arguments.iterator();
                var it2 = method.Parameters.iterator();
                int i;
                for (i = 0; i < fixedArgumentCount; i++) {
                    var argNode = it1.next();
                    var paramType = it2.next().Type;
                    parameterTypes[i] = paramType;
                    if (!isArgumentCompatible(argNode, paramType)) {
                        isCompatible = false;
                        break;
                    } else if (argNode.ExpressionKind == ExpressionKind.Lambda) {
                        hasLambda = true;
                    }
                }
                if (isCompatible && method.IsVarargs) {
                    var paramType = it2.next().Type.ElementType;
                    var first = true;
                    while (isCompatible && it1.hasNext()) {
                        var argNode = it1.next();
                        parameterTypes[i++] = paramType;
                        switch (isVarargCompatible(argNode, paramType, first)) {
                        case False:
                            isCompatible = false;
                            break;
                        case True:
                            expandedForm = false;
                            if (it1.hasNext()) {
                                isCompatible = false;
                                break;
                            } else if (argNode.ExpressionKind == ExpressionKind.Lambda) {
                                hasLambda = true;
                            }
                            break;
                        }
                        first = false;
                    }
                }
                if (isCompatible) {
                    candidates.add(new CandidateMethodInfo(method, parameterTypes, arguments, expandedForm));
                }
            continueLookup:
                ;
            }

            if (candidates.size() == 0) {
                return null;
            }

            CandidateMethodInfo result;
            if (candidates.size() > 1) {
                result = resolveOverloading(candidates, extensionMethods);
                if (result == null) {
                    return null;
                }
            } else {
                result = candidates[0];
            }
            if (hasLambda) {
                int parameterCount = result.method.Parameters.count();
                int argumentCount = arguments.count();
                int fixedArgumentCount = (result.method.IsVarargs) ? parameterCount - 1 : parameterCount;

                var parameterTypes = new TypeInfo[argumentCount];
                var pit = result.method.getParameters().iterator();
                int i;
                for (i = 0; i < fixedArgumentCount; i++) {
                    parameterTypes[i] = pit.next().Type;
                }
                if (result.method.IsVarargs) {
                    if (result.expandedForm) {
                        var paramType = pit.next().Type.ElementType;
                        while (i < argumentCount) {
                            parameterTypes[i++] = paramType;
                        }
                    } else {
                        parameterTypes[i] = pit.next().Type;
                    }
                }
                i = 0;
                foreach (var argNode in arguments) {
					expressionValidator.handleExpression(argNode, parameterTypes[i], true);
                    i++;
                }
            }
            return result.method;
        }