public static BoundCall GenerateGetHashCode(
            MethodSymbol system_Collections_Generic_EqualityComparer_T__GetHashCode,
            MethodSymbol system_Collections_Generic_EqualityComparer_T__get_Default,
            BoundExpression valueToHash,
            SyntheticBoundNodeFactory F
            )
        {
            // Prepare constructed symbols
            NamedTypeSymbol equalityComparerType =
                system_Collections_Generic_EqualityComparer_T__GetHashCode.ContainingType;
            NamedTypeSymbol constructedEqualityComparer = equalityComparerType.Construct(
                valueToHash.Type
                );

            return(F.Call(
                       F.StaticCall(
                           constructedEqualityComparer,
                           system_Collections_Generic_EqualityComparer_T__get_Default.AsMember(
                               constructedEqualityComparer
                               )
                           ),
                       system_Collections_Generic_EqualityComparer_T__GetHashCode.AsMember(
                           constructedEqualityComparer
                           ),
                       valueToHash
                       ));
        }
Esempio n. 2
0
 /// <summary>
 /// Returns a constructed named type symbol if 'type' is generic, otherwise just returns 'type'
 /// </summary>
 public static NamedTypeSymbol ConstructIfGeneric(
     this NamedTypeSymbol type,
     ImmutableArray <TypeWithAnnotations> typeArguments
     )
 {
     Debug.Assert(type.TypeParameters.IsEmpty == (typeArguments.Length == 0));
     return(type.TypeParameters.IsEmpty
       ? type
       : type.Construct(typeArguments, unbound: false));
 }
