コード例 #1
0
        /// <summary>
        /// Return the Invoke method symbol if the type is a delegate
        /// type and the Invoke method is available, otherwise null.
        /// </summary>
        private static MethodSymbol GetDelegateInvokeMethodIfAvailable(TypeSymbol type)
        {
            var delegateType = type.GetDelegateType();

            if ((object)delegateType == null)
            {
                return(null);
            }

            MethodSymbol methodSymbol = delegateType.DelegateInvokeMethod;

            if ((object)methodSymbol == null || methodSymbol.HasUseSiteError)
            {
                return(null);
            }

            return(methodSymbol);
        }
コード例 #2
0
        /// <summary>
        /// Return the Invoke method symbol if the type is a delegate
        /// type and the Invoke method is available, otherwise null.
        /// </summary>
        private static MethodSymbol GetDelegateInvokeMethodIfAvailable(TypeSymbol type)
        {
            var delegateType = type.GetDelegateType();
            if ((object)delegateType == null)
            {
                return null;
            }

            MethodSymbol methodSymbol = delegateType.DelegateInvokeMethod;
            if ((object)methodSymbol == null || methodSymbol.HasUseSiteError)
            {
                return null;
            }

            return methodSymbol;
        }
コード例 #3
0
        internal void GenerateAnonymousFunctionConversionError(DiagnosticBag diagnostics, CSharpSyntaxNode syntax,
            UnboundLambda anonymousFunction, TypeSymbol targetType)
        {
            Debug.Assert((object)targetType != null);
            Debug.Assert(anonymousFunction != null);

            // Is the target type simply bad?

            // If the target type is an error then we've already reported a diagnostic. Don't bother
            // reporting the conversion error.
            if (targetType.IsErrorType() || syntax.HasErrors)
            {
                return;
            }

            // CONSIDER: Instead of computing this again, cache the reason why the conversion failed in
            // CONSIDER: the Conversion result, and simply report that.

            var reason = Conversions.IsAnonymousFunctionCompatibleWithType(anonymousFunction, targetType);

            // It is possible that the conversion from lambda to delegate is just fine, and 
            // that we ended up here because the target type, though itself is not an error
            // type, contains a type argument which is an error type. For example, converting
            // (Foo foo)=>{} to Action<Foo> is a perfectly legal conversion even if Foo is undefined!
            // In that case we have already reported an error that Foo is undefined, so just bail out.

            if (reason == LambdaConversionResult.Success)
            {
                return;
            }

            var id = anonymousFunction.MessageID.Localize();

            if (reason == LambdaConversionResult.BadTargetType)
            {
                if (ReportDelegateInvokeUseSiteDiagnostic(diagnostics, targetType, node: syntax))
                {
                    return;
                }

                // Cannot convert {0} to type '{1}' because it is not a delegate type
                Error(diagnostics, ErrorCode.ERR_AnonMethToNonDel, syntax, id, targetType);
                return;
            }

            if (reason == LambdaConversionResult.ExpressionTreeMustHaveDelegateTypeArgument)
            {
                Debug.Assert(targetType.IsExpressionTree());
                Error(diagnostics, ErrorCode.ERR_ExpressionTreeMustHaveDelegate, syntax, ((NamedTypeSymbol)targetType).TypeArgumentsNoUseSiteDiagnostics[0]);
                return;
            }

            if (reason == LambdaConversionResult.ExpressionTreeFromAnonymousMethod)
            {
                Debug.Assert(targetType.IsExpressionTree());
                Error(diagnostics, ErrorCode.ERR_AnonymousMethodToExpressionTree, syntax);
                return;
            }

            // At this point we know that we have either a delegate type or an expression type for the target.

            var delegateType = targetType.GetDelegateType();

            // The target type is a vaid delegate or expression tree type. Is there something wrong with the 
            // parameter list?

            // First off, is there a parameter list at all?

            if (reason == LambdaConversionResult.MissingSignatureWithOutParameter)
            {
                // COMPATIBILITY: The C# 4 compiler produces two errors for:
                //
                // delegate void D (out int x);
                // ...
                // D d = delegate {};
                //
                // error CS1676: Parameter 1 must be declared with the 'out' keyword
                // error CS1688: Cannot convert anonymous method block without a parameter list 
                // to delegate type 'D' because it has one or more out parameters
                //
                // This seems redundant, (because there is no "parameter 1" in the source code)
                // and unnecessary. I propose that we eliminate the first error.

                Error(diagnostics, ErrorCode.ERR_CantConvAnonMethNoParams, syntax, targetType);
                return;
            }

            // There is a parameter list. Does it have the right number of elements?

            if (reason == LambdaConversionResult.BadParameterCount)
            {
                // Delegate '{0}' does not take {1} arguments
                Error(diagnostics, ErrorCode.ERR_BadDelArgCount, syntax, targetType, anonymousFunction.ParameterCount);
                return;
            }

            // The parameter list exists and had the right number of parameters. Were any of its types bad?

            // If any parameter type of the lambda is an error type then suppress 
            // further errors. We've already reported errors on the bad type.
            if (anonymousFunction.HasExplicitlyTypedParameterList)
            {
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    if (anonymousFunction.ParameterType(i).IsErrorType())
                    {
                        return;
                    }
                }
            }

            // The parameter list exists and had the right number of parameters. Were any of its types
            // mismatched with the delegate parameter types?

            // The simplest possible case is (x, y, z)=>whatever where the target type has a ref or out parameter.

            var delegateParameters = delegateType.DelegateParameters();
            if (reason == LambdaConversionResult.RefInImplicitlyTypedLambda)
            {
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    var delegateRefKind = delegateParameters[i].RefKind;
                    if (delegateRefKind != RefKind.None)
                    {
                        // Parameter {0} must be declared with the '{1}' keyword
                        Error(diagnostics, ErrorCode.ERR_BadParamRef, anonymousFunction.ParameterLocation(i),
                            i + 1, delegateRefKind.ToDisplayString());
                    }
                }
                return;
            }

            // See the comments in IsAnonymousFunctionCompatibleWithDelegate for an explanation of this one.
            if (reason == LambdaConversionResult.StaticTypeInImplicitlyTypedLambda)
            {
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    if (delegateParameters[i].Type.IsStatic)
                    {
                        // {0}: Static types cannot be used as parameter
                        Error(diagnostics, ErrorCode.ERR_ParameterIsStaticClass, anonymousFunction.ParameterLocation(i), delegateParameters[i].Type);
                    }
                }
                return;
            }

            // Otherwise, there might be a more complex reason why the parameter types are mismatched.

            if (reason == LambdaConversionResult.MismatchedParameterType)
            {
                // Cannot convert {0} to delegate type '{1}' because the parameter types do not match the delegate parameter types
                Error(diagnostics, ErrorCode.ERR_CantConvAnonMethParams, syntax, id, targetType);
                Debug.Assert(anonymousFunction.ParameterCount == delegateParameters.Length);
                for (int i = 0; i < anonymousFunction.ParameterCount; ++i)
                {
                    var lambdaParameterType = anonymousFunction.ParameterType(i);
                    if (lambdaParameterType.IsErrorType())
                    {
                        continue;
                    }

                    var lambdaParameterLocation = anonymousFunction.ParameterLocation(i);
                    var lambdaRefKind = anonymousFunction.RefKind(i);
                    var delegateParameterType = delegateParameters[i].Type;
                    var delegateRefKind = delegateParameters[i].RefKind;

                    if (!lambdaParameterType.Equals(delegateParameterType, ignoreCustomModifiers: true, ignoreDynamic: true))
                    {
                        SymbolDistinguisher distinguisher = new SymbolDistinguisher(this.Compilation, lambdaParameterType, delegateParameterType);

                        // Parameter {0} is declared as type '{1}{2}' but should be '{3}{4}'
                        Error(diagnostics, ErrorCode.ERR_BadParamType, lambdaParameterLocation,
                            i + 1, lambdaRefKind.ToPrefix(), distinguisher.First, delegateRefKind.ToPrefix(), distinguisher.Second);
                    }
                    else if (lambdaRefKind != delegateRefKind)
                    {
                        if (delegateRefKind == RefKind.None)
                        {
                            // Parameter {0} should not be declared with the '{1}' keyword
                            Error(diagnostics, ErrorCode.ERR_BadParamExtraRef, lambdaParameterLocation, i + 1, lambdaRefKind.ToDisplayString());
                        }
                        else
                        {
                            // Parameter {0} must be declared with the '{1}' keyword
                            Error(diagnostics, ErrorCode.ERR_BadParamRef, lambdaParameterLocation, i + 1, delegateRefKind.ToDisplayString());
                        }
                    }
                }
                return;
            }

            if (reason == LambdaConversionResult.BindingFailed)
            {
                var bindingResult = anonymousFunction.Bind(delegateType);
                Debug.Assert(ErrorFacts.PreventsSuccessfulDelegateConversion(bindingResult.Diagnostics));
                diagnostics.AddRange(bindingResult.Diagnostics);
                return;
            }

            // UNDONE: LambdaConversionResult.VoidExpressionLambdaMustBeStatementExpression:

            Debug.Assert(false, "Missing case in lambda conversion error reporting");
        }
