Example #1
0
        public SynthesizedRecordEquals(
            NamedTypeSymbol containingType,
            TypeSymbol parameterType,
            bool isOverride,
            PropertySymbol equalityContract,
            MethodSymbol?otherEqualsMethod,
            int memberOffset)
        {
            // If the parameter is a struct type, it should be declared `in`
            // and we need to call EnsureIsReadOnlyAttributeExists().
            Debug.Assert(!parameterType.IsStructType());

            var compilation = containingType.DeclaringCompilation;

            _equalityContract  = equalityContract;
            _otherEqualsMethod = otherEqualsMethod;
            _memberOffset      = memberOffset;

            ContainingType = containingType;
            IsVirtual      = !isOverride;
            IsOverride     = isOverride;
            Parameters     = ImmutableArray.Create(SynthesizedParameterSymbol.Create(
                                                       this,
                                                       TypeWithAnnotations.Create(parameterType, nullableAnnotation: NullableAnnotation.Annotated),
                                                       ordinal: 0,
                                                       RefKind.None));
            ReturnTypeWithAnnotations = TypeWithAnnotations.Create(compilation.GetSpecialType(SpecialType.System_Boolean));
        }
            static void addFromClassOrStruct(ArrayBuilder <TypeSymbol> result, bool excludeExisting, TypeSymbol type, bool includeBaseTypes, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo)
            {
                if (type.IsClassType() || type.IsStructType())
                {
                    if (!excludeExisting || !HasIdentityConversionToAny(type, result))
                    {
                        result.Add(type);
                    }
                }

                if (!includeBaseTypes)
                {
                    return;
                }

                NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo);

                while ((object)t != null)
                {
                    if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                    {
                        result.Add(t);
                    }

                    t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo);
                }
            }
 /// <summary>
 /// Copies a value type from the top of evaluation stack into a temporary variable and loads its address.
 /// </summary>
 private void EmitStructAddr(TypeSymbol t)
 {
     Debug.Assert(t.IsStructType());
     var tmp = GetTemporaryLocal(t, true);
     _il.EmitLocalStore(tmp);
     _il.EmitLocalAddress(tmp);
 }
Example #4
0
        /// <summary>
        /// Copies a value type from the top of evaluation stack into a temporary variable and loads its address.
        /// </summary>
        private void EmitStructAddr(TypeSymbol t)
        {
            Debug.Assert(t.IsStructType());
            var tmp = GetTemporaryLocal(t, true);

            _il.EmitLocalStore(tmp);
            _il.EmitLocalAddress(tmp);
        }
Example #5
0
        public static void AddTypesParticipatingInUserDefinedConversion(
            ArrayBuilder <NamedTypeSymbol> result,
            TypeSymbol type,
            bool includeBaseTypes,
            ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo
            )
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            if (type.IsClassType() || type.IsStructType())
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo);

            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo);
            }
        }
Example #6
0
        public static void AddTypesParticipatingInUserDefinedConversion(ArrayBuilder <NamedTypeSymbol> result, TypeSymbol type, bool includeBaseTypes, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            // The decimal type does not contribute its user-defined conversions to the mix; though its
            // conversions are actually implemented via user-defined operators, we logically treat it as
            // though those conversions were built-in.

            if (type.IsClassType() || type.IsStructType() && type.SpecialType != SpecialType.System_Decimal)
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);

            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }
        }
        public static void AddTypesParticipatingInUserDefinedConversion(ArrayBuilder<NamedTypeSymbol> result, TypeSymbol type, bool includeBaseTypes, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            // The decimal type does not contribute its user-defined conversions to the mix; though its 
            // conversions are actually implemented via user-defined operators, we logically treat it as 
            // though those conversions were built-in.  

            if (type.IsClassType() || type.IsStructType() && type.SpecialType != SpecialType.System_Decimal)
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }
        }
