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 ); } }
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))); }
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)); }
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); } }
public override object VisitArrayAccess(BoundArrayAccess node, object arg) { VisitExpression(node.Expression); foreach (var i in node.Indices) { VisitExpression(i); } return(null); }
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); } }
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); }
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); }
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))); }
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)); }
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); }
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; }
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); } }
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); }