Exemple #1
0
        private void UnwrapCollectionExpressionIfNullable(ref BoundExpression collectionExpr, DiagnosticBag diagnostics)
        {
            TypeSymbol collectionExprType = collectionExpr.Type;

            // If collectionExprType is a nullable type, then use the underlying type and take the value (i.e. .Value) of collectionExpr.
            // This behavior is not spec'd, but it's what Dev10 does.
            if ((object)collectionExprType != null && collectionExprType.IsNullableType())
            {
                CSharpSyntaxNode exprSyntax = collectionExpr.Syntax;

                MethodSymbol nullableValueGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Nullable_T_get_Value, diagnostics, exprSyntax);
                if ((object)nullableValueGetter != null)
                {
                    nullableValueGetter = nullableValueGetter.AsMember((NamedTypeSymbol)collectionExprType);

                    // Synthesized call, because we don't want to modify the type in the SemanticModel.
                    collectionExpr = BoundCall.Synthesized(
                        syntax: exprSyntax,
                        receiverOpt: collectionExpr,
                        method: nullableValueGetter);
                }
                else
                {
                    collectionExpr = new BoundBadExpression(
                        exprSyntax,
                        LookupResultKind.Empty,
                        ImmutableArray <Symbol> .Empty,
                        ImmutableArray.Create <BoundNode>(collectionExpr),
                        collectionExprType.GetNullableUnderlyingType())
                    {
                        WasCompilerGenerated = true
                    };                               // Don't affect the type in the SemanticModel.
                }
            }
        }
Exemple #2
0
        private static bool TryGetWellKnownMethodAsMember(SyntheticBoundNodeFactory F, WellKnownMember wellKnownMethod, NamedTypeSymbol containingType, out MethodSymbol methodSymbol)
        {
            methodSymbol = F.WellKnownMember(wellKnownMethod) as MethodSymbol;
            if ((object)methodSymbol == null)
            {
                return(false);
            }

            methodSymbol = methodSymbol.AsMember(containingType);
            return(true);
        }