Example #8
0
        public static void AddTypesParticipatingInUserDefinedConversion(ArrayBuilder<NamedTypeSymbol> result, TypeSymbol type, bool includeBaseTypes, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            if ((object)type == null)
            {
                return;
            }

            // CONSIDER: These sets are usually small; if they are large then this is an O(n^2)
            // CONSIDER: algorithm. We could use a hash table instead to build up the set.

            Debug.Assert(!type.IsTypeParameter());

            // optimization:
            bool excludeExisting = result.Count > 0;

            if (type.IsClassType() || type.IsStructType())
            {
                var namedType = (NamedTypeSymbol)type;
                if (!excludeExisting || !HasIdentityConversionToAny(namedType, result))
                {
                    result.Add(namedType);
                }
            }

            if (!includeBaseTypes)
            {
                return;
            }

            NamedTypeSymbol t = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            while ((object)t != null)
            {
                if (!excludeExisting || !HasIdentityConversionToAny(t, result))
                {
                    result.Add(t);
                }

                t = t.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }
        }
        /// <summary>
        /// Lower a foreach loop that will enumerate a collection using an enumerator.
        ///
        /// E e = ((C)(x)).GetEnumerator()
        /// try {
        ///     while (e.MoveNext()) {
        ///         V v = (V)(T)e.Current;
        ///         // body
        ///     }
        /// }
        /// finally {
        ///     // clean up e
        /// }
        /// </summary>
        private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            ForEachEnumeratorInfo enumeratorInfo = node.EnumeratorInfoOpt;

            Debug.Assert(enumeratorInfo != null);

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            BoundExpression rewrittenExpression  = (BoundExpression)Visit(collectionExpression);
            BoundStatement  rewrittenBody        = (BoundStatement)Visit(node.Body);

            TypeSymbol enumeratorType = enumeratorInfo.GetEnumeratorMethod.ReturnType;
            TypeSymbol elementType    = enumeratorInfo.ElementType;

            // E e
            LocalSymbol enumeratorVar = _factory.SynthesizedLocal(enumeratorType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachEnumerator);

            // Reference to e.
            BoundLocal boundEnumeratorVar = MakeBoundLocal(forEachSyntax, enumeratorVar, enumeratorType);

            // ((C)(x)).GetEnumerator() or (x).GetEnumerator();
            BoundExpression enumeratorVarInitValue = SynthesizeCall(forEachSyntax, rewrittenExpression, enumeratorInfo.GetEnumeratorMethod, enumeratorInfo.CollectionConversion, enumeratorInfo.CollectionType);

            // E e = ((C)(x)).GetEnumerator();
            BoundStatement enumeratorVarDecl = MakeLocalDeclaration(forEachSyntax, enumeratorVar, enumeratorVarInitValue);

            AddForEachExpressionSequencePoint(forEachSyntax, ref enumeratorVarDecl);

            // V v
            LocalSymbol iterationVar = node.IterationVariable;

            //(V)(T)e.Current
            BoundExpression iterationVarAssignValue = MakeConversion(
                syntax: forEachSyntax,
                rewrittenOperand: MakeConversion(
                    syntax: forEachSyntax,
                    rewrittenOperand: BoundCall.Synthesized(
                        syntax: forEachSyntax,
                        receiverOpt: boundEnumeratorVar,
                        method: enumeratorInfo.CurrentPropertyGetter),
                    conversion: enumeratorInfo.CurrentConversion,
                    rewrittenType: elementType,
                    @checked: node.Checked),
                conversion: node.ElementConversion,
                rewrittenType: iterationVar.Type,
                @checked: node.Checked);

            // V v = (V)(T)e.Current;
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarAssignValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // while (e.MoveNext()) {
            //     V v = (V)(T)e.Current;
            //     /* node.Body */
            // }

            var rewrittenBodyBlock = CreateBlockDeclaringIterationVariable(iterationVar, iterationVarDecl, rewrittenBody, forEachSyntax);

            BoundStatement whileLoop = RewriteWhileStatement(
                syntax: forEachSyntax,
                rewrittenCondition: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundEnumeratorVar,
                    method: enumeratorInfo.MoveNextMethod),
                conditionSequencePointSpan: forEachSyntax.InKeyword.Span,
                rewrittenBody: rewrittenBodyBlock,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel,
                hasErrors: false);

            BoundStatement result;

            MethodSymbol disposeMethod;

            if (enumeratorInfo.NeedsDisposeMethod && Binder.TryGetSpecialTypeMember(_compilation, SpecialMember.System_IDisposable__Dispose, forEachSyntax, _diagnostics, out disposeMethod))
            {
                Binder.ReportDiagnosticsIfObsolete(_diagnostics, disposeMethod, forEachSyntax,
                                                   hasBaseReceiver: false,
                                                   containingMember: _factory.CurrentMethod,
                                                   containingType: _factory.CurrentType,
                                                   location: enumeratorInfo.Location);

                BoundBlock finallyBlockOpt;
                var        idisposableTypeSymbol = disposeMethod.ContainingType;
                var        conversions           = new TypeConversions(_factory.CurrentMethod.ContainingAssembly.CorLibrary);

                HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                var isImplicit = conversions.ClassifyImplicitConversion(enumeratorType, idisposableTypeSymbol, ref useSiteDiagnostics).IsImplicit;
                _diagnostics.Add(forEachSyntax, useSiteDiagnostics);

                if (isImplicit)
                {
                    Debug.Assert(enumeratorInfo.NeedsDisposeMethod);

                    Conversion receiverConversion = enumeratorType.IsStructType() ?
                                                    Conversion.Boxing :
                                                    Conversion.ImplicitReference;

                    // ((IDisposable)e).Dispose(); or e.Dispose();
                    BoundStatement disposeCall = new BoundExpressionStatement(forEachSyntax,
                                                                              expression: SynthesizeCall(forEachSyntax, boundEnumeratorVar, disposeMethod, receiverConversion, idisposableTypeSymbol));

                    BoundStatement disposeStmt;
                    if (enumeratorType.IsValueType)
                    {
                        // No way for the struct to be nullable and disposable.
                        Debug.Assert(((TypeSymbol)enumeratorType.OriginalDefinition).SpecialType != SpecialType.System_Nullable_T);

                        // For non-nullable structs, no null check is required.
                        disposeStmt = disposeCall;
                    }
                    else
                    {
                        // NB: cast to object missing from spec.  Needed to ignore user-defined operators and box type parameters.
                        // if ((object)e != null) ((IDisposable)e).Dispose();
                        disposeStmt = RewriteIfStatement(
                            syntax: forEachSyntax,
                            rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                        operatorKind: BinaryOperatorKind.NotEqual,
                                                                        left: MakeConversion(
                                                                            syntax: forEachSyntax,
                                                                            rewrittenOperand: boundEnumeratorVar,
                                                                            conversion: enumeratorInfo.EnumeratorConversion,
                                                                            rewrittenType: _compilation.GetSpecialType(SpecialType.System_Object),
                                                                            @checked: false),
                                                                        right: MakeLiteral(forEachSyntax,
                                                                                           constantValue: ConstantValue.Null,
                                                                                           type: null),
                                                                        constantValueOpt: null,
                                                                        methodOpt: null,
                                                                        resultKind: LookupResultKind.Viable,
                                                                        type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                            rewrittenConsequence: disposeCall,
                            rewrittenAlternativeOpt: null,
                            hasErrors: false);
                    }

                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     locals: ImmutableArray <LocalSymbol> .Empty,
                                                     localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                     statements: ImmutableArray.Create <BoundStatement>(disposeStmt));
                }
                else
                {
                    Debug.Assert(!enumeratorType.IsSealed);

                    // IDisposable d
                    LocalSymbol disposableVar = _factory.SynthesizedLocal(idisposableTypeSymbol);

                    // Reference to d.
                    BoundLocal boundDisposableVar = MakeBoundLocal(forEachSyntax, disposableVar, idisposableTypeSymbol);

                    BoundTypeExpression boundIDisposableTypeExpr = new BoundTypeExpression(forEachSyntax,
                                                                                           aliasOpt: null,
                                                                                           type: idisposableTypeSymbol);

                    // e as IDisposable
                    BoundExpression disposableVarInitValue = new BoundAsOperator(forEachSyntax,
                                                                                 operand: boundEnumeratorVar,
                                                                                 targetType: boundIDisposableTypeExpr,
                                                                                 conversion: Conversion.ExplicitReference, // Explicit so the emitter won't optimize it away.
                                                                                 type: idisposableTypeSymbol);

                    // IDisposable d = e as IDisposable;
                    BoundStatement disposableVarDecl = MakeLocalDeclaration(forEachSyntax, disposableVar, disposableVarInitValue);

                    // if (d != null) d.Dispose();
                    BoundStatement ifStmt = RewriteIfStatement(
                        syntax: forEachSyntax,
                        rewrittenCondition: new BoundBinaryOperator(forEachSyntax,
                                                                    operatorKind: BinaryOperatorKind.NotEqual, // reference equality
                                                                    left: boundDisposableVar,
                                                                    right: MakeLiteral(forEachSyntax,
                                                                                       constantValue: ConstantValue.Null,
                                                                                       type: null),
                                                                    constantValueOpt: null,
                                                                    methodOpt: null,
                                                                    resultKind: LookupResultKind.Viable,
                                                                    type: _compilation.GetSpecialType(SpecialType.System_Boolean)),
                        rewrittenConsequence: new BoundExpressionStatement(forEachSyntax,
                                                                           expression: BoundCall.Synthesized(
                                                                               syntax: forEachSyntax,
                                                                               receiverOpt: boundDisposableVar,
                                                                               method: disposeMethod)),
                        rewrittenAlternativeOpt: null,
                        hasErrors: false);

                    // IDisposable d = e as IDisposable;
                    // if (d != null) d.Dispose();
                    finallyBlockOpt = new BoundBlock(forEachSyntax,
                                                     locals: ImmutableArray.Create <LocalSymbol>(disposableVar),
                                                     localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                     statements: ImmutableArray.Create <BoundStatement>(disposableVarDecl, ifStmt));
                }

                // try {
                //     while (e.MoveNext()) {
                //         V v = (V)(T)e.Current;
                //         /* loop body */
                //     }
                // }
                // finally {
                //     /* dispose of e */
                // }
                BoundStatement tryFinally = new BoundTryStatement(forEachSyntax,
                                                                  tryBlock: new BoundBlock(forEachSyntax,
                                                                                           locals: ImmutableArray <LocalSymbol> .Empty,
                                                                                           localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                                                                                           statements: ImmutableArray.Create <BoundStatement>(whileLoop)),
                                                                  catchBlocks: ImmutableArray <BoundCatchBlock> .Empty,
                                                                  finallyBlockOpt: finallyBlockOpt);

                // E e = ((C)(x)).GetEnumerator();
                // try {
                //     /* as above */
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                    statements: ImmutableArray.Create <BoundStatement>(enumeratorVarDecl, tryFinally));
            }
            else
            {
                // E e = ((C)(x)).GetEnumerator();
                // while (e.MoveNext()) {
                //     V v = (V)(T)e.Current;
                //     /* loop body */
                // }
                result = new BoundBlock(
                    syntax: forEachSyntax,
                    locals: ImmutableArray.Create(enumeratorVar),
                    localFunctions: ImmutableArray <LocalFunctionSymbol> .Empty,
                    statements: ImmutableArray.Create <BoundStatement>(enumeratorVarDecl, whileLoop));
            }

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return(result);
        }