/// <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); }
/// <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); }
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)); }
/// <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); }
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)); }
public static TypeSymbol InferBestType(ImmutableArray<TypeSymbol> types, ConversionsBase conversions, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { var inferrer = new BestTypeInferrer(conversions); return inferrer.GetBestType(types, ref useSiteDiagnostics); }
public static TypeSymbol InferBestType(ImmutableArray <TypeSymbol> types, Conversions conversions, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { var inferrer = new BestTypeInferrer(conversions); return(inferrer.GetBestType(types, ref useSiteDiagnostics)); }