未验证 提交 5d70e9b1 编写于 作者: A Andy Gocke 提交者: GitHub

Implement full spec changes for Index/Range (#33679)

Reflects the changes described in https://github.com/dotnet/csharplang/pull/2214.

Range now looks optimistically for some special members with optional
parameters, but will fall back to the Range constructor if they aren't
present.

This change also removes all of the specialized codegen that was going
on with arrays and strings in favor of expected helpers or real members.
上级 8e898658
......@@ -1974,7 +1974,43 @@ private BoundExpression BindRangeExpression(RangeExpressionSyntax node, Diagnost
if (!rangeType.IsErrorType())
{
symbolOpt = (MethodSymbol)GetWellKnownTypeMember(Compilation, WellKnownMember.System_Range__ctor, diagnostics, syntax: node);
// Depending on the available arguments to the range expression, there are four
// possible well-known members we could bind to. The constructor is always the
// fallback member, usable in any situation. However, if any of the other members
// are available and applicable, we will prefer that.
WellKnownMember? memberOpt = null;
if (node.LeftOperand is null && node.RightOperand is null)
{
memberOpt = WellKnownMember.System_Range__get_All;
}
else if (node.LeftOperand is null)
{
memberOpt = WellKnownMember.System_Range__EndAt;
}
else if (node.RightOperand is null)
{
memberOpt = WellKnownMember.System_Range__StartAt;
}
if (!(memberOpt is null))
{
symbolOpt = (MethodSymbol)GetWellKnownTypeMember(
Compilation,
memberOpt.GetValueOrDefault(),
diagnostics,
syntax: node,
isOptional: true);
}
if (symbolOpt is null)
{
symbolOpt = (MethodSymbol)GetWellKnownTypeMember(
Compilation,
WellKnownMember.System_Range__ctor,
diagnostics,
syntax: node);
}
}
BoundExpression left = BindRangeExpressionOperand(node.LeftOperand, diagnostics);
......@@ -6864,8 +6900,11 @@ private BoundExpression BindArrayAccess(ExpressionSyntax node, BoundExpression e
}
}
var resultType = rank == 1 &&
TypeSymbol.Equals(convertedArguments[0].Type, Compilation.GetWellKnownType(WellKnownType.System_Range), TypeCompareKind.ConsiderEverything2)
TypeSymbol resultType = rank == 1 &&
TypeSymbol.Equals(
convertedArguments[0].Type,
Compilation.GetWellKnownType(WellKnownType.System_Range),
TypeCompareKind.ConsiderEverything)
? arrayType
: arrayType.ElementType.TypeSymbol;
......@@ -6893,9 +6932,30 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no
if (result is null && allowIndexAndRange)
{
result =
TryImplicitConversionToArrayIndex(index, WellKnownType.System_Index, node, diagnostics) ??
TryImplicitConversionToArrayIndex(index, WellKnownType.System_Range, node, diagnostics);
result = TryImplicitConversionToArrayIndex(index, WellKnownType.System_Index, node, diagnostics);
if (result is null)
{
result = TryImplicitConversionToArrayIndex(index, WellKnownType.System_Range, node, diagnostics);
if (!(result is null))
{
// This member is needed for lowering and should produce an error if not present
_ = GetWellKnownTypeMember(
Compilation,
WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T,
diagnostics,
syntax: node);
}
}
else
{
// This member is needed for lowering and should produce an error if not present
_ = GetWellKnownTypeMember(
Compilation,
WellKnownMember.System_Index__GetOffset,
diagnostics,
syntax: node);
}
}
if (result is null)
......@@ -7216,43 +7276,6 @@ private BoundExpression BindIndexedPropertyAccess(SyntaxNode syntax, BoundExpres
if (!analyzedArguments.HasErrors)
{
// https://github.com/dotnet/roslyn/issues/30620
// Pretend like there are indexers that support range and index
if (receiverOpt?.Type.SpecialType == SpecialType.System_String &&
analyzedArguments.Arguments.Count == 1)
{
var argType = analyzedArguments.Arguments[0].Type;
TypeSymbol resultType = null;
if (TypeSymbol.Equals(argType, Compilation.GetWellKnownType(WellKnownType.System_Index), TypeCompareKind.ConsiderEverything2))
{
resultType = GetSpecialType(SpecialType.System_Char, diagnostics, syntax);
}
else if (TypeSymbol.Equals(argType, Compilation.GetWellKnownType(WellKnownType.System_Range), TypeCompareKind.ConsiderEverything2))
{
resultType = GetSpecialType(SpecialType.System_String, diagnostics, syntax);
}
if (!(resultType is null))
{
var args = analyzedArguments.Arguments.ToImmutable();
overloadResolutionResult.Free();
return new BoundIndexerAccess(
syntax,
receiverOpt,
candidates[0],
args,
argumentNames,
argumentRefKinds,
expanded: false,
argsToParamsOpt: default,
binderOpt: this,
useSetterForDefaultArgumentGeneration: false,
resultType,
hasErrors: false);
}
}
// Dev10 uses the "this" keyword as the method name for indexers.
var candidate = candidates[0];
var name = candidate.IsIndexer ? SyntaxFacts.GetText(SyntaxKind.ThisKeyword) : candidate.Name;
......
......@@ -344,8 +344,8 @@
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="LeftOperand" Type="BoundExpression" Null="allow"/>
<Field Name="RightOperand" Type="BoundExpression" Null="allow"/>
<Field Name="LeftOperandOpt" Type="BoundExpression" Null="allow"/>
<Field Name="RightOperandOpt" Type="BoundExpression" Null="allow"/>
<Field Name="MethodOpt" Type="MethodSymbol" Null="allow"/>
</Node>
......
......@@ -2100,14 +2100,14 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
public override BoundNode VisitRangeExpression(BoundRangeExpression node)
{
if (node.LeftOperand != null)
if (node.LeftOperandOpt != null)
{
VisitRvalue(node.LeftOperand);
VisitRvalue(node.LeftOperandOpt);
}
if (node.RightOperand != null)
if (node.RightOperandOpt != null)
{
VisitRvalue(node.RightOperand);
VisitRvalue(node.RightOperandOpt);
}
return null;
......
......@@ -4759,17 +4759,7 @@ public override BoundNode VisitIndexerAccess(BoundIndexerAccess node)
// https://github.com/dotnet/roslyn/issues/29964 Update indexer based on inferred receiver type.
VisitArguments(node, node.Arguments, node.ArgumentRefKindsOpt, node.Indexer, node.ArgsToParamsOpt, node.Expanded);
// https://github.com/dotnet/roslyn/issues/30620 remove before shipping dev16
TypeSymbolWithAnnotations type;
if (node.Arguments.Length == 1 &&
TypeSymbol.Equals(node.Arguments[0].Type, compilation.GetWellKnownType(WellKnownType.System_Range), TypeCompareKind.ConsiderEverything2))
{
type = TypeSymbolWithAnnotations.Create(node.Type);
}
else
{
type = node.Indexer.Type;
}
TypeSymbolWithAnnotations type = node.Indexer.Type;
SetResult(type, type);
return null;
}
......
......@@ -1318,21 +1318,21 @@ protected override BoundExpression ShallowClone()
internal sealed partial class BoundRangeExpression : BoundExpression
{
public BoundRangeExpression(SyntaxNode syntax, BoundExpression leftOperand, BoundExpression rightOperand, MethodSymbol methodOpt, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.RangeExpression, syntax, type, hasErrors || leftOperand.HasErrors() || rightOperand.HasErrors())
public BoundRangeExpression(SyntaxNode syntax, BoundExpression leftOperandOpt, BoundExpression rightOperandOpt, MethodSymbol methodOpt, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.RangeExpression, syntax, type, hasErrors || leftOperandOpt.HasErrors() || rightOperandOpt.HasErrors())
{
Debug.Assert((object)type != null, "Field 'type' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.LeftOperand = leftOperand;
this.RightOperand = rightOperand;
this.LeftOperandOpt = leftOperandOpt;
this.RightOperandOpt = rightOperandOpt;
this.MethodOpt = methodOpt;
}
public BoundExpression LeftOperand { get; }
public BoundExpression LeftOperandOpt { get; }
public BoundExpression RightOperand { get; }
public BoundExpression RightOperandOpt { get; }
public MethodSymbol MethodOpt { get; }
......@@ -1341,11 +1341,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor)
return visitor.VisitRangeExpression(this);
}
public BoundRangeExpression Update(BoundExpression leftOperand, BoundExpression rightOperand, MethodSymbol methodOpt, TypeSymbol type)
public BoundRangeExpression Update(BoundExpression leftOperandOpt, BoundExpression rightOperandOpt, MethodSymbol methodOpt, TypeSymbol type)
{
if (leftOperand != this.LeftOperand || rightOperand != this.RightOperand || methodOpt != this.MethodOpt || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
if (leftOperandOpt != this.LeftOperandOpt || rightOperandOpt != this.RightOperandOpt || methodOpt != this.MethodOpt || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
{
var result = new BoundRangeExpression(this.Syntax, leftOperand, rightOperand, methodOpt, type, this.HasErrors);
var result = new BoundRangeExpression(this.Syntax, leftOperandOpt, rightOperandOpt, methodOpt, type, this.HasErrors);
result.CopyAttributes(this);
return result;
}
......@@ -1354,7 +1354,7 @@ public BoundRangeExpression Update(BoundExpression leftOperand, BoundExpression
protected override BoundExpression ShallowClone()
{
var result = new BoundRangeExpression(this.Syntax, this.LeftOperand, this.RightOperand, this.MethodOpt, this.Type, this.HasErrors);
var result = new BoundRangeExpression(this.Syntax, this.LeftOperandOpt, this.RightOperandOpt, this.MethodOpt, this.Type, this.HasErrors);
result.CopyAttributes(this);
return result;
}
......@@ -10201,8 +10201,8 @@ public override BoundNode VisitFromEndIndexExpression(BoundFromEndIndexExpressio
}
public override BoundNode VisitRangeExpression(BoundRangeExpression node)
{
this.Visit(node.LeftOperand);
this.Visit(node.RightOperand);
this.Visit(node.LeftOperandOpt);
this.Visit(node.RightOperandOpt);
return null;
}
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
......@@ -11168,10 +11168,10 @@ public override BoundNode VisitFromEndIndexExpression(BoundFromEndIndexExpressio
}
public override BoundNode VisitRangeExpression(BoundRangeExpression node)
{
BoundExpression leftOperand = (BoundExpression)this.Visit(node.LeftOperand);
BoundExpression rightOperand = (BoundExpression)this.Visit(node.RightOperand);
BoundExpression leftOperandOpt = (BoundExpression)this.Visit(node.LeftOperandOpt);
BoundExpression rightOperandOpt = (BoundExpression)this.Visit(node.RightOperandOpt);
TypeSymbol type = this.VisitType(node.Type);
return node.Update(leftOperand, rightOperand, node.MethodOpt, type);
return node.Update(leftOperandOpt, rightOperandOpt, node.MethodOpt, type);
}
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
{
......@@ -12381,8 +12381,8 @@ public override TreeDumperNode VisitRangeExpression(BoundRangeExpression node, o
{
return new TreeDumperNode("rangeExpression", null, new TreeDumperNode[]
{
new TreeDumperNode("leftOperand", null, new TreeDumperNode[] { Visit(node.LeftOperand, null) }),
new TreeDumperNode("rightOperand", null, new TreeDumperNode[] { Visit(node.RightOperand, null) }),
new TreeDumperNode("leftOperandOpt", null, new TreeDumperNode[] { Visit(node.LeftOperandOpt, null) }),
new TreeDumperNode("rightOperandOpt", null, new TreeDumperNode[] { Visit(node.RightOperandOpt, null) }),
new TreeDumperNode("methodOpt", node.MethodOpt, null),
new TreeDumperNode("type", node.Type, null),
new TreeDumperNode("isSuppressed", node.IsSuppressed, null)
......
......@@ -539,131 +539,66 @@ public override BoundNode VisitTypeOrInstanceInitializers(BoundTypeOrInstanceIni
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.
// An array access expression can be indexed using any of the following types:
// * an integer primitive
// * a System.Index
// * a System.Range
// The last two are only supported on SZArrays. For those cases we need to
// lower into the appropriate helper methods.
if (node.Indices.Length != 1)
{
return base.VisitArrayAccess(node);
}
TypeSymbol rawIndexType = node.Indices[0].Type;
if (!(TypeSymbol.Equals(rawIndexType, _compilation.GetWellKnownType(WellKnownType.System_Index), TypeCompareKind.ConsiderEverything) ||
TypeSymbol.Equals(rawIndexType, _compilation.GetWellKnownType(WellKnownType.System_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 F = _factory;
var indexValueSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__Value);
var indexFromEndSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__IsFromEnd);
BoundExpression resultExpr;
if (TypeSymbol.Equals(indexType, _compilation.GetWellKnownType(WellKnownType.System_Index), TypeCompareKind.ConsiderEverything))
BoundNode resultExpr;
if (TypeSymbol.Equals(
indexType,
_compilation.GetWellKnownType(WellKnownType.System_Index),
TypeCompareKind.ConsiderEverything))
{
// array[Index] is compiled to:
// array[Index.GetOffset(array.Length)]
// array[Index] is translated to:
// array[index.FromEnd ? array.Length - index.Value : index.Value]
var arrayLocal = F.StoreToTemp(
VisitExpression(node.Expression),
out BoundAssignmentOperator arrayAssign);
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.System_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(arrayLocal.LocalSymbol),
ImmutableArray.Create<BoundExpression>(arrayAssign),
F.ArrayAccess(
arrayLocal,
ImmutableArray.Create<BoundExpression>(
F.Call(
VisitExpression(node.Indices[0]),
WellKnownMember.System_Index__GetOffset,
F.ArrayLength(arrayLocal)))));
}
else if (TypeSymbol.Equals(
indexType,
_compilation.GetWellKnownType(WellKnownType.System_Range),
TypeCompareKind.ConsiderEverything))
{
// array[Range] is compiled to:
// System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray(array, Range)
var elementType = ((ArrayTypeSymbol)node.Expression.Type).ElementType;
resultExpr = F.Call(
receiver: null,
F.WellKnownMethod(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T)
.Construct(ImmutableArray.Create(elementType)),
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);
VisitExpression(node.Expression),
VisitExpression(node.Indices[0])));
}
else
{
throw ExceptionUtilities.Unreachable;
resultExpr = base.VisitArrayAccess(node);
}
return resultExpr;
}
......
......@@ -83,101 +83,6 @@ private BoundExpression VisitIndexerAccess(BoundIndexerAccess node, bool isLeftO
// NOTE: This is done later by MakeArguments, for now we just lower each argument.
ImmutableArray<BoundExpression> rewrittenArguments = VisitList(node.Arguments);
// https://github.com/dotnet/roslyn/issues/30620
if (rewrittenReceiver?.Type.SpecialType == SpecialType.System_String &&
rewrittenArguments.Length == 1 && rewrittenArguments[0].Type.SpecialType == SpecialType.None)
{
var F = _factory;
var indexLocal = F.StoreToTemp(rewrittenArguments[0], out BoundAssignmentOperator indexAssign);
var stringLocal = F.StoreToTemp(rewrittenReceiver, out BoundAssignmentOperator stringAssign);
var indexValueSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__Value);
var indexFromEndSymbol = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Index__IsFromEnd);
var argType = rewrittenArguments[0].Type;
if (TypeSymbol.Equals(argType, _compilation.GetWellKnownType(WellKnownType.System_Index), TypeCompareKind.ConsiderEverything2))
{
// string[Index] is rewritten as:
// index.FromEnd ? s[s.Length - index.Value] : s[index.Value];
var indexValueExpr = F.Property(indexLocal, indexValueSymbol);
return F.Sequence(
ImmutableArray.Create<LocalSymbol>(
indexLocal.LocalSymbol,
stringLocal.LocalSymbol),
ImmutableArray.Create<BoundExpression>(
indexAssign,
stringAssign),
F.Conditional(
F.Property(indexLocal, indexFromEndSymbol),
F.Indexer(stringLocal, node.Indexer,
F.Binary(
BinaryOperatorKind.Subtraction,
F.SpecialType(SpecialType.System_Int32),
F.Call(stringLocal, F.SpecialMethod(SpecialMember.System_String__Length)),
indexValueExpr)),
F.Indexer(stringLocal, node.Indexer, indexValueExpr),
F.SpecialType(SpecialType.System_Char)));
}
else if (TypeSymbol.Equals(argType, _compilation.GetWellKnownType(WellKnownType.System_Range), TypeCompareKind.ConsiderEverything2))
{
// string[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;
// string.Substring(start, end - start)
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.Call(stringLocal, F.SpecialMethod(SpecialMember.System_String__Length)),
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.Call(stringLocal, F.SpecialMethod(SpecialMember.System_String__Length)),
F.Property(F.Property(indexLocal, rangeEndSymbol), indexValueSymbol)),
F.Property(F.Property(indexLocal, rangeEndSymbol), indexValueSymbol),
F.SpecialType(SpecialType.System_Int32)),
out BoundAssignmentOperator endAssign);
var substringExpr = F.Call(
stringLocal,
F.WellKnownMethod(WellKnownMember.System_String__Substring),
startLocal,
F.Binary(BinaryOperatorKind.Subtraction, F.SpecialType(SpecialType.System_Int32), endLocal, startLocal));
return F.Sequence(
ImmutableArray.Create(
indexLocal.LocalSymbol,
stringLocal.LocalSymbol,
startLocal.LocalSymbol,
endLocal.LocalSymbol),
ImmutableArray.Create<BoundExpression>(
indexAssign,
stringAssign,
startAssign,
endAssign),
substringExpr);
}
else
{
throw ExceptionUtilities.Unreachable;
}
}
return MakeIndexerAccess(
node.Syntax,
rewrittenReceiver,
......
......@@ -5,6 +5,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -17,39 +18,25 @@ public override BoundNode VisitRangeExpression(BoundRangeExpression node)
bool needLifting = false;
var F = _factory;
var left = node.LeftOperand;
var left = node.LeftOperandOpt;
if (left != null)
{
left = tryOptimizeOperand(left);
}
else
{
left = newIndexZero(fromEnd: false);
}
var right = node.RightOperand;
var right = node.RightOperandOpt;
if (right != null)
{
right = tryOptimizeOperand(right);
}
else
{
right = newIndexZero(fromEnd: true);
}
var operands = ImmutableArray.Create(left, right);
if (needLifting)
{
return LiftRangeExpression(node, operands);
return LiftRangeExpression(node, left, right);
}
else
{
BoundExpression rangeCreation = new BoundObjectCreationExpression(
node.Syntax,
node.MethodOpt,
binderOpt: null,
operands);
BoundExpression rangeCreation = MakeRangeExpression(node.MethodOpt, left, right);
if (node.Type.IsNullableType())
{
......@@ -64,12 +51,6 @@ public override BoundNode VisitRangeExpression(BoundRangeExpression node)
return rangeCreation;
}
BoundExpression newIndexZero(bool fromEnd) =>
// new Index(0, fromEnd: fromEnd)
F.New(
WellKnownMember.System_Index__ctor,
ImmutableArray.Create<BoundExpression>(F.Literal(0), F.Literal(fromEnd)));
BoundExpression tryOptimizeOperand(BoundExpression operand)
{
Debug.Assert(operand != null);
......@@ -93,65 +74,37 @@ BoundExpression tryOptimizeOperand(BoundExpression operand)
}
}
private BoundExpression LiftRangeExpression(BoundRangeExpression node, ImmutableArray<BoundExpression> operands)
private BoundExpression LiftRangeExpression(BoundRangeExpression node, BoundExpression left, BoundExpression right)
{
Debug.Assert(node.Type.IsNullableType());
Debug.Assert(operands.Any(operand => operand.Type.IsNullableType()));
Debug.Assert(operands.Length == 1 || operands.Length == 2);
Debug.Assert(left?.Type.IsNullableType() == true || right?.Type.IsNullableType() == true);
Debug.Assert(!(left is null && right is null));
ArrayBuilder<BoundExpression> sideeffects = ArrayBuilder<BoundExpression>.GetInstance();
ArrayBuilder<LocalSymbol> locals = ArrayBuilder<LocalSymbol>.GetInstance();
ArrayBuilder<BoundExpression> arguments = ArrayBuilder<BoundExpression>.GetInstance();
var sideeffects = ArrayBuilder<BoundExpression>.GetInstance();
var locals = ArrayBuilder<LocalSymbol>.GetInstance();
// left.HasValue && right.HasValue
// makeRange(left.GetValueOrDefault(), right.GetValueOrDefault())
BoundExpression condition = null;
foreach (var operand in operands)
{
BoundExpression tempOperand = CaptureExpressionInTempIfNeeded(operand, sideeffects, locals);
if (tempOperand.Type.IsNullableType())
{
BoundExpression operandHasValue = MakeOptimizedHasValue(tempOperand.Syntax, tempOperand);
if (condition is null)
{
condition = operandHasValue;
}
else
{
TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
condition = MakeBinaryOperator(node.Syntax, BinaryOperatorKind.BoolAnd, condition, operandHasValue, boolType, method: null);
}
arguments.Add(MakeOptimizedGetValueOrDefault(tempOperand.Syntax, tempOperand));
}
else
{
arguments.Add(tempOperand);
}
}
left = getIndexFromPossibleNullable(left);
right = getIndexFromPossibleNullable(right);
var rangeExpr = MakeRangeExpression(node.MethodOpt, left, right);
Debug.Assert(condition != null);
// method(left.GetValueOrDefault(), right.GetValueOrDefault())
BoundExpression rangeCall = new BoundObjectCreationExpression(
node.Syntax,
node.MethodOpt,
binderOpt: null,
arguments.ToImmutableArray());
if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor))
{
return BadExpression(node.Syntax, node.Type, node);
}
// new Nullable(method(left.GetValueOrDefault(), right.GetValueOrDefault()))
BoundExpression consequence = new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeCall);
// new Nullable(makeRange(left.GetValueOrDefault(), right.GetValueOrDefault()))
BoundExpression consequence = new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeExpr);
// default
BoundExpression alternative = new BoundDefaultExpression(node.Syntax, constantValueOpt: null, node.Type);
// left.HasValue && right.HasValue ? new Nullable(method(left.GetValueOrDefault(), right.GetValueOrDefault())) : default
// left.HasValue && right.HasValue
// ? new Nullable(makeRange(left.GetValueOrDefault(), right.GetValueOrDefault()))
// : default
BoundExpression conditionalExpression = RewriteConditionalOperator(
syntax: node.Syntax,
rewrittenCondition: condition,
......@@ -167,6 +120,86 @@ private BoundExpression LiftRangeExpression(BoundRangeExpression node, Immutable
sideEffects: sideeffects.ToImmutableAndFree(),
value: conditionalExpression,
type: node.Type);
BoundExpression getIndexFromPossibleNullable(BoundExpression arg)
{
if (arg is null)
return null;
BoundExpression tempOperand = CaptureExpressionInTempIfNeeded(arg, sideeffects, locals);
if (tempOperand.Type.IsNullableType())
{
BoundExpression operandHasValue = MakeOptimizedHasValue(tempOperand.Syntax, tempOperand);
if (condition is null)
{
condition = operandHasValue;
}
else
{
TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
condition = MakeBinaryOperator(node.Syntax, BinaryOperatorKind.BoolAnd, condition, operandHasValue, boolType, method: null);
}
return MakeOptimizedGetValueOrDefault(tempOperand.Syntax, tempOperand);
}
else
{
return tempOperand;
}
}
}
private BoundExpression MakeRangeExpression(
MethodSymbol constructionMethod,
BoundExpression left,
BoundExpression right)
{
var F = _factory;
// The construction method may vary based on what well-known
// members were available during binding. Depending on which member
// is chosen we need to change our adjust our calling node.
switch (constructionMethod.MethodKind)
{
case MethodKind.Constructor:
// Represents Range..ctor(Index left, Index right)
// The constructor can always be used to construct a range,
// but if any of the arguments are missing then we need to
// construct replacement Indexes
left = left ?? newIndexZero(fromEnd: false);
right = right ?? newIndexZero(fromEnd: true);
return F.New(constructionMethod, ImmutableArray.Create(left, right));
case MethodKind.Ordinary:
// Represents either Range.StartAt or Range.EndAt, which
// means that the `..` expression is missing an argument on
// either the left or the right (i.e., `x..` or `..x`)
Debug.Assert(left is null ^ right is null);
Debug.Assert(constructionMethod.MetadataName == "StartAt" ||
constructionMethod.MetadataName == "EndAt");
Debug.Assert(constructionMethod.IsStatic);
var arg = left ?? right;
return F.StaticCall(constructionMethod, ImmutableArray.Create(arg));
case MethodKind.PropertyGet:
// The only property is Range.All, so the expression must
// be `..` with both arguments missing
Debug.Assert(constructionMethod.MetadataName == "get_All");
Debug.Assert(constructionMethod.IsStatic);
Debug.Assert(left is null && right is null);
return F.StaticCall(constructionMethod, ImmutableArray<BoundExpression>.Empty);
default:
throw ExceptionUtilities.UnexpectedValue(constructionMethod.MethodKind);
}
BoundExpression newIndexZero(bool fromEnd) =>
// new Index(0, fromEnd: fromEnd)
F.New(
WellKnownMember.System_Index__ctor,
ImmutableArray.Create<BoundExpression>(F.Literal(0), F.Literal(fromEnd)));
}
}
}
......@@ -587,9 +587,10 @@ public BoundObjectCreationExpression New(NamedTypeSymbol type, params BoundExpre
}
public BoundObjectCreationExpression New(MethodSymbol ctor, params BoundExpression[] args)
{
return new BoundObjectCreationExpression(Syntax, ctor, null, args) { WasCompilerGenerated = true };
}
=> New(ctor, args.ToImmutableArray());
public BoundObjectCreationExpression New(MethodSymbol ctor, ImmutableArray<BoundExpression> args)
=> new BoundObjectCreationExpression(Syntax, ctor, binderOpt: null, args) { WasCompilerGenerated = true };
public BoundObjectCreationExpression New(WellKnownMember wm, ImmutableArray<BoundExpression> args)
{
......@@ -632,6 +633,9 @@ public BoundExpression StaticCall(TypeSymbol receiver, MethodSymbol method, para
return Call(null, method, args);
}
public BoundExpression StaticCall(MethodSymbol method, ImmutableArray<BoundExpression> args)
=> Call(null, method, args);
public BoundExpression StaticCall(WellKnownMember method, params BoundExpression[] args)
{
MethodSymbol methodSymbol = WellKnownMethod(method);
......@@ -668,6 +672,9 @@ public BoundCall Call(BoundExpression receiver, MethodSymbol method, params Boun
return Call(receiver, method, ImmutableArray.Create<BoundExpression>(args));
}
public BoundCall Call(BoundExpression receiver, WellKnownMember method, BoundExpression arg0)
=> Call(receiver, WellKnownMethod(method), ImmutableArray.Create(arg0));
public BoundCall Call(BoundExpression receiver, MethodSymbol method, ImmutableArray<BoundExpression> args)
{
Debug.Assert(method.ParameterCount == args.Length);
......
......@@ -1837,12 +1837,12 @@ internal sealed class CSharpLazyRangeOperation : LazyRangeOperation
protected override IOperation CreateLeftOperand()
{
return _operationFactory.Create(_rangeExpression.LeftOperand);
return _operationFactory.Create(_rangeExpression.LeftOperandOpt);
}
protected override IOperation CreateRightOperand()
{
return _operationFactory.Create(_rangeExpression.RightOperand);
return _operationFactory.Create(_rangeExpression.RightOperandOpt);
}
}
}
......@@ -10,6 +10,11 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class IOperationTests : SemanticModelTestBase
{
private const string RangeCtorSignature = "System.Range..ctor(System.Index start, System.Index end)";
private const string RangeStartAtSignature = "System.Range System.Range.StartAt(System.Index start)";
private const string RangeEndAtSignature = "System.Range System.Range.EndAt(System.Index end)";
private const string RangeAllSignature = "System.Range System.Range.All.get";
[CompilerTrait(CompilerFeature.IOperation)]
[Fact]
public void VerifyLiftedBinaryOperators1()
......@@ -7913,7 +7918,7 @@ void M()
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -7943,7 +7948,7 @@ void M(int arg)
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -7971,7 +7976,7 @@ void M()
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeEndAtSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -7999,7 +8004,7 @@ void M()
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeStartAtSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -8024,7 +8029,7 @@ void M()
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeAllSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -8055,7 +8060,7 @@ void M(int? start, int? end)
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -8085,7 +8090,7 @@ void M(int? start, int? end)
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -8113,7 +8118,7 @@ void M(int? end)
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeEndAtSignature, operation.Method.ToTestDisplayString());
}
[Fact]
......@@ -8141,7 +8146,7 @@ void M(int? start)
";
var operation = (IRangeOperation)VerifyOperationTreeForTest<RangeExpressionSyntax>(compilation, expectedOperationTree);
Assert.Equal("System.Range..ctor(System.Index start, System.Index end)", operation.Method.ToTestDisplayString());
Assert.Equal(RangeStartAtSignature, operation.Method.ToTestDisplayString());
}
}
}
......@@ -11,12 +11,43 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests
public class IndexAndRangeTests : CompilingTestBase
{
private const string RangeCtorSignature = "System.Range..ctor(System.Index start, System.Index end)";
private const string RangeStartAtSignature = "System.Range System.Range.StartAt(System.Index start)";
private const string RangeEndAtSignature = "System.Range System.Range.EndAt(System.Index end)";
private const string RangeAllSignature = "System.Range System.Range.All.get";
[Fact]
[WorkItem(31889, "https://github.com/dotnet/roslyn/issues/31889")]
public void ArrayRangeIllegalRef()
{
var comp = CreateCompilationWithIndexAndRange(@"
var comp = CreateEmptyCompilation(@"
namespace System
{
public struct Int32 { }
public struct Boolean { }
public class ValueType { }
public class String { }
public class Object { }
public class Void { }
public struct Nullable<T> where T : struct
{
}
public struct Index
{
public Index(int value, bool fromEnd) { }
public static implicit operator Index(int value) => default;
}
public struct Range
{
public Range(Index start, Index end) { }
}
}
namespace System.Runtime.CompilerServices
{
public static class RuntimeHelpers
{
public static T[] GetSubArray<T>(T[] array, Range range) => null;
}
}
public class C {
public ref int[] M(int[] arr) {
ref int[] x = ref arr[0..2];
......@@ -27,15 +58,15 @@ public class C {
void M(in int[] arr) { }
}");
comp.VerifyDiagnostics(
// (4,27): error CS1510: A ref or out value must be an assignable variable
// (32,27): error CS1510: A ref or out value must be an assignable variable
// ref int[] x = ref arr[0..2];
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "arr[0..2]").WithLocation(4, 27),
// (5,14): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "arr[0..2]").WithLocation(32, 27),
// (33,14): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// M(in arr[0..2]);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "arr[0..2]").WithLocation(5, 14),
// (7,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "arr[0..2]").WithLocation(33, 14),
// (35,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref arr[0..2];
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "arr[0..2]").WithLocation(7, 20));
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "arr[0..2]").WithLocation(35, 20));
}
[Fact]
......@@ -54,6 +85,86 @@ public class C {
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "0..2").WithArguments("System.Range").WithLocation(4, 31));
}
[Fact]
public void ArrayRangeIndexerNoHelper()
{
var comp = CreateCompilationWithIndex(@"
namespace System
{
public readonly struct Range
{
public Range(Index start, Index end) { }
}
}
public class C {
public void M(int[] arr) {
var x = arr[0..2];
}
}");
comp.VerifyDiagnostics(
// (11,17): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray'
// var x = arr[0..2];
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "arr[0..2]").WithArguments("System.Runtime.CompilerServices.RuntimeHelpers", "GetSubArray").WithLocation(11, 17));
}
[Fact]
public void ArrayIndexIndexerNoHelper()
{
const string source = @"
class C
{
public void M(int[] arr)
{
var x = arr[^2];
}
}";
var comp = CreateCompilation(source + @"
namespace System
{
public readonly struct Index
{
public Index(int value, bool fromEnd) { }
}
}");
comp.VerifyDiagnostics(
// (6,17): error CS0656: Missing compiler required member 'System.Index.GetOffset'
// var x = arr[^2];
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "arr[^2]").WithArguments("System.Index", "GetOffset").WithLocation(6, 17));
comp = CreateCompilation(source + @"
namespace System
{
public readonly struct Index
{
public Index(int value, bool fromEnd) { }
public int GetOffset(int length) => 0;
}
}");
comp.VerifyDiagnostics();
}
[Fact]
public void StringIndexers()
{
// The string type in our standard references don't have indexers for string or range
var comp = CreateCompilationWithIndexAndRange(@"
class C
{
public void M(string s)
{
var x = s[^0];
var y = s[1..];
}
}");
comp.VerifyDiagnostics(
// (6,19): error CS1503: Argument 1: cannot convert from 'System.Index' to 'int'
// var x = s[^0];
Diagnostic(ErrorCode.ERR_BadArgType, "^0").WithArguments("1", "System.Index", "int").WithLocation(6, 19),
// (7,19): error CS1503: Argument 1: cannot convert from 'System.Range' to 'int'
// var y = s[1..];
Diagnostic(ErrorCode.ERR_BadArgType, "1..").WithArguments("1", "System.Range", "int").WithLocation(7, 19));
}
[Fact]
[WorkItem(31889, "https://github.com/dotnet/roslyn/issues/31889")]
public void FromEndIllegalRef()
......@@ -101,29 +212,24 @@ public class C {
}
[Fact]
[WorkItem(31889, "https://github.com/dotnet/roslyn/issues/31889")]
public void StringIndexIllegalRef()
public void NetStandard20StringNoIndexRangeIndexers()
{
var comp = CreateCompilationWithIndexAndRange(@"
public class C {
public ref char M(string s) {
ref readonly char x = ref s[^2];
M(in s[^2]);
M(s[^2]);
return ref s[^2];
public class C
{
public void M(string s)
{
var x = s[^2];
var y = s[0..2];
}
void M(in char c) { }
}");
comp.VerifyDiagnostics(
// (4,35): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// ref readonly char x = ref s[^2];
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s[^2]").WithArguments("string.this[int]").WithLocation(4, 35),
// (5,14): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// M(in s[^2]);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s[^2]").WithArguments("string.this[int]").WithLocation(5, 14),
// (7,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference
// return ref s[^2];
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s[^2]").WithArguments("string.this[int]").WithLocation(7, 20));
// (6,19): error CS1503: Argument 1: cannot convert from 'System.Index' to 'int'
// var x = s[^2];
Diagnostic(ErrorCode.ERR_BadArgType, "^2").WithArguments("1", "System.Index", "int").WithLocation(6, 19),
// (7,19): error CS1503: Argument 1: cannot convert from 'System.Range' to 'int'
// var y = s[0..2];
Diagnostic(ErrorCode.ERR_BadArgType, "0..2").WithArguments("1", "System.Range", "int").WithLocation(7, 19));
}
[Fact]
......@@ -419,17 +525,17 @@ void M(int? index)
}
[Fact]
public void RangeExpression_WithoutRangeCreate()
public void RangeExpression_WithoutRangeCtor()
{
var compilation = CreateCompilationWithIndex(@"
namespace System
{
public readonly struct Range
{
// public static Range Create(Index start, Index end) => default;
public static Range FromStart(Index start) => default;
public static Range ToEnd(Index end) => default;
public static Range All() => default;
// public Range(Index start, Index end) => default;
public static Range StartAt(Index start) => default;
public static Range EndAt(Index end) => default;
public static Range All => default;
}
}
class Test
......@@ -444,25 +550,33 @@ void M(int arg)
}").VerifyDiagnostics(
// (16,17): error CS0656: Missing compiler required member 'System.Range..ctor'
// var a = 1..2;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1..2").WithArguments("System.Range", ".ctor").WithLocation(16, 17),
// (17,17): error CS0656: Missing compiler required member 'System.Range..ctor'
// var b = 1..;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1..").WithArguments("System.Range", ".ctor").WithLocation(17, 17),
// (18,17): error CS0656: Missing compiler required member 'System.Range..ctor'
// var c = ..2;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "..2").WithArguments("System.Range", ".ctor").WithLocation(18, 17),
// (19,17): error CS0656: Missing compiler required member 'System.Range..ctor'
// var d = ..;
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "..").WithArguments("System.Range", ".ctor").WithLocation(19, 17));
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "1..2").WithArguments("System.Range", ".ctor").WithLocation(16, 17));
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
foreach (var node in tree.GetRoot().DescendantNodes().OfType<RangeExpressionSyntax>())
{
Assert.Equal("System.Range", model.GetTypeInfo(node).Type.ToTestDisplayString());
Assert.Null(model.GetSymbolInfo(node).Symbol);
}
var expressions = tree.GetRoot().DescendantNodes().OfType<RangeExpressionSyntax>().ToArray();
Assert.Equal(4, expressions.Length);
Assert.Equal("System.Range", model.GetTypeInfo(expressions[0]).Type.ToTestDisplayString());
Assert.Null(model.GetSymbolInfo(expressions[0]).Symbol);
Assert.Equal("System.Int32", model.GetTypeInfo(expressions[0].RightOperand).Type.ToTestDisplayString());
Assert.Equal("System.Int32", model.GetTypeInfo(expressions[0].LeftOperand).Type.ToTestDisplayString());
Assert.Equal("System.Range", model.GetTypeInfo(expressions[1]).Type.ToTestDisplayString());
Assert.Equal(RangeStartAtSignature, model.GetSymbolInfo(expressions[1]).Symbol.ToTestDisplayString());
Assert.Null(expressions[1].RightOperand);
Assert.Equal("System.Int32", model.GetTypeInfo(expressions[1].LeftOperand).Type.ToTestDisplayString());
Assert.Equal("System.Range", model.GetTypeInfo(expressions[2]).Type.ToTestDisplayString());
Assert.Equal(RangeEndAtSignature, model.GetSymbolInfo(expressions[2]).Symbol.ToTestDisplayString());
Assert.Equal("System.Int32", model.GetTypeInfo(expressions[2].RightOperand).Type.ToTestDisplayString());
Assert.Null(expressions[2].LeftOperand);
Assert.Equal("System.Range", model.GetTypeInfo(expressions[3]).Type.ToTestDisplayString());
Assert.Equal(RangeAllSignature, model.GetSymbolInfo(expressions[3]).Symbol.ToTestDisplayString());
Assert.Null(expressions[3].RightOperand);
Assert.Null(expressions[3].LeftOperand);
}
[Fact]
......@@ -543,7 +657,7 @@ void M(System.Index? arg)
}
[Fact]
public void RangeExpression_WithoutRangeFromStart()
public void RangeExpression_WithoutRangeStartAt()
{
var compilation = CreateCompilationWithIndex(@"
namespace System
......@@ -551,8 +665,8 @@ namespace System
public readonly struct Range
{
public Range(Index start, Index end) { }
// public static Range FromStart(Index start) => default;
public static Range ToEnd(Index end) => default;
// public static Range StartAt(Index start) => default;
public static Range EndAt(Index end) => default;
public static Range All() => default;
}
}
......@@ -576,7 +690,7 @@ void M(int arg)
}
[Fact]
public void RangeExpression_WithoutRangeToEnd()
public void RangeExpression_WithoutRangeEndAt()
{
var compilation = CreateCompilationWithIndex(@"
namespace System
......@@ -584,8 +698,8 @@ namespace System
public readonly struct Range
{
public Range(Index start, Index end) { }
public static Range FromStart(Index start) => default;
// public static Range ToEnd(Index end) => default;
public static Range StartAt(Index start) => default;
// public static Range EndAt(Index end) => default;
public static Range All() => default;
}
}
......@@ -617,8 +731,8 @@ namespace System
public readonly struct Range
{
public Range(Index start, Index end) { }
public static Range FromStart(Index start) => default;
public static Range ToEnd(Index end) => default;
public static Range StartAt(Index start) => default;
public static Range EndAt(Index end) => default;
// public static Range All() => default;
}
}
......@@ -669,17 +783,17 @@ void M(Index start, Index end)
Assert.Equal("System.Index", model.GetTypeInfo(expressions[0].LeftOperand).Type.ToTestDisplayString());
Assert.Equal("System.Range", model.GetTypeInfo(expressions[1]).Type.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, model.GetSymbolInfo(expressions[1]).Symbol.ToTestDisplayString());
Assert.Equal(RangeStartAtSignature, model.GetSymbolInfo(expressions[1]).Symbol.ToTestDisplayString());
Assert.Null(expressions[1].RightOperand);
Assert.Equal("System.Index", model.GetTypeInfo(expressions[1].LeftOperand).Type.ToTestDisplayString());
Assert.Equal("System.Range", model.GetTypeInfo(expressions[2]).Type.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, model.GetSymbolInfo(expressions[2]).Symbol.ToTestDisplayString());
Assert.Equal(RangeEndAtSignature, model.GetSymbolInfo(expressions[2]).Symbol.ToTestDisplayString());
Assert.Equal("System.Index", model.GetTypeInfo(expressions[2].RightOperand).Type.ToTestDisplayString());
Assert.Null(expressions[2].LeftOperand);
Assert.Equal("System.Range", model.GetTypeInfo(expressions[3]).Type.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, model.GetSymbolInfo(expressions[3]).Symbol.ToTestDisplayString());
Assert.Equal(RangeAllSignature, model.GetSymbolInfo(expressions[3]).Symbol.ToTestDisplayString());
Assert.Null(expressions[3].RightOperand);
Assert.Null(expressions[3].LeftOperand);
}
......@@ -712,17 +826,17 @@ void M(Index? start, Index? end)
Assert.Equal("System.Index?", model.GetTypeInfo(expressions[0].LeftOperand).Type.ToTestDisplayString());
Assert.Equal("System.Range?", model.GetTypeInfo(expressions[1]).Type.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, model.GetSymbolInfo(expressions[1]).Symbol.ToTestDisplayString());
Assert.Equal(RangeStartAtSignature, model.GetSymbolInfo(expressions[1]).Symbol.ToTestDisplayString());
Assert.Null(expressions[1].RightOperand);
Assert.Equal("System.Index?", model.GetTypeInfo(expressions[1].LeftOperand).Type.ToTestDisplayString());
Assert.Equal("System.Range?", model.GetTypeInfo(expressions[2]).Type.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, model.GetSymbolInfo(expressions[2]).Symbol.ToTestDisplayString());
Assert.Equal(RangeEndAtSignature, model.GetSymbolInfo(expressions[2]).Symbol.ToTestDisplayString());
Assert.Equal("System.Index?", model.GetTypeInfo(expressions[2].RightOperand).Type.ToTestDisplayString());
Assert.Null(expressions[2].LeftOperand);
Assert.Equal("System.Range", model.GetTypeInfo(expressions[3]).Type.ToTestDisplayString());
Assert.Equal(RangeCtorSignature, model.GetSymbolInfo(expressions[3]).Symbol.ToTestDisplayString());
Assert.Equal(RangeAllSignature, model.GetSymbolInfo(expressions[3]).Symbol.ToTestDisplayString());
Assert.Null(expressions[3].RightOperand);
Assert.Null(expressions[3].LeftOperand);
}
......
......@@ -891,11 +891,12 @@ public void AllWellKnownTypeMembers()
case WellKnownMember.System_ReadOnlySpan_T__get_Item:
case WellKnownMember.System_ReadOnlySpan_T__get_Length:
case WellKnownMember.System_Index__ctor:
case WellKnownMember.System_Index__IsFromEnd:
case WellKnownMember.System_Index__Value:
case WellKnownMember.System_Range__Start:
case WellKnownMember.System_Range__End:
case WellKnownMember.System_Index__GetOffset:
case WellKnownMember.System_Range__ctor:
case WellKnownMember.System_Range__StartAt:
case WellKnownMember.System_Range__EndAt:
case WellKnownMember.System_Range__get_All:
case WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T:
case WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor:
case WellKnownMember.System_IAsyncDisposable__DisposeAsync:
case WellKnownMember.System_Collections_Generic_IAsyncEnumerable_T__GetAsyncEnumerator:
......
......@@ -10,7 +10,6 @@ internal enum WellKnownMember
System_Array__get_Length,
System_Array__Empty,
System_Array__Copy,
System_Convert__ToBooleanDecimal,
System_Convert__ToBooleanInt32,
......@@ -145,6 +144,7 @@ internal enum WellKnownMember
System_Runtime_CompilerServices_RuntimeHelpers__GetObjectValueObject,
System_Runtime_CompilerServices_RuntimeHelpers__InitializeArrayArrayRuntimeFieldHandle,
System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData,
System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T,
System_Runtime_ExceptionServices_ExceptionDispatchInfo__Capture,
System_Runtime_ExceptionServices_ExceptionDispatchInfo__Throw,
......@@ -414,7 +414,6 @@ internal enum WellKnownMember
System_Runtime_CompilerServices_TupleElementNamesAttribute__ctorTransformNames,
System_String__Format_IFormatProvider,
System_String__Substring,
Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile,
Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningMultipleFiles,
......@@ -447,11 +446,11 @@ internal enum WellKnownMember
System_Math__TruncateDouble,
System_Index__ctor,
System_Index__IsFromEnd,
System_Index__Value,
System_Range__Start,
System_Range__End,
System_Index__GetOffset,
System_Range__ctor,
System_Range__StartAt,
System_Range__EndAt,
System_Range__get_All,
System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor,
......
......@@ -45,18 +45,6 @@ static WellKnownMembers()
0, // Method Signature
(byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return Type
// System_Array__Copy
(byte)(MemberFlags.Method | MemberFlags.Static), // Flags
(byte)WellKnownType.System_Array, // DeclaringTypeId
0, // Arity
5, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Array,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Array,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
// System_Convert__ToBooleanDecimal
(byte)(MemberFlags.Method | MemberFlags.Static), // Flags
(byte)WellKnownType.System_Convert, // DeclaringTypeId
......@@ -1008,6 +996,15 @@ static WellKnownMembers()
0, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, // Return Type
// System_Runtime_CompilerServices__GetSubArray_T
(byte)(MemberFlags.Method | MemberFlags.Static), // Flags
(byte)WellKnownType.System_Runtime_CompilerServices_RuntimeHelpers, // DeclaringTypeId
1, // Arity
2, // Method Signature
(byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.GenericMethodParameter, 0, // Return type
(byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.GenericMethodParameter, 0,
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel),
// System_Runtime_ExceptionServices_ExceptionDispatchInfo__Capture
(byte)(MemberFlags.Method | MemberFlags.Static), // Flags
(byte)WellKnownType.System_Runtime_ExceptionServices_ExceptionDispatchInfo, // DeclaringTypeId
......@@ -2878,15 +2875,6 @@ static WellKnownMembers()
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String,
(byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Object,
// System_String__Substring
(byte)MemberFlags.Method, // Flags
(byte)SpecialType.System_String, // DeclaringTypeId
0, // Arity
2, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, // Return Type
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
// Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile
(byte)(MemberFlags.Method | MemberFlags.Static), // Flags
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.Microsoft_CodeAnalysis_Runtime_Instrumentation - WellKnownType.ExtSentinel), // DeclaringTypeId
......@@ -3077,42 +3065,45 @@ static WellKnownMembers()
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean,
// System_Index__IsFromEnd
(byte)(MemberFlags.Property), // Flags
// System_Index__GetOffset
(byte)MemberFlags.Method, // Flags
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel), // DeclaringTypeId
0, // Arity
0, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Boolean, // Return Type
1, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32,
// System_Index__Value
(byte)(MemberFlags.Property), // Flags
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel), // DeclaringTypeId
// System_Range__ctor
(byte)(MemberFlags.Constructor),
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel), // DeclaringTypeId
0, // Arity
0, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, // Return type
2, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void,
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel),
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel),
// System_Range__Start
(byte)MemberFlags.Property, // Flags
// System_Range__StartAt
(byte)(MemberFlags.Method | MemberFlags.Static),
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel), // DeclaringTypeId
0, // Arity
0, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel), // Return Type: System.Index
1, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel),
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel),
// System_Range__End
(byte)MemberFlags.Property, // Flags
// System_Range__EndAt
(byte)(MemberFlags.Method | MemberFlags.Static),
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel), // DeclaringTypeId
0, // Arity
0, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel), // Return Type: System.Index
1, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel),
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel),
// System_Range__ctor
(byte)(MemberFlags.Constructor),
// System_Range__get_All
(byte)(MemberFlags.PropertyGet | MemberFlags.Static),
(byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel), // DeclaringTypeId
0, // Arity
2, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void,
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel),
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Index - WellKnownType.ExtSentinel),
0, // Method Signature
(byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Range - WellKnownType.ExtSentinel),
// System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor
(byte)MemberFlags.Constructor, // Flags
......@@ -3390,7 +3381,6 @@ static WellKnownMembers()
"Pow", // System_Math__PowDoubleDouble
"get_Length", // System_Array__get_Length
"Empty", // System_Array__Empty
"Copy", // System_Array__Copy
"ToBoolean", // System_Convert__ToBooleanDecimal
"ToBoolean", // System_Convert__ToBooleanInt32
"ToBoolean", // System_Convert__ToBooleanUInt32
......@@ -3508,6 +3498,7 @@ static WellKnownMembers()
"GetObjectValue", // System_Runtime_CompilerServices_RuntimeHelpers__GetObjectValueObject
"InitializeArray", // System_Runtime_CompilerServices_RuntimeHelpers__InitializeArrayArrayRuntimeFieldHandle
"get_OffsetToStringData", // System_Runtime_CompilerServices_RuntimeHelpers__get_OffsetToStringData
"GetSubArray", // System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T
"Capture", // System_Runtime_ExceptionServices_ExceptionDispatchInfo__Capture
"Throw", // System_Runtime_ExceptionServices_ExceptionDispatchInfo__Throw
".ctor", // System_Security_UnverifiableCodeAttribute__ctor
......@@ -3740,7 +3731,6 @@ static WellKnownMembers()
".ctor", // System_Runtime_CompilerServices_TupleElementNamesAttribute__ctorTransformNames
"Format", // System_String__Format_IFormatProvider
"Substring", // System_string__Substring
"CreatePayload", // Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile
"CreatePayload", // Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningMultipleFiles
......@@ -3768,11 +3758,11 @@ static WellKnownMembers()
"Truncate", // System_Math__TruncateDouble
".ctor", // System_Index__ctor
"IsFromEnd", // System_Index__IsFromEnd
"Value", // System_Index__Value
"Start", // System_Range__Start
"End", // System_Range__End
"GetOffset", // System_Index__GetOffset
".ctor", // System_Range__ctor
"StartAt", // System_Range__StartAt
"EndAt", // System_Range__StartAt
"get_All", // System_Range__get_All
".ctor", // System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor
......
......@@ -368,5 +368,22 @@ public void Deconstruct(out int offset, out int length)
}
}
}";
public const string GetSubArray = @"
namespace System.Runtime.CompilerServices
{
public static class RuntimeHelpers
{
public static T[] GetSubArray<T>(T[] array, Range range)
{
Type elementType = array.GetType().GetElementType();
var (offset, length) = range.GetOffsetAndLength(array.Length);
T[] newArray = (T[])Array.CreateInstance(elementType, length);
Array.Copy(array, offset, newArray, 0, length);
return newArray;
}
}
}";
}
}
......@@ -663,7 +663,8 @@ End Namespace
WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__Complete,
WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__Create,
WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__MoveNext_T,
WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor
WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor,
WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T
' Not available yet, but will be in upcoming release.
Continue For
Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile,
......@@ -672,11 +673,11 @@ End Namespace
WellKnownMember.System_Runtime_CompilerServices_IsByRefLikeAttribute__ctor,
WellKnownMember.System_Runtime_CompilerServices_IsUnmanagedAttribute__ctor,
WellKnownMember.System_Index__ctor,
WellKnownMember.System_Index__IsFromEnd,
WellKnownMember.System_Index__Value,
WellKnownMember.System_Range__Start,
WellKnownMember.System_Range__End,
WellKnownMember.System_Index__GetOffset,
WellKnownMember.System_Range__ctor,
WellKnownMember.System_Range__EndAt,
WellKnownMember.System_Range__get_All,
WellKnownMember.System_Range__StartAt,
WellKnownMember.System_Runtime_CompilerServices_IsUnmanagedAttribute__ctor,
WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Item,
WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Length,
......@@ -797,7 +798,8 @@ End Namespace
WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__Complete,
WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__Create,
WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__MoveNext_T,
WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor
WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor,
WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T
' Not available yet, but will be in upcoming release.
Continue For
Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile,
......@@ -806,11 +808,11 @@ End Namespace
WellKnownMember.System_Runtime_CompilerServices_IsByRefLikeAttribute__ctor,
WellKnownMember.System_Runtime_CompilerServices_IsUnmanagedAttribute__ctor,
WellKnownMember.System_Index__ctor,
WellKnownMember.System_Index__IsFromEnd,
WellKnownMember.System_Index__Value,
WellKnownMember.System_Range__Start,
WellKnownMember.System_Range__End,
WellKnownMember.System_Index__GetOffset,
WellKnownMember.System_Range__ctor,
WellKnownMember.System_Range__EndAt,
WellKnownMember.System_Range__get_All,
WellKnownMember.System_Range__StartAt,
WellKnownMember.System_Runtime_CompilerServices_IsUnmanagedAttribute__ctor,
WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Item,
WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Length,
......
......@@ -6756,17 +6756,11 @@ .maxstack 1
Evaluate(source, OutputKind.ConsoleApplication, "C.Main", "..").GetMethodData("<>x.<>m0").VerifyIL(
@"{
// Code size 20 (0x14)
.maxstack 3
// Code size 6 (0x6)
.maxstack 1
.locals init (System.Range V_0) //x
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: newobj ""System.Index..ctor(int, bool)""
IL_0007: ldc.i4.0
IL_0008: ldc.i4.1
IL_0009: newobj ""System.Index..ctor(int, bool)""
IL_000e: newobj ""System.Range..ctor(System.Index, System.Index)""
IL_0013: ret
IL_0000: call ""System.Range System.Range.All.get""
IL_0005: ret
}");
}
......@@ -6806,16 +6800,13 @@ .maxstack 1
Evaluate(source, OutputKind.ConsoleApplication, "C.Main", "2..").GetMethodData("<>x.<>m0").VerifyIL(
@"{
// Code size 19 (0x13)
.maxstack 3
// Code size 12 (0xc)
.maxstack 1
.locals init (System.Range V_0) //x
IL_0000: ldc.i4.2
IL_0001: call ""System.Index System.Index.op_Implicit(int)""
IL_0006: ldc.i4.0
IL_0007: ldc.i4.1
IL_0008: newobj ""System.Index..ctor(int, bool)""
IL_000d: newobj ""System.Range..ctor(System.Index, System.Index)""
IL_0012: ret
IL_0006: call ""System.Range System.Range.StartAt(System.Index)""
IL_000b: ret
}");
}
......@@ -6855,16 +6846,13 @@ .maxstack 1
Evaluate(source, OutputKind.ConsoleApplication, "C.Main", "..2").GetMethodData("<>x.<>m0").VerifyIL(
@"{
// Code size 19 (0x13)
.maxstack 2
// Code size 12 (0xc)
.maxstack 1
.locals init (System.Range V_0) //x
IL_0000: ldc.i4.0
IL_0001: ldc.i4.0
IL_0002: newobj ""System.Index..ctor(int, bool)""
IL_0007: ldc.i4.2
IL_0008: call ""System.Index System.Index.op_Implicit(int)""
IL_000d: newobj ""System.Range..ctor(System.Index, System.Index)""
IL_0012: ret
IL_0000: ldc.i4.2
IL_0001: call ""System.Index System.Index.op_Implicit(int)""
IL_0006: call ""System.Range System.Range.EndAt(System.Index)""
IL_000b: ret
}");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册