IType[] OutputTypes(ResolveResult e, IType t) { // C# 4.0 spec: §7.5.2.4 Output types LambdaResolveResult lrr = e as LambdaResolveResult; if (lrr != null || e is MethodGroupResolveResult) { IMethod m = GetDelegateOrExpressionTreeSignature(t); if (m != null) { return(new[] { m.ReturnType }); } } return(emptyTypeArray); }
void MakeExplicitParameterTypeInference(LambdaResolveResult e, IType t) { // C# 4.0 spec: §7.5.2.7 Explicit parameter type inferences if (e.IsImplicitlyTyped || !e.HasParameterList) { return; } Log.WriteLine(" MakeExplicitParameterTypeInference from " + e + " to " + t); IMethod m = GetDelegateOrExpressionTreeSignature(t); if (m == null) { return; } for (int i = 0; i < e.Parameters.Count && i < m.Parameters.Count; i++) { MakeExactInference(e.Parameters[i].Type, m.Parameters[i].Type); } }
IType[] InputTypes(ResolveResult e, IType t) { // C# 4.0 spec: §7.5.2.3 Input types LambdaResolveResult lrr = e as LambdaResolveResult; if (lrr != null && lrr.IsImplicitlyTyped || e is MethodGroupResolveResult) { IMethod m = GetDelegateOrExpressionTreeSignature(t); if (m != null) { IType[] inputTypes = new IType[m.Parameters.Count]; for (int i = 0; i < inputTypes.Length; i++) { inputTypes[i] = m.Parameters[i].Type; } return(inputTypes); } } return(emptyTypeArray); }
void PhaseOne() { // C# 4.0 spec: §7.5.2.1 The first phase Log.WriteLine("Phase One"); for (int i = 0; i < arguments.Length; i++) { ResolveResult Ei = arguments[i]; IType Ti = parameterTypes[i]; LambdaResolveResult lrr = Ei as LambdaResolveResult; if (lrr != null) { MakeExplicitParameterTypeInference(lrr, Ti); } if (lrr != null || Ei is MethodGroupResolveResult) { // this is not in the spec??? if (OutputTypeContainsUnfixed(Ei, Ti) && !InputTypesContainsUnfixed(Ei, Ti)) { MakeOutputTypeInference(Ei, Ti); } } if (IsValidType(Ei.Type)) { if (Ti is ByReferenceType) { MakeExactInference(Ei.Type, Ti); } else { MakeLowerBoundInference(Ei.Type, Ti); } } } }
Conversion AnonymousFunctionConversion(ResolveResult resolveResult, IType toType) { // C# 4.0 spec §6.5 Anonymous function conversions LambdaResolveResult f = resolveResult as LambdaResolveResult; if (f == null) { return(Conversion.None); } if (!f.IsAnonymousMethod) { // It's a lambda, so conversions to expression trees exist // (even if the conversion leads to a compile-time error, e.g. for statement lambdas) toType = UnpackExpressionTreeType(toType); } IMethod d = toType.GetDelegateInvokeMethod(); if (d == null) { return(Conversion.None); } IType[] dParamTypes = new IType[d.Parameters.Count]; for (int i = 0; i < dParamTypes.Length; i++) { dParamTypes[i] = d.Parameters[i].Type; } IType dReturnType = d.ReturnType; if (f.HasParameterList) { // If F contains an anonymous-function-signature, then D and F have the same number of parameters. if (d.Parameters.Count != f.Parameters.Count) { return(Conversion.None); } if (f.IsImplicitlyTyped) { // If F has an implicitly typed parameter list, D has no ref or out parameters. foreach (IParameter p in d.Parameters) { if (p.IsOut || p.IsRef) { return(Conversion.None); } } } else { // If F has an explicitly typed parameter list, each parameter in D has the same type // and modifiers as the corresponding parameter in F. for (int i = 0; i < f.Parameters.Count; i++) { IParameter pD = d.Parameters[i]; IParameter pF = f.Parameters[i]; if (pD.IsRef != pF.IsRef || pD.IsOut != pF.IsOut) { return(Conversion.None); } if (!dParamTypes[i].Equals(pF.Type)) { return(Conversion.None); } } } } else { // If F does not contain an anonymous-function-signature, then D may have zero or more parameters of any // type, as long as no parameter of D has the out parameter modifier. foreach (IParameter p in d.Parameters) { if (p.IsOut) { return(Conversion.None); } } } return(f.IsValid(dParamTypes, dReturnType, this)); }
/// <summary> /// Gets the better conversion (C# 4.0 spec, §7.5.3.3) /// </summary> /// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns> public int BetterConversion(ResolveResult resolveResult, IType t1, IType t2) { LambdaResolveResult lambda = resolveResult as LambdaResolveResult; if (lambda != null) { if (!lambda.IsAnonymousMethod) { t1 = UnpackExpressionTreeType(t1); t2 = UnpackExpressionTreeType(t2); } IMethod m1 = t1.GetDelegateInvokeMethod(); IMethod m2 = t2.GetDelegateInvokeMethod(); if (m1 == null || m2 == null) { return(0); } int r = BetterConversionTarget(t1, t2); if (r != 0) { return(r); } if (m1.Parameters.Count != m2.Parameters.Count) { return(0); } IType[] parameterTypes = new IType[m1.Parameters.Count]; for (int i = 0; i < parameterTypes.Length; i++) { parameterTypes[i] = m1.Parameters[i].Type; if (!parameterTypes[i].Equals(m2.Parameters[i].Type)) { return(0); } } if (lambda.HasParameterList && parameterTypes.Length != lambda.Parameters.Count) { return(0); } IType ret1 = m1.ReturnType; IType ret2 = m2.ReturnType; if (ret1.Kind == TypeKind.Void && ret2.Kind != TypeKind.Void) { return(2); } if (ret1.Kind != TypeKind.Void && ret2.Kind == TypeKind.Void) { return(1); } IType inferredRet = lambda.GetInferredReturnType(parameterTypes); r = BetterConversion(inferredRet, ret1, ret2); if (r == 0 && lambda.IsAsync) { ret1 = UnpackTask(ret1); ret2 = UnpackTask(ret2); inferredRet = UnpackTask(inferredRet); if (ret1 != null && ret2 != null && inferredRet != null) { r = BetterConversion(inferredRet, ret1, ret2); } } return(r); } else { return(BetterConversion(resolveResult.Type, t1, t2)); } }
void MakeExplicitParameterTypeInference(LambdaResolveResult e, IType t) { // C# 4.0 spec: §7.5.2.7 Explicit parameter type inferences if (e.IsImplicitlyTyped || !e.HasParameterList) return; Log.WriteLine(" MakeExplicitParameterTypeInference from " + e + " to " + t); IMethod m = GetDelegateOrExpressionTreeSignature(t); if (m == null) return; for (int i = 0; i < e.Parameters.Count && i < m.Parameters.Count; i++) { MakeExactInference(e.Parameters[i].Type, m.Parameters[i].Type); } }
void MakeOutputTypeInference(ResolveResult e, IType t) { Log.WriteLine(" MakeOutputTypeInference from " + e + " to " + t); // If E is an anonymous function with inferred return type U (§7.5.2.12) and T is a delegate type or expression // tree type with return type Tb, then a lower-bound inference (§7.5.2.9) is made from U to Tb. LambdaResolveResult lrr = e as LambdaResolveResult; if (lrr != null) { IMethod m = GetDelegateOrExpressionTreeSignature(t); if (m != null) { IType inferredReturnType; if (lrr.IsImplicitlyTyped) { if (m.Parameters.Count != lrr.Parameters.Count) { return; // cannot infer due to mismatched parameter lists } TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs(); IType[] inferredParameterTypes = new IType[m.Parameters.Count]; for (int i = 0; i < inferredParameterTypes.Length; i++) { IType parameterType = m.Parameters[i].Type; inferredParameterTypes[i] = parameterType.AcceptVisitor(substitution); } inferredReturnType = lrr.GetInferredReturnType(inferredParameterTypes); } else { inferredReturnType = lrr.GetInferredReturnType(null); } MakeLowerBoundInference(inferredReturnType, m.ReturnType); return; } } // Otherwise, if E is a method group and T is a delegate type or expression tree type // with parameter types T1…Tk and return type Tb, and overload resolution // of E with the types T1…Tk yields a single method with return type U, then a lower-bound // inference is made from U to Tb. MethodGroupResolveResult mgrr = e as MethodGroupResolveResult; if (mgrr != null) { IMethod m = GetDelegateOrExpressionTreeSignature(t); if (m != null) { ResolveResult[] args = new ResolveResult[m.Parameters.Count]; TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs(); for (int i = 0; i < args.Length; i++) { IParameter param = m.Parameters[i]; IType parameterType = param.Type.AcceptVisitor(substitution); if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference) { parameterType = ((ByReferenceType)parameterType).ElementType; args[i] = new ByReferenceResolveResult(parameterType, param.IsOut); } else { args[i] = new ResolveResult(parameterType); } } var or = mgrr.PerformOverloadResolution(compilation, args, allowExtensionMethods: false, allowExpandingParams: false); if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null) { IType returnType = or.BestCandidate.ReturnType; MakeLowerBoundInference(returnType, m.ReturnType); } } return; } // Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T. if (IsValidType(e.Type)) { MakeLowerBoundInference(e.Type, t); } }