Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -656,21 +656,20 @@ private void ErrAppendType(CType pType, SubstContext pctx, bool fArgs)
// Add [] with (rank-1) commas inside
ErrAppendChar('[');

#if ! CSEE
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does anyone know what this CSEE constant refers to?

Copy link
Contributor

@OmarTawfik OmarTawfik Apr 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@OmarTawfik OmarTawfik Apr 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, we need to find out why would the result be different?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case the CSEE behaviour is what I'd think would be correct for any case (except that it doesn't handle single-ranked non-SZ arrays but the assembly as a whole had no concept of SZ/non-SZ distinction before this PR).

In other cases I'm not sure what to do when I come across it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears to be pieces that supports Expression Evaluator that is used at debug time. They make no sense in the dynamic binder code.
I guess they were just ported together with the rest of the code. Perhaps the initial pass used some automated translator and it picked up everything, or it was expected that there would be a need for a special binder - specifically for EE to call into, but that need never materialized...

Anyways, I am not aware of any CSEE flavor of the runtime binder.
The "CSEE" seems just dead code and can/should be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do that soon, so.

// known rank.
if (rank > 1)
if (rank == 1)
{
ErrAppendChar('*');
if (!elementType.AsArrayType().IsSZArray)
{
ErrAppendChar('*');
}
}
#endif

for (int i = rank; i > 1; --i)
else
{
ErrAppendChar(',');
#if ! CSEE

ErrAppendChar('*');
#endif
for (int i = rank; i > 1; --i)
{
ErrAppendChar(',');
}
}

ErrAppendChar(']');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,16 @@ public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst
// o An explicit reference conversion exists from SE to TE.
if (typeSrc.IsArrayType() && typeDst.IsArrayType())
{
return typeSrc.AsArrayType().rank == typeDst.AsArrayType().rank && FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsArrayType().GetElementType());
return typeSrc.AsArrayType().rank == typeDst.AsArrayType().rank
&& typeSrc.AsArrayType().IsSZArray == typeDst.AsArrayType().IsSZArray
&& FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsArrayType().GetElementType());
}

// * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T>
// and their base interfaces, provided there is an explicit reference conversion from S to T.
if (typeSrc.IsArrayType())
{
if (typeSrc.AsArrayType().rank != 1 ||
if (!typeSrc.AsArrayType().IsSZArray ||
!typeDst.isInterfaceType() || typeDst.AsAggregateType().GetTypeArgsAll().Count != 1)
{
return false;
Expand Down Expand Up @@ -161,7 +163,7 @@ public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst
// are the same type or there is an implicit or explicit reference conversion from S to T.
ArrayType arrayDest = typeDst.AsArrayType();
AggregateType aggtypeSrc = typeSrc.AsAggregateType();
if (arrayDest.rank != 1 || !typeSrc.isInterfaceType() ||
if (!arrayDest.IsSZArray || !typeSrc.isInterfaceType() ||
aggtypeSrc.GetTypeArgsAll().Count != 1)
{
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ private bool bindExplicitConversionFromArrayToIList()
Debug.Assert(_typeSrc != null);
Debug.Assert(_typeDest != null);

if (!_typeSrc.IsArrayType() || _typeSrc.AsArrayType().rank != 1 ||
if (!_typeSrc.IsArrayType() || !_typeSrc.AsArrayType().IsSZArray ||
!_typeDest.isInterfaceType() || _typeDest.AsAggregateType().GetTypeArgsAll().Count != 1)
{
return false;
Expand Down Expand Up @@ -319,7 +319,7 @@ private bool bindExplicitConversionFromIListToArray(ArrayType arrayDest)
// S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T
// are the same type or there is an implicit or explicit reference conversion from S to T.

if (arrayDest.rank != 1 || !_typeSrc.isInterfaceType() ||
if (!arrayDest.IsSZArray || !_typeSrc.isInterfaceType() ||
_typeSrc.AsAggregateType().GetTypeArgsAll().Count != 1)
{
return false;
Expand Down Expand Up @@ -363,7 +363,7 @@ private bool bindExplicitConversionFromArrayToArray(ArrayType arraySrc, ArrayTyp
//
// * An explicit reference conversion exists from SE to TE.

if (arraySrc.rank != arrayDest.rank)
if (arraySrc.rank != arrayDest.rank || arraySrc.IsSZArray != arrayDest.IsSZArray)
{
return false; // Ranks do not match.
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ private ExprQuestionMark BindPtrToArray(ExprLocal exprLoc, Expr array)
Expr nullTest = GetExprFactory().CreateBinop(ExpressionKind.EK_NE, GetReqPDT(PredefinedType.PT_BOOL), save, GetExprFactory().CreateConstant(wrapArray.Type, ConstVal.Get(0)));
Expr lenTest;

if (array.Type.AsArrayType().rank == 1)
if (array.Type.AsArrayType().IsSZArray)
{
Expr len = GetExprFactory().CreateArrayLength(wrapArray);
lenTest = GetExprFactory().CreateBinop(ExpressionKind.EK_NE, GetReqPDT(PredefinedType.PT_BOOL), len, GetExprFactory().CreateConstant(GetReqPDT(PredefinedType.PT_INT), ConstVal.Get(0)));
Expand Down Expand Up @@ -2069,7 +2069,7 @@ private void AdjustCallArgumentsForParams(CType callingObjectType, CType type, M

// we need to create an array and put it as the last arg...
CType substitutedArrayType = GetTypes().SubstType(mp.Params[mp.Params.Count - 1], type, pTypeArgs);
if (!substitutedArrayType.IsArrayType() || substitutedArrayType.AsArrayType().rank != 1)
if (!substitutedArrayType.IsArrayType() || !substitutedArrayType.AsArrayType().IsSZArray)
{
// Invalid type for params array parameter. Happens in LAF scenarios, e.g.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1185,7 +1185,7 @@ private bool ExactArrayInference(CType pSource, CType pDest)
}
ArrayType pArraySource = pSource.AsArrayType();
ArrayType pArrayDest = pDest.AsArrayType();
if (pArraySource.rank != pArrayDest.rank)
if (pArraySource.rank != pArrayDest.rank || pArraySource.IsSZArray != pArrayDest.IsSZArray)
{
return false;
}
Expand Down Expand Up @@ -1379,7 +1379,7 @@ private bool LowerBoundArrayInference(CType pSource, CType pDest)
if (pDest.IsArrayType())
{
ArrayType pArrayDest = pDest.AsArrayType();
if (pArrayDest.rank != pArraySource.rank)
if (pArrayDest.rank != pArraySource.rank || pArrayDest.IsSZArray != pArraySource.IsSZArray)
{
return false;
}
Expand All @@ -1391,7 +1391,7 @@ private bool LowerBoundArrayInference(CType pSource, CType pDest)
pDest.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION) ||
pDest.isPredefType(PredefinedType.PT_G_IREADONLYLIST))
{
if (pArraySource.rank != 1)
if (!pArraySource.IsSZArray)
{
return false;
}
Expand Down Expand Up @@ -1727,7 +1727,7 @@ private bool UpperBoundArrayInference(CType pSource, CType pDest)
if (pSource.IsArrayType())
{
ArrayType pArraySource = pSource.AsArrayType();
if (pArrayDest.rank != pArraySource.rank)
if (pArrayDest.rank != pArraySource.rank || pArrayDest.IsSZArray != pArraySource.IsSZArray)
{
return false;
}
Expand All @@ -1739,7 +1739,7 @@ private bool UpperBoundArrayInference(CType pSource, CType pDest)
pSource.isPredefType(PredefinedType.PT_G_IREADONLYLIST) ||
pSource.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION))
{
if (pArrayDest.rank != 1)
if (!pArrayDest.IsSZArray)
{
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ private CType LoadTypeFromSignature(int[] signature, ref int indexIntoSignatures
{
return null;
}
return GetTypeManager().GetArray(elementType, 1);
return GetTypeManager().GetArray(elementType, 1, true);
}
case MethodSignatureEnum.SIG_METH_TYVAR:
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ private bool HasCovariantArrayConversion(ArrayType pSource, ArrayType pDest)
// * S and T differ only in element type. In other words, S and T have the same number of dimensions.
// * Both SE and TE are reference types.
// * An implicit reference conversion exists from SE to TE.
return (pSource.rank == pDest.rank) &&
return (pSource.rank == pDest.rank) && pSource.IsSZArray == pDest.IsSZArray &&
HasImplicitReferenceConversion(pSource.GetElementType(), pDest.GetElementType());
}

Expand All @@ -301,7 +301,7 @@ private bool HasArrayConversionToInterface(ArrayType pSource, CType pDest)
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
if (pSource.rank != 1)
if (!pSource.IsSZArray)
{
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1174,7 +1174,7 @@ private ExprArrayInit GenerateParamsArray(Expr args, PredefinedType pt)
{
int parameterCount = ExpressionIterator.Count(args);
AggregateType paramsArrayElementType = GetSymbolLoader().GetOptPredefTypeErr(pt, true);
ArrayType paramsArrayType = GetSymbolLoader().GetTypeManager().GetArray(paramsArrayElementType, 1);
ArrayType paramsArrayType = GetSymbolLoader().GetTypeManager().GetArray(paramsArrayElementType, 1, true);
ExprConstant paramsArrayArg = GetExprFactory().CreateIntegerConstant(parameterCount);
ExprArrayInit arrayInit = GetExprFactory().CreateArrayInit(EXPRFLAG.EXF_CANTBENULL, paramsArrayType, args, paramsArrayArg, null);
arrayInit.DimensionSize = parameterCount;
Expand Down Expand Up @@ -1204,7 +1204,7 @@ private ExprArrayInit GenerateMembersArray(AggregateType anonymousType, Predefin
}

AggregateType paramsArrayElementType = GetSymbolLoader().GetOptPredefTypeErr(pt, true);
ArrayType paramsArrayType = GetSymbolLoader().GetTypeManager().GetArray(paramsArrayElementType, 1);
ArrayType paramsArrayType = GetSymbolLoader().GetTypeManager().GetArray(paramsArrayElementType, 1, true);
ExprConstant paramsArrayArg = GetExprFactory().CreateIntegerConstant(methodCount);
ExprArrayInit arrayInit = GetExprFactory().CreateArrayInit(EXPRFLAG.EXF_CANTBENULL, paramsArrayType, newArgs, paramsArrayArg, null);
arrayInit.DimensionSize = methodCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ internal sealed class ArrayType : CType
// rank of the array. zero means unknown rank int [?].
public int rank;

public bool IsSZArray { get; set; }

public CType GetElementType() { return _pElementType; }
public void SetElementType(CType pType) { _pElementType = pType; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,7 @@ private static Type CalculateAssociatedSystemType(CType src)
case TypeKind.TK_ArrayType:
ArrayType a = src.AsArrayType();
Type elementType = a.GetElementType().AssociatedSystemType;
if (a.rank == 1)
{
result = elementType.MakeArrayType();
}
else
{
result = elementType.MakeArrayType(a.rank);
}
result = a.IsSZArray ? elementType.MakeArrayType() : elementType.MakeArrayType(a.rank);
break;

case TypeKind.TK_NullableType:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,13 @@ public ErrorType CreateError(
}

// Derived types - parent is base type
public ArrayType CreateArray(Name name, CType pElementType, int rank)
public ArrayType CreateArray(Name name, CType pElementType, int rank, bool isSZArray)
{
ArrayType type = new ArrayType();

type.SetName(name);
type.rank = rank;
type.IsSZArray = isSZArray;
type.SetElementType(pElementType);

type.SetTypeKind(TypeKind.TK_ArrayType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,24 @@ public TypeParameterType GetTypeVarSym(int iv, TypeManager pTypeManager, bool fM
}
}

public ArrayType GetArray(CType elementType, int args)
public ArrayType GetArray(CType elementType, int args, bool isSZArray)
{
Name name;

Debug.Assert(args > 0 && args < 32767);
Debug.Assert(args == 1 || !isSZArray);

switch (args)
{
case 1:
if (isSZArray)
{
goto case 2;
}
else
{
goto default;
}
case 2:
name = NameManager.GetPredefinedName(PredefinedName.PN_ARRAY0 + args);
break;
Expand All @@ -191,7 +200,7 @@ public ArrayType GetArray(CType elementType, int args)
if (pArray == null)
{
// No existing array symbol. Create a new one.
pArray = _typeFactory.CreateArray(name, elementType, args);
pArray = _typeFactory.CreateArray(name, elementType, args, isSZArray);
pArray.InitFromParent();

_typeTable.InsertArray(name, elementType, pArray);
Expand Down Expand Up @@ -567,7 +576,7 @@ private CType SubstTypeCore(CType type, SubstContext pctx)

case TypeKind.TK_ArrayType:
typeDst = SubstTypeCore(typeSrc = type.AsArrayType().GetElementType(), pctx);
return (typeDst == typeSrc) ? type : GetArray(typeDst, type.AsArrayType().rank);
return (typeDst == typeSrc) ? type : GetArray(typeDst, type.AsArrayType().rank, type.AsArrayType().IsSZArray);

case TypeKind.TK_PointerType:
typeDst = SubstTypeCore(typeSrc = type.AsPointerType().GetReferentType(), pctx);
Expand Down Expand Up @@ -703,7 +712,7 @@ private bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx
return false;

case TypeKind.TK_ArrayType:
if (typeDst.GetTypeKind() != TypeKind.TK_ArrayType || typeDst.AsArrayType().rank != typeSrc.AsArrayType().rank)
if (typeDst.GetTypeKind() != TypeKind.TK_ArrayType || typeDst.AsArrayType().rank != typeSrc.AsArrayType().rank || typeDst.AsArrayType().IsSZArray != typeSrc.AsArrayType().IsSZArray)
return false;
goto LCheckBases;

Expand Down Expand Up @@ -1282,7 +1291,7 @@ private bool TryArrayVarianceAdjustmentToGetAccessibleType(CSemanticChecker sema
CType intermediateType;
if (GetBestAccessibleType(semanticChecker, bindingContext, elementType, out intermediateType))
{
typeDst = this.GetArray(intermediateType, typeSrc.rank);
typeDst = this.GetArray(intermediateType, typeSrc.rank, typeSrc.IsSZArray);

Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,15 @@ private CType ProcessSpecialTypeInChain(NamespaceOrAggregateSymbol parent, Type
else if (t.IsArray)
{
// Now we return an array of nesting level corresponding to the rank.
ctype = _typeManager.GetArray(GetCTypeFromType(t.GetElementType()), t.GetArrayRank());
ctype = _typeManager.GetArray(
GetCTypeFromType(t.GetElementType()),
t.GetArrayRank(),
#if netcoreapp
t.IsSZArray
#else
t.GetElementType().MakeArrayType() == t
#endif
);
return ctype;
}
else if (t.IsPointer)
Expand Down
55 changes: 55 additions & 0 deletions src/Microsoft.CSharp/tests/ArrayHandling.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;

namespace Microsoft.CSharp.RuntimeBinder.Tests
{
public class ArrayHandling
{
[Fact]
public void SingleRankNonSZArray()
{
dynamic d = Array.CreateInstance(typeof(int), new[] { 8 }, new[] { -2 });
d.SetValue(32, 3);
d.SetValue(28, -1);
Assert.Equal(32, d.GetValue(3));
Assert.Equal(28, d.GetValue(-1));
}

[Fact]
public void SingleRankNonSZArrayIndexed()
{
dynamic d = Array.CreateInstance(typeof(int), new[] { 8 }, new[] { -2 });
d[3] = 32;
d[-1] = 28;
Assert.Equal(32, d[3]);
Assert.Equal(28, d[-1]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is an interesting side-effect in that it's not possible to do compile the static equivalent, and yet the usage here seems reasonable and so not worth the explicit prohibition it would require to refuse it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, one can currently do the equivalent with non-zero-based arrays of higher ranks, so prohibiting it here would have to either be a breaking change to that or else inconsistent with it.

}

[Fact]
public void ArrayTypeNames()
{
dynamic d = Array.CreateInstance(typeof(int), new[] { 8 }, new[] { -2 });
RuntimeBinderException ex = Assert.Throws<RuntimeBinderException>(() => { string s = d; });
Assert.Contains("int[*]", ex.Message);

d = new int[3];
ex = Assert.Throws<RuntimeBinderException>(() => { string s = d; });
Assert.Contains("int[]", ex.Message);

d = new int[3, 2, 1];
ex = Assert.Throws<RuntimeBinderException>(() => { string s = d; });
Assert.Contains("int[,,]", ex.Message);

d = Array.CreateInstance(typeof(int), new[] { 3, 2, 1 }, new[] { -2, 2, -0 });
ex = Assert.Throws<RuntimeBinderException>(() => { string s = d; });
Assert.Contains("int[,,]", ex.Message);

}
}
}
3 changes: 2 additions & 1 deletion src/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs">
<Link>Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs</Link>
</Compile>
<Compile Include="ArrayHandling.cs" />
<Compile Include="CSharpArgumentInfoTests.cs" />
<Compile Include="EnumArithmeticTests.cs" />
<Compile Include="IntegerBinaryOperationTests.cs" />
Expand All @@ -18,4 +19,4 @@
<Compile Include="RuntimeBinderTests.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>