Exemple #3
0
        internal EEMethodSymbol(
            EENamedTypeSymbol container,
            string name,
            Location location,
            MethodSymbol sourceMethod,
            ImmutableArray <LocalSymbol> sourceLocals,
            ImmutableArray <LocalSymbol> sourceLocalsForBinding,
            ImmutableDictionary <string, DisplayClassVariable> sourceDisplayClassVariables,
            GenerateMethodBody generateMethodBody)
        {
            Debug.Assert(sourceMethod.IsDefinition);
            Debug.Assert(sourceMethod.ContainingSymbol == container.SubstitutedSourceType.OriginalDefinition);
            Debug.Assert(sourceLocals.All(l => l.ContainingSymbol == sourceMethod));

            _container = container;
            _name      = name;
            _locations = ImmutableArray.Create(location);

            // What we want is to map all original type parameters to the corresponding new type parameters
            // (since the old ones have the wrong owners).  Unfortunately, we have a circular dependency:
            //   1) Each new type parameter requires the entire map in order to be able to construct its constraint list.
            //   2) The map cannot be constructed until all new type parameters exist.
            // Our solution is to pass each new type parameter a lazy reference to the type map.  We then
            // initialize the map as soon as the new type parameters are available - and before they are
            // handed out - so that there is never a period where they can require the type map and find
            // it uninitialized.

            var sourceMethodTypeParameters = sourceMethod.TypeParameters;
            var allSourceTypeParameters    = container.SourceTypeParameters.Concat(sourceMethodTypeParameters);

            var getTypeMap = new Func <TypeMap>(() => this.TypeMap);

            _typeParameters = sourceMethodTypeParameters.SelectAsArray(
                (tp, i, arg) => (TypeParameterSymbol) new EETypeParameterSymbol(this, tp, i, getTypeMap),
                (object)null);
            _allTypeParameters = container.TypeParameters.Concat(_typeParameters);
            this.TypeMap       = new TypeMap(allSourceTypeParameters, _allTypeParameters);

            EENamedTypeSymbol.VerifyTypeParameters(this, _typeParameters);

            var substitutedSourceType = container.SubstitutedSourceType;

            this.SubstitutedSourceMethod = sourceMethod.AsMember(substitutedSourceType);
            if (sourceMethod.Arity > 0)
            {
                this.SubstitutedSourceMethod = this.SubstitutedSourceMethod.Construct(_typeParameters.As <TypeSymbol>());
            }
            TypeParameterChecker.Check(this.SubstitutedSourceMethod, _allTypeParameters);

            // Create a map from original parameter to target parameter.
            var parameterBuilder = ArrayBuilder <ParameterSymbol> .GetInstance();

            var substitutedSourceThisParameter    = this.SubstitutedSourceMethod.ThisParameter;
            var substitutedSourceHasThisParameter = (object)substitutedSourceThisParameter != null;

            if (substitutedSourceHasThisParameter)
            {
                _thisParameter = MakeParameterSymbol(0, GeneratedNames.ThisProxyFieldName(), substitutedSourceThisParameter);
                Debug.Assert(_thisParameter.Type == this.SubstitutedSourceMethod.ContainingType);
                parameterBuilder.Add(_thisParameter);
            }

            var ordinalOffset = (substitutedSourceHasThisParameter ? 1 : 0);

            foreach (var substitutedSourceParameter in this.SubstitutedSourceMethod.Parameters)
            {
                var ordinal = substitutedSourceParameter.Ordinal + ordinalOffset;
                Debug.Assert(ordinal == parameterBuilder.Count);
                var parameter = MakeParameterSymbol(ordinal, substitutedSourceParameter.Name, substitutedSourceParameter);
                parameterBuilder.Add(parameter);
            }

            _parameters = parameterBuilder.ToImmutableAndFree();

            var localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance();

            var localsMap = PooledDictionary <LocalSymbol, LocalSymbol> .GetInstance();

            foreach (var sourceLocal in sourceLocals)
            {
                var local = sourceLocal.ToOtherMethod(this, this.TypeMap);
                localsMap.Add(sourceLocal, local);
                localsBuilder.Add(local);
            }
            this.Locals   = localsBuilder.ToImmutableAndFree();
            localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance();

            foreach (var sourceLocal in sourceLocalsForBinding)
            {
                LocalSymbol local;
                if (!localsMap.TryGetValue(sourceLocal, out local))
                {
                    local = sourceLocal.ToOtherMethod(this, this.TypeMap);
                    localsMap.Add(sourceLocal, local);
                }
                localsBuilder.Add(local);
            }
            this.LocalsForBinding = localsBuilder.ToImmutableAndFree();

            // Create a map from variable name to display class field.
            var displayClassVariables = PooledDictionary <string, DisplayClassVariable> .GetInstance();

            foreach (var pair in sourceDisplayClassVariables)
            {
                var variable = pair.Value;
                var oldDisplayClassInstance = variable.DisplayClassInstance;

                // Note: we don't call ToOtherMethod in the local case because doing so would produce
                // a new LocalSymbol that would not be ReferenceEquals to the one in this.LocalsForBinding.
                var oldDisplayClassInstanceFromLocal = oldDisplayClassInstance as DisplayClassInstanceFromLocal;
                var newDisplayClassInstance          = (oldDisplayClassInstanceFromLocal == null) ?
                                                       oldDisplayClassInstance.ToOtherMethod(this, this.TypeMap) :
                                                       new DisplayClassInstanceFromLocal((EELocalSymbol)localsMap[oldDisplayClassInstanceFromLocal.Local]);

                variable = variable.SubstituteFields(newDisplayClassInstance, this.TypeMap);
                displayClassVariables.Add(pair.Key, variable);
            }

            _displayClassVariables = displayClassVariables.ToImmutableDictionary();
            displayClassVariables.Free();
            localsMap.Free();

            _generateMethodBody = generateMethodBody;
        }
        /// <summary>
        /// Generate a thread-safe accessor for a WinRT field-like event.
        ///
        /// Add:
        ///   return EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value);
        ///
        /// Remove:
        ///   EventRegistrationTokenTable&lt;Event&gt;.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value);
        /// </summary>
        internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode;

            MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;

            Debug.Assert((object)accessor != null);

            FieldSymbol field = eventSymbol.AssociatedField;

            Debug.Assert((object)field != null);

            NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type;

            Debug.Assert(fieldType.Name == "EventRegistrationTokenTable");

            MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable,
                diagnostics,
                syntax: syntax);

            if ((object)getOrCreateMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return(null);
            }

            getOrCreateMethod = getOrCreateMethod.AsMember(fieldType);

            WellKnownMember processHandlerMember = isAddMethod
                ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler
                : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler;

            MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember(
                compilation,
                processHandlerMember,
                diagnostics,
                syntax: syntax);

            if ((object)processHandlerMethod == null)
            {
                Debug.Assert(diagnostics.HasAnyErrors());
                return(null);
            }

            processHandlerMethod = processHandlerMethod.AsMember(fieldType);

            // _tokenTable
            BoundFieldAccess fieldAccess = new BoundFieldAccess(
                syntax,
                field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type),
                field,
                constantValueOpt: null)
            {
                WasCompilerGenerated = true
            };

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable)
            BoundCall getOrCreateCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: null,
                method: getOrCreateMethod,
                arg0: fieldAccess);

            // value
            BoundParameter parameterAccess = new BoundParameter(
                syntax,
                accessor.Parameters.Single());

            // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler
            BoundCall processHandlerCall = BoundCall.Synthesized(
                syntax,
                receiverOpt: getOrCreateCall,
                method: processHandlerMethod,
                arg0: parameterAccess);

            if (isAddMethod)
            {
                // {
                //     return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value);
                // }
                BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, processHandlerCall);
                return(BoundBlock.SynthesizedNoLocals(syntax, returnStatement));
            }
            else
            {
                // {
                //     EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value);
                //     return;
                // }
                BoundStatement callStatement   = new BoundExpressionStatement(syntax, processHandlerCall);
                BoundStatement returnStatement = new BoundReturnStatement(syntax, expressionOpt: null);
                return(BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement));
            }
        }
