//////////////////////////////////////////////////////////////////////////////// // // Inferred return type // private TypeSymbol InferReturnType(BoundExpression source, NamedTypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { Debug.Assert((object)target != null); Debug.Assert(target.IsDelegateType()); Debug.Assert((object)target.DelegateInvokeMethod != null && !target.DelegateInvokeMethod.HasUseSiteError, "This method should only be called for legal delegate types."); Debug.Assert(!target.DelegateInvokeMethod.ReturnsVoid); // We should not be computing the inferred return type unless we are converting // to a delegate type where all the input types are fixed. Debug.Assert(!HasUnfixedParamInInputType(source, target)); // Spec 7.5.2.12: Inferred return type: // The inferred return type of an anonymous function F is used during // type inference and overload resolution. The inferred return type // can only be determined for an anonymous function where all parameter // types are known, either because they are explicitly given, provided // through an anonymous function conversion, or inferred during type // inference on an enclosing generic method invocation. // The inferred return type is determined as follows: // * If the body of F is an expression (that has a type) then the // inferred return type of F is the type of that expression. // * If the body of F is a block and the set of expressions in the // blocks return statements has a best common type T then the // inferred return type of F is T. // * Otherwise, a return type cannot be inferred for F. if (source.Kind != BoundKind.UnboundLambda) { return null; } var anonymousFunction = (UnboundLambda)source; if (anonymousFunction.HasSignature) { // Optimization: // We know that the anonymous function has a parameter list. If it does not // have the same arity as the delegate, then it cannot possibly be applicable. // Rather than have type inference fail, we will simply not make a return // type inference and have type inference continue on. Either inference // will fail, or we will infer a nonapplicable method. Either way, there // is no change to the semantics of overload resolution. var originalDelegateParameters = target.DelegateParameters(); if (originalDelegateParameters.IsDefault) { return null; } if (originalDelegateParameters.Length != anonymousFunction.ParameterCount) { return null; } } var fixedDelegate = GetFixedDelegate(target); var fixedDelegateParameters = fixedDelegate.DelegateParameters(); // Optimization: // Similarly, if we have an entirely fixed delegate and an explicitly typed // anonymous function, then the parameter types had better be identical. // If not, applicability will eventually fail, so there is no semantic // difference caused by failing to make a return type inference. if (anonymousFunction.HasExplicitlyTypedParameterList) { for (int p = 0; p < anonymousFunction.ParameterCount; ++p) { if (anonymousFunction.ParameterType(p) != fixedDelegateParameters[p].Type) { return null; } } } // Future optimization: We could return null if the delegate has out or ref parameters // and the anonymous function is an implicitly typed lambda. It will not be applicable. // We have an entirely fixed delegate parameter list, which is of the same arity as // the anonymous function parameter list, and possibly exactly the same types if // the anonymous function is explicitly typed. Make an inference from the // delegate parameters to the return type. return anonymousFunction.InferReturnType(fixedDelegate, ref useSiteDiagnostics); }