private NamedTypeSymbol GetFixedDelegate(NamedTypeSymbol delegateType) { Debug.Assert((object)delegateType != null); Debug.Assert(delegateType.IsDelegateType()); // We have a delegate where the input types use no unfixed parameters. Create // a substitution context; we can substitute unfixed parameters for themselves // since they don't actually occur in the inputs. (They may occur in the outputs, // or there may be input parameters fixed to _unfixed_ method type variables. // Both of those scenarios are legal.) var fixedArguments = ArrayBuilder<TypeWithModifiers>.GetInstance(_methodTypeParameters.Length); for (int iParam = 0; iParam < _methodTypeParameters.Length; iParam++) { fixedArguments.Add(new TypeWithModifiers(IsUnfixed(iParam) ? _methodTypeParameters[iParam] : _fixedResults[iParam])); } TypeMap typeMap = new TypeMap(_constructedContainingTypeOfMethod, _methodTypeParameters, fixedArguments.ToImmutableAndFree()); return typeMap.SubstituteNamedType(delegateType); }
//////////////////////////////////////////////////////////////////////////////// // // 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); }