Exemple #5
0
        internal LoweredDynamicOperation MakeDynamicOperation(
            BoundExpression binderConstruction,
            BoundExpression loweredReceiver,
            RefKind receiverRefKind,
            ImmutableArray <BoundExpression> loweredArguments,
            ImmutableArray <RefKind> refKinds,
            BoundExpression loweredRight,
            TypeSymbol resultType)
        {
            Debug.Assert(!loweredArguments.IsDefault);

            // get well-known types and members we need:
            NamedTypeSymbol delegateTypeOverMethodTypeParameters = GetDelegateType(loweredReceiver, receiverRefKind, loweredArguments, refKinds, loweredRight, resultType);
            NamedTypeSymbol callSiteTypeGeneric        = _factory.WellKnownType(WellKnownType.core_runtime_compiler_CallSite_T);
            MethodSymbol    callSiteFactoryGeneric     = _factory.WellKnownMethod(WellKnownMember.System_Runtime_CompilerServices_CallSite_T__Create);
            FieldSymbol     callSiteTargetFieldGeneric = (FieldSymbol)_factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_CallSite_T__Target);
            MethodSymbol    delegateInvoke;

            if (binderConstruction == null ||
                (object)delegateTypeOverMethodTypeParameters == null ||
                delegateTypeOverMethodTypeParameters.IsErrorType() ||
                (object)(delegateInvoke = delegateTypeOverMethodTypeParameters.DelegateInvokeMethod) == null ||
                callSiteTypeGeneric.IsErrorType() ||
                (object)callSiteFactoryGeneric == null ||
                (object)callSiteTargetFieldGeneric == null)
            {
                // CS1969: One or more types required to compile a dynamic expression cannot be found.
                // Dev11 reports it with source location for each dynamic operation, which results in many error messages.
                // The diagnostic that names the specific missing type or member has already been reported.
                _factory.Diagnostics.Add(ErrorCode.ERR_DynamicRequiredTypesMissing, NoLocation.Singleton);

                return(LoweredDynamicOperation.Bad(loweredReceiver, loweredArguments, loweredRight, resultType));
            }

            if ((object)_currentDynamicCallSiteContainer == null)
            {
                _currentDynamicCallSiteContainer = CreateCallSiteContainer(_factory, _methodOrdinal);
            }

            var containerDef = (SynthesizedContainer)_currentDynamicCallSiteContainer.OriginalDefinition;
            var methodToContainerTypeParametersMap = containerDef.TypeMap;

            ImmutableArray <LocalSymbol> temps = MakeTempsForDiscardArguments(ref loweredArguments);

            var callSiteType          = callSiteTypeGeneric.Construct(new[] { delegateTypeOverMethodTypeParameters });
            var callSiteFactoryMethod = callSiteFactoryGeneric.AsMember(callSiteType);
            var callSiteTargetField   = callSiteTargetFieldGeneric.AsMember(callSiteType);
            var callSiteField         = DefineCallSiteStorageSymbol(containerDef, delegateTypeOverMethodTypeParameters, methodToContainerTypeParametersMap);
            var callSiteFieldAccess   = _factory.Field(null, callSiteField);
            var callSiteArguments     = GetCallSiteArguments(callSiteFieldAccess, loweredReceiver, loweredArguments, loweredRight);

            var nullCallSite = _factory.Null(callSiteField.Type.TypeSymbol);

            var siteInitialization = _factory.Conditional(
                _factory.ObjectEqual(callSiteFieldAccess, nullCallSite),
                _factory.AssignmentExpression(callSiteFieldAccess, _factory.Call(null, callSiteFactoryMethod, binderConstruction)),
                nullCallSite,
                callSiteField.Type.TypeSymbol);

            var siteInvocation = _factory.Call(
                _factory.Field(callSiteFieldAccess, callSiteTargetField),
                delegateInvoke,
                callSiteArguments);

            return(new LoweredDynamicOperation(_factory, siteInitialization, siteInvocation, resultType, temps));
        }
