/// <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); }
/// <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, 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 object && seenTypes.Add(type)) { typesInOrder.Add(type); } } seenTypes.Free(); HashSet <DiagnosticInfo> useSiteDiagnostics = null; var commonType = BestTypeInferrer.GetBestType(typesInOrder, Conversions, ref useSiteDiagnostics); 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 useSiteDiagnostics).Exists) { commonType = null; break; } } } diagnostics.Add(SwitchExpressionSyntax, useSiteDiagnostics); return(commonType); }
public static Imports FromSyntax( CSharpSyntaxNode declarationSyntax, InContainerBinder binder, ConsList <TypeSymbol> basesBeingResolved, bool inUsing) { SyntaxList <UsingDirectiveSyntax> usingDirectives; SyntaxList <ExternAliasDirectiveSyntax> externAliasDirectives; if (declarationSyntax.Kind() == SyntaxKind.CompilationUnit) { var compilationUnit = (CompilationUnitSyntax)declarationSyntax; // using directives are not in scope within using directives usingDirectives = inUsing ? default(SyntaxList <UsingDirectiveSyntax>) : compilationUnit.Usings; externAliasDirectives = compilationUnit.Externs; } else if (declarationSyntax.Kind() == SyntaxKind.NamespaceDeclaration) { var namespaceDecl = (NamespaceDeclarationSyntax)declarationSyntax; // using directives are not in scope within using directives usingDirectives = inUsing ? default(SyntaxList <UsingDirectiveSyntax>) : namespaceDecl.Usings; externAliasDirectives = namespaceDecl.Externs; } else { return(Empty); } if (usingDirectives.Count == 0 && externAliasDirectives.Count == 0) { return(Empty); } // define all of the extern aliases first. They may used by the target of a using // using Bar=Goo::Bar; // using Goo::Baz; // extern alias Goo; var diagnostics = new DiagnosticBag(); var compilation = binder.Compilation; var externAliases = BuildExternAliases(externAliasDirectives, binder, diagnostics); var usings = ArrayBuilder <NamespaceOrTypeAndUsingDirective> .GetInstance(); ImmutableDictionary <string, AliasAndUsingDirective> .Builder usingAliases = null; if (usingDirectives.Count > 0) { // A binder that contains the extern aliases but not the usings. The resolution of the target of a using directive or alias // should not make use of other peer usings. Binder usingsBinder; if (declarationSyntax.SyntaxTree.Options.Kind != SourceCodeKind.Regular) { usingsBinder = compilation.GetBinderFactory(declarationSyntax.SyntaxTree).GetImportsBinder(declarationSyntax, inUsing: true); } else { var imports = externAliases.Length == 0 ? Empty : new Imports( compilation, ImmutableDictionary <string, AliasAndUsingDirective> .Empty, ImmutableArray <NamespaceOrTypeAndUsingDirective> .Empty, externAliases, diagnostics: null); usingsBinder = new InContainerBinder(binder.Container, binder.Next, imports); } var uniqueUsings = SpecializedCollections.GetPooledSymbolHashSetInstance <NamespaceOrTypeSymbol>(); foreach (var usingDirective in usingDirectives) { compilation.RecordImport(usingDirective); if (usingDirective.Alias != null) { if (usingDirective.Alias.Name.Identifier.ContextualKind() == SyntaxKind.GlobalKeyword) { diagnostics.Add(ErrorCode.WRN_GlobalAliasDefn, usingDirective.Alias.Name.Location); } if (usingDirective.StaticKeyword != default(SyntaxToken)) { diagnostics.Add(ErrorCode.ERR_NoAliasHere, usingDirective.Alias.Name.Location); } string identifierValueText = usingDirective.Alias.Name.Identifier.ValueText; if (usingAliases != null && usingAliases.ContainsKey(identifierValueText)) { // Suppress diagnostics if we're already broken. if (!usingDirective.Name.IsMissing) { // The using alias '{0}' appeared previously in this namespace diagnostics.Add(ErrorCode.ERR_DuplicateAlias, usingDirective.Alias.Name.Location, identifierValueText); } } else { // an O(m*n) algorithm here but n (number of extern aliases) will likely be very small. foreach (var externAlias in externAliases) { if (externAlias.Alias.Name == identifierValueText) { // The using alias '{0}' appeared previously in this namespace diagnostics.Add(ErrorCode.ERR_DuplicateAlias, usingDirective.Location, identifierValueText); break; } } if (usingAliases == null) { usingAliases = ImmutableDictionary.CreateBuilder <string, AliasAndUsingDirective>(); } // construct the alias sym with the binder for which we are building imports. That // way the alias target can make use of extern alias definitions. usingAliases.Add(identifierValueText, new AliasAndUsingDirective(new AliasSymbol(usingsBinder, usingDirective), usingDirective)); } } else { if (usingDirective.Name.IsMissing) { //don't try to lookup namespaces inserted by parser error recovery continue; } var declarationBinder = usingsBinder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); var imported = declarationBinder.BindNamespaceOrTypeSymbol(usingDirective.Name, diagnostics, basesBeingResolved).NamespaceOrTypeSymbol; if (imported.Kind == SymbolKind.Namespace) { if (usingDirective.StaticKeyword != default(SyntaxToken)) { diagnostics.Add(ErrorCode.ERR_BadUsingType, usingDirective.Name.Location, imported); } else if (uniqueUsings.Contains(imported)) { diagnostics.Add(ErrorCode.WRN_DuplicateUsing, usingDirective.Name.Location, imported); } else { uniqueUsings.Add(imported); usings.Add(new NamespaceOrTypeAndUsingDirective(imported, usingDirective)); } } else if (imported.Kind == SymbolKind.NamedType) { if (usingDirective.StaticKeyword == default(SyntaxToken)) { diagnostics.Add(ErrorCode.ERR_BadUsingNamespace, usingDirective.Name.Location, imported); } else { var importedType = (NamedTypeSymbol)imported; if (uniqueUsings.Contains(importedType)) { diagnostics.Add(ErrorCode.WRN_DuplicateUsing, usingDirective.Name.Location, importedType); } else { declarationBinder.ReportDiagnosticsIfObsolete(diagnostics, importedType, usingDirective.Name, hasBaseReceiver: false); uniqueUsings.Add(importedType); usings.Add(new NamespaceOrTypeAndUsingDirective(importedType, usingDirective)); } } } else if (imported.Kind != SymbolKind.ErrorType) { // Do not report additional error if the symbol itself is erroneous. // error: '<symbol>' is a '<symbol kind>' but is used as 'type or namespace' diagnostics.Add(ErrorCode.ERR_BadSKknown, usingDirective.Name.Location, usingDirective.Name, imported.GetKindText(), MessageID.IDS_SK_TYPE_OR_NAMESPACE.Localize()); } } } uniqueUsings.Free(); } if (diagnostics.IsEmptyWithoutResolution) { diagnostics = null; } return(new Imports(compilation, usingAliases.ToImmutableDictionaryOrEmpty(), usings.ToImmutableAndFree(), externAliases, diagnostics)); }