コード例 #4
0
 public static MethodSymbol DelegateInvokeMethod(this TypeSymbol type)
 {
     Debug.Assert((object)type != null);
     Debug.Assert(type.IsDelegateType() || type.IsExpressionTree());
     return(type.GetDelegateType().DelegateInvokeMethod);
 }
コード例 #5
0
        private static TypeSymbol InferReturnType(
            BoundBlock block,
            Binder binder,
            TypeSymbol delegateType,
            bool isAsync,
            ref HashSet <DiagnosticInfo> useSiteDiagnostics,
            out RefKind refKind,
            out bool inferredFromSingleType)
        {
            int numberOfDistinctReturns;
            var resultTypes = BlockReturns.GetReturnTypes(block, out refKind, out numberOfDistinctReturns);

            inferredFromSingleType = numberOfDistinctReturns < 2;

            TypeSymbol bestResultType;

            if (resultTypes.IsDefaultOrEmpty)
            {
                bestResultType = null;
            }
            else if (resultTypes.Length == 1)
            {
                bestResultType = resultTypes[0];
            }
            else
            {
                bestResultType = BestTypeInferrer.InferBestType(resultTypes, binder.Conversions, ref useSiteDiagnostics);
            }

            if (!isAsync)
            {
                return(bestResultType);
            }

            // For async lambdas, the return type is the return type of the
            // delegate Invoke method if Invoke has a Task-like return type.
            // Otherwise the return type is Task or Task<T>.
            NamedTypeSymbol taskType           = null;
            var             delegateReturnType = delegateType?.GetDelegateType()?.DelegateInvokeMethod?.ReturnType as NamedTypeSymbol;

            if ((object)delegateReturnType != null)
            {
                NamedTypeSymbol builderType;
                MethodSymbol    createBuilderMethod;
                if (delegateReturnType.IsCustomTaskType(out builderType, out createBuilderMethod))
                {
                    taskType = delegateReturnType;
                }
            }

            if (resultTypes.IsEmpty)
            {
                // No return statements have expressions; use delegate InvokeMethod
                // or infer type Task if delegate type not available.
                return((object)taskType != null && taskType.Arity == 0 ?
                       taskType :
                       binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task));
            }

            if ((object)bestResultType == null || bestResultType.SpecialType == SpecialType.System_Void)
            {
                // If the best type was 'void', ERR_CantReturnVoid is reported while binding the "return void"
                // statement(s).
                return(null);
            }

            // Some non-void best type T was found; use delegate InvokeMethod
            // or infer type Task<T> if delegate type not available.
            var taskTypeT = (object)taskType != null && taskType.Arity == 1 ?
                            delegateReturnType.ConstructedFrom :
                            binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T);

            return(taskTypeT.Construct(bestResultType));
        }