Exemple #6
0
        /// <summary>
        /// The spec describes an algorithm for finding the following types:
        ///   1) Collection type
        ///   2) Enumerator type
        ///   3) Element type
        ///
        /// The implementation details are a bit difference.  If we're iterating over a string or an array, then we don't need to record anything
        /// but the inferredType (in case the iteration variable is implicitly typed).  If we're iterating over anything else, then we want the
        /// inferred type plus a ForEachEnumeratorInfo.Builder with:
        ///   1) Collection type
        ///   2) Element type
        ///   3) GetEnumerator method of the collection type (return type will be the enumerator type from the spec)
        ///   4) Current property of the enumerator type
        ///   5) MoveNext method of the enumerator type
        ///
        /// The caller will have to do some extra conversion checks before creating a ForEachEnumeratorInfo for the BoundForEachStatement.
        /// </summary>
        /// <param name="builder">Builder to fill in (partially, all but conversions).</param>
        /// <param name="collectionExpr">The expression over which to iterate.</param>
        /// <param name="diagnostics">Populated with binding diagnostics.</param>
        /// <returns>Partially populated (all but conversions) or null if there was an error.</returns>
        private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundExpression collectionExpr, DiagnosticBag diagnostics)
        {
            TypeSymbol collectionExprType = collectionExpr.Type;

            if (collectionExpr.ConstantValue != null && collectionExpr.ConstantValue.IsNull)
            {
                // Spec seems to refer to null literals, but Dev10 reports anything known to be null.
                Debug.Assert(collectionExpr.ConstantValue.IsNull); // only constant value with no type
                diagnostics.Add(ErrorCode.ERR_NullNotValid, syntax.Expression.Location);

                return(false);
            }

            if ((object)collectionExprType == null) // There's no way to enumerate something without a type.
            {
                // The null literal was caught above, so anything else with a null type is a method group or anonymous function
                diagnostics.Add(ErrorCode.ERR_AnonMethGrpInForEach, syntax.Expression.Location, collectionExpr.Display);
                // CONSIDER: dev10 also reports ERR_ForEachMissingMember (i.e. failed pattern match).

                return(false);
            }

            if (collectionExpr.ResultKind == LookupResultKind.NotAValue)
            {
                // Short-circuiting to prevent strange behavior in the case where the collection
                // expression is a type expression and the type is enumerable.
                Debug.Assert(collectionExpr.HasAnyErrors); // should already have been reported
                return(false);
            }

            // The spec specifically lists the collection, enumerator, and element types for arrays and dynamic.
            if (collectionExprType.Kind == SymbolKind.ArrayType || collectionExprType.Kind == SymbolKind.DynamicType)
            {
                // NOTE: for arrays, we won't actually use any of these members - they're just for the API.
                builder.CollectionType = GetSpecialType(SpecialType.System_Collections_IEnumerable, diagnostics, this.syntax);
                builder.ElementType    =
                    collectionExprType.IsDynamic() ?
                    (this.syntax.Type.IsVar ? (TypeSymbol)DynamicTypeSymbol.Instance : GetSpecialType(SpecialType.System_Object, diagnostics, this.syntax)) :
                    ((ArrayTypeSymbol)collectionExprType).ElementType;

                // CONSIDER:
                // For arrays none of these members will actually be emitted, so it seems strange to prevent compilation if they can't be found.
                // skip this work in the batch case? (If so, also special case string, which won't use the pattern methods.)
                builder.GetEnumeratorMethod   = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator, diagnostics, this.syntax);
                builder.CurrentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__get_Current, diagnostics, this.syntax);
                builder.MoveNextMethod        = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, this.syntax);

                Debug.Assert((object)builder.GetEnumeratorMethod == null ||
                             builder.GetEnumeratorMethod.ReturnType == this.Compilation.GetSpecialType(SpecialType.System_Collections_IEnumerator));

                // We don't know the runtime type, so we will have to insert a runtime check for IDisposable (with a conditional call to IDisposable.Dispose).
                builder.NeedsDisposeMethod = true;

                return(true);
            }

            bool foundMultipleGenericIEnumerableInterfaces;

            if (SatisfiesGetEnumeratorPattern(ref builder, collectionExprType, diagnostics))
            {
                Debug.Assert((object)builder.GetEnumeratorMethod != null);

                builder.CollectionType = collectionExprType;

                if (SatisfiesForEachPattern(ref builder, diagnostics))
                {
                    builder.ElementType = ((PropertySymbol)builder.CurrentPropertyGetter.AssociatedSymbol).Type;

                    // NOTE: if IDisposable is not available at all, no diagnostics will be reported - we will just assume that
                    // the enumerator is not disposable.  If it has IDisposable in its interface list, there will be a diagnostic there.
                    // If IDisposable is available but its Dispose method is not, then diagnostics will be reported only if the enumerator
                    // is potentially disposable.

                    var        useSiteDiagnosticBag             = DiagnosticBag.GetInstance();
                    TypeSymbol enumeratorType                   = builder.GetEnumeratorMethod.ReturnType;
                    HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                    if (!enumeratorType.IsSealed || this.Conversions.ClassifyImplicitConversion(enumeratorType, this.Compilation.GetSpecialType(SpecialType.System_IDisposable), ref useSiteDiagnostics).IsImplicit)
                    {
                        builder.NeedsDisposeMethod = true;
                        diagnostics.AddRange(useSiteDiagnosticBag);
                    }
                    useSiteDiagnosticBag.Free();

                    diagnostics.Add(this.syntax, useSiteDiagnostics);
                    return(true);
                }

                MethodSymbol getEnumeratorMethod = builder.GetEnumeratorMethod;
                diagnostics.Add(ErrorCode.ERR_BadGetEnumerator, this.syntax.Expression.Location, getEnumeratorMethod.ReturnType, getEnumeratorMethod);
                return(false);
            }

            if (IsIEnumerable(collectionExprType))
            {
                // This indicates a problem with the special IEnumerable type - it should have satisfied the GetEnumerator pattern.
                diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, syntax.Expression.Location, collectionExprType, GetEnumeratorMethodName);
                return(false);
            }

            if (AllInterfacesContainsIEnumerable(ref builder, collectionExprType, diagnostics, out foundMultipleGenericIEnumerableInterfaces))
            {
                CSharpSyntaxNode errorLocationSyntax = this.syntax.Expression;

                if (foundMultipleGenericIEnumerableInterfaces)
                {
                    diagnostics.Add(ErrorCode.ERR_MultipleIEnumOfT, errorLocationSyntax.Location, collectionExprType, this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T));
                    return(false);
                }

                Debug.Assert((object)builder.CollectionType != null);

                NamedTypeSymbol collectionType = (NamedTypeSymbol)builder.CollectionType;
                if (collectionType.IsGenericType)
                {
                    // If the type is generic, we have to search for the methods
                    Debug.Assert(collectionType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T);
                    builder.ElementType = collectionType.TypeArgumentsNoUseSiteDiagnostics.Single();

                    MethodSymbol getEnumeratorMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerable_T__GetEnumerator, diagnostics, errorLocationSyntax);
                    if ((object)getEnumeratorMethod != null)
                    {
                        builder.GetEnumeratorMethod = getEnumeratorMethod.AsMember(collectionType);

                        TypeSymbol enumeratorType = builder.GetEnumeratorMethod.ReturnType;
                        Debug.Assert(enumeratorType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerator_T);
                        MethodSymbol currentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_Generic_IEnumerator_T__get_Current, diagnostics, errorLocationSyntax);
                        if ((object)currentPropertyGetter != null)
                        {
                            builder.CurrentPropertyGetter = currentPropertyGetter.AsMember((NamedTypeSymbol)enumeratorType);
                        }
                    }

                    builder.MoveNextMethod = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax); // NOTE: MoveNext is actually inherited from System.Collections.IEnumerator
                }
                else
                {
                    // Non-generic - use special members to avoid re-computing
                    Debug.Assert(collectionType.SpecialType == SpecialType.System_Collections_IEnumerable);
                    builder.ElementType = GetSpecialType(SpecialType.System_Object, diagnostics, errorLocationSyntax);

                    builder.GetEnumeratorMethod   = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator, diagnostics, errorLocationSyntax);
                    builder.CurrentPropertyGetter = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__get_Current, diagnostics, errorLocationSyntax);
                    builder.MoveNextMethod        = (MethodSymbol)GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext, diagnostics, errorLocationSyntax);

                    Debug.Assert((object)builder.GetEnumeratorMethod == null ||
                                 builder.GetEnumeratorMethod.ReturnType == GetSpecialType(SpecialType.System_Collections_IEnumerator, diagnostics, errorLocationSyntax));
                }

                // We don't know the runtime type, so we will have to insert a runtime check for IDisposable (with a conditional call to IDisposable.Dispose).
                builder.NeedsDisposeMethod = true;
                return(true);
            }

            // This is a type that we don't know how to enumerate.
            // Skip the diagnostic if the type has no name - it makes the message unhelpful.
            if (!string.IsNullOrEmpty(collectionExprType.Name))
            {
                diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, syntax.Expression.Location, collectionExprType, GetEnumeratorMethodName);
            }
            return(false);
        }
        private BoundExpression MakeEventAccess(
            SyntaxNode syntax,
            BoundExpression rewrittenReceiver,
            EventSymbol eventSymbol,
            ConstantValue constantValueOpt,
            LookupResultKind resultKind,
            TypeSymbol type)
        {
            Debug.Assert(eventSymbol.HasAssociatedField);

            FieldSymbol fieldSymbol = eventSymbol.AssociatedField;

            Debug.Assert((object)fieldSymbol != null);

            if (!eventSymbol.IsWindowsRuntimeEvent)
            {
                return(MakeFieldAccess(syntax, rewrittenReceiver, fieldSymbol, constantValueOpt, resultKind, type));
            }

            NamedTypeSymbol fieldType = (NamedTypeSymbol)fieldSymbol.Type;

            Debug.Assert(fieldType.Name == "EventRegistrationTokenTable");

            // _tokenTable
            BoundFieldAccess fieldAccess = new BoundFieldAccess(
                syntax,
                fieldSymbol.IsStatic ? null : rewrittenReceiver,
                fieldSymbol,
                constantValueOpt: null)
            {
                WasCompilerGenerated = true
            };

            BoundExpression getOrCreateCall;

            MethodSymbol getOrCreateMethod;

            if (TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable, out getOrCreateMethod))
            {
                getOrCreateMethod = getOrCreateMethod.AsMember(fieldType);

                // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable)
                getOrCreateCall = BoundCall.Synthesized(
                    syntax,
                    receiverOpt: null,
                    method: getOrCreateMethod,
                    arg0: fieldAccess);
            }
            else
            {
                getOrCreateCall = new BoundBadExpression(syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(fieldAccess), ErrorTypeSymbol.UnknownResultType);
            }

            PropertySymbol invocationListProperty;

            if (TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__InvocationList, out invocationListProperty))
            {
                MethodSymbol invocationListAccessor = invocationListProperty.GetMethod;

                if ((object)invocationListAccessor == null)
                {
                    string accessorName = SourcePropertyAccessorSymbol.GetAccessorName(invocationListProperty.Name,
                                                                                       getNotSet: true,
                                                                                       isWinMdOutput: invocationListProperty.IsCompilationOutputWinMdObj());
                    _diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, invocationListProperty.ContainingType, accessorName), syntax.Location);
                }
                else
                {
                    invocationListAccessor = invocationListAccessor.AsMember(fieldType);
                    return(_factory.Call(getOrCreateCall, invocationListAccessor));
                }
            }

            return(new BoundBadExpression(syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create(getOrCreateCall), ErrorTypeSymbol.UnknownResultType));
        }