/// <summary> /// Lookup member declaration in predefined CorLib type in this Assembly. Only valid if this /// assembly is the Cor Library /// </summary> internal Symbol GetDeclaredSpecialTypeMember(SpecialMember member) { if (_lazySpecialTypeMembers == null || ReferenceEquals(_lazySpecialTypeMembers[(int)member], ErrorTypeSymbol.UnknownResultType)) { if (_lazySpecialTypeMembers == null) { var specialTypeMembers = new Symbol[(int)SpecialMember.Count]; for (int i = 0; i < specialTypeMembers.Length; i++) { specialTypeMembers[i] = ErrorTypeSymbol.UnknownResultType; } Interlocked.CompareExchange(ref _lazySpecialTypeMembers, specialTypeMembers, null); } var descriptor = SpecialMembers.GetDescriptor(member); NamedTypeSymbol type = GetDeclaredSpecialType((SpecialType)descriptor.DeclaringTypeId); Symbol result = null; if (!type.IsErrorType()) { result = PhpCompilation.GetRuntimeMember(type, ref descriptor, PhpCompilation.SpecialMembersSignatureComparer.Instance, null); } Interlocked.CompareExchange(ref _lazySpecialTypeMembers[(int)member], result, ErrorTypeSymbol.UnknownResultType); } return(_lazySpecialTypeMembers[(int)member]); }
internal override Symbol GetDeclaredSpecialTypeMember(SpecialMember member) { #if DEBUG foreach (var module in this.Modules) { Debug.Assert(module.GetReferencedAssemblies().Length == 0); } #endif if ( _lazySpecialTypeMembers == null || ReferenceEquals( _lazySpecialTypeMembers[(int)member], ErrorTypeSymbol.UnknownResultType ) ) { if (_lazySpecialTypeMembers == null) { var specialTypeMembers = new Symbol[(int)SpecialMember.Count]; for (int i = 0; i < specialTypeMembers.Length; i++) { specialTypeMembers[i] = ErrorTypeSymbol.UnknownResultType; } Interlocked.CompareExchange( ref _lazySpecialTypeMembers, specialTypeMembers, null ); } var descriptor = SpecialMembers.GetDescriptor(member); NamedTypeSymbol type = GetDeclaredSpecialType( (SpecialType)descriptor.DeclaringTypeId ); Symbol result = null; if (!type.IsErrorType()) { result = CSharpCompilation.GetRuntimeMember( type, descriptor, CSharpCompilation.SpecialMembersSignatureComparer.Instance, accessWithinOpt: null ); } Interlocked.CompareExchange( ref _lazySpecialTypeMembers[(int)member], result, ErrorTypeSymbol.UnknownResultType ); } return(_lazySpecialTypeMembers[(int)member]); }
private static void ReportErrorOnSpecialMember(Symbol symbol, SpecialMember member, BindingDiagnosticBag diagnostics, ref bool hasError) { if ((object)symbol == null) { MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(member); diagnostics.Add(ErrorCode.ERR_MissingPredefinedMember, NoLocation.Singleton, memberDescriptor.DeclaringTypeMetadataName, memberDescriptor.Name); hasError = true; } else { ReportErrorOnSymbol(symbol, diagnostics, ref hasError); } }
/// <summary> /// Get the symbol for a special member. The use of this method to get a special member /// that does not exist will result in an exception of type MissingPredefinedMember being thrown /// containing an appropriate diagnostic for the caller to report. /// </summary> /// <param name="sm">The desired special member</param> /// <returns>A symbol for the special member.</returns> public Symbol SpecialMember(SpecialMember sm) { Symbol specialMember = Compilation.GetSpecialTypeMember(sm); if (specialMember == null) { RuntimeMembers.MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(sm); SpecialType containingType = (SpecialType)memberDescriptor.DeclaringTypeId; var diagnostic = new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, containingType.GetMetadataName(), memberDescriptor.Name), Syntax.Location); throw new MissingPredefinedMember(diagnostic); } Binder.ReportUseSiteDiagnostics(specialMember, Diagnostics, Syntax); return(specialMember); }
/// <summary> /// This function provides a false sense of security, it is likely going to surprise you when the requested member is missing. /// Recommendation: Do not use, use <see cref="TryGetSpecialTypeMethod(SyntaxNode, SpecialMember, CSharpCompilation, DiagnosticBag, out MethodSymbol)"/> instead! /// If used, a unit-test with a missing member is absolutely a must have. /// </summary> private static MethodSymbol UnsafeGetSpecialTypeMethod(SyntaxNode syntax, SpecialMember specialMember, CSharpCompilation compilation, DiagnosticBag diagnostics) { MethodSymbol method; if (TryGetSpecialTypeMethod(syntax, specialMember, compilation, diagnostics, out method)) { return(method); } else { MemberDescriptor descriptor = SpecialMembers.GetDescriptor(specialMember); SpecialType type = (SpecialType)descriptor.DeclaringTypeId; TypeSymbol container = compilation.Assembly.GetSpecialType(type); TypeSymbol returnType = new ExtendedErrorTypeSymbol(compilation: compilation, name: descriptor.Name, errorInfo: null, arity: descriptor.Arity); return(new ErrorMethodSymbol(container, returnType, "Missing")); } }
private MethodSymbol GetSpecialTypeMethod(CSharpSyntaxNode syntax, SpecialMember specialMember) { MethodSymbol method; if (Binder.TryGetSpecialTypeMember(_compilation, specialMember, syntax, _diagnostics, out method)) { return(method); } else { MemberDescriptor descriptor = SpecialMembers.GetDescriptor(specialMember); SpecialType type = (SpecialType)descriptor.DeclaringTypeId; TypeSymbol container = _compilation.Assembly.GetSpecialType(type); TypeSymbol returnType = new ExtendedErrorTypeSymbol(compilation: _compilation, name: descriptor.Name, errorInfo: null, arity: descriptor.Arity); return(new ErrorMethodSymbol(container, returnType, "Missing")); } }
private bool TryGetSpecialTypeMember <TSymbol>(CSharpSyntaxNode syntax, SpecialMember specialMember, out TSymbol symbol) where TSymbol : Symbol { symbol = (TSymbol)this.compilation.Assembly.GetSpecialTypeMember(specialMember); if ((object)symbol == null) { MemberDescriptor descriptor = SpecialMembers.GetDescriptor(specialMember); diagnostics.Add(ErrorCode.ERR_MissingPredefinedMember, syntax.Location, descriptor.DeclaringTypeMetadataName, descriptor.Name); return(false); } else { var useSiteDiagnostic = symbol.GetUseSiteDiagnosticForSymbolOrContainingType(); if (useSiteDiagnostic != null) { Symbol.ReportUseSiteDiagnostic(useSiteDiagnostic, diagnostics, new SourceLocation(syntax)); } } return(true); }
/// <summary> /// Generate a thread-safe accessor for a regular field-like event. /// /// DelegateType tmp0 = _event; //backing field /// DelegateType tmp1; /// DelegateType tmp2; /// do { /// tmp1 = tmp0; /// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -= /// tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); /// } while ((object)tmp0 != (object)tmp1); /// /// Note, if System.Threading.Interlocked.CompareExchange<T> is not available, /// we emit the following code and mark the method Synchronized (unless it is a struct). /// /// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -= /// /// </summary> internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag 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, 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(new BoundBlock(syntax, locals: ImmutableArray <LocalSymbol> .Empty, statements: ImmutableArray.Create <BoundStatement>(@return)) { WasCompilerGenerated = true }); } Binder.ReportUseSiteDiagnostics(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)), kind: ConversionKind.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(new BoundBlock(syntax, locals: ImmutableArray <LocalSymbol> .Empty, statements: ImmutableArray.Create <BoundStatement>( eventUpdate, @return)) { WasCompilerGenerated = true }); } compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType)); Binder.ReportUseSiteDiagnostics(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, delegateType, SynthesizedLocalKind.LoweringTemp); boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType); } // 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)), kind: ConversionKind.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, 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 }); }