internal void MakeIterator() { if (_iteratorInfo == null) { _iteratorInfo = IteratorInfo.Empty; } }
internal void MakeIterator() { if (this.iteratorInfo == null) { this.iteratorInfo = IteratorInfo.Empty; } }
internal override TypeSymbol GetIteratorElementType(YieldStatementSyntax node, DiagnosticBag diagnostics) { RefKind refKind = _methodSymbol.RefKind; TypeSymbol returnType = _methodSymbol.ReturnType.TypeSymbol; if (!this.IsDirectlyInIterator) { // This should only happen when speculating, but we don't have a good way to assert that since the // original binder isn't available here. // If we're speculating about a yield statement inside a non-iterator method, we'll try to be nice // and deduce an iterator element type from the return type. If we didn't do this, the // TypeInfo.ConvertedType of the yield statement would always be an error type. However, we will // not mutate any state (i.e. we won't store the result). return(GetIteratorElementTypeFromReturnType(refKind, returnType, node, diagnostics).elementType ?? CreateErrorType()); } if (_iteratorInfo == IteratorInfo.Empty) { DiagnosticBag elementTypeDiagnostics = DiagnosticBag.GetInstance(); (TypeSymbol elementType, bool asyncInterface) = GetIteratorElementTypeFromReturnType(refKind, returnType, node, elementTypeDiagnostics); Location errorLocation = _methodSymbol.Locations[0]; if ((object)elementType == null) { if (refKind != RefKind.None) { Error(elementTypeDiagnostics, ErrorCode.ERR_BadIteratorReturnRef, errorLocation, _methodSymbol); } else if (!returnType.IsErrorType()) { Error(elementTypeDiagnostics, ErrorCode.ERR_BadIteratorReturn, errorLocation, _methodSymbol, returnType); } elementType = CreateErrorType(); } else if (asyncInterface && !_methodSymbol.IsAsync) { Error(elementTypeDiagnostics, ErrorCode.ERR_IteratorMustBeAsync, errorLocation, _methodSymbol, returnType); } var info = new IteratorInfo(elementType, elementTypeDiagnostics.ToReadOnlyAndFree()); Interlocked.CompareExchange(ref _iteratorInfo, info, IteratorInfo.Empty); } if (node == null) { // node==null indicates this we are being called from the top-level of processing of a method. We report // the diagnostic, if any, at that time to ensure it is reported exactly once. diagnostics.AddRange(_iteratorInfo.ElementTypeDiagnostics); } return(_iteratorInfo.ElementType); }
internal override TypeSymbol GetIteratorElementType(YieldStatementSyntax node, DiagnosticBag diagnostics) { TypeSymbol returnType = this.Owner.ReturnType; if (!this.IsDirectlyInIterator) { // This should only happen when speculating, but we don't have a good way to assert that since the // original binder isn't available here. // If we're speculating about a yield statement inside a non-iterator method, we'll try to be nice // and deduce an iterator element type from the return type. If we didn't do this, the // TypeInfo.ConvertedType of the yield statement would always be an error type. However, we will // not mutate any state (i.e. we won't store the result). return GetIteratorElementTypeFromReturnType(returnType, node, diagnostics) ?? CreateErrorType(); } if (this.iteratorInfo == IteratorInfo.Empty) { TypeSymbol elementType = null; DiagnosticBag elementTypeDiagnostics = DiagnosticBag.GetInstance(); elementType = GetIteratorElementTypeFromReturnType(returnType, node, elementTypeDiagnostics); if ((object)elementType == null) { Error(elementTypeDiagnostics, ErrorCode.ERR_BadIteratorReturn, this.Owner.Locations[0], this.Owner, returnType); elementType = CreateErrorType(); } var info = new IteratorInfo(elementType, elementTypeDiagnostics.ToReadOnlyAndFree()); Interlocked.CompareExchange(ref this.iteratorInfo, info, IteratorInfo.Empty); } if (node == null) { // node==null indicates this we are being called from the top-level of processing of a method. We report // the diagnostic, if any, at that time to ensure it is reported exactly once. diagnostics.AddRange(this.iteratorInfo.ElementTypeDiagnostics); } return this.iteratorInfo.ElementType; }