Esempio n. 1
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndices(arrayAccess.Indices);

            if (ShouldEmitReadOnlyPrefix(arrayAccess, addressKind))
            {
                _builder.EmitOpCode(ILOpCode.Readonly);
            }

            if (((ArrayTypeSymbol)arrayAccess.Expression.Type).IsSZArray)
            {
                _builder.EmitOpCode(ILOpCode.Ldelema);
                var elementType = arrayAccess.Type;
                EmitSymbolToken(elementType, arrayAccess.Syntax);
            }
            else
            {
                _builder.EmitArrayElementAddress(
                    _module.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type),
                    arrayAccess.Syntax,
                    _diagnostics
                    );
            }
        }
Esempio n. 2
0
        public override BoundNode VisitArrayAccess(BoundArrayAccess node)
        {
            BoundSpillSequenceBuilder builder = null;
            var expression = VisitExpression(ref builder, node.Expression);

            BoundSpillSequenceBuilder indicesBuilder = null;
            var index = this.VisitExpression(ref indicesBuilder, node.Index);

            if (indicesBuilder != null)
            {
                // spill the array if there were await expressions in the indices
                if (builder == null)
                {
                    builder = new BoundSpillSequenceBuilder();
                }

                expression = Spill(builder, expression);
            }

            if (builder != null)
            {
                builder.Include(indicesBuilder);
                indicesBuilder = builder;
                builder        = null;
            }

            return(UpdateExpression(indicesBuilder, node.Update(expression, index, node.Type)));
        }
Esempio n. 3
0
        private BoundExpression BindElementAccess(ElementAccessExpressionSyntax node)
        {
            Debug.Assert(node != null);

            var expr = BindExpression(node.Expression); // , BIND_RVALUEREQUIRED);

            var arguments = node.ArgumentList.Arguments
                            .Select(arg => BindExpression(arg.Expression))
                            .ToList();

            var argumentNames = node.ArgumentList.Arguments
                                .Select(arg => arg.NameColonOpt)
                                .Select(namecolon => namecolon != null ? namecolon.Identifier.GetText() : null)
                                .ToList();

            if (expr.GetExpressionType() == null)
            {
                return(BoundArrayAccess.AsError(node, expr, arguments, null));
            }

            if (!expr.IsOK || arguments.Any(x => !x.IsOK))
            {
                // At this point we definitely have reported an error, but we still might be
                // able to get more semantic analysis of the indexing operation. We do not
                // want to report cascading errors.

                // UNDONE: Set the error bit on the result?
                return(GetErrorSuppressingAnalyzer().BindElementAccessCore(node, expr, arguments, argumentNames));
            }

            return(BindElementAccessCore(node, expr, arguments, argumentNames));
        }
Esempio n. 4
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndices(arrayAccess.Indices);

            if (addressKind == AddressKind.ReadOnly)
            {
                Debug.Assert(arrayAccess.Type.TypeKind == TypeKind.TypeParameter,
                             ".readonly is only needed when element type is a type param");

                _builder.EmitOpCode(ILOpCode.Readonly);
            }

            if (arrayAccess.Indices.Length == 1)
            {
                _builder.EmitOpCode(ILOpCode.Ldelema);
                var elementType = arrayAccess.Type;
                EmitSymbolToken(elementType, arrayAccess.Syntax);
            }
            else
            {
                _builder.EmitArrayElementAddress(Emit.PEModuleBuilder.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type),
                                                 arrayAccess.Syntax, _diagnostics);
            }
        }
Esempio n. 5
0
 public override object VisitArrayAccess(BoundArrayAccess node, object arg)
 {
     VisitExpression(node.Expression);
     foreach (var i in node.Indices)
     {
         VisitExpression(i);
     }
     return(null);
 }
Esempio n. 6
0
 internal void Parse(BoundArrayAccess boundArrayAccess)
 {
     base.Parse(boundArrayAccess);
     this.Expression = Deserialize(boundArrayAccess.Expression) as Expression;
     foreach (var boundExpression in boundArrayAccess.Indices)
     {
         var item = Deserialize(boundExpression) as Expression;
         Debug.Assert(item != null);
         this._indices.Add(item);
     }
 }
Esempio n. 7
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndex(arrayAccess.Index);

            if (ShouldEmitReadOnlyPrefix(arrayAccess, addressKind))
            {
                _builder.EmitOpCode(ILOpCode.Readonly);
            }

            _builder.EmitOpCode(ILOpCode.Ldelema);
            var elementType = arrayAccess.Type;

            EmitSymbolToken(elementType, arrayAccess.Syntax);
        }
