protected BoundExpression ConvertCaseExpression(CSharpSyntaxNode node, BoundExpression caseExpression, Binder sectionBinder, out ConstantValue constantValueOpt, BindingDiagnosticBag diagnostics, bool isGotoCaseExpr = false) { bool hasErrors = false; if (isGotoCaseExpr) { // SPEC VIOLATION for Dev10 COMPATIBILITY: // Dev10 compiler violates the SPEC comment below: // "if the constant-expression is not implicitly convertible (§6.1) to // the governing type of the nearest enclosing switch statement, // a compile-time error occurs" // If there is no implicit conversion from gotoCaseExpression to switchGoverningType, // but there exists an explicit conversion, Dev10 compiler generates a warning "WRN_GotoCaseShouldConvert" // instead of an error. See test "CS0469_NoImplicitConversionWarning". CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); Conversion conversion = Conversions.ClassifyConversionFromExpression(caseExpression, SwitchGoverningType, ref useSiteInfo); diagnostics.Add(node, useSiteInfo); if (!conversion.IsValid) { GenerateImplicitConversionError(diagnostics, node, conversion, caseExpression, SwitchGoverningType); hasErrors = true; } else if (!conversion.IsImplicit) { diagnostics.Add(ErrorCode.WRN_GotoCaseShouldConvert, node.Location, SwitchGoverningType); hasErrors = true; } caseExpression = CreateConversion(caseExpression, conversion, SwitchGoverningType, diagnostics); } return(ConvertPatternExpression(SwitchGoverningType, node, caseExpression, out constantValueOpt, hasErrors, diagnostics)); }
internal static bool CheckFeatureAvailability( this MessageID feature, BindingDiagnosticBag diagnostics, SyntaxNode syntax, Location?location = null) { var diag = GetFeatureAvailabilityDiagnosticInfo(feature, (CSharpParseOptions)syntax.SyntaxTree.Options); if (diag is object) { diagnostics.Add(diag, location ?? syntax.GetLocation()); return(false); } return(true); }
internal static bool CheckFeatureAvailability( this MessageID feature, BindingDiagnosticBag diagnostics, Compilation compilation, Location location ) { if ( GetFeatureAvailabilityDiagnosticInfo(feature, (CSharpCompilation)compilation) is { } diagInfo ) { diagnostics.Add(diagInfo, location); return(false); } return(true); }
/// <summary> /// Checks that the Awaiter implements System.Runtime.CompilerServices.INotifyCompletion. /// </summary> /// <remarks> /// Spec 7.7.7.1: /// An Awaiter A implements the interface System.Runtime.CompilerServices.INotifyCompletion. /// </remarks> private bool AwaiterImplementsINotifyCompletion(TypeSymbol awaiterType, SyntaxNode node, BindingDiagnosticBag diagnostics) { var INotifyCompletion = GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_INotifyCompletion, diagnostics, node); CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); var conversion = this.Conversions.ClassifyImplicitConversionFromType(awaiterType, INotifyCompletion, ref useSiteInfo); if (!conversion.IsImplicit) { diagnostics.Add(node, useSiteInfo); Error(diagnostics, ErrorCode.ERR_DoesntImplementAwaitInterface, node, awaiterType, INotifyCompletion); return(false); } Debug.Assert(conversion.IsValid); return(true); }
private static bool ReportQueryInferenceFailedSelectMany( FromClauseSyntax fromClause, string methodName, BoundExpression receiver, AnalyzedArguments arguments, ImmutableArray <Symbol> symbols, BindingDiagnosticBag diagnostics ) { Debug.Assert(methodName == "SelectMany"); // Estimate the return type of Select's lambda argument BoundExpression arg = arguments.Argument(arguments.IsExtensionMethodInvocation ? 1 : 0); TypeSymbol type = null; if (arg.Kind == BoundKind.UnboundLambda) { var unbound = (UnboundLambda)arg; foreach (var t in unbound.Data.InferredReturnTypes()) { if (!t.IsErrorType()) { type = t; break; } } } if ((object)type == null || type.IsErrorType()) { return(false); } TypeSymbol receiverType = receiver?.Type; diagnostics.Add( new DiagnosticInfoWithSymbols( ErrorCode.ERR_QueryTypeInferenceFailedSelectMany, new object[] { type, receiverType, methodName }, symbols ), fromClause.Expression.Location ); return(true); }
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)); }
internal override BoundStatement BindSwitchStatementCore(SwitchStatementSyntax node, Binder originalBinder, BindingDiagnosticBag diagnostics) { Debug.Assert(SwitchSyntax.Equals(node)); if (node.Sections.Count == 0) { diagnostics.Add(ErrorCode.WRN_EmptySwitch, node.OpenBraceToken.GetLocation()); } // Bind switch expression and set the switch governing type. BoundExpression boundSwitchGoverningExpression = SwitchGoverningExpression; diagnostics.AddRange(SwitchGoverningDiagnostics, allowMismatchInDependencyAccumulation: true); ImmutableArray <BoundSwitchSection> switchSections = BindSwitchSections(originalBinder, diagnostics, out BoundSwitchLabel defaultLabel); ImmutableArray <LocalSymbol> locals = GetDeclaredLocalsForScope(node); ImmutableArray <LocalFunctionSymbol> functions = GetDeclaredLocalFunctionsForScope(node); BoundDecisionDag decisionDag = DecisionDagBuilder.CreateDecisionDagForSwitchStatement( compilation: this.Compilation, syntax: node, switchGoverningExpression: boundSwitchGoverningExpression, switchSections: switchSections, // If there is no explicit default label, the default action is to break out of the switch defaultLabel: defaultLabel?.Label ?? BreakLabel, diagnostics); // Report subsumption errors, but ignore the input's constant value for that. CheckSwitchErrors(node, boundSwitchGoverningExpression, ref switchSections, decisionDag, diagnostics); // When the input is constant, we use that to reshape the decision dag that is returned // so that flow analysis will see that some of the cases may be unreachable. decisionDag = decisionDag.SimplifyDecisionDagIfConstantInput(boundSwitchGoverningExpression); return(new BoundSwitchStatement( syntax: node, expression: boundSwitchGoverningExpression, innerLocals: locals, innerLocalFunctions: functions, switchSections: switchSections, defaultLabel: defaultLabel, breakLabel: this.BreakLabel, reachabilityDecisionDag: decisionDag)); }
internal bool ReportUnsafeIfNotAllowed( SyntaxNode node, BindingDiagnosticBag diagnostics, TypeSymbol sizeOfTypeOpt = null ) { Debug.Assert( (node.Kind() == SyntaxKind.SizeOfExpression) == ((object)sizeOfTypeOpt != null), "Should have a type for (only) sizeof expressions." ); var diagnosticInfo = GetUnsafeDiagnosticInfo(sizeOfTypeOpt); if (diagnosticInfo == null) { return(false); } diagnostics.Add(new CSDiagnostic(diagnosticInfo, node.Location)); return(true); }
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); }
internal RangeVariableSymbol AddRangeVariable( Binder binder, SyntaxToken identifier, BindingDiagnosticBag diagnostics ) { string name = identifier.ValueText; var result = new RangeVariableSymbol( name, binder.ContainingMemberOrLambda, identifier.GetLocation() ); bool error = false; foreach (var existingRangeVariable in allRangeVariables.Keys) { if (existingRangeVariable.Name == name) { diagnostics.Add( ErrorCode.ERR_QueryDuplicateRangeVariable, identifier.GetLocation(), name ); error = true; } } if (!error) { var collisionDetector = new LocalScopeBinder(binder); collisionDetector.ValidateDeclarationNameConflictsInScope(result, diagnostics); } allRangeVariables.Add(result, ArrayBuilder <string> .GetInstance()); return(result); }
private bool CheckSwitchExpressionExhaustive( SwitchExpressionSyntax node, BoundExpression boundInputExpression, ImmutableArray <BoundSwitchExpressionArm> switchArms, out BoundDecisionDag decisionDag, out LabelSymbol defaultLabel, BindingDiagnosticBag diagnostics) { defaultLabel = new GeneratedLabelSymbol("default"); decisionDag = DecisionDagBuilder.CreateDecisionDagForSwitchExpression(this.Compilation, node, boundInputExpression, switchArms, defaultLabel, diagnostics); var reachableLabels = decisionDag.ReachableLabels; bool hasErrors = false; foreach (BoundSwitchExpressionArm arm in switchArms) { hasErrors |= arm.HasErrors; if (!hasErrors && !reachableLabels.Contains(arm.Label)) { diagnostics.Add(ErrorCode.ERR_SwitchArmSubsumed, arm.Pattern.Syntax.Location); } } if (!reachableLabels.Contains(defaultLabel)) { // switch expression is exhaustive; no default label needed. defaultLabel = null; return(false); } if (hasErrors) { return(true); } // We only report exhaustive warnings when the default label is reachable through some series of // tests that do not include a test in which the value is known to be null. Handling paths with // nulls is the job of the nullable walker. bool wasAcyclic = TopologicalSort.TryIterativeSort <BoundDecisionDagNode>(new[] { decisionDag.RootNode }, nonNullSuccessors, out var nodes); // Since decisionDag.RootNode is acyclic by construction, its subset of nodes sorted here cannot be cyclic Debug.Assert(wasAcyclic); foreach (var n in nodes) { if (n is BoundLeafDecisionDagNode leaf && leaf.Label == defaultLabel) { var samplePattern = PatternExplainer.SamplePatternForPathToDagNode( BoundDagTemp.ForOriginalInput(boundInputExpression), nodes, n, nullPaths: false, out bool requiresFalseWhenClause, out bool unnamedEnumValue); ErrorCode warningCode = requiresFalseWhenClause ? ErrorCode.WRN_SwitchExpressionNotExhaustiveWithWhen : unnamedEnumValue ? ErrorCode.WRN_SwitchExpressionNotExhaustiveWithUnnamedEnumValue : ErrorCode.WRN_SwitchExpressionNotExhaustive; diagnostics.Add( warningCode, node.SwitchKeyword.GetLocation(), samplePattern); return(true); } } return(false); ImmutableArray <BoundDecisionDagNode> nonNullSuccessors(BoundDecisionDagNode n) { switch (n) { case BoundTestDecisionDagNode p: switch (p.Test) { case BoundDagNonNullTest t: // checks that the input is not null return(ImmutableArray.Create(p.WhenTrue)); case BoundDagExplicitNullTest t: // checks that the input is null return(ImmutableArray.Create(p.WhenFalse)); default: return(BoundDecisionDag.Successors(n)); } default: return(BoundDecisionDag.Successors(n)); } } }
private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpressionSyntax node, BindingDiagnosticBag diagnostics) { // prepare var initializers = node.Initializers; int fieldCount = initializers.Count; bool hasError = false; // bind field initializers BoundExpression[] boundExpressions = new BoundExpression[fieldCount]; AnonymousTypeField[] fields = new AnonymousTypeField[fieldCount]; CSharpSyntaxNode[] fieldSyntaxNodes = new CSharpSyntaxNode[fieldCount]; // WARNING: Note that SemanticModel.GetDeclaredSymbol for field initializer node relies on // the fact that the order of properties in anonymous type template corresponds // 1-to-1 to the appropriate filed initializer syntax nodes; This means such // correspondence must be preserved all the time including erroneous scenarios // set of names already used var uniqueFieldNames = PooledHashSet <string> .GetInstance(); for (int i = 0; i < fieldCount; i++) { AnonymousObjectMemberDeclaratorSyntax fieldInitializer = initializers[i]; NameEqualsSyntax?nameEquals = fieldInitializer.NameEquals; ExpressionSyntax expression = fieldInitializer.Expression; SyntaxToken nameToken = default(SyntaxToken); if (nameEquals != null) { nameToken = nameEquals.Name.Identifier; } else { if (!IsAnonymousTypeMemberExpression(expression)) { hasError = true; diagnostics.Add(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, expression.GetLocation()); } nameToken = expression.ExtractAnonymousTypeMemberName(); } hasError |= expression.HasErrors; boundExpressions[i] = BindRValueWithoutTargetType(expression, diagnostics); // check the name to be unique string?fieldName = null; if (nameToken.Kind() == SyntaxKind.IdentifierToken) { fieldName = nameToken.ValueText; if (!uniqueFieldNames.Add(fieldName !)) { // name duplication Error(diagnostics, ErrorCode.ERR_AnonymousTypeDuplicatePropertyName, fieldInitializer); hasError = true; fieldName = null; } } else { // there is something wrong with field's name hasError = true; } // calculate the expression's type and report errors if needed TypeSymbol fieldType = GetAnonymousTypeFieldType(boundExpressions[i], fieldInitializer, diagnostics, ref hasError); // build anonymous type field descriptor fieldSyntaxNodes[i] = (nameToken.Kind() == SyntaxKind.IdentifierToken) ? (CSharpSyntaxNode)nameToken.Parent ! : fieldInitializer; fields[i] = new AnonymousTypeField( fieldName == null ? "$" + i.ToString() : fieldName, fieldSyntaxNodes[i].Location, TypeWithAnnotations.Create(fieldType), RefKind.None, DeclarationScope.Unscoped); // NOTE: ERR_InvalidAnonymousTypeMemberDeclarator (CS0746) would be generated by parser if needed } uniqueFieldNames.Free(); // Create anonymous type AnonymousTypeManager manager = this.Compilation.AnonymousTypeManager; AnonymousTypeDescriptor descriptor = new AnonymousTypeDescriptor(fields.AsImmutableOrNull(), node.NewKeyword.GetLocation()); NamedTypeSymbol anonymousType = manager.ConstructAnonymousTypeSymbol(descriptor); // declarators - bound nodes created for providing semantic info // on anonymous type fields having explicitly specified name ArrayBuilder <BoundAnonymousPropertyDeclaration> declarators = ArrayBuilder <BoundAnonymousPropertyDeclaration> .GetInstance(); for (int i = 0; i < fieldCount; i++) { NameEqualsSyntax?explicitName = initializers[i].NameEquals; if (explicitName != null) { AnonymousTypeField field = fields[i]; if (field.Name != null) { // get property symbol and create a bound property declaration node foreach (var symbol in anonymousType.GetMembers(field.Name)) { if (symbol.Kind == SymbolKind.Property) { declarators.Add(new BoundAnonymousPropertyDeclaration(fieldSyntaxNodes[i], (PropertySymbol)symbol, field.Type)); break; } } } } } // check if anonymous object creation is allowed in this context if (!this.IsAnonymousTypesAllowed()) { Error(diagnostics, ErrorCode.ERR_AnonymousTypeNotAvailable, node.NewKeyword); hasError = true; } // Finally create a bound node return(new BoundAnonymousObjectCreationExpression( node, anonymousType.InstanceConstructors[0], boundExpressions.AsImmutableOrNull(), declarators.ToImmutableAndFree(), anonymousType, hasError)); }
private BoundExpression SelectField( SimpleNameSyntax node, BoundExpression receiver, string name, BindingDiagnosticBag diagnostics ) { var receiverType = receiver.Type as NamedTypeSymbol; if ((object)receiverType == null || !receiverType.IsAnonymousType) { // We only construct transparent query variables using anonymous types, so if we're trying to navigate through // some other type, we must have some query API where the types don't match up as expected. var info = new CSDiagnosticInfo( ErrorCode.ERR_UnsupportedTransparentIdentifierAccess, name, receiver.ExpressionSymbol ?? receiverType ); if (receiver.Type?.IsErrorType() != true) { Error(diagnostics, info, node); } return(new BoundBadExpression( node, LookupResultKind.Empty, ImmutableArray.Create <Symbol>(receiver.ExpressionSymbol), ImmutableArray.Create(BindToTypeForErrorRecovery(receiver)), new ExtendedErrorTypeSymbol(this.Compilation, "", 0, info) )); } LookupResult lookupResult = LookupResult.GetInstance(); LookupOptions options = LookupOptions.MustBeInstance; CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo( diagnostics ); LookupMembersWithFallback( lookupResult, receiver.Type, name, 0, ref useSiteInfo, basesBeingResolved: null, options: options ); diagnostics.Add(node, useSiteInfo); var result = BindMemberOfType( node, node, name, 0, indexed: false, receiver, default(SeparatedSyntaxList <TypeSyntax>), default(ImmutableArray <TypeWithAnnotations>), lookupResult, BoundMethodGroupFlags.None, diagnostics ); lookupResult.Free(); return(result); }
/// <summary> /// Given a list of viable lookup results (based on the name, arity, and containing symbol), /// attempt to select one. /// </summary> private ImmutableArray <Symbol> ProcessCrefMemberLookupResults( ImmutableArray <Symbol> symbols, int arity, MemberCrefSyntax memberSyntax, TypeArgumentListSyntax?typeArgumentListSyntax, BaseCrefParameterListSyntax?parameterListSyntax, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { Debug.Assert(!symbols.IsEmpty); if (parameterListSyntax == null) { return(ProcessParameterlessCrefMemberLookupResults(symbols, arity, memberSyntax, typeArgumentListSyntax, out ambiguityWinner, diagnostics)); } ArrayBuilder <Symbol> candidates = ArrayBuilder <Symbol> .GetInstance(); GetCrefOverloadResolutionCandidates(symbols, arity, typeArgumentListSyntax, candidates); ImmutableArray <ParameterSymbol> parameterSymbols = BindCrefParameters(parameterListSyntax, diagnostics); ImmutableArray <Symbol> results = PerformCrefOverloadResolution(candidates, parameterSymbols, arity, memberSyntax, out ambiguityWinner, diagnostics); candidates.Free(); // NOTE: This diagnostic is just a hint that might help fix a broken cref, so don't do // any work unless there are no viable candidates. if (results.Length == 0) { for (int i = 0; i < parameterSymbols.Length; i++) { if (ContainsNestedTypeOfUnconstructedGenericType(parameterSymbols[i].Type)) { // This warning is new in Roslyn, because our better-defined semantics for // cref lookup disallow some things that were possible in dev12. // // Consider the following code: // // public class C<T> // { // public class Inner { } // // public void M(Inner i) { } // // /// <see cref="M"/> // /// <see cref="C{T}.M"/> // /// <see cref="C{Q}.M"/> // /// <see cref="C{Q}.M(C{Q}.Inner)"/> // /// <see cref="C{Q}.M(Inner)"/> // WRN_UnqualifiedNestedTypeInCref // public void N() { } // } // // Dev12 binds all of the crefs as "M:C`1.M(C{`0}.Inner)". // Roslyn accepts all but the last. The issue is that the context for performing // the lookup is not C<Q>, but C<T>. Consequently, Inner binds to C<T>.Inner and // then overload resolution fails because C<T>.Inner does not match C<Q>.Inner, // the parameter type of C<Q>.M. Since we could not agree that the old behavior // was desirable (other than for backwards compatibility) and since mimicking it // would have been expensive, we settled on introducing a new warning that at // least hints to the user how then can work around the issue (i.e. by qualifying // Inner as C{Q}.Inner). Additional details are available in DevDiv #743425. // // CONSIDER: We could actually put the qualified form in the warning message, // but that would probably just make it more frustrating (i.e. if the compiler // knows exactly what I mean, why do I have to type it). // // NOTE: This is not a great location (whole parameter instead of problematic type), // but it's better than nothing. diagnostics.Add(ErrorCode.WRN_UnqualifiedNestedTypeInCref, parameterListSyntax.Parameters[i].Location); break; } } } return(results); }
/// <summary> /// At this point, we have a list of viable symbols and no parameter list with which to perform /// overload resolution. We'll just return the first symbol, giving a diagnostic if there are /// others. /// Caveat: If there are multiple candidates and only one is from source, then the source symbol /// wins and no diagnostic is reported. /// </summary> private ImmutableArray <Symbol> ProcessParameterlessCrefMemberLookupResults( ImmutableArray <Symbol> symbols, int arity, MemberCrefSyntax memberSyntax, TypeArgumentListSyntax?typeArgumentListSyntax, out Symbol?ambiguityWinner, BindingDiagnosticBag diagnostics) { // If the syntax indicates arity zero, then we match methods of any arity. // However, if there are both generic and non-generic methods, then the // generic methods should be ignored. if (symbols.Length > 1 && arity == 0) { bool hasNonGenericMethod = false; bool hasGenericMethod = false; foreach (Symbol s in symbols) { if (s.Kind != SymbolKind.Method) { continue; } if (((MethodSymbol)s).Arity == 0) { hasNonGenericMethod = true; } else { hasGenericMethod = true; } if (hasGenericMethod && hasNonGenericMethod) { break; //Nothing else to be learned. } } if (hasNonGenericMethod && hasGenericMethod) { symbols = symbols.WhereAsArray(s => s.Kind != SymbolKind.Method || ((MethodSymbol)s).Arity == 0); } } Debug.Assert(!symbols.IsEmpty); Symbol symbol = symbols[0]; // If there's ambiguity, prefer source symbols. // Logic is similar to ResultSymbol, but separate because the error handling is totally different. if (symbols.Length > 1) { // Size is known, but IndexOfSymbolFromCurrentCompilation expects a builder. ArrayBuilder <Symbol> unwrappedSymbols = ArrayBuilder <Symbol> .GetInstance(symbols.Length); foreach (Symbol wrapped in symbols) { unwrappedSymbols.Add(UnwrapAliasNoDiagnostics(wrapped)); } BestSymbolInfo secondBest; BestSymbolInfo best = GetBestSymbolInfo(unwrappedSymbols, out secondBest); Debug.Assert(!best.IsNone); Debug.Assert(!secondBest.IsNone); unwrappedSymbols.Free(); int symbolIndex = 0; if (best.IsFromCompilation) { symbolIndex = best.Index; symbol = symbols[symbolIndex]; // NOTE: symbols, not unwrappedSymbols. } if (symbol.Kind == SymbolKind.TypeParameter) { CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax); diagnostics.Add(ErrorCode.WRN_BadXMLRefTypeVar, crefSyntax.Location, crefSyntax.ToString()); } else if (secondBest.IsFromCompilation == best.IsFromCompilation) { CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax); int otherIndex = symbolIndex == 0 ? 1 : 0; diagnostics.Add(ErrorCode.WRN_AmbiguousXMLReference, crefSyntax.Location, crefSyntax.ToString(), symbol, symbols[otherIndex]); ambiguityWinner = ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, symbol); return(symbols.SelectAsArray(sym => ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, sym))); } } else if (symbol.Kind == SymbolKind.TypeParameter) { CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax); diagnostics.Add(ErrorCode.WRN_BadXMLRefTypeVar, crefSyntax.Location, crefSyntax.ToString()); } ambiguityWinner = null; return(ImmutableArray.Create <Symbol>(ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, symbol))); }
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, @checked: false) { 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 BoundBlock Rewrite( MethodSymbol method, BoundBlock block, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, bool hasTrailingExpression, bool originalBodyNested) { #if DEBUG // We should only see a trailingExpression if we're in a Script initializer. Debug.Assert(!hasTrailingExpression || method.IsScriptInitializer); var initialDiagnosticCount = diagnostics.ToReadOnly().Diagnostics.Length; #endif var compilation = method.DeclaringCompilation; if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation)) { ImmutableArray <FieldSymbol> implicitlyInitializedFields = default; bool needsImplicitReturn = true; // we don't analyze synthesized void methods. if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || Analyze(compilation, method, block, diagnostics.DiagnosticBag, out needsImplicitReturn, out implicitlyInitializedFields)) { if (!implicitlyInitializedFields.IsDefault) { Debug.Assert(!implicitlyInitializedFields.IsEmpty); block = PrependImplicitInitializations(block, method, implicitlyInitializedFields, compilationState, diagnostics); } if (needsImplicitReturn) { block = AppendImplicitReturn(block, method, originalBodyNested); } } } else if (Analyze(compilation, method, block, diagnostics.DiagnosticBag, out var needsImplicitReturn, out var unusedImplicitlyInitializedFields)) { Debug.Assert(unusedImplicitlyInitializedFields.IsDefault); Debug.Assert(needsImplicitReturn); // If the method is a lambda expression being converted to a non-void delegate type // and the end point is reachable then suppress the error here; a special error // will be reported by the lambda binder. Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction); // Add implicit "return default(T)" if this is a submission that does not have a trailing expression. var submissionResultType = (method as SynthesizedInteractiveInitializerMethod)?.ResultType; if (!hasTrailingExpression && ((object)submissionResultType != null)) { Debug.Assert(!submissionResultType.IsVoidType()); var trailingExpression = new BoundDefaultExpression(method.GetNonNullSyntaxNode(), submissionResultType); var newStatements = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, RefKind.None, trailingExpression, @checked: false)); block = new BoundBlock(block.Syntax, ImmutableArray <LocalSymbol> .Empty, newStatements) { WasCompilerGenerated = true }; #if DEBUG // It should not be necessary to repeat analysis after adding this node, because adding a trailing // return in cases where one was missing should never produce different Diagnostics. IEnumerable <Diagnostic> getErrorsOnly(IEnumerable <Diagnostic> diags) => diags.Where(d => d.Severity == DiagnosticSeverity.Error); var flowAnalysisDiagnostics = DiagnosticBag.GetInstance(); Debug.Assert(!Analyze(compilation, method, block, flowAnalysisDiagnostics, needsImplicitReturn: out _, out unusedImplicitlyInitializedFields)); Debug.Assert(unusedImplicitlyInitializedFields.IsDefault); // Ignore warnings since flow analysis reports nullability mismatches. Debug.Assert(getErrorsOnly(flowAnalysisDiagnostics.ToReadOnly()).SequenceEqual(getErrorsOnly(diagnostics.ToReadOnly().Diagnostics.Skip(initialDiagnosticCount)))); flowAnalysisDiagnostics.Free(); #endif } // If there's more than one location, then the method is partial and we // have already reported a non-void partial method error. else if (method.Locations.Length == 1) { diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method); } } return(block); }
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(); }
public void AddAnError(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InsufficientStack, GetTooLongOrComplexExpressionErrorLocation(Node)); }
private static void ReportNamesMismatchesIfAny( BoundExpression left, BoundExpression right, ImmutableArray <string> leftNames, ImmutableArray <string> rightNames, BindingDiagnosticBag diagnostics ) { bool leftIsTupleLiteral = left is BoundTupleExpression; bool rightIsTupleLiteral = right is BoundTupleExpression; if (!leftIsTupleLiteral && !rightIsTupleLiteral) { return; } bool leftNoNames = leftNames.IsDefault; bool rightNoNames = rightNames.IsDefault; if (leftNoNames && rightNoNames) { return; } Debug.Assert(leftNoNames || rightNoNames || leftNames.Length == rightNames.Length); ImmutableArray <bool> leftInferred = leftIsTupleLiteral ? ((BoundTupleExpression)left).InferredNamesOpt : default; bool leftNoInferredNames = leftInferred.IsDefault; ImmutableArray <bool> rightInferred = rightIsTupleLiteral ? ((BoundTupleExpression)right).InferredNamesOpt : default; bool rightNoInferredNames = rightInferred.IsDefault; int length = leftNoNames ? rightNames.Length : leftNames.Length; for (int i = 0; i < length; i++) { string leftName = leftNoNames ? null : leftNames[i]; string rightName = rightNoNames ? null : rightNames[i]; bool different = string.CompareOrdinal(rightName, leftName) != 0; if (!different) { continue; } bool leftWasInferred = leftNoInferredNames ? false : leftInferred[i]; bool rightWasInferred = rightNoInferredNames ? false : rightInferred[i]; bool leftComplaint = leftIsTupleLiteral && leftName != null && !leftWasInferred; bool rightComplaint = rightIsTupleLiteral && rightName != null && !rightWasInferred; if (!leftComplaint && !rightComplaint) { // No complaints, let's move on continue; } // When in doubt, we'll complain on the right side if it's a literal bool useRight = (leftComplaint && rightComplaint) ? rightIsTupleLiteral : rightComplaint; Location location = ((BoundTupleExpression)(useRight ? right : left)).Arguments[ i ].Syntax.Parent.Location; string complaintName = useRight ? rightName : leftName; diagnostics.Add( ErrorCode.WRN_TupleBinopLiteralNameMismatch, location, complaintName ); } }
private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSyntax node, BindingDiagnosticBag diagnostics) { var builder = ArrayBuilder <BoundExpression> .GetInstance(); var stringType = GetSpecialType(SpecialType.System_String, diagnostics, node); ConstantValue?resultConstant = null; bool isResultConstant = true; if (node.Contents.Count == 0) { resultConstant = ConstantValue.Create(string.Empty); } else { var objectType = GetSpecialType(SpecialType.System_Object, diagnostics, node); var intType = GetSpecialType(SpecialType.System_Int32, diagnostics, node); foreach (var content in node.Contents) { switch (content.Kind()) { case SyntaxKind.Interpolation: { var interpolation = (InterpolationSyntax)content; var value = BindValue(interpolation.Expression, diagnostics, BindValueKind.RValue); if (value.Type is null) { value = GenerateConversionForAssignment(objectType, value, diagnostics); } else { value = BindToNaturalType(value, diagnostics); _ = GenerateConversionForAssignment(objectType, value, diagnostics); } // We need to ensure the argument is not a lambda, method group, etc. It isn't nice to wait until lowering, // when we perform overload resolution, to report a problem. So we do that check by calling // GenerateConversionForAssignment with objectType. However we want to preserve the original expression's // natural type so that overload resolution may select a specialized implementation of string.Format, // so we discard the result of that call and only preserve its diagnostics. BoundExpression?alignment = null; BoundLiteral? format = null; if (interpolation.AlignmentClause != null) { alignment = GenerateConversionForAssignment(intType, BindValue(interpolation.AlignmentClause.Value, diagnostics, Binder.BindValueKind.RValue), diagnostics); var alignmentConstant = alignment.ConstantValue; if (alignmentConstant != null && !alignmentConstant.IsBad) { const int magnitudeLimit = 32767; // check that the magnitude of the alignment is "in range". int alignmentValue = alignmentConstant.Int32Value; // We do the arithmetic using negative numbers because the largest negative int has no corresponding positive (absolute) value. alignmentValue = (alignmentValue > 0) ? -alignmentValue : alignmentValue; if (alignmentValue < -magnitudeLimit) { diagnostics.Add(ErrorCode.WRN_AlignmentMagnitude, alignment.Syntax.Location, alignmentConstant.Int32Value, magnitudeLimit); } } else if (!alignment.HasErrors) { diagnostics.Add(ErrorCode.ERR_ConstantExpected, interpolation.AlignmentClause.Value.Location); } } if (interpolation.FormatClause != null) { var text = interpolation.FormatClause.FormatStringToken.ValueText; char lastChar; bool hasErrors = false; if (text.Length == 0) { diagnostics.Add(ErrorCode.ERR_EmptyFormatSpecifier, interpolation.FormatClause.Location); hasErrors = true; } else if (SyntaxFacts.IsWhitespace(lastChar = text[text.Length - 1]) || SyntaxFacts.IsNewLine(lastChar)) { diagnostics.Add(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, interpolation.FormatClause.Location); hasErrors = true; } format = new BoundLiteral(interpolation.FormatClause, ConstantValue.Create(text), stringType, hasErrors); } builder.Add(new BoundStringInsert(interpolation, value, alignment, format, null)); if (!isResultConstant || value.ConstantValue == null || !(interpolation is { FormatClause: null, AlignmentClause: null }) || !(value.ConstantValue is { IsString: true, IsBad: false }))
/// <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.AddAll(this, questionToken, type: null, 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 bool ValidateAttributeUsage( CSharpAttributeData attribute, AttributeSyntax node, CSharpCompilation compilation, AttributeLocation symbolPart, BindingDiagnosticBag diagnostics, HashSet <NamedTypeSymbol> uniqueAttributeTypes ) { Debug.Assert(!attribute.HasErrors); NamedTypeSymbol attributeType = attribute.AttributeClass; AttributeUsageInfo attributeUsageInfo = attributeType.GetAttributeUsageInfo(); // Given attribute can't be specified more than once if AllowMultiple is false. if (!uniqueAttributeTypes.Add(attributeType) && !attributeUsageInfo.AllowMultiple) { diagnostics.Add( ErrorCode.ERR_DuplicateAttribute, node.Name.Location, node.GetErrorDisplayName() ); return(false); } // Verify if the attribute type can be applied to given owner symbol. AttributeTargets attributeTarget; if (symbolPart == AttributeLocation.Return) { // attribute on return type Debug.Assert(this.Kind == SymbolKind.Method); attributeTarget = AttributeTargets.ReturnValue; } else { attributeTarget = this.GetAttributeTarget(); } if ((attributeTarget & attributeUsageInfo.ValidTargets) == 0) { // generate error diagnostics.Add( ErrorCode.ERR_AttributeOnBadSymbolType, node.Name.Location, node.GetErrorDisplayName(), attributeUsageInfo.GetValidTargetsErrorArgument() ); return(false); } if (attribute.IsSecurityAttribute(compilation)) { switch (this.Kind) { case SymbolKind.Assembly: case SymbolKind.NamedType: case SymbolKind.Method: break; default: // CS7070: Security attribute '{0}' is not valid on this declaration type. Security attributes are only valid on assembly, type and method declarations. diagnostics.Add( ErrorCode.ERR_SecurityAttributeInvalidTarget, node.Name.Location, node.GetErrorDisplayName() ); return(false); } } return(true); }
private static bool MatchAttributeTarget( IAttributeTargetSymbol attributeTarget, AttributeLocation symbolPart, AttributeTargetSpecifierSyntax targetOpt, BindingDiagnosticBag diagnostics ) { IAttributeTargetSymbol attributesOwner = attributeTarget.AttributesOwner; // Determine if the target symbol owns the attribute declaration. // We need to report diagnostics only once, so do it when visiting attributes for the owner. bool isOwner = symbolPart == AttributeLocation.None && ReferenceEquals(attributesOwner, attributeTarget); if (targetOpt == null) { // only attributes with an explicit target match if the symbol doesn't own the attributes: return(isOwner); } AttributeLocation allowedTargets = attributesOwner.AllowedAttributeLocations; AttributeLocation explicitTarget = targetOpt.GetAttributeLocation(); if (explicitTarget == AttributeLocation.None) { // error: unknown attribute location if (isOwner) { //NOTE: ValueText so that we accept targets like "@return", to match dev10 (DevDiv #2591). diagnostics.Add( ErrorCode.WRN_InvalidAttributeLocation, targetOpt.Identifier.GetLocation(), targetOpt.Identifier.ValueText, allowedTargets.ToDisplayString() ); } return(false); } if ((explicitTarget & allowedTargets) == 0) { // error: invalid target for symbol if (isOwner) { if (allowedTargets == AttributeLocation.None) { switch (attributeTarget.DefaultAttributeLocation) { case AttributeLocation.Assembly: case AttributeLocation.Module: // global attributes are disallowed in interactive code: diagnostics.Add( ErrorCode.ERR_GlobalAttributesNotAllowed, targetOpt.Identifier.GetLocation() ); break; default: // currently this can't happen throw ExceptionUtilities.UnexpectedValue( attributeTarget.DefaultAttributeLocation ); } } else { diagnostics.Add( ErrorCode.WRN_AttributeLocationOnBadDeclaration, targetOpt.Identifier.GetLocation(), targetOpt.Identifier.ToString(), allowedTargets.ToDisplayString() ); } } return(false); } if (symbolPart == AttributeLocation.None) { return(explicitTarget == attributeTarget.DefaultAttributeLocation); } else { return(explicitTarget == symbolPart); } }
internal static BoundStatement Rewrite( BoundStatement bodyWithAwaitLifted, MethodSymbol method, int methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, out AsyncStateMachine stateMachineType ) { if (!method.IsAsync) { stateMachineType = null; return(bodyWithAwaitLifted); } CSharpCompilation compilation = method.DeclaringCompilation; bool isAsyncEnumerableOrEnumerator = method.IsAsyncReturningIAsyncEnumerable(compilation) || method.IsAsyncReturningIAsyncEnumerator(compilation); if (isAsyncEnumerableOrEnumerator && !method.IsIterator) { bool containsAwait = AwaitDetector.ContainsAwait(bodyWithAwaitLifted); diagnostics.Add( containsAwait ? ErrorCode.ERR_PossibleAsyncIteratorWithoutYield : ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, method.Locations[0], method.ReturnTypeWithAnnotations ); stateMachineType = null; return(bodyWithAwaitLifted); } // The CLR doesn't support adding fields to structs, so in order to enable EnC in an async method we need to generate a class. // For async-iterators, we also need to generate a class. var typeKind = (compilationState.Compilation.Options.EnableEditAndContinue || method.IsIterator) ? TypeKind.Class : TypeKind.Struct; stateMachineType = new AsyncStateMachine( slotAllocatorOpt, compilationState, method, methodOrdinal, typeKind ); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType( method, stateMachineType ); AsyncRewriter rewriter = isAsyncEnumerableOrEnumerator ? new AsyncIteratorRewriter( bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics ) : new AsyncRewriter( bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics ); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return(bodyWithAwaitLifted); } try { return(rewriter.Rewrite()); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); return(new BoundBadStatement( bodyWithAwaitLifted.Syntax, ImmutableArray.Create <BoundNode>(bodyWithAwaitLifted), hasErrors: true )); } }
internal BoundExpression BindQuery(QueryExpressionSyntax node, BindingDiagnosticBag diagnostics) { var fromClause = node.FromClause; var boundFromExpression = BindLeftOfPotentialColorColorMemberAccess(fromClause.Expression, diagnostics); // If the from expression is of the type dynamic we can't infer the types for any lambdas that occur in the query. // Only if there are none we could bind the query but we report an error regardless since such queries are not useful. if (boundFromExpression.HasDynamicType()) { diagnostics.Add(ErrorCode.ERR_BadDynamicQuery, fromClause.Expression.Location); boundFromExpression = BadExpression(fromClause.Expression, boundFromExpression); } else { boundFromExpression = BindToNaturalType(boundFromExpression, diagnostics); } QueryTranslationState state = new QueryTranslationState(); state.fromExpression = MakeMemberAccessValue(boundFromExpression, diagnostics); var x = state.rangeVariable = state.AddRangeVariable(this, fromClause.Identifier, diagnostics); for (int i = node.Body.Clauses.Count - 1; i >= 0; i--) { state.clauses.Push(node.Body.Clauses[i]); } state.selectOrGroup = node.Body.SelectOrGroup; // A from clause that explicitly specifies a range variable type // from T x in e // is translated into // from x in ( e ) . Cast < T > ( ) BoundExpression?cast = null; if (fromClause.Type != null) { var typeRestriction = BindTypeArgument(fromClause.Type, diagnostics); cast = MakeQueryInvocation(fromClause, state.fromExpression, "Cast", fromClause.Type, typeRestriction, diagnostics); state.fromExpression = cast; } state.fromExpression = MakeQueryClause(fromClause, state.fromExpression, x, castInvocation: cast); BoundExpression result = BindQueryInternal1(state, diagnostics); for (QueryContinuationSyntax?continuation = node.Body.Continuation; continuation != null; continuation = continuation.Body.Continuation) { // A query expression with a continuation // from ... into x ... // is translated into // from x in ( from ... ) ... state.Clear(); state.fromExpression = result; x = state.rangeVariable = state.AddRangeVariable(this, continuation.Identifier, diagnostics); Debug.Assert(state.clauses.IsEmpty()); var clauses = continuation.Body.Clauses; for (int i = clauses.Count - 1; i >= 0; i--) { state.clauses.Push(clauses[i]); } state.selectOrGroup = continuation.Body.SelectOrGroup; result = BindQueryInternal1(state, diagnostics); result = MakeQueryClause(continuation.Body, result, x); result = MakeQueryClause(continuation, result, x); } state.Free(); return(MakeQueryClause(node, result)); }
private XNode[] RewriteIncludeElement(XElement includeElement, string currentXmlFilePath, CSharpSyntaxNode originatingSyntax, out string commentMessage) { Location location = GetIncludeElementLocation(includeElement, ref currentXmlFilePath, ref originatingSyntax); Debug.Assert(originatingSyntax != null); bool diagnose = originatingSyntax.SyntaxTree.ReportDocumentationCommentDiagnostics(); if (!EnterIncludeElement(location)) { // NOTE: these must exist since we're already processed this node elsewhere in the call stack. XAttribute fileAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.FileAttributeName)); XAttribute pathAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.PathAttributeName)); string filePathValue = fileAttr.Value; string xpathValue = pathAttr.Value; if (diagnose) { _diagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new LocalizableErrorArgument(MessageID.IDS_OperationCausedStackOverflow)); } commentMessage = ErrorFacts.GetMessage(MessageID.IDS_XMLNOINCLUDE, CultureInfo.CurrentUICulture); // Don't inspect the children - we're already in a cycle. return(new XNode[] { new XComment(commentMessage), includeElement.Copy(copyAttributeAnnotations: false) }); } DiagnosticBag includeDiagnostics = DiagnosticBag.GetInstance(); try { XAttribute fileAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.FileAttributeName)); XAttribute pathAttr = includeElement.Attribute(XName.Get(DocumentationCommentXmlNames.PathAttributeName)); bool hasFileAttribute = fileAttr != null; bool hasPathAttribute = pathAttr != null; if (!hasFileAttribute || !hasPathAttribute) { var subMessage = hasFileAttribute ? MessageID.IDS_XMLMISSINGINCLUDEPATH.Localize() : MessageID.IDS_XMLMISSINGINCLUDEFILE.Localize(); includeDiagnostics.Add(ErrorCode.WRN_InvalidInclude, location, subMessage); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLBADINCLUDE); return(null); } string xpathValue = pathAttr.Value; string filePathValue = fileAttr.Value; var resolver = _compilation.Options.XmlReferenceResolver; if (resolver == null) { includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new CodeAnalysisResourcesLocalizableErrorArgument(nameof(CodeAnalysisResources.XmlReferencesNotSupported))); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); return(null); } string resolvedFilePath = resolver.ResolveReference(filePathValue, currentXmlFilePath); if (resolvedFilePath == null) { // NOTE: same behavior as IOException. includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, new CodeAnalysisResourcesLocalizableErrorArgument(nameof(CodeAnalysisResources.FileNotFound))); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); return(null); } if (_includedFileCache == null) { _includedFileCache = new DocumentationCommentIncludeCache(resolver); } try { XDocument doc; try { doc = _includedFileCache.GetOrMakeDocument(resolvedFilePath); } catch (IOException e) { // NOTE: same behavior as resolvedFilePath == null. includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, e.Message); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); return(null); } Debug.Assert(doc != null); string errorMessage; bool invalidXPath; XElement[] loadedElements = XmlUtilities.TrySelectElements(doc, xpathValue, out errorMessage, out invalidXPath); if (loadedElements == null) { includeDiagnostics.Add(ErrorCode.WRN_FailedInclude, location, filePathValue, xpathValue, errorMessage); commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLFAILEDINCLUDE); if (invalidXPath) { // leave the include node as is return(null); } if (location.IsInSource) { // As in Dev11, return only the comment - drop the include element. return(new XNode[] { new XComment(commentMessage) }); } else { commentMessage = null; return(Array.Empty <XNode>()); } } if (loadedElements != null && loadedElements.Length > 0) { // change the current XML file path for nodes contained in the document: XNode[] result = RewriteMany(loadedElements, resolvedFilePath, originatingSyntax); // The elements could be rewritten away if they are includes that refer to invalid // (but existing and accessible) XML files. If this occurs, behave as if we // had failed to find any XPath results (as in Dev11). if (result.Length > 0) { // NOTE: in this case, we do NOT visit the children of the include element - // they are dropped. commentMessage = null; return(result); } } commentMessage = MakeCommentMessage(location, MessageID.IDS_XMLNOINCLUDE); return(null); } catch (XmlException e) { // NOTE: invalid XML is handled differently from other errors - we don't include the include element // in the results and the location is in the included (vs includING) file. Location errorLocation = XmlLocation.Create(e, resolvedFilePath); includeDiagnostics.Add(ErrorCode.WRN_XMLParseIncludeError, errorLocation, GetDescription(e)); //NOTE: location is in included file. if (location.IsInSource) { commentMessage = string.Format(ErrorFacts.GetMessage(MessageID.IDS_XMLIGNORED2, CultureInfo.CurrentUICulture), resolvedFilePath); // As in Dev11, return only the comment - drop the include element. return(new XNode[] { new XComment(commentMessage) }); } else { commentMessage = null; return(Array.Empty <XNode>()); } } } finally { if (diagnose) { _diagnostics.AddRange(includeDiagnostics); } includeDiagnostics.Free(); LeaveIncludeElement(location); } }
static void reportTypeConstraintsMustBeUniqueAndFirst(CSharpSyntaxNode syntax, BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_TypeConstraintsMustBeUniqueAndFirst, syntax.GetLocation()); }
/// <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() !); }
private void Error(ErrorCode code, BoundNode node, params object[] args) { _diagnostics.Add(code, node.Syntax.Location, args); }