private bool fixTypeVariable(TypeVariableInfo info) { info.fixedType = getFixedType(context.TypeSystem, info.bounds); return info.fixedType != null; }
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; }