コード例 #6
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        // Output types
        //
        private static bool DoesOutputTypeContain(BoundExpression argument, TypeSymbol formalParameterType,
            TypeParameterSymbol typeParameter)
        {
            // SPEC: If E is a method group or an anonymous function and T is a delegate
            // SPEC: type or expression tree type then the return type of T is an output type
            // SPEC: of E with type T.

            var delegateType = formalParameterType.GetDelegateType();
            if ((object)delegateType == null)
            {
                return false;
            }

            if (argument.Kind != BoundKind.UnboundLambda && argument.Kind != BoundKind.MethodGroup)
            {
                return false;
            }

            MethodSymbol delegateInvoke = delegateType.DelegateInvokeMethod;
            if ((object)delegateInvoke == null || delegateInvoke.HasUseSiteError)
            {
                return false;
            }

            var delegateReturnType = delegateInvoke.ReturnType;
            if ((object)delegateReturnType == null)
            {
                return false;
            }

            return delegateReturnType.ContainsTypeParameter(typeParameter);
        }
コード例 #7
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        // Input types
        //
        private static bool DoesInputTypeContain(BoundExpression argument, TypeSymbol formalParameterType, TypeParameterSymbol typeParameter)
        {
            // SPEC: If E is a method group or an anonymous function and T is a delegate
            // SPEC: type or expression tree type then all the parameter types of T are
            // SPEC: input types of E with type T.

            var delegateType = formalParameterType.GetDelegateType();
            if ((object)delegateType == null)
            {
                return false; // No input types.
            }

            if (argument.Kind != BoundKind.UnboundLambda && argument.Kind != BoundKind.MethodGroup)
            {
                return false; // No input types.
            }

            var delegateParameters = delegateType.DelegateParameters();
            if (delegateParameters.IsDefaultOrEmpty)
            {
                return false;
            }

            foreach (var delegateParameter in delegateParameters)
            {
                if (delegateParameter.Type.ContainsTypeParameter(typeParameter))
                {
                    return true;
                }
            }

            return false;
        }