Esempio n. 3
0
        protected override BoundExpression GenerateReceiver(SyntheticBoundNodeFactory f)
        {
            // The receiver has one argument, namely the calling witness.
            // We generate an empty local for it, and then call into that local.
            // We then place the local into the block.
            var recvType  = _defaultStruct.Construct(ImmutableArray.Create <TypeSymbol>(ContainingType));
            var recvLocal = f.SynthesizedLocal(recvType, syntax: f.Syntax, kind: SynthesizedLocalKind.ConceptDictionary);

            return(f.Local(recvLocal));
        }
        /// <summary>
        /// Given a set of fields, produce an expression that is true when all of the given fields on
        /// `this` are equal to the fields on <paramref name="otherReceiver" /> according to the
        /// default EqualityComparer.
        /// </summary>
        public static BoundExpression GenerateFieldEquals(
            BoundExpression?initialExpression,
            BoundExpression otherReceiver,
            ArrayBuilder <FieldSymbol> fields,
            SyntheticBoundNodeFactory F
            )
        {
            Debug.Assert(fields.Count > 0);

            //  Expression:
            //
            //      System.Collections.Generic.EqualityComparer<T_1>.Default.Equals(this.backingFld_1, value.backingFld_1)
            //      ...
            //      && System.Collections.Generic.EqualityComparer<T_N>.Default.Equals(this.backingFld_N, value.backingFld_N)

            //  prepare symbols
            var equalityComparer_get_Default = F.WellKnownMethod(
                WellKnownMember.System_Collections_Generic_EqualityComparer_T__get_Default
                );
            var equalityComparer_Equals = F.WellKnownMethod(
                WellKnownMember.System_Collections_Generic_EqualityComparer_T__Equals
                );

            NamedTypeSymbol equalityComparerType = equalityComparer_Equals.ContainingType;

            BoundExpression?retExpression = initialExpression;

            // Compare fields
            foreach (var field in fields)
            {
                // Prepare constructed comparer
                var constructedEqualityComparer = equalityComparerType.Construct(field.Type);

                // System.Collections.Generic.EqualityComparer<T_index>.
                //   Default.Equals(this.backingFld_index, local.backingFld_index)'
                BoundExpression nextEquals = F.Call(
                    F.StaticCall(
                        constructedEqualityComparer,
                        equalityComparer_get_Default.AsMember(constructedEqualityComparer)
                        ),
                    equalityComparer_Equals.AsMember(constructedEqualityComparer),
                    F.Field(F.This(), field),
                    F.Field(otherReceiver, field)
                    );

                // Generate 'retExpression' = 'retExpression && nextEquals'
                retExpression = retExpression is null
                    ? nextEquals
                    : F.LogicalAnd(retExpression, nextEquals);
            }

            RoslynDebug.AssertNotNull(retExpression);

            return(retExpression);
        }
            internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
            {
                AnonymousTypeManager      manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager;
                SyntheticBoundNodeFactory F       = this.CreateBoundNodeFactory(compilationState, diagnostics);

                //  Method body:
                //
                //  {
                //      $anonymous$ local = value as $anonymous$;
                //      return local != null
                //             && System.Collections.Generic.EqualityComparer<T_1>.Default.Equals(this.backingFld_1, local.backingFld_1)
                //             ...
                //             && System.Collections.Generic.EqualityComparer<T_N>.Default.Equals(this.backingFld_N, local.backingFld_N);
                //  }

                // Type and type expression
                AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType;

                //  local
                BoundAssignmentOperator assignmentToTemp;
                BoundLocal boundLocal = F.StoreToTemp(F.As(F.Parameter(this.parameters[0]), anonymousType), out assignmentToTemp);

                //  Generate: statement <= 'local = value as $anonymous$'
                BoundStatement assignment = F.ExpressionStatement(assignmentToTemp);

                //  Generate expression for return statement
                //      retExpression <= 'local != null'
                BoundExpression retExpression = F.Binary(BinaryOperatorKind.ObjectNotEqual,
                                                         manager.System_Boolean,
                                                         F.Convert(manager.System_Object, boundLocal),
                                                         F.Null(manager.System_Object));

                //  prepare symbols
                MethodSymbol    equalityComparer_Equals      = manager.System_Collections_Generic_EqualityComparer_T__Equals;
                MethodSymbol    equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default;
                NamedTypeSymbol equalityComparerType         = equalityComparer_Equals.ContainingType;

                // Compare fields
                for (int index = 0; index < anonymousType.Properties.Length; index++)
                {
                    // Prepare constructed symbols
                    TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index];
                    FieldSymbol         fieldSymbol   = anonymousType.Properties[index].BackingField;
                    NamedTypeSymbol     constructedEqualityComparer = equalityComparerType.Construct(typeParameter);

                    // Generate 'retExpression' = 'retExpression && System.Collections.Generic.EqualityComparer<T_index>.
                    //                                                  Default.Equals(this.backingFld_index, local.backingFld_index)'
                    retExpression = F.LogicalAnd(retExpression,
                                                 F.Call(F.StaticCall(constructedEqualityComparer,
                                                                     equalityComparer_get_Default.AsMember(constructedEqualityComparer)),
                                                        equalityComparer_Equals.AsMember(constructedEqualityComparer),
                                                        F.Field(F.This(), fieldSymbol),
                                                        F.Field(boundLocal, fieldSymbol)));
                }

                // Final return statement
                BoundStatement retStatement = F.Return(retExpression);

                // Create a bound block
                F.CloseMethod(F.Block(ImmutableArray.Create <LocalSymbol>(boundLocal.LocalSymbol), assignment, retStatement));
            }
            internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
            {
                AnonymousTypeManager      manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager;
                SyntheticBoundNodeFactory F       = this.CreateBoundNodeFactory(compilationState, diagnostics);

                //  Method body:
                //
                //  HASH_FACTOR = 0xa5555529;
                //  INIT_HASH = (...((0 * HASH_FACTOR) + backingFld_1.Name.GetHashCode()) * HASH_FACTOR
                //                                     + backingFld_2.Name.GetHashCode()) * HASH_FACTOR
                //                                     + ...
                //                                     + backingFld_N.Name.GetHashCode()
                //
                //  {
                //      return (...((INITIAL_HASH * HASH_FACTOR) + EqualityComparer<T_1>.Default.GetHashCode(this.backingFld_1)) * HASH_FACTOR
                //                                               + EqualityComparer<T_2>.Default.GetHashCode(this.backingFld_2)) * HASH_FACTOR
                //                                               ...
                //                                               + EqualityComparer<T_N>.Default.GetHashCode(this.backingFld_N)
                //  }

                const int HASH_FACTOR = -1521134295; // (int)0xa5555529

                // Type expression
                AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType;

                //  INIT_HASH
                int initHash = 0;

                foreach (var property in anonymousType.Properties)
                {
                    initHash = unchecked (initHash * HASH_FACTOR + property.BackingField.Name.GetHashCode());
                }

                //  Generate expression for return statement
                //      retExpression <= 'INITIAL_HASH'
                BoundExpression retExpression = F.Literal(initHash);

                //  prepare symbols
                MethodSymbol    equalityComparer_GetHashCode = manager.System_Collections_Generic_EqualityComparer_T__GetHashCode;
                MethodSymbol    equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default;
                NamedTypeSymbol equalityComparerType         = equalityComparer_GetHashCode.ContainingType;

                //  bound HASH_FACTOR
                BoundLiteral boundHashFactor = F.Literal(HASH_FACTOR);

                // Process fields
                for (int index = 0; index < anonymousType.Properties.Length; index++)
                {
                    // Prepare constructed symbols
                    TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index];
                    NamedTypeSymbol     constructedEqualityComparer = equalityComparerType.Construct(typeParameter);

                    // Generate 'retExpression' <= 'retExpression * HASH_FACTOR
                    retExpression = F.Binary(BinaryOperatorKind.IntMultiplication, manager.System_Int32, retExpression, boundHashFactor);

                    // Generate 'retExpression' <= 'retExpression + EqualityComparer<T_index>.Default.GetHashCode(this.backingFld_index)'
                    retExpression = F.Binary(BinaryOperatorKind.IntAddition,
                                             manager.System_Int32,
                                             retExpression,
                                             F.Call(
                                                 F.StaticCall(constructedEqualityComparer,
                                                              equalityComparer_get_Default.AsMember(constructedEqualityComparer)),
                                                 equalityComparer_GetHashCode.AsMember(constructedEqualityComparer),
                                                 F.Field(F.This(), anonymousType.Properties[index].BackingField)));
                }

                // Create a bound block
                F.CloseMethod(F.Block(F.Return(retExpression)));
            }
        internal sealed override TypeSymbolWithAnnotations GetFieldType(ConsList <FieldSymbol> fieldsBeingBound)
        {
            Debug.Assert(fieldsBeingBound != null);

            if (!_lazyType.IsNull)
            {
                return(_lazyType.ToType());
            }

            var declarator  = VariableDeclaratorNode;
            var fieldSyntax = GetFieldDeclaration(declarator);
            var typeSyntax  = fieldSyntax.Declaration.Type;

            var compilation = this.DeclaringCompilation;

            var diagnostics = DiagnosticBag.GetInstance();
            TypeSymbolWithAnnotations type;

            // When we have multiple declarators, we report the type diagnostics on only the first.
            DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance();

            Symbol associatedPropertyOrEvent = this.AssociatedSymbol;

            if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event)
            {
                EventSymbol @event = (EventSymbol)associatedPropertyOrEvent;
                if (@event.IsWindowsRuntimeEvent)
                {
                    NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T);
                    Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation);

                    // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T>
                    // type that has additional generic constraints?
                    type = TypeSymbolWithAnnotations.Create(tokenTableType.Construct(ImmutableArray.Create(@event.Type)));
                }
                else
                {
                    type = @event.Type;
                }
            }
            else
            {
                var binderFactory = compilation.GetBinderFactory(SyntaxTree);
                var binder        = binderFactory.GetBinder(typeSyntax);

                binder = binder.WithContainingMemberOrLambda(this);
                if (!ContainingType.IsScriptClass)
                {
                    type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator);
                }
                else
                {
                    bool isVar;
                    type = binder.BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar);

                    Debug.Assert(!type.IsNull || isVar);

                    if (isVar)
                    {
                        if (this.IsConst)
                        {
                            diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location);
                        }

                        if (fieldsBeingBound.ContainsReference(this))
                        {
                            diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this);
                            type = default;
                        }
                        else if (fieldSyntax.Declaration.Variables.Count > 1)
                        {
                            diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location);
                        }
                        else if (this.IsConst && this.ContainingType.IsScriptClass)
                        {
                            // For const var in script, we won't try to bind the initializer (case below), as it can lead to an unbound recursion
                            type = default;
                        }
                        else
                        {
                            fieldsBeingBound = new ConsList <FieldSymbol>(this, fieldsBeingBound);

                            var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound);
                            var initializerOpt    = initializerBinder.BindInferredVariableInitializer(diagnostics, RefKind.None, (EqualsValueClauseSyntax)declarator.Initializer, declarator);

                            if (initializerOpt != null)
                            {
                                if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType())
                                {
                                    type = TypeSymbolWithAnnotations.Create(nonNullTypesContext: this, initializerOpt.Type);
                                }

                                _lazyFieldTypeInferred = 1;
                            }
                        }

                        if (type.IsNull)
                        {
                            type = TypeSymbolWithAnnotations.Create(nonNullTypesContext: this, binder.CreateErrorType("var"));
                        }
                    }
                }

                if (IsFixed)
                {
                    type = TypeSymbolWithAnnotations.Create(new PointerTypeSymbol(type));

                    if (ContainingType.TypeKind != TypeKind.Struct)
                    {
                        diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, ErrorLocation);
                    }

                    var elementType = ((PointerTypeSymbol)type.TypeSymbol).PointedAtType.TypeSymbol;
                    int elementSize = elementType.FixedBufferElementSizeInBytes();
                    if (elementSize == 0)
                    {
                        var loc = typeSyntax.Location;
                        diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc);
                    }

                    if (!binder.InUnsafeRegion)
                    {
                        diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location);
                    }
                }
            }

            // update the lazyType only if it contains value last seen by the current thread:
            if (_lazyType.InterlockedInitialize(type.WithModifiers(this.RequiredCustomModifiers)))
            {
                TypeChecks(type.TypeSymbol, diagnostics);

                // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics.
                compilation.DeclarationDiagnostics.AddRange(diagnostics);

                bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator;
                if (isFirstDeclarator)
                {
                    compilation.DeclarationDiagnostics.AddRange(diagnosticsForFirstDeclarator);
                }

                state.NotePartComplete(CompletionPart.Type);
            }

            diagnostics.Free();
            diagnosticsForFirstDeclarator.Free();
            return(_lazyType.ToType());
        }