/// <summary> /// Bind and return a single type parameter constraint clause along with syntax nodes corresponding to type constraints. /// </summary> private (TypeParameterConstraintClause, ArrayBuilder <TypeConstraintSyntax>?) BindTypeParameterConstraints(TypeParameterSyntax typeParameterSyntax, TypeParameterConstraintClauseSyntax constraintClauseSyntax, bool isForOverride, BindingDiagnosticBag diagnostics) { var constraints = TypeParameterConstraintKind.None; ArrayBuilder <TypeWithAnnotations>? constraintTypes = null; ArrayBuilder <TypeConstraintSyntax>?syntaxBuilder = null; SeparatedSyntaxList <TypeParameterConstraintSyntax> constraintsSyntax = constraintClauseSyntax.Constraints; Debug.Assert(!InExecutableBinder); // Cannot eagerly report diagnostics handled by LazyMissingNonNullTypesContextDiagnosticInfo bool hasTypeLikeConstraint = false; bool reportedOverrideWithConstraints = false; for (int i = 0, n = constraintsSyntax.Count; i < n; i++) { var syntax = constraintsSyntax[i]; switch (syntax.Kind()) { case SyntaxKind.ClassConstraint: hasTypeLikeConstraint = true; if (i != 0) { if (!reportedOverrideWithConstraints) { reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics); } if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0) { continue; } } var constraintSyntax = (ClassOrStructConstraintSyntax)syntax; SyntaxToken questionToken = constraintSyntax.QuestionToken; if (questionToken.IsKind(SyntaxKind.QuestionToken)) { constraints |= TypeParameterConstraintKind.NullableReferenceType; if (isForOverride) { reportOverrideWithConstraints(ref reportedOverrideWithConstraints, syntax, diagnostics); } else if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag) { LazyMissingNonNullTypesContextDiagnosticInfo.ReportNullableReferenceTypesIfNeeded( AreNullableAnnotationsEnabled(questionToken), IsGeneratedCode(questionToken), questionToken.GetLocation(), diagnosticBag); } } else if (isForOverride || AreNullableAnnotationsEnabled(constraintSyntax.ClassOrStructKeyword)) { constraints |= TypeParameterConstraintKind.NotNullableReferenceType; } else { constraints |= TypeParameterConstraintKind.ReferenceType; } continue; case SyntaxKind.StructConstraint: hasTypeLikeConstraint = true; if (i != 0) { if (!reportedOverrideWithConstraints) { reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics); } if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0) { continue; } } constraints |= TypeParameterConstraintKind.ValueType; continue; case SyntaxKind.ConstructorConstraint: if (isForOverride) { reportOverrideWithConstraints(ref reportedOverrideWithConstraints, syntax, diagnostics); continue; } if ((constraints & TypeParameterConstraintKind.ValueType) != 0) { diagnostics.Add(ErrorCode.ERR_NewBoundWithVal, syntax.GetFirstToken().GetLocation()); } if ((constraints & TypeParameterConstraintKind.Unmanaged) != 0) { diagnostics.Add(ErrorCode.ERR_NewBoundWithUnmanaged, syntax.GetFirstToken().GetLocation()); } if (i != n - 1) { diagnostics.Add(ErrorCode.ERR_NewBoundMustBeLast, syntax.GetFirstToken().GetLocation()); } constraints |= TypeParameterConstraintKind.Constructor; continue; case SyntaxKind.DefaultConstraint: if (!isForOverride) { diagnostics.Add(ErrorCode.ERR_DefaultConstraintOverrideOnly, syntax.GetLocation()); } if (i != 0) { if (!reportedOverrideWithConstraints) { reportTypeConstraintsMustBeUniqueAndFirst(syntax, diagnostics); } if (isForOverride && (constraints & (TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.ReferenceType)) != 0) { continue; } } constraints |= TypeParameterConstraintKind.Default; continue; case SyntaxKind.TypeConstraint: if (isForOverride) { reportOverrideWithConstraints(ref reportedOverrideWithConstraints, syntax, diagnostics); } else { hasTypeLikeConstraint = true; if (constraintTypes == null) { constraintTypes = ArrayBuilder <TypeWithAnnotations> .GetInstance(); syntaxBuilder = ArrayBuilder <TypeConstraintSyntax> .GetInstance(); } var typeConstraintSyntax = (TypeConstraintSyntax)syntax; var typeSyntax = typeConstraintSyntax.Type; var type = BindTypeOrConstraintKeyword(typeSyntax, diagnostics, out ConstraintContextualKeyword keyword); switch (keyword) { case ConstraintContextualKeyword.Unmanaged: if (i != 0) { reportTypeConstraintsMustBeUniqueAndFirst(typeSyntax, diagnostics); continue; } // This should produce diagnostics if the types are missing GetWellKnownType(WellKnownType.System_Runtime_InteropServices_UnmanagedType, diagnostics, typeSyntax); GetSpecialType(SpecialType.System_ValueType, diagnostics, typeSyntax); constraints |= TypeParameterConstraintKind.Unmanaged; continue; case ConstraintContextualKeyword.NotNull: if (i != 0) { reportTypeConstraintsMustBeUniqueAndFirst(typeSyntax, diagnostics); } constraints |= TypeParameterConstraintKind.NotNull; continue; case ConstraintContextualKeyword.None: break; default: throw ExceptionUtilities.UnexpectedValue(keyword); } constraintTypes.Add(type); syntaxBuilder !.Add(typeConstraintSyntax); } continue; default: throw ExceptionUtilities.UnexpectedValue(syntax.Kind()); } } if (!isForOverride && !hasTypeLikeConstraint && !AreNullableAnnotationsEnabled(typeParameterSyntax.Identifier)) { constraints |= TypeParameterConstraintKind.ObliviousNullabilityIfReferenceType; } Debug.Assert(!isForOverride || (constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)) != (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType)); return(TypeParameterConstraintClause.Create(constraints, constraintTypes?.ToImmutableAndFree() ?? ImmutableArray <TypeWithAnnotations> .Empty), syntaxBuilder);
private ImmutableArray <Symbol> BindQualifiedCref(QualifiedCrefSyntax syntax, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { // NOTE: we won't check whether container is an error type - we'll just let BindMemberCref fail // and report a blanket diagnostic. NamespaceOrTypeSymbol container = BindNamespaceOrTypeSymbolInCref(syntax.Container); return(BindMemberCref(syntax.Member, container, out ambiguityWinner, diagnostics)); }
internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, BindingDiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; Debug.Assert((object)accessor != null); FieldSymbol field = eventSymbol.AssociatedField; Debug.Assert((object)field != null); NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type; Debug.Assert(fieldType.Name == "EventRegistrationTokenTable"); MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable, diagnostics, syntax: syntax); if ((object)getOrCreateMethod == null) { Debug.Assert(diagnostics.DiagnosticBag is null || diagnostics.HasAnyErrors()); return(null); } getOrCreateMethod = getOrCreateMethod.AsMember(fieldType); WellKnownMember processHandlerMember = isAddMethod ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler; MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, processHandlerMember, diagnostics, syntax: syntax); if ((object)processHandlerMethod == null) { Debug.Assert(diagnostics.DiagnosticBag is null || diagnostics.HasAnyErrors()); return(null); } processHandlerMethod = processHandlerMethod.AsMember(fieldType); // _tokenTable BoundFieldAccess fieldAccess = new BoundFieldAccess( syntax, field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type), field, constantValueOpt: null) { WasCompilerGenerated = true }; // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable) BoundCall getOrCreateCall = BoundCall.Synthesized( syntax, receiverOpt: null, method: getOrCreateMethod, arg0: fieldAccess); // value BoundParameter parameterAccess = new BoundParameter( syntax, accessor.Parameters[0]); // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler BoundCall processHandlerCall = BoundCall.Synthesized( syntax, receiverOpt: getOrCreateCall, method: processHandlerMethod, arg0: parameterAccess); if (isAddMethod) { // { // return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value); // } BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, RefKind.None, processHandlerCall); return(BoundBlock.SynthesizedNoLocals(syntax, returnStatement)); } else { // { // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value); // return; // } BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall); BoundStatement returnStatement = new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null); return(BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement)); } }
private ImmutableArray <Symbol> BindCrefInternal(CrefSyntax syntax, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { switch (syntax.Kind()) { case SyntaxKind.TypeCref: return(BindTypeCref((TypeCrefSyntax)syntax, out ambiguityWinner, diagnostics)); case SyntaxKind.QualifiedCref: return(BindQualifiedCref((QualifiedCrefSyntax)syntax, out ambiguityWinner, diagnostics)); case SyntaxKind.NameMemberCref: case SyntaxKind.IndexerMemberCref: case SyntaxKind.OperatorMemberCref: case SyntaxKind.ConversionOperatorMemberCref: return(BindMemberCref((MemberCrefSyntax)syntax, containerOpt: null, ambiguityWinner: out ambiguityWinner, diagnostics: diagnostics)); default: throw ExceptionUtilities.UnexpectedValue(syntax.Kind()); } }
/// <summary> /// Perform lookup (optionally, in a specified container). If nothing is found and the member name matches the containing type /// name, then use the instance constructors of the type instead. The resulting symbols are sorted since tie-breaking is based /// on order and we want cref binding to be repeatable. /// </summary> /// <remarks> /// Never returns null. /// </remarks> private ImmutableArray <Symbol> ComputeSortedCrefMembers(CSharpSyntaxNode syntax, NamespaceOrTypeSymbol?containerOpt, string memberName, string memberNameText, int arity, bool hasParameterList, BindingDiagnosticBag diagnostics) { CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); var result = ComputeSortedCrefMembers(containerOpt, memberName, memberNameText, arity, hasParameterList, syntax, diagnostics, ref useSiteInfo); diagnostics.Add(syntax, useSiteInfo); return(result); }
private ImmutableArray <Symbol> BindNameMemberCref(NameMemberCrefSyntax syntax, NamespaceOrTypeSymbol?containerOpt, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { SimpleNameSyntax?nameSyntax = syntax.Name as SimpleNameSyntax; int arity; string memberName; string memberNameText; if (nameSyntax != null) { arity = nameSyntax.Arity; memberName = nameSyntax.Identifier.ValueText; memberNameText = nameSyntax.Identifier.Text; } else { // If the name isn't a SimpleNameSyntax, then we must have a type name followed by a parameter list. // Thus, we're looking for a constructor. Debug.Assert((object?)containerOpt == null); // Could be an error type, but we'll just lookup fail below. containerOpt = BindNamespaceOrTypeSymbolInCref(syntax.Name); arity = 0; memberName = memberNameText = WellKnownMemberNames.InstanceConstructorName; } if (string.IsNullOrEmpty(memberName)) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, memberNameText, arity, syntax.Parameters != null, diagnostics); if (sortedSymbols.IsEmpty) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } return(ProcessCrefMemberLookupResults( sortedSymbols, arity, syntax, typeArgumentListSyntax: arity == 0 ? null : ((GenericNameSyntax)nameSyntax !).TypeArgumentList, parameterListSyntax: syntax.Parameters, ambiguityWinner: out ambiguityWinner, diagnostics: diagnostics)); }
private ImmutableArray <Symbol> BindIndexerMemberCref(IndexerMemberCrefSyntax syntax, NamespaceOrTypeSymbol?containerOpt, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { const int arity = 0; ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, WellKnownMemberNames.Indexer, memberNameText: WellKnownMemberNames.Indexer, arity, syntax.Parameters != null, diagnostics); if (sortedSymbols.IsEmpty) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } // Since only indexers are named WellKnownMemberNames.Indexer. Debug.Assert(sortedSymbols.All(SymbolExtensions.IsIndexer)); // NOTE: guaranteed to be a property, because only indexers are considered. return(ProcessCrefMemberLookupResults( sortedSymbols, arity, syntax, typeArgumentListSyntax: null, parameterListSyntax: syntax.Parameters, ambiguityWinner: out ambiguityWinner, diagnostics: diagnostics)); }
public override void GenerateAnonymousFunctionConversionError(BindingDiagnosticBag diagnostics, TypeSymbol targetType) { // TODO: improved diagnostics for query expressions base.GenerateAnonymousFunctionConversionError(diagnostics, targetType); }
/// <remarks> /// Don't call this one directly - call one of the helpers. /// </remarks> private bool ValidateNameConflictsInScope(Symbol?symbol, Location location, string name, BindingDiagnosticBag diagnostics) { if (string.IsNullOrEmpty(name)) { return(false); } bool allowShadowing = Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions); for (Binder?binder = this; binder != null; binder = binder.Next) { // no local scopes enclose members if (binder is InContainerBinder) { return(false); } var scope = binder as LocalScopeBinder; if (scope?.EnsureSingleDefinition(symbol, name, location, diagnostics) == true) { return(true); } // If shadowing is enabled, avoid checking for conflicts outside of local functions or lambdas. if (allowShadowing && binder.IsNestedFunctionBinder) { return(false); } if (binder.IsLastBinderWithinMember()) { // Declarations within a member do not conflict with declarations outside. return(false); } } return(false); }
protected override BoundBlock CreateBlockFromLambdaExpressionBody(Binder lambdaBodyBinder, BoundExpression expression, BindingDiagnosticBag diagnostics) { throw ExceptionUtilities.Unreachable; }
protected override BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, Binder lambdaBodyBinder, BindingDiagnosticBag diagnostics) { return(_bodyFactory(lambdaSymbol, lambdaBodyBinder, diagnostics)); }
static void reportTypeConstraintsMustBeUniqueAndFirst(CSharpSyntaxNode syntax, BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, syntax.GetLocation()); }
static void reportOverrideWithConstraints(ref bool reportedOverrideWithConstraints, TypeParameterConstraintSyntax syntax, BindingDiagnosticBag diagnostics) { if (!reportedOverrideWithConstraints) { diagnostics.Add(ErrorCode.ERR_OverrideWithConstraints, syntax.GetLocation()); reportedOverrideWithConstraints = true; } }
/// <summary> /// Return a collection of bound constraint clauses indexed by type parameter /// ordinal. All constraint clauses are bound, even if there are multiple constraints /// for the same type parameter, or constraints for unrecognized type parameters. /// Extra constraints are not included in the returned collection however. /// </summary> internal ImmutableArray <TypeParameterConstraintClause> BindTypeParameterConstraintClauses( Symbol containingSymbol, ImmutableArray <TypeParameterSymbol> typeParameters, TypeParameterListSyntax typeParameterList, SyntaxList <TypeParameterConstraintClauseSyntax> clauses, BindingDiagnosticBag diagnostics, bool performOnlyCycleSafeValidation, bool isForOverride = false) { Debug.Assert(this.Flags.Includes(BinderFlags.GenericConstraintsClause)); RoslynDebug.Assert((object)containingSymbol != null); Debug.Assert((containingSymbol.Kind == SymbolKind.NamedType) || (containingSymbol.Kind == SymbolKind.Method)); Debug.Assert(typeParameters.Length > 0); Debug.Assert(clauses.Count > 0); int n = typeParameters.Length; // Create a map from type parameter name to ordinal. // No need to report duplicate names since duplicates // are reported when the type parameters are bound. var names = new Dictionary <string, int>(n, StringOrdinalComparer.Instance); foreach (var typeParameter in typeParameters) { var name = typeParameter.Name; if (!names.ContainsKey(name)) { names.Add(name, names.Count); } } // An array of constraint clauses, one for each type parameter, indexed by ordinal. var results = ArrayBuilder <TypeParameterConstraintClause?> .GetInstance(n, fillWithValue : null); var syntaxNodes = ArrayBuilder <ArrayBuilder <TypeConstraintSyntax>?> .GetInstance(n, fillWithValue : null); // Bind each clause and add to the results. foreach (var clause in clauses) { var name = clause.Name.Identifier.ValueText; RoslynDebug.Assert(name is object); int ordinal; if (names.TryGetValue(name, out ordinal)) { Debug.Assert(ordinal >= 0); Debug.Assert(ordinal < n); (TypeParameterConstraintClause constraintClause, ArrayBuilder <TypeConstraintSyntax>?typeConstraintNodes) = this.BindTypeParameterConstraints(typeParameterList.Parameters[ordinal], clause, isForOverride, diagnostics); if (results[ordinal] == null) { results[ordinal] = constraintClause; syntaxNodes[ordinal] = typeConstraintNodes; } else { // "A constraint clause has already been specified for type parameter '{0}'. ..." diagnostics.Add(ErrorCode.ERR_DuplicateConstraintClause, clause.Name.Location, name); typeConstraintNodes?.Free(); } } else { // Unrecognized type parameter. Don't bother binding the constraints // (the ": I<U>" in "where U : I<U>") since that will lead to additional // errors ("type or namespace 'U' could not be found") if the type // parameter is referenced in the constraints. // "'{1}' does not define type parameter '{0}'" diagnostics.Add(ErrorCode.ERR_TyVarNotFoundInConstraint, clause.Name.Location, name, containingSymbol.ConstructedFrom()); } } // Add default values for type parameters without constraint clauses. for (int i = 0; i < n; i++) { if (results[i] == null) { results[i] = GetDefaultTypeParameterConstraintClause(typeParameterList.Parameters[i], isForOverride); } } RemoveInvalidConstraints(typeParameters, results !, syntaxNodes, performOnlyCycleSafeValidation, diagnostics); foreach (var typeConstraintsSyntaxes in syntaxNodes) { typeConstraintsSyntaxes?.Free(); } syntaxNodes.Free(); return(results.ToImmutableAndFree() !); }
// An anonymous function can be of the form: // // delegate { } (missing parameter list) // delegate (int x) { } (typed parameter list) // x => ... (type-inferred parameter list) // (x) => ... (type-inferred parameter list) // (x, y) => ... (type-inferred parameter list) // ( ) => ... (typed parameter list) // (ref int x) => ... (typed parameter list) // (int x, out int y) => ... (typed parameter list) // // and so on. We want to canonicalize these various ways of writing the signatures. // // If we are in the first case then the name, modifier and type arrays are all null. // If we have a parameter list then the names array is non-null, but possibly empty. // If we have types then the types array is non-null, but possibly empty. // If we have no modifiers then the modifiers array is null; if we have any modifiers // then the modifiers array is non-null and not empty. private UnboundLambda AnalyzeAnonymousFunction( AnonymousFunctionExpressionSyntax syntax, BindingDiagnosticBag diagnostics) { Debug.Assert(syntax != null); Debug.Assert(syntax.IsAnonymousFunction()); var names = default(ImmutableArray <string>); var refKinds = default(ImmutableArray <RefKind>); var types = default(ImmutableArray <TypeWithAnnotations>); var attributes = default(ImmutableArray <SyntaxList <AttributeListSyntax> >); var namesBuilder = ArrayBuilder <string> .GetInstance(); ImmutableArray <bool> discardsOpt = default; SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null; bool hasSignature; if (syntax is LambdaExpressionSyntax lambdaSyntax) { checkAttributes(syntax, lambdaSyntax.AttributeLists, diagnostics); } switch (syntax.Kind()) { default: case SyntaxKind.SimpleLambdaExpression: // x => ... hasSignature = true; var simple = (SimpleLambdaExpressionSyntax)syntax; namesBuilder.Add(simple.Parameter.Identifier.ValueText); break; case SyntaxKind.ParenthesizedLambdaExpression: // (T x, U y) => ... // (x, y) => ... hasSignature = true; var paren = (ParenthesizedLambdaExpressionSyntax)syntax; parameterSyntaxList = paren.ParameterList.Parameters; CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics); break; case SyntaxKind.AnonymousMethodExpression: // delegate (int x) { } // delegate { } var anon = (AnonymousMethodExpressionSyntax)syntax; hasSignature = anon.ParameterList != null; if (hasSignature) { parameterSyntaxList = anon.ParameterList !.Parameters; } break; } var isAsync = syntax.Modifiers.Any(SyntaxKind.AsyncKeyword); var isStatic = syntax.Modifiers.Any(SyntaxKind.StaticKeyword); if (parameterSyntaxList != null) { var hasExplicitlyTypedParameterList = true; var allValue = true; var typesBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); var refKindsBuilder = ArrayBuilder <RefKind> .GetInstance(); var attributesBuilder = ArrayBuilder <SyntaxList <AttributeListSyntax> > .GetInstance(); // In the batch compiler case we probably should have given a syntax error if the // user did something like (int x, y)=>x+y -- but in the IDE scenario we might be in // this case. If we are, then rather than try to make partial deductions from the // typed formal parameters, simply bail out and treat it as an untyped lambda. // // However, we still want to give errors on every bad type in the list, even if one // is missing. int underscoresCount = 0; foreach (var p in parameterSyntaxList.Value) { if (p.Identifier.IsUnderscoreToken()) { underscoresCount++; } checkAttributes(syntax, p.AttributeLists, diagnostics); if (p.Default != null) { Error(diagnostics, ErrorCode.ERR_DefaultValueNotAllowed, p.Default.EqualsToken); } if (p.IsArgList) { Error(diagnostics, ErrorCode.ERR_IllegalVarArgs, p); continue; } var typeSyntax = p.Type; TypeWithAnnotations type = default; var refKind = RefKind.None; if (typeSyntax == null) { hasExplicitlyTypedParameterList = false; } else { type = BindType(typeSyntax, diagnostics); foreach (var modifier in p.Modifiers) { switch (modifier.Kind()) { case SyntaxKind.RefKeyword: refKind = RefKind.Ref; allValue = false; break; case SyntaxKind.OutKeyword: refKind = RefKind.Out; allValue = false; break; case SyntaxKind.InKeyword: refKind = RefKind.In; allValue = false; break; case SyntaxKind.ParamsKeyword: // This was a parse error in the native compiler; // it is a semantic analysis error in Roslyn. See comments to // changeset 1674 for details. Error(diagnostics, ErrorCode.ERR_IllegalParams, p); break; case SyntaxKind.ThisKeyword: Error(diagnostics, ErrorCode.ERR_ThisInBadContext, modifier); break; } } } namesBuilder.Add(p.Identifier.ValueText); typesBuilder.Add(type); refKindsBuilder.Add(refKind); attributesBuilder.Add(syntax.Kind() == SyntaxKind.ParenthesizedLambdaExpression ? p.AttributeLists : default);
private bool ValidateLambdaParameterNameConflictsInScope(Location location, string name, BindingDiagnosticBag diagnostics) { return(ValidateNameConflictsInScope(null, location, name, diagnostics)); }
private ImmutableArray <Symbol> BindMemberCref(MemberCrefSyntax syntax, NamespaceOrTypeSymbol?containerOpt, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { if ((object?)containerOpt != null && containerOpt.Kind == SymbolKind.TypeParameter) { // As in normal lookup (see CreateErrorIfLookupOnTypeParameter), you can't dot into a type parameter // (though you can dot into an expression of type parameter type). CrefSyntax crefSyntax = GetRootCrefSyntax(syntax); var noTrivia = syntax.WithLeadingTrivia(null).WithTrailingTrivia(null); diagnostics.Add(ErrorCode.WRN_BadXMLRef, crefSyntax.Location, noTrivia.ToFullString()); ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } ImmutableArray <Symbol> result; switch (syntax.Kind()) { case SyntaxKind.NameMemberCref: result = BindNameMemberCref((NameMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; case SyntaxKind.IndexerMemberCref: result = BindIndexerMemberCref((IndexerMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; case SyntaxKind.OperatorMemberCref: result = BindOperatorMemberCref((OperatorMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; case SyntaxKind.ConversionOperatorMemberCref: result = BindConversionOperatorMemberCref((ConversionOperatorMemberCrefSyntax)syntax, containerOpt, out ambiguityWinner, diagnostics); break; default: throw ExceptionUtilities.UnexpectedValue(syntax.Kind()); } if (!result.Any()) { CrefSyntax crefSyntax = GetRootCrefSyntax(syntax); var noTrivia = syntax.WithLeadingTrivia(null).WithTrailingTrivia(null); diagnostics.Add(ErrorCode.WRN_BadXMLRef, crefSyntax.Location, noTrivia.ToFullString()); } return(result); }
internal bool ValidateDeclarationNameConflictsInScope(Symbol symbol, BindingDiagnosticBag diagnostics) { Location location = GetLocation(symbol); return(ValidateNameConflictsInScope(symbol, location, symbol.Name, diagnostics)); }
internal ImmutableArray <Symbol> BindCref(CrefSyntax syntax, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { ImmutableArray <Symbol> symbols = BindCrefInternal(syntax, out ambiguityWinner, diagnostics); Debug.Assert(!symbols.IsDefault, "Prefer empty to null."); Debug.Assert((symbols.Length > 1) == ((object?)ambiguityWinner != null), "ambiguityWinner should be set iff more than one symbol is returned."); return(symbols); }
internal void ValidateParameterNameConflicts( ImmutableArray <TypeParameterSymbol> typeParameters, ImmutableArray <ParameterSymbol> parameters, bool allowShadowingNames, BindingDiagnosticBag diagnostics) { PooledHashSet <string>?tpNames = null; if (!typeParameters.IsDefaultOrEmpty) { tpNames = PooledHashSet <string> .GetInstance(); foreach (var tp in typeParameters) { var name = tp.Name; if (string.IsNullOrEmpty(name)) { continue; } if (!tpNames.Add(name)) { // Type parameter declaration name conflicts are detected elsewhere } else if (!allowShadowingNames) { ValidateDeclarationNameConflictsInScope(tp, diagnostics); } } } PooledHashSet <string>?pNames = null; if (!parameters.IsDefaultOrEmpty) { pNames = PooledHashSet <string> .GetInstance(); foreach (var p in parameters) { var name = p.Name; if (string.IsNullOrEmpty(name)) { continue; } if (tpNames != null && tpNames.Contains(name)) { // CS0412: 'X': a parameter or local variable cannot have the same name as a method type parameter diagnostics.Add(ErrorCode.ERR_LocalSameNameAsTypeParam, GetLocation(p), name); } if (!pNames.Add(name)) { // The parameter name '{0}' is a duplicate diagnostics.Add(ErrorCode.ERR_DuplicateParamName, GetLocation(p), name); } else if (!allowShadowingNames) { ValidateDeclarationNameConflictsInScope(p, diagnostics); } } } tpNames?.Free(); pNames?.Free(); }
// NOTE: not guaranteed to be a method (e.g. class op_Addition) // NOTE: constructor fallback logic applies private ImmutableArray <Symbol> BindOperatorMemberCref(OperatorMemberCrefSyntax syntax, NamespaceOrTypeSymbol?containerOpt, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { const int arity = 0; CrefParameterListSyntax?parameterListSyntax = syntax.Parameters; bool isChecked = syntax.CheckedKeyword.IsKind(SyntaxKind.CheckedKeyword); // NOTE: Prefer binary to unary, unless there is exactly one parameter. // CONSIDER: we're following dev11 by never using a binary operator name if there's // exactly one parameter, but doing so would allow us to match single-parameter constructors. SyntaxKind operatorTokenKind = syntax.OperatorToken.Kind(); string? memberName = parameterListSyntax != null && parameterListSyntax.Parameters.Count == 1 ? null : OperatorFacts.BinaryOperatorNameFromSyntaxKindIfAny(operatorTokenKind, isChecked); memberName = memberName ?? OperatorFacts.UnaryOperatorNameFromSyntaxKindIfAny(operatorTokenKind, isChecked: isChecked); if (memberName == null || (isChecked && !syntax.OperatorToken.IsMissing && !SyntaxFacts.IsCheckedOperator(memberName))) // the operator cannot be checked { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, memberNameText: memberName, arity, syntax.Parameters != null, diagnostics); if (sortedSymbols.IsEmpty) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } return(ProcessCrefMemberLookupResults( sortedSymbols, arity, syntax, typeArgumentListSyntax: null, parameterListSyntax: parameterListSyntax, ambiguityWinner: out ambiguityWinner, diagnostics: diagnostics)); }
private bool ReportConflictWithLocal(Symbol local, Symbol newSymbol, string name, Location newLocation, BindingDiagnosticBag diagnostics) { // Quirk of the way we represent lambda parameters. SymbolKind newSymbolKind = (object)newSymbol == null ? SymbolKind.Parameter : newSymbol.Kind; if (newSymbolKind == SymbolKind.ErrorType) { return(true); } var declaredInThisScope = false; declaredInThisScope |= newSymbolKind == SymbolKind.Local && this.Locals.Contains((LocalSymbol)newSymbol); declaredInThisScope |= newSymbolKind == SymbolKind.Method && this.LocalFunctions.Contains((LocalFunctionSymbol)newSymbol); if (declaredInThisScope && newLocation.SourceSpan.Start >= local.Locations[0].SourceSpan.Start) { // A local variable or function named '{0}' is already defined in this scope diagnostics.Add(ErrorCode.ERR_LocalDuplicate, newLocation, name); return(true); } switch (newSymbolKind) { case SymbolKind.Local: case SymbolKind.Parameter: case SymbolKind.Method: case SymbolKind.TypeParameter: // A local or parameter named '{0}' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter diagnostics.Add(ErrorCode.ERR_LocalIllegallyOverrides, newLocation, name); return(true); case SymbolKind.RangeVariable: // The range variable '{0}' conflicts with a previous declaration of '{0}' diagnostics.Add(ErrorCode.ERR_QueryRangeVariableOverrides, newLocation, name); return(true); } Debug.Assert(false, "what else can be declared inside a local scope?"); diagnostics.Add(ErrorCode.ERR_InternalError, newLocation); return(false); }
// NOTE: not guaranteed to be a method (e.g. class op_Implicit) private ImmutableArray <Symbol> BindConversionOperatorMemberCref(ConversionOperatorMemberCrefSyntax syntax, NamespaceOrTypeSymbol?containerOpt, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { const int arity = 0; bool isChecked = syntax.CheckedKeyword.IsKind(SyntaxKind.CheckedKeyword); string memberName; if (syntax.ImplicitOrExplicitKeyword.Kind() == SyntaxKind.ImplicitKeyword) { if (isChecked) { // checked form is not supported ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } memberName = WellKnownMemberNames.ImplicitConversionName; } else if (isChecked) { memberName = WellKnownMemberNames.CheckedExplicitConversionName; } else { memberName = WellKnownMemberNames.ExplicitConversionName; } ImmutableArray <Symbol> sortedSymbols = ComputeSortedCrefMembers(syntax, containerOpt, memberName, memberNameText: memberName, arity, syntax.Parameters != null, diagnostics); if (sortedSymbols.IsEmpty) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } TypeSymbol returnType = BindCrefParameterOrReturnType(syntax.Type, syntax, diagnostics); // Filter out methods with the wrong return type, since overload resolution won't catch these. sortedSymbols = sortedSymbols.WhereAsArray((symbol, returnType) => symbol.Kind != SymbolKind.Method || TypeSymbol.Equals(((MethodSymbol)symbol).ReturnType, returnType, TypeCompareKind.ConsiderEverything2), returnType); if (!sortedSymbols.Any()) { ambiguityWinner = null; return(ImmutableArray <Symbol> .Empty); } return(ProcessCrefMemberLookupResults( sortedSymbols, arity, syntax, typeArgumentListSyntax: null, parameterListSyntax: syntax.Parameters, ambiguityWinner: out ambiguityWinner, diagnostics: diagnostics)); }
internal virtual bool EnsureSingleDefinition(Symbol symbol, string name, Location location, BindingDiagnosticBag diagnostics) { LocalSymbol existingLocal = null; LocalFunctionSymbol existingLocalFunction = null; var localsMap = this.LocalsMap; var localFunctionsMap = this.LocalFunctionsMap; // TODO: Handle case where 'name' exists in both localsMap and localFunctionsMap. Right now locals are preferred over local functions. if ((localsMap != null && localsMap.TryGetValue(name, out existingLocal)) || (localFunctionsMap != null && localFunctionsMap.TryGetValue(name, out existingLocalFunction))) { var existingSymbol = (Symbol)existingLocal ?? existingLocalFunction; if (symbol == existingSymbol) { // reference to same symbol, by far the most common case. return(false); } return(ReportConflictWithLocal(existingSymbol, symbol, name, location, diagnostics)); } return(false); }
private ImmutableArray <Symbol> BindTypeCref(TypeCrefSyntax syntax, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { NamespaceOrTypeSymbol result = BindNamespaceOrTypeSymbolInCref(syntax.Type); // NOTE: we don't have to worry about the case where a non-error type is constructed // with erroneous type arguments, because only MemberCrefs have type arguments - // all other crefs only have type parameters. if (result.Kind == SymbolKind.ErrorType) { var noTrivia = syntax.WithLeadingTrivia(null).WithTrailingTrivia(null); diagnostics.Add(ErrorCode.WRN_BadXMLRef, syntax.Location, noTrivia.ToFullString()); } // We'll never have more than one type, but it is conceivable that result could // be an ExtendedErrorTypeSymbol with multiple candidates. ambiguityWinner = null; return(ImmutableArray.Create <Symbol>(result)); }
public static void IssueDiagnostics(CSharpCompilation compilation, BoundNode node, BindingDiagnosticBag diagnostics, MethodSymbol containingSymbol) { Debug.Assert(node != null); Debug.Assert((object)containingSymbol != null); ExecutableCodeBinder.ValidateIteratorMethod(compilation, containingSymbol, diagnostics); try { var diagnosticPass = new DiagnosticsPass(compilation, diagnostics, containingSymbol); diagnosticPass.Visit(node); } catch (CancelledByStackGuardException ex) { ex.AddAnError(diagnostics); } }
internal static BoundBlock ConstructFieldLikeEventAccessorBody(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, BindingDiagnosticBag diagnostics) { Debug.Assert(eventSymbol.HasAssociatedField); return(eventSymbol.IsWindowsRuntimeEvent ? ConstructFieldLikeEventAccessorBody_WinRT(eventSymbol, isAddMethod, compilation, diagnostics) : ConstructFieldLikeEventAccessorBody_Regular(eventSymbol, isAddMethod, compilation, diagnostics)); }
internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag diagnostics = null) => null;
internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, BindingDiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; TypeSymbol delegateType = eventSymbol.Type; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; ParameterSymbol thisParameter = accessor.ThisParameter; TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); SpecialMember updateMethodId = isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove; MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(updateMethodId); BoundStatement @return = new BoundReturnStatement(syntax, refKind: RefKind.None, expressionOpt: null) { WasCompilerGenerated = true }; if (updateMethod == null) { MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(updateMethodId); diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, memberDescriptor.DeclaringTypeMetadataName, memberDescriptor.Name), syntax.Location)); return(BoundBlock.SynthesizedNoLocals(syntax, @return)); } Binder.ReportUseSite(updateMethod, diagnostics, syntax); BoundThisReference fieldReceiver = eventSymbol.IsStatic ? null : new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true }; BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax, receiver: fieldReceiver, fieldSymbol: eventSymbol.AssociatedField, constantValueOpt: null) { WasCompilerGenerated = true }; BoundParameter boundParameter = new BoundParameter(syntax, parameterSymbol: accessor.Parameters[0]) { WasCompilerGenerated = true }; BoundExpression delegateUpdate; MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T); if ((object)compareExchangeMethod == null) { // (DelegateType)Delegate.Combine(_event, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // _event = (DelegateType)Delegate.Combine(_event, value); BoundStatement eventUpdate = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundBackingField, right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; return(BoundBlock.SynthesizedNoLocals(syntax, statements: ImmutableArray.Create <BoundStatement>( eventUpdate, @return))); } compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType)); Binder.ReportUseSite(compareExchangeMethod, diagnostics, syntax); GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop"); const int numTemps = 3; LocalSymbol[] tmps = new LocalSymbol[numTemps]; BoundLocal[] boundTmps = new BoundLocal[numTemps]; for (int i = 0; i < numTemps; i++) { tmps[i] = new SynthesizedLocal(accessor, TypeWithAnnotations.Create(delegateType), SynthesizedLocalKind.LoweringTemp); boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType) { WasCompilerGenerated = true }; } // tmp0 = _event; BoundStatement tmp0Init = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: boundBackingField, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // LOOP: BoundStatement loopStart = new BoundLabelStatement(syntax, label: loopLabel) { WasCompilerGenerated = true }; // tmp1 = tmp0; BoundStatement tmp1Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[1], right: boundTmps[0], type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // (DelegateType)Delegate.Combine(tmp1, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // tmp2 = (DelegateType)Delegate.Combine(tmp1, value); BoundStatement tmp2Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[2], right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1) BoundExpression compareExchange = BoundCall.Synthesized(syntax, receiverOpt: null, method: compareExchangeMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1])); // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); BoundStatement tmp0Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: compareExchange, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise BoundExpression loopExitCondition = new BoundBinaryOperator(syntax, operatorKind: BinaryOperatorKind.ObjectEqual, left: boundTmps[0], right: boundTmps[1], constantValueOpt: null, methodOpt: null, constrainedToTypeOpt: null, resultKind: LookupResultKind.Viable, type: boolType) { WasCompilerGenerated = true }; // branchfalse (tmp0 == tmp1) LOOP BoundStatement loopEnd = new BoundConditionalGoto(syntax, condition: loopExitCondition, jumpIfTrue: false, label: loopLabel) { WasCompilerGenerated = true }; return(new BoundBlock(syntax, locals: tmps.AsImmutable(), statements: ImmutableArray.Create <BoundStatement>( tmp0Init, loopStart, tmp1Update, tmp2Update, tmp0Update, loopEnd, @return)) { WasCompilerGenerated = true }); }
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 = SpecializedSymbolCollections.GetPooledSymbolHashSetInstance <NamespaceOrTypeSymbol>(); foreach (var usingDirective in usingDirectives) { compilation.RecordImport(usingDirective); if (usingDirective.Alias != null) { SyntaxToken identifier = usingDirective.Alias.Name.Identifier; Location location = usingDirective.Alias.Name.Location; if (identifier.ContextualKind() == SyntaxKind.GlobalKeyword) { diagnostics.Add(ErrorCode.WRN_GlobalAliasDefn, location); } if (usingDirective.StaticKeyword != default(SyntaxToken)) { diagnostics.Add(ErrorCode.ERR_NoAliasHere, location); } SourceMemberContainerTypeSymbol.ReportTypeNamedRecord(identifier.Text, compilation, diagnostics, location); string identifierValueText = 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, 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.Name, usingDirective.Alias), usingDirective)); } } else { if (usingDirective.Name.IsMissing) { //don't try to lookup namespaces inserted by parser error recovery continue; } var directiveDiagnostics = BindingDiagnosticBag.GetInstance(); var declarationBinder = usingsBinder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); var imported = declarationBinder.BindNamespaceOrTypeSymbol(usingDirective.Name, directiveDiagnostics, basesBeingResolved).NamespaceOrTypeSymbol; if (imported.Kind == SymbolKind.Namespace) { Debug.Assert(directiveDiagnostics.DependenciesBag.IsEmpty()); if (usingDirective.StaticKeyword != default(SyntaxToken)) { diagnostics.Add(ErrorCode.ERR_BadUsingType, usingDirective.Name.Location, imported); } else if (!uniqueUsings.Add(imported)) { diagnostics.Add(ErrorCode.WRN_DuplicateUsing, usingDirective.Name.Location, imported); } else { usings.Add(new NamespaceOrTypeAndUsingDirective(imported, usingDirective, dependencies: default)); } } 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, directiveDiagnostics.DependenciesBag.ToImmutableArray())); } } } 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()); } diagnostics.AddRange(directiveDiagnostics.DiagnosticBag); directiveDiagnostics.Free(); } } uniqueUsings.Free(); } if (diagnostics.IsEmptyWithoutResolution) { diagnostics = null; } return(new Imports(compilation, usingAliases.ToImmutableDictionaryOrEmpty(), usings.ToImmutableAndFree(), externAliases, diagnostics)); }