Esempio n. 8
0
        private bool ShouldEmitReadOnlyPrefix(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            if (addressKind == AddressKind.Constrained)
            {
                Debug.Assert(arrayAccess.Type.TypeKind == TypeKind.TypeParameter, "constrained call should only be used with type parameter types");
                return(true);
            }

            if (!IsAnyReadOnly(addressKind))
            {
                return(false);
            }

            // no benefits to value types
            return(!arrayAccess.Type.IsValueType);
        }
Esempio n. 9
0
        private BoundExpression VisitArrayAccess(BoundArrayAccess node)
        {
            var array = Visit(node.Expression);

            if (node.Indices.Length == 1)
            {
                var arg   = node.Indices[0];
                var index = Visit(arg);
                if (!TypeSymbol.Equals(index.Type, _int32Type, TypeCompareKind.ConsiderEverything2))
                {
                    index = ConvertIndex(index, arg.Type, _int32Type);
                }
                return(ExprFactory("ArrayIndex", array, index));
            }
            else
            {
                return(ExprFactory("ArrayIndex", array, Indices(node.Indices)));
            }
        }
        private BoundStatement AddAnalysisPoint(SyntaxNode syntaxForSpan, FileLinePositionSpan span, SyntheticBoundNodeFactory statementFactory)
        {
            // Add an entry in the spans array.
            int spansIndex = _spansBuilder.Count;

            _spansBuilder.Add(new SourceSpan(
                                  GetSourceDocument(_debugDocumentProvider, syntaxForSpan, span),
                                  span.StartLinePosition.Line,
                                  span.StartLinePosition.Character,
                                  span.EndLinePosition.Line,
                                  span.EndLinePosition.Character));

            // Generate "_payload[pointIndex] = true".
            BoundArrayAccess payloadCell =
                statementFactory.ArrayAccess(
                    statementFactory.Local(_methodPayload),
                    statementFactory.Literal(spansIndex));

            return(statementFactory.Assignment(payloadCell, statementFactory.Literal(true)));
        }
Esempio n. 11
0
        private BoundExpression BindArrayAccess(ElementAccessExpressionSyntax node, BoundExpression expr, IList <BoundExpression> arguments, IList <string> argumentNames)
        {
            Debug.Assert(node != null);
            Debug.Assert(expr != null);
            Debug.Assert(arguments != null);
            Debug.Assert(argumentNames != null);

            // For an array access, the primary-no-array-creation-expression of the element-access must
            // be a value of an array-type. Furthermore, the argument-list of an array access is not
            // allowed to contain named arguments.The number of expressions in the argument-list must
            // be the same as the rank of the array-type, and each expression must be of type
            // int, uint, long, ulong, or must be implicitly convertible to one or more of these types.

            if (argumentNames.Any(x => x != null))
            {
                Error(ErrorCode.ERR_NamedArgumentForArray, node);
            }

            var arrayType = (ArrayTypeSymbol)expr.GetExpressionType();

            // Note that the spec says to determine which of {int, uint, long, ulong} *each*
            // index expression is convertible to. That is not what C# 1 through 4
            // did; the implementations instead determined which of those four
            // types *all* of the index expressions converted to.



            int rank = arrayType.Rank;

            if (arguments.Count != arrayType.Rank)
            {
                Error(ErrorCode.ERR_BadIndexCount, node, rank);
                return(BoundArrayAccess.AsError(node, expr, arguments, arrayType.ElementType));
            }

            var convertedArguments = arguments.Select(x => ConvertToArrayIndex(x)).ToList();

            return(new BoundArrayAccess(node, expr, convertedArguments, arrayType.ElementType));
        }