コード例 #8
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        // Explicit parameter type inferences
        //
        private void ExplicitParameterTypeInference(BoundExpression source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(source != null);
            Debug.Assert((object)target != null);

            // SPEC: An explicit type parameter type inference is made from an expression
            // SPEC: E to a type T in the following way.
            // SPEC: If E is an explicitly typed anonymous function with parameter types
            // SPEC: U1...Uk and T is a delegate type or expression tree type with
            // SPEC: parameter types V1...Vk then for each Ui an exact inference is made
            // SPEC: from Ui to the corresponding Vi.

            if (source.Kind != BoundKind.UnboundLambda)
            {
                return;
            }

            UnboundLambda anonymousFunction = (UnboundLambda)source;

            if (!anonymousFunction.HasExplicitlyTypedParameterList)
            {
                return;
            }

            var delegateType = target.GetDelegateType();
            if ((object)delegateType == null)
            {
                return;
            }

            var delegateParameters = delegateType.DelegateParameters();
            if (delegateParameters.IsDefault)
            {
                return;
            }

            int size = delegateParameters.Length;
            if (anonymousFunction.ParameterCount < size)
            {
                size = anonymousFunction.ParameterCount;
            }

            // SPEC ISSUE: What should we do if there is an out/ref mismatch between an
            // SPEC ISSUE: anonymous function parameter and a delegate parameter?
            // SPEC ISSUE: The result will not be applicable no matter what, but should
            // SPEC ISSUE: we make any inferences?  This is going to be an error
            // SPEC ISSUE: ultimately, but it might make a difference for intellisense or
            // SPEC ISSUE: other analysis.

            for (int i = 0; i < size; ++i)
            {
                ExactInference(anonymousFunction.ParameterType(i), delegateParameters[i].Type, ref useSiteDiagnostics);
            }
        }
コード例 #9
0
        private bool MethodGroupReturnTypeInference(Binder binder, BoundExpression source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(source != null);
            Debug.Assert((object)target != null);
            // SPEC: * Otherwise, if E is a method group and T is a delegate type or
            // SPEC:   expression tree type with parameter types T1...Tk and return
            // SPEC:   type Tb and overload resolution of E with the types T1...Tk
            // SPEC:   yields a single method with return type U then a lower-bound
            // SPEC:   inference is made from U to Tb.

            if (source.Kind != BoundKind.MethodGroup)
            {
                return false;
            }

            var delegateType = target.GetDelegateType();
            if ((object)delegateType == null)
            {
                return false;
            }

            // this part of the code is only called if the targetType has an unfixed type argument in the output 
            // type, which is not the case for invalid delegate invoke methods.
            Debug.Assert((object)delegateType.DelegateInvokeMethod != null && !delegateType.DelegateInvokeMethod.HasUseSiteError,
                         "This method should only be called for valid delegate types");

            TypeSymbol delegateReturnType = delegateType.DelegateInvokeMethod.ReturnType;
            if ((object)delegateReturnType == null || delegateReturnType.SpecialType == SpecialType.System_Void)
            {
                return false;
            }

            // At this point we are in the second phase; we know that all the input types are fixed.

            var fixedDelegateParameters = GetFixedDelegate(delegateType).DelegateParameters();
            if (fixedDelegateParameters.IsDefault)
            {
                return false;
            }

            var returnType = MethodGroupReturnType(binder, (BoundMethodGroup)source, fixedDelegateParameters, ref useSiteDiagnostics);
            if ((object)returnType == null || returnType.SpecialType == SpecialType.System_Void)
            {
                return false;
            }

            LowerBoundInference(returnType, delegateReturnType, ref useSiteDiagnostics);

            return true;
        }
コード例 #10
0
        private bool InferredReturnTypeInference(BoundExpression source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(source != null);
            Debug.Assert((object)target != null);
            // SPEC: * If E is an anonymous function with inferred return type U and
            // SPEC:   T is a delegate type or expression tree with return type Tb
            // SPEC:   then a lower bound inference is made from U to Tb.

            var delegateType = target.GetDelegateType();
            if ((object)delegateType == null)
            {
                return false;
            }

            // cannot be hit, because an invalid delegate does not have an unfixed return type
            // this will be checked earlier.
            Debug.Assert((object)delegateType.DelegateInvokeMethod != null && !delegateType.DelegateInvokeMethod.HasUseSiteError,
                         "This method should only be called for valid delegate types.");
            var returnType = delegateType.DelegateInvokeMethod.ReturnType;
            if ((object)returnType == null || returnType.SpecialType == SpecialType.System_Void)
            {
                return false;
            }

            var inferredReturnType = InferReturnType(source, delegateType, ref useSiteDiagnostics);
            if ((object)inferredReturnType == null)
            {
                return false;
            }

            LowerBoundInference(inferredReturnType, returnType, ref useSiteDiagnostics);
            return true;
        }