예제 #1
0
        /// <summary>
        /// Infer the result type of the switch expression by looking for a common type.
        /// </summary>
        private TypeSymbol InferResultType(ImmutableArray <BoundSwitchExpressionArm> switchCases, DiagnosticBag diagnostics)
        {
            var seenTypes = PooledHashSet <TypeSymbol> .GetInstance();

            var typesInOrder = ArrayBuilder <TypeSymbol> .GetInstance();

            foreach (var @case in switchCases)
            {
                var type = @case.Value.Type;
                if (!(type is null) && seenTypes.Add(type))
                {
                    typesInOrder.Add(type);
                }
            }

            HashSet <DiagnosticInfo> useSiteDiagnostics = null;
            var commonType = BestTypeInferrer.GetBestType(typesInOrder, Conversions, ref useSiteDiagnostics);

            diagnostics.Add(SwitchExpressionSyntax, useSiteDiagnostics);
            if (commonType is null)
            {
                diagnostics.Add(ErrorCode.ERR_SwitchExpressionNoBestType, SwitchExpressionSyntax.Location);
                commonType = CreateErrorType();
            }

            seenTypes.Free();
            return(commonType);
        }
예제 #2
0
        /// <summary>
        /// Infer the result type of the switch expression by looking for a common type
        /// to which every arm's expression can be converted.
        /// </summary>
        private TypeSymbol?InferResultType(
            ImmutableArray <BoundSwitchExpressionArm> switchCases,
            BindingDiagnosticBag diagnostics
            )
        {
            var seenTypes =
                Symbols.SpecializedSymbolCollections.GetPooledSymbolHashSetInstance <TypeSymbol>();
            var typesInOrder = ArrayBuilder <TypeSymbol> .GetInstance();

            foreach (var @case in switchCases)
            {
                var type = @case.Value.Type;
                if (type is object && seenTypes.Add(type))
                {
                    typesInOrder.Add(type);
                }
            }

            seenTypes.Free();
            CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(
                diagnostics
                );
            var commonType = BestTypeInferrer.GetBestType(
                typesInOrder,
                Conversions,
                ref useSiteInfo
                );

            typesInOrder.Free();

            // We've found a candidate common type among those arms that have a type.  Also check that every arm's
            // expression (even those without a type) can be converted to that type.
            if (commonType is object)
            {
                foreach (var @case in switchCases)
                {
                    if (
                        !this.Conversions.ClassifyImplicitConversionFromExpression(
                            @case.Value,
                            commonType,
                            ref useSiteInfo
                            ).Exists
                        )
                    {
                        commonType = null;
                        break;
                    }
                }
            }

            diagnostics.Add(SwitchExpressionSyntax, useSiteInfo);
            return(commonType);
        }
예제 #3
0
        private TypeSymbol InferReturnType(ref HashSet <DiagnosticInfo> useSiteDiagnostics, out bool inferredFromSingeType)
        {
            int numberOfDistinctReturns;
            var resultTypes = BlockReturns.GetReturnTypes(this.Body, out numberOfDistinctReturns);

            inferredFromSingeType = numberOfDistinctReturns < 2;

            TypeSymbol bestResultType;

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

            if (!Symbol.IsAsync)
            {
                return(bestResultType);
            }

            // Async:

            if (resultTypes.IsEmpty)
            {
                // No return statements have expressions; inferred type Task:
                return(this.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; infer type Task<T>:
            return(this.Binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T).Construct(bestResultType));
        }
예제 #4
0
        /// <summary>
        /// Infer the result type of the switch expression by looking for a common type.
        /// </summary>
        private TypeSymbol InferResultType(ImmutableArray <BoundSwitchExpressionArm> switchCases, DiagnosticBag diagnostics)
        {
            var seenTypes    = SpecializedCollections.GetPooledSymbolHashSetInstance <TypeSymbol>();
            var typesInOrder = ArrayBuilder <TypeSymbol> .GetInstance();

            foreach (var @case in switchCases)
            {
                var type = @case.Value.Type;
                if (!(type is null) && seenTypes.Add(type))
                {
                    typesInOrder.Add(type);
                }
            }

            HashSet <DiagnosticInfo> useSiteDiagnostics = null;
            var commonType = BestTypeInferrer.GetBestType(typesInOrder, Conversions, ref useSiteDiagnostics);

            diagnostics.Add(SwitchExpressionSyntax, useSiteDiagnostics);
            seenTypes.Free();
            return(commonType);
        }
예제 #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
 public static TypeSymbol InferBestType(ImmutableArray<TypeSymbol> types, ConversionsBase conversions, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
 {
     var inferrer = new BestTypeInferrer(conversions);
     return inferrer.GetBestType(types, ref useSiteDiagnostics);
 }
예제 #7
0
        public static TypeSymbol InferBestType(ImmutableArray <TypeSymbol> types, Conversions conversions, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            var inferrer = new BestTypeInferrer(conversions);

            return(inferrer.GetBestType(types, ref useSiteDiagnostics));
        }