Esempio n. 12
0
        private void EmitArrayElementLoad(BoundArrayAccess arrayAccess, bool used)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndices(arrayAccess.Indices);

            if (((ArrayTypeSymbol)arrayAccess.Expression.Type).IsSZArray)
            {
                var elementType = arrayAccess.Type;
                if (elementType.IsEnumType())
                {
                    //underlying primitives do not need type tokens.
                    elementType = ((NamedTypeSymbol)elementType).EnumUnderlyingType;
                }

                switch (elementType.PrimitiveTypeCode)
                {
                    case Microsoft.Cci.PrimitiveTypeCode.Int8:
                        _builder.EmitOpCode(ILOpCode.Ldelem_i1);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.Boolean:
                    case Microsoft.Cci.PrimitiveTypeCode.UInt8:
                        _builder.EmitOpCode(ILOpCode.Ldelem_u1);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.Int16:
                        _builder.EmitOpCode(ILOpCode.Ldelem_i2);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.Char:
                    case Microsoft.Cci.PrimitiveTypeCode.UInt16:
                        _builder.EmitOpCode(ILOpCode.Ldelem_u2);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.Int32:
                        _builder.EmitOpCode(ILOpCode.Ldelem_i4);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.UInt32:
                        _builder.EmitOpCode(ILOpCode.Ldelem_u4);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.Int64:
                    case Microsoft.Cci.PrimitiveTypeCode.UInt64:
                        _builder.EmitOpCode(ILOpCode.Ldelem_i8);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.IntPtr:
                    case Microsoft.Cci.PrimitiveTypeCode.UIntPtr:
                    case Microsoft.Cci.PrimitiveTypeCode.Pointer:
                        _builder.EmitOpCode(ILOpCode.Ldelem_i);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.Float32:
                        _builder.EmitOpCode(ILOpCode.Ldelem_r4);
                        break;

                    case Microsoft.Cci.PrimitiveTypeCode.Float64:
                        _builder.EmitOpCode(ILOpCode.Ldelem_r8);
                        break;

                    default:
                        if (elementType.IsVerifierReference())
                        {
                            _builder.EmitOpCode(ILOpCode.Ldelem_ref);
                        }
                        else
                        {
                            if (used)
                            {
                                _builder.EmitOpCode(ILOpCode.Ldelem);
                            }
                            else
                            {
                                // no need to read whole element of nontrivial type/size here
                                // just take a reference to an element for array access side-effects 
                                if (elementType.TypeKind == TypeKind.TypeParameter)
                                {
                                    _builder.EmitOpCode(ILOpCode.Readonly);
                                }

                                _builder.EmitOpCode(ILOpCode.Ldelema);
                            }

                            EmitSymbolToken(elementType, arrayAccess.Syntax);
                        }
                        break;
                }
            }
            else
            {
                _builder.EmitArrayElementLoad(Emit.PEModuleBuilder.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type), arrayAccess.Expression.Syntax, _diagnostics);
            }

            EmitPopIfUnused(used);
        }
Esempio n. 13
0
        public override BoundNode VisitArrayAccess(BoundArrayAccess node)
        {
            // regardless of purpose, array access visits its children as values
            // TODO: do we need to save/restore old context here?
            var oldContext = _context;
            _context = ExprContext.Value;

            var result = base.VisitArrayAccess(node);

            _context = oldContext;
            return result;
        }
Esempio n. 14
0
        private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind addressKind)
        {
            EmitExpression(arrayAccess.Expression, used: true);
            EmitArrayIndices(arrayAccess.Indices);

            if (addressKind == AddressKind.ReadOnly)
            {
                Debug.Assert(arrayAccess.Type.TypeKind == TypeKind.TypeParameter,
                    ".readonly is only needed when element type is a type param");

                builder.EmitOpCode(ILOpCode.Readonly);
            }

            if (arrayAccess.Indices.Length == 1)
            {
                builder.EmitOpCode(ILOpCode.Ldelema);
                var elementType = arrayAccess.Type;
                EmitSymbolToken(elementType, arrayAccess.Syntax);
            }
            else
            {
                builder.EmitArrayElementAddress(Emit.PEModuleBuilder.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type),
                                                arrayAccess.Syntax, diagnostics);
            }
        }
Esempio n. 15
0
        public override BoundNode VisitArrayAccess(BoundArrayAccess node)
        {
            // https://github.com/dotnet/roslyn/issues/30620
            // If the array access index is of type System.Index or System.Range
            // we need to emit code as if there were a real indexer, instead
            // of a simple array element access.

            if (node.Indices.Length != 1)
            {
                return(base.VisitArrayAccess(node));
            }

            TypeSymbol rawIndexType = node.Indices[0].Type;

            if (!(TypeSymbol.Equals(rawIndexType, _compilation.GetWellKnownType(WellKnownType.core_Index), TypeCompareKind.ConsiderEverything) ||
                  TypeSymbol.Equals(rawIndexType, _compilation.GetWellKnownType(WellKnownType.core_Range), TypeCompareKind.ConsiderEverything)))
            {
                return(base.VisitArrayAccess(node));
            }

            var syntax     = node.Syntax;
            var F          = _factory;
            var indexLocal = F.StoreToTemp(
                VisitExpression(node.Indices[0]),
                out BoundAssignmentOperator indexAssign);
            var arrayLocal = F.StoreToTemp(
                VisitExpression(node.Expression),
                out BoundAssignmentOperator arrayAssign);
            var indexType = VisitType(node.Indices[0].Type);

            var indexValueSymbol   = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__Value);
            var indexFromEndSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__FromEnd);

            BoundExpression resultExpr;

            if (TypeSymbol.Equals(indexType, _compilation.GetWellKnownType(WellKnownType.core_Index), TypeCompareKind.ConsiderEverything))
            {
                // array[Index] is translated to:
                // array[index.FromEnd ? array.Length - index.Value : index.Value]

                var indexValueExpr = F.Property(indexLocal, indexValueSymbol);

                resultExpr = F.Sequence(
                    ImmutableArray.Create <LocalSymbol>(
                        indexLocal.LocalSymbol,
                        arrayLocal.LocalSymbol),
                    ImmutableArray.Create <BoundExpression>(
                        indexAssign,
                        arrayAssign),
                    F.ArrayAccess(arrayLocal, ImmutableArray.Create(
                                      F.Conditional(
                                          F.Property(indexLocal, indexFromEndSymbol),
                                          F.Binary(
                                              BinaryOperatorKind.Subtraction,
                                              F.SpecialType(SpecialType.System_Int32),
                                              F.ArrayLength(arrayLocal),
                                              indexValueExpr),
                                          indexValueExpr,
                                          node.Type))));
            }
            else if (TypeSymbol.Equals(indexType, _compilation.GetWellKnownType(WellKnownType.core_Range), TypeCompareKind.ConsiderEverything))
            {
                // array[Range] is translated to:
                // var start = range.Start.FromEnd ? array.Length - range.Start.Value : range.Start.Value;
                // var end = range.End.FromEnd ? array.Length - range.End.Value : range.End.Value;
                // var length = end - start;
                // var newArr = new T[length];
                // Array.Copy(array, start, newArr, 0, length);
                // push newArray

                var rangeStartSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Range__Start);
                var rangeEndSymbol   = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Range__End);
                var arrayCopySymbol  = F.WellKnownMethod(WellKnownMember.System_Array__Copy);

                var startLocal = F.StoreToTemp(
                    F.Conditional(
                        F.Property(F.Property(indexLocal, rangeStartSymbol), indexFromEndSymbol),
                        F.Binary(
                            BinaryOperatorKind.Subtraction,
                            F.SpecialType(SpecialType.System_Int32),
                            F.ArrayLength(arrayLocal),
                            F.Property(F.Property(indexLocal, rangeStartSymbol), indexValueSymbol)),
                        F.Property(F.Property(indexLocal, rangeStartSymbol), indexValueSymbol),
                        F.SpecialType(SpecialType.System_Int32)),
                    out BoundAssignmentOperator startAssign);
                var endLocal = F.StoreToTemp(
                    F.Conditional(
                        F.Property(F.Property(indexLocal, rangeEndSymbol), indexFromEndSymbol),
                        F.Binary(
                            BinaryOperatorKind.Subtraction,
                            F.SpecialType(SpecialType.System_Int32),
                            F.ArrayLength(arrayLocal),
                            F.Property(F.Property(indexLocal, rangeEndSymbol), indexValueSymbol)),
                        F.Property(F.Property(indexLocal, rangeEndSymbol), indexValueSymbol),
                        F.SpecialType(SpecialType.System_Int32)),
                    out BoundAssignmentOperator endAssign);
                var lengthLocal = F.StoreToTemp(
                    F.Binary(BinaryOperatorKind.Subtraction, F.SpecialType(SpecialType.System_Int32), endLocal, startLocal),
                    out BoundAssignmentOperator lengthAssign);
                var elementType = ((ArrayTypeSymbol)node.Type).ElementType.TypeSymbol;
                var newArrLocal = F.StoreToTemp(F.Array(elementType, lengthLocal), out BoundAssignmentOperator newArrAssign);
                var copyExpr    = F.Call(null, arrayCopySymbol, ImmutableArray.Create <BoundExpression>(
                                             arrayLocal,
                                             startLocal,
                                             newArrLocal,
                                             F.Literal(0),
                                             lengthLocal));
                resultExpr = F.Sequence(
                    ImmutableArray.Create(
                        indexLocal.LocalSymbol,
                        arrayLocal.LocalSymbol,
                        startLocal.LocalSymbol,
                        endLocal.LocalSymbol,
                        lengthLocal.LocalSymbol,
                        newArrLocal.LocalSymbol),
                    ImmutableArray.Create <BoundExpression>(
                        indexAssign,
                        arrayAssign,
                        startAssign,
                        endAssign,
                        lengthAssign,
                        newArrAssign,
                        copyExpr),
                    newArrLocal);
            }
            else
            {
                throw ExceptionUtilities.Unreachable;
            }
            return(resultExpr);
        }