// basesBeingResolved is only used to break circular references. internal NamespaceOrTypeSymbol GetAliasTarget(ConsList <TypeSymbol>?basesBeingResolved) { if (!_state.HasComplete(CompletionPart.AliasTarget)) { // the target is not yet bound. If it is an ordinary alias, bind the target // symbol. If it is an extern alias then find the target in the list of metadata references. var newDiagnostics = BindingDiagnosticBag.GetInstance(); NamespaceOrTypeSymbol symbol = this.IsExtern ? ResolveExternAliasTarget(newDiagnostics) : ResolveAliasTarget(_aliasTargetName, newDiagnostics, basesBeingResolved); if ((object?)Interlocked.CompareExchange(ref _aliasTarget, symbol, null) == null) { // Note: It's important that we don't call newDiagnosticsToReadOnlyAndFree here. That call // can force the prompt evaluation of lazy initialized diagnostics. That in turn can // call back into GetAliasTarget on the same thread resulting in a dead lock scenario. bool won = Interlocked.Exchange(ref _aliasTargetDiagnostics, newDiagnostics) == null; Debug.Assert(won, "Only one thread can win the alias target CompareExchange"); _state.NotePartComplete(CompletionPart.AliasTarget); // we do not clear this.aliasTargetName, as another thread might be about to use it for ResolveAliasTarget(...) } else { newDiagnostics.Free(); // Wait for diagnostics to have been reported if another thread resolves the alias _state.SpinWaitComplete(CompletionPart.AliasTarget, default(CancellationToken)); } } return(_aliasTarget !); }
internal sealed override ImmutableArray <NamedTypeSymbol> InterfacesNoUseSiteDiagnostics( ConsList <TypeSymbol> basesBeingResolved ) { if (_lazyInterfaces.IsDefault) { if ( basesBeingResolved != null && basesBeingResolved.ContainsReference(this.OriginalDefinition) ) { return(ImmutableArray <NamedTypeSymbol> .Empty); } var diagnostics = BindingDiagnosticBag.GetInstance(); var acyclicInterfaces = MakeAcyclicInterfaces(basesBeingResolved, diagnostics); if ( ImmutableInterlocked.InterlockedCompareExchange( ref _lazyInterfaces, acyclicInterfaces, default(ImmutableArray <NamedTypeSymbol>) ).IsDefault ) { AddDeclarationDiagnostics(diagnostics); } diagnostics.Free(); } return(_lazyInterfaces); }
internal void ComputeReturnType() { if (_lazyReturnType is object) { return; } var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); TypeSyntax returnTypeSyntax = Syntax.ReturnType; TypeWithAnnotations returnType = _binder.BindType(returnTypeSyntax.SkipRef(), diagnostics); var compilation = DeclaringCompilation; // Skip some diagnostics when the local function is not associated with a compilation // (specifically, local functions nested in expressions in the EE). if (compilation is object) { var location = returnTypeSyntax.Location; if (_refKind == RefKind.RefReadOnly) { compilation.EnsureIsReadOnlyAttributeExists(diagnostics, location, modifyCompilation: false); } if (returnType.Type.ContainsNativeInteger()) { compilation.EnsureNativeIntegerAttributeExists(diagnostics, location, modifyCompilation: false); } if (compilation.ShouldEmitNullableAttributes(this) && returnType.NeedsNullableAttribute()) { compilation.EnsureNullableAttributeExists(diagnostics, location, modifyCompilation: false); // Note: we don't need to warn on annotations used in #nullable disable context for local functions, as this is handled in binding already } } // span-like types are returnable in general if (returnType.IsRestrictedType(ignoreSpanLikeTypes: true)) { // The return type of a method, delegate, or function pointer cannot be '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, returnTypeSyntax.Location, returnType.Type); } Debug.Assert(_refKind == RefKind.None || !returnType.IsVoidType() || returnTypeSyntax.HasErrors); lock (_declarationDiagnostics) { if (_lazyReturnType is object) { diagnostics.Free(); return; } _declarationDiagnostics.AddRangeAndFree(diagnostics); Interlocked.CompareExchange(ref _lazyReturnType, new TypeWithAnnotations.Boxed(returnType), null); } }
internal override TypeWithAnnotations GetFieldType(ConsList <FieldSymbol> fieldsBeingBound) { Debug.Assert(fieldsBeingBound != null); if (_lazyType != null) { return(_lazyType.Value); } var typeSyntax = TypeSyntax; var compilation = this.DeclaringCompilation; var diagnostics = BindingDiagnosticBag.GetInstance(); TypeWithAnnotations type; bool isVar; var binderFactory = compilation.GetBinderFactory(SyntaxTree); var binder = binderFactory.GetBinder(typeSyntax ?? SyntaxNode); if (typeSyntax != null) { type = binder.BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar); } else { // Recursive patterns may omit the type syntax isVar = true; type = default; } Debug.Assert(type.HasType || isVar); if (isVar && !fieldsBeingBound.ContainsReference(this)) { InferFieldType(fieldsBeingBound, binder); Debug.Assert(_lazyType != null); } else { if (isVar) { diagnostics.Add( ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this ); type = TypeWithAnnotations.Create(binder.CreateErrorType("var")); } SetType(compilation, diagnostics, type); } diagnostics.Free(); return(_lazyType.Value); }
protected void LazyMethodChecks() { if (!state.HasComplete(CompletionPart.FinishMethodChecks)) { // TODO: if this lock ever encloses a potential call to Debugger.NotifyOfCrossThreadDependency, // then we should call DebuggerUtilities.CallBeforeAcquiringLock() (see method comment for more // details). object lockObject = MethodChecksLockObject; Debug.Assert(lockObject != null); lock (lockObject) { if (state.NotePartComplete(CompletionPart.StartMethodChecks)) { // By setting StartMethodChecks, we've committed to doing the checks and setting // FinishMethodChecks. So there is no cancellation supported between one and the other. var diagnostics = BindingDiagnosticBag.GetInstance(); try { MethodChecks(diagnostics); AddDeclarationDiagnostics(diagnostics); } finally { state.NotePartComplete(CompletionPart.FinishMethodChecks); diagnostics.Free(); } } else { // Either (1) this thread is in the process of completing the method, // or (2) some other thread has beat us to the punch and completed the method. // We can distinguish the two cases here by checking for the FinishMethodChecks // part to be complete, which would only occur if another thread completed this // method. // // The other case, in which this thread is in the process of completing the method, // requires that we return here even though the checks are not complete. That's because // methods are processed by first populating the return type and parameters by binding // the syntax from source. Those values are visible to the same thread for the purpose // of computing which methods are implemented and overridden. But then those values // may be rewritten (by the same thread) to copy down custom modifiers. In order to // allow the same thread to see the return type and parameters from the syntax (though // they do not yet take on their final values), we return here. // Due to the fact that LazyMethodChecks is potentially reentrant, we must use a // reentrant lock to avoid deadlock and cannot assert that at this point method checks // have completed (state.HasComplete(CompletionPart.FinishMethodChecks)). } } } }
private void ComputeParameters() { if (_lazyParameters != null) { return; } SyntaxToken arglistToken; var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); var parameters = ParameterHelpers.MakeParameters( _binder, this, this.Syntax.ParameterList, arglistToken: out arglistToken, allowRefOrOut: true, allowThis: true, addRefReadOnlyModifier: false, diagnostics: diagnostics); var compilation = DeclaringCompilation; ParameterHelpers.EnsureIsReadOnlyAttributeExists(compilation, parameters, diagnostics, modifyCompilation: false); ParameterHelpers.EnsureNativeIntegerAttributeExists(compilation, parameters, diagnostics, modifyCompilation: false); ParameterHelpers.EnsureNullableAttributeExists(compilation, this, parameters, diagnostics, modifyCompilation: false); foreach (var parameter in parameters) { ParameterHelpers.ReportParameterNullCheckingErrors(diagnostics.DiagnosticBag, parameter); } // Note: we don't need to warn on annotations used in #nullable disable context for local functions, as this is handled in binding already var isVararg = arglistToken.Kind() == SyntaxKind.ArgListKeyword; if (isVararg) { diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation()); } lock (_declarationDiagnostics) { if (_lazyParameters != null) { diagnostics.Free(); return; } _declarationDiagnostics.AddRangeAndFree(diagnostics); _lazyIsVarArg = isVararg; _lazyParameters = parameters; } }
internal Tuple <NamedTypeSymbol, ImmutableArray <NamedTypeSymbol> > GetDeclaredBases(ConsList <TypeSymbol> basesBeingResolved) { if (ReferenceEquals(_lazyDeclaredBases, null)) { var diagnostics = BindingDiagnosticBag.GetInstance(); if (Interlocked.CompareExchange(ref _lazyDeclaredBases, MakeDeclaredBases(basesBeingResolved, diagnostics), null) == null) { AddDeclarationDiagnostics(diagnostics); } diagnostics.Free(); } return(_lazyDeclaredBases); }
private void MakeConstantTuple(LocalSymbol inProgress, BoundExpression boundInitValue) { if (this.IsConst && _constantTuple == null) { var value = Microsoft.CodeAnalysis.ConstantValue.Bad; Location initValueNodeLocation = _initializer.Value.Location; var diagnostics = BindingDiagnosticBag.GetInstance(); Debug.Assert(inProgress != this); var type = this.Type; if (boundInitValue == null) { var inProgressBinder = new LocalInProgressBinder(this, this._initializerBinder); boundInitValue = inProgressBinder.BindVariableOrAutoPropInitializerValue(_initializer, this.RefKind, type, diagnostics); } value = ConstantValueUtils.GetAndValidateConstantValue(boundInitValue, this, type, initValueNodeLocation, diagnostics); Interlocked.CompareExchange(ref _constantTuple, new EvaluatedConstant(value, diagnostics.ToReadOnlyAndFree()), null); } }
internal void GetDeclarationDiagnostics(BindingDiagnosticBag addTo) { // Force complete type parameters foreach (var typeParam in _typeParameters) { typeParam.ForceComplete(null, default(CancellationToken)); } // force lazy init ComputeParameters(); foreach (var p in _lazyParameters) { // Force complete parameters to retrieve all diagnostics p.ForceComplete(null, default(CancellationToken)); } ComputeReturnType(); GetAttributes(); GetReturnTypeAttributes(); AsyncMethodChecks(_declarationDiagnostics); addTo.AddRange(_declarationDiagnostics, allowMismatchInDependencyAccumulation: true); var diagnostics = BindingDiagnosticBag.GetInstance( withDiagnostics: false, withDependencies: addTo.AccumulatesDependencies ); if ( IsEntryPointCandidate && !IsGenericMethod && ContainingSymbol is SynthesizedSimpleProgramEntryPointSymbol && DeclaringCompilation.HasEntryPointSignature(this, diagnostics).IsCandidate ) { addTo.Add(ErrorCode.WRN_MainIgnored, Syntax.Identifier.GetLocation(), this); } addTo.AddRangeAndFree(diagnostics); }
protected sealed override void LazyAsyncMethodChecks(CancellationToken cancellationToken) { Debug.Assert(this.IsPartial == state.HasComplete(CompletionPart.FinishMethodChecks), "Partial methods complete method checks during construction. " + "Other methods can't complete method checks before executing this method."); if (!this.IsAsync) { CompleteAsyncMethodChecks(diagnosticsOpt: null, cancellationToken: cancellationToken); return; } var diagnostics = BindingDiagnosticBag.GetInstance(); AsyncMethodChecks(diagnostics); CompleteAsyncMethodChecks(diagnostics, cancellationToken); diagnostics.Free(); }
internal ImmutableArray <Diagnostic> FlowDiagnostics(CSharpCompilation compilation) { var flowDiagnostics = BindingDiagnosticBag.GetInstance(); foreach (var method in AllMethods(compilation.SourceModule.GlobalNamespace)) { var sourceSymbol = method as SourceMemberMethodSymbol; if (sourceSymbol == null) { continue; } var compilationState = new TypeCompilationState(sourceSymbol.ContainingType, compilation, null); var boundBody = MethodCompiler.BindMethodBody(sourceSymbol, compilationState, new BindingDiagnosticBag(new DiagnosticBag())); if (boundBody != null) { FlowAnalysisPass.Rewrite(sourceSymbol, boundBody, compilationState, flowDiagnostics, hasTrailingExpression: false, originalBodyNested: false); } } return(flowDiagnostics.ToReadOnlyAndFree().Diagnostics); }
private TypeParameterBounds GetBounds(ConsList <TypeParameterSymbol> inProgress) { Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); if (!_lazyBounds.IsSet()) { var diagnostics = BindingDiagnosticBag.GetInstance(); var bounds = this.ResolveBounds(inProgress, diagnostics); if (ReferenceEquals(Interlocked.CompareExchange(ref _lazyBounds, bounds, TypeParameterBounds.Unset), TypeParameterBounds.Unset)) { this.CheckConstraintTypeConstraints(diagnostics); this.CheckUnmanagedConstraint(diagnostics); this.EnsureAttributesFromConstraints(diagnostics); this.AddDeclarationDiagnostics(diagnostics); _state.NotePartComplete(CompletionPart.TypeParameterConstraints); } diagnostics.Free(); } return(_lazyBounds); }
internal override void ForceComplete(SourceLocation locationOpt, CancellationToken cancellationToken) { while (true) { cancellationToken.ThrowIfCancellationRequested(); var incompletePart = _state.NextIncompletePart; switch (incompletePart) { case CompletionPart.Attributes: GetAttributes(); break; case CompletionPart.StartValidatingReferencedAssemblies: { BindingDiagnosticBag diagnostics = null; if (AnyReferencedAssembliesAreLinked) { diagnostics = BindingDiagnosticBag.GetInstance(); ValidateLinkedAssemblies(diagnostics, cancellationToken); } if (_state.NotePartComplete(CompletionPart.StartValidatingReferencedAssemblies)) { if (diagnostics != null) { _assemblySymbol.AddDeclarationDiagnostics(diagnostics); } _state.NotePartComplete(CompletionPart.FinishValidatingReferencedAssemblies); } if (diagnostics != null) { diagnostics.Free(); } } break; case CompletionPart.FinishValidatingReferencedAssemblies: // some other thread has started validating references (otherwise we would be in the case above) so // we just wait for it to both finish and report the diagnostics. Debug.Assert(_state.HasComplete(CompletionPart.StartValidatingReferencedAssemblies)); _state.SpinWaitComplete(CompletionPart.FinishValidatingReferencedAssemblies, cancellationToken); break; case CompletionPart.MembersCompleted: this.GlobalNamespace.ForceComplete(locationOpt, cancellationToken); if (this.GlobalNamespace.HasComplete(CompletionPart.MembersCompleted)) { _state.NotePartComplete(CompletionPart.MembersCompleted); } else { Debug.Assert(locationOpt != null, "If no location was specified, then the namespace members should be completed"); return; } break; case CompletionPart.None: return; default: // any other values are completion parts intended for other kinds of symbols _state.NotePartComplete(incompletePart); break; } _state.SpinWaitComplete(incompletePart, cancellationToken); } }
internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingType, Binder binder, SyntaxTokenList modifiers, VariableDeclaratorSyntax declaratorSyntax, BindingDiagnosticBag diagnostics) : base(containingType, declaratorSyntax, modifiers, isFieldLike: true, interfaceSpecifierSyntaxOpt: null, nameTokenSyntax: declaratorSyntax.Identifier, diagnostics: diagnostics) { Debug.Assert(declaratorSyntax.Parent is object); _name = declaratorSyntax.Identifier.ValueText; var declaratorDiagnostics = BindingDiagnosticBag.GetInstance(); var declarationSyntax = (VariableDeclarationSyntax)declaratorSyntax.Parent; _type = BindEventType(binder, declarationSyntax.Type, declaratorDiagnostics); // The runtime will not treat the accessors of this event as overrides or implementations // of those of another event unless both the signatures and the custom modifiers match. // Hence, in the case of overrides and *explicit* implementations (not possible for field-like // events), we need to copy the custom modifiers that are in the signatures of the // overridden/implemented event accessors. (From source, we know that there can only be one // overridden/implemented event, so there are no conflicts.) This is unnecessary for implicit // implementations because, if the custom modifiers don't match, we'll insert bridge methods // for the accessors (explicit implementations that delegate to the implicit implementations) // with the correct custom modifiers (see SourceMemberContainerTypeSymbol.SynthesizeInterfaceMemberImplementation). // If this event is an override, we may need to copy custom modifiers from // the overridden event (so that the runtime will recognize it as an override). // We check for this case here, while we can still modify the parameters and // return type without losing the appearance of immutability. if (this.IsOverride) { EventSymbol?overriddenEvent = this.OverriddenEvent; if ((object?)overriddenEvent != null) { CopyEventCustomModifiers(overriddenEvent, ref _type, ContainingAssembly); } } bool hasInitializer = declaratorSyntax.Initializer != null; bool inInterfaceType = containingType.IsInterfaceType(); if (hasInitializer) { if (inInterfaceType && !this.IsStatic) { diagnostics.Add(ErrorCode.ERR_InterfaceEventInitializer, this.Locations[0], this); } else if (this.IsAbstract) { diagnostics.Add(ErrorCode.ERR_AbstractEventInitializer, this.Locations[0], this); } else if (this.IsExtern) { diagnostics.Add(ErrorCode.ERR_ExternEventInitializer, this.Locations[0], this); } } // NOTE: if there's an initializer in source, we'd better create a backing field, regardless of // whether or not the initializer is legal. if (hasInitializer || !(this.IsExtern || this.IsAbstract)) { AssociatedEventField = MakeAssociatedField(declaratorSyntax); // Don't initialize this.type - we'll just use the type of the field (which is lazy and handles var) } if (!IsStatic && ContainingType.IsReadOnly) { diagnostics.Add(ErrorCode.ERR_FieldlikeEventsInRoStruct, this.Locations[0]); } if (inInterfaceType) { if ((IsAbstract || IsVirtual) && IsStatic) { if (!ContainingAssembly.RuntimeSupportsStaticAbstractMembersInInterfaces) { diagnostics.Add(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, this.Locations[0]); } } else if (this.IsExtern || this.IsStatic) { if (!ContainingAssembly.RuntimeSupportsDefaultInterfaceImplementation) { diagnostics.Add(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, this.Locations[0]); } } else if (!this.IsAbstract) { diagnostics.Add(ErrorCode.ERR_EventNeedsBothAccessors, this.Locations[0], this); } } // Accessors will assume that Type is available. _addMethod = new SynthesizedEventAccessorSymbol(this, isAdder: true); _removeMethod = new SynthesizedEventAccessorSymbol(this, isAdder: false); if (declarationSyntax.Variables[0] == declaratorSyntax) { // Don't report these diagnostics for every declarator in this declaration. diagnostics.AddRange(declaratorDiagnostics); } declaratorDiagnostics.Free(); }