Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge dev15.7.x to master #25503

Merged
merged 57 commits into from
Mar 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
9c31503
Implement stackalloc initializers
alrz Jan 25, 2018
1ff896d
Update resources
alrz Jan 26, 2018
edc09fc
Address test failures
alrz Jan 26, 2018
cf00fbe
Visit initializer elements in flow analysis
alrz Jan 31, 2018
9e86f06
Whitespaces.
alrz Feb 1, 2018
2a65a3d
Explicitly import ImmutableArray extensions
alrz Feb 1, 2018
27253fa
Revert code.
alrz Feb 1, 2018
9ef4752
Avoid binding the initializer twice
alrz Feb 1, 2018
6e9010a
Fix up formatting
alrz Feb 1, 2018
47a58ff
Add flowpass tests
alrz Feb 1, 2018
d641f40
Clean up tests
alrz Feb 1, 2018
aa4b04d
Fix typo
alrz Feb 1, 2018
7ff7236
Revert code.
alrz Feb 8, 2018
facb834
Add parsing test for bad implicit stackalloc
alrz Feb 8, 2018
f95fb81
Test stackalloc in catch and finally
alrz Feb 8, 2018
6584454
Whitespaces.
alrz Feb 8, 2018
974ee8b
Add more best type tests
alrz Feb 8, 2018
dde9175
Verify execution order
alrz Feb 8, 2018
1eb9599
Assert symbols
alrz Feb 8, 2018
b2a28eb
Emit element-wise assignments for anything larger than byte
alrz Feb 8, 2018
c13dd3a
Revert code.
alrz Feb 8, 2018
9c5a72e
Clean up.
alrz Feb 8, 2018
442c0d7
Add braces.
alrz Feb 8, 2018
779ff18
Assert symbol from syntax
alrz Feb 8, 2018
916304f
Merge pull request #24249 from alrz/features/stackalloc-init
VSadov Feb 8, 2018
0f92e1d
Share code.
alrz Feb 9, 2018
1f8a00f
Use initblk whenever possible regardless of type size
alrz Feb 17, 2018
5836dda
Address test failures
alrz Feb 17, 2018
8e467f4
PR feedback
alrz Feb 21, 2018
d06666d
Merge pull request #24915 from alrz/stackalloc-initblk
VSadov Feb 21, 2018
130659f
Create testplan doc for stackalloc initializers.
VSadov Feb 22, 2018
82f521c
[stackalloc-init] Improve error tolerance when parsing invalid implic…
alrz Feb 27, 2018
1e681a5
Add more tests.
alrz Feb 27, 2018
2037b29
Delete stackalloc_initializers.md
alrz Mar 1, 2018
a1a7258
PR feedback
alrz Mar 2, 2018
1c292ee
Merge pull request #25101 from alrz/stackalloc-init-tests
VSadov Mar 5, 2018
44c96b9
Merge pull request #25309 from dotnet/merges/dev15.7.x-to-features/co…
Shyam-Gupta Mar 7, 2018
0fdddd9
Renamings
alrz Mar 9, 2018
3eb28cc
Add symbol tests
alrz Mar 9, 2018
07ca909
Add capture test
alrz Mar 9, 2018
3a3ed9b
Merge remote-tracking branch 'origin/features/compiler' into stackall…
alrz Mar 9, 2018
b9b337f
Follow-up on merge from 'features/compiler' into stackalloc-init
alrz Mar 9, 2018
29092d4
Add IOperation tests
alrz Mar 9, 2018
3d07cef
Add symbol tests for error cases
alrz Mar 10, 2018
b4d5380
Merge pull request #25382 from alrz/stackalloc-init-api
VSadov Mar 11, 2018
575e457
Merge remote-tracking branch 'origin/features/stackalloc-init' into s…
alrz Mar 12, 2018
6d45baf
Fix up IOperation test
alrz Mar 12, 2018
5952447
Merge pull request #25384 from alrz/stackalloc-init-merge
VSadov Mar 12, 2018
3925afd
Merge remote-tracking branch 'upstream/dev15.7.x' into stackallocMerge
VSadov Mar 12, 2018
4258cf3
Merge pull request #25430 from VSadov/stackallocMerge
VSadov Mar 13, 2018
6fee994
merge from dev15.7.x to features/stackalloc-init
VSadov Mar 14, 2018
bd0c63c
Updated error IDs after merge
VSadov Mar 14, 2018
b144b34
Merge pull request #25474 from VSadov/inits01
VSadov Mar 14, 2018
7dcb04d
Merge pull request #25476 from dotnet/features/stackalloc-init
VSadov Mar 15, 2018
96df47d
Remove props file reference
jaredpar Mar 15, 2018
52aedee
Merge pull request #25499 from jaredpar/fix-feed
jaredpar Mar 15, 2018
9289f08
Update test baselines after merge.
VSadov Mar 16, 2018
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
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/BinderFlagsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@ public static bool Includes(this BinderFlags self, BinderFlags other)
{
return (self & other) == other;
}

public static bool IncludesAny(this BinderFlags self, BinderFlags other)
{
return (self & other) != 0;
}
}
}
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpre
throw ExceptionUtilities.UnexpectedValue(conversion.Kind);
}

var convertedNode = new BoundConvertedStackAllocExpression(syntax, elementType, boundStackAlloc.Count, stackAllocType, boundStackAlloc.HasErrors);
var convertedNode = new BoundConvertedStackAllocExpression(syntax, elementType, boundStackAlloc.Count, boundStackAlloc.InitializerOpt, stackAllocType, boundStackAlloc.HasErrors);

var underlyingConversion = conversion.UnderlyingConversions.Single();
return CreateConversion(syntax, convertedNode, underlyingConversion, isCast, destination, diagnostics);
Expand Down
175 changes: 138 additions & 37 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,8 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic
return BindImplicitArrayCreationExpression((ImplicitArrayCreationExpressionSyntax)node, diagnostics);
case SyntaxKind.StackAllocArrayCreationExpression:
return BindStackAllocArrayCreationExpression((StackAllocArrayCreationExpressionSyntax)node, diagnostics);
case SyntaxKind.ImplicitStackAllocArrayCreationExpression:
return BindImplicitStackAllocArrayCreationExpression((ImplicitStackAllocArrayCreationExpressionSyntax)node, diagnostics);
case SyntaxKind.ObjectCreationExpression:
return BindObjectCreationExpression((ObjectCreationExpressionSyntax)node, diagnostics);
case SyntaxKind.IdentifierName:
Expand Down Expand Up @@ -2716,6 +2718,37 @@ private BoundExpression BindImplicitArrayCreationExpression(ImplicitArrayCreatio
sizes: ImmutableArray<BoundExpression>.Empty, boundInitExprOpt: boundInitializerExpressions);
}

private BoundExpression BindImplicitStackAllocArrayCreationExpression(ImplicitStackAllocArrayCreationExpressionSyntax node, DiagnosticBag diagnostics)
{
InitializerExpressionSyntax initializer = node.Initializer;
ImmutableArray<BoundExpression> boundInitializerExpressions = BindArrayInitializerExpressions(initializer, diagnostics, dimension: 1, rank: 1);

HashSet<DiagnosticInfo> useSiteDiagnostics = null;
TypeSymbol bestType = BestTypeInferrer.InferBestType(boundInitializerExpressions, this.Conversions, out bool hadMultipleCandidates, ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);

if ((object)bestType == null || bestType.SpecialType == SpecialType.System_Void)
{
Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, node);
bestType = CreateErrorType();
}

if (!bestType.IsErrorType() && bestType.IsManagedType)
{
Error(diagnostics, ErrorCode.ERR_ManagedAddr, node, bestType);
}

return BindStackAllocWithInitializer(
node,
initializer,
type: GetStackAllocType(node, bestType, diagnostics, out bool hasErrors),
elementType: bestType,
sizeOpt: null,
diagnostics,
hasErrors: hasErrors,
boundInitializerExpressions);
}

// This method binds all the array initializer expressions.
// NOTE: It doesn't convert the bound initializer expressions to array's element type.
// NOTE: This is done separately in ConvertAndBindArrayInitialization method below.
Expand Down Expand Up @@ -3034,26 +3067,6 @@ private BoundArrayCreation BindArrayCreationWithInitializer(
private BoundExpression BindStackAllocArrayCreationExpression(
StackAllocArrayCreationExpressionSyntax node, DiagnosticBag diagnostics)
{
bool hasErrors = false;
var inLegalPosition = (IsInMethodBody || IsLocalFunctionsScopeBinder) && node.IsLegalSpanStackAllocPosition();

if (!inLegalPosition)
{
hasErrors = true;
diagnostics.Add(
ErrorCode.ERR_InvalidExprTerm,
node.StackAllocKeyword.GetLocation(),
SyntaxFacts.GetText(SyntaxKind.StackAllocKeyword));
}

// Check if we're syntactically within a catch or finally clause.
if (this.Flags.Includes(BinderFlags.InCatchBlock) ||
this.Flags.Includes(BinderFlags.InCatchFilter) ||
this.Flags.Includes(BinderFlags.InFinallyBlock))
{
Error(diagnostics, ErrorCode.ERR_StackallocInCatchFinally, node);
}

TypeSyntax typeSyntax = node.Type;

if (typeSyntax.Kind() != SyntaxKind.ArrayType)
Expand All @@ -3072,24 +3085,23 @@ private BoundExpression BindStackAllocArrayCreationExpression(
TypeSyntax elementTypeSyntax = arrayTypeSyntax.ElementType;
TypeSymbol elementType = BindType(elementTypeSyntax, diagnostics);

bool typeHasErrors = elementType.IsErrorType();
if (!typeHasErrors && elementType.IsManagedType)
TypeSymbol type = GetStackAllocType(node, elementType, diagnostics, out bool hasErrors);
if (!elementType.IsErrorType() && elementType.IsManagedType)
{
Error(diagnostics, ErrorCode.ERR_ManagedAddr, elementTypeSyntax, elementType);
typeHasErrors = true;
hasErrors = true;
}

SyntaxList<ArrayRankSpecifierSyntax> rankSpecifiers = arrayTypeSyntax.RankSpecifiers;

if (rankSpecifiers.Count != 1 ||
rankSpecifiers[0].Sizes.Count != 1 ||
rankSpecifiers[0].Sizes[0].Kind() == SyntaxKind.OmittedArraySizeExpression)
rankSpecifiers[0].Sizes.Count != 1)
{
// NOTE: Dev10 reported several parse errors here.
Error(diagnostics, ErrorCode.ERR_BadStackAllocExpr, typeSyntax);

var builder = ArrayBuilder<BoundExpression>.GetInstance();
DiagnosticBag discardedDiagnostics = DiagnosticBag.GetInstance();
var discardedDiagnostics = DiagnosticBag.GetInstance();
foreach (ArrayRankSpecifierSyntax rankSpecifier in rankSpecifiers)
{
foreach (ExpressionSyntax size in rankSpecifier.Sizes)
Expand All @@ -3100,6 +3112,7 @@ private BoundExpression BindStackAllocArrayCreationExpression(
}
}
}

discardedDiagnostics.Free();

return new BoundBadExpression(
Expand All @@ -3111,37 +3124,125 @@ private BoundExpression BindStackAllocArrayCreationExpression(
}

ExpressionSyntax countSyntax = rankSpecifiers[0].Sizes[0];
var count = BindValue(countSyntax, diagnostics, BindValueKind.RValue);
if (!count.HasAnyErrors)
BoundExpression count = null;
if (countSyntax.Kind() != SyntaxKind.OmittedArraySizeExpression)
{
// NOTE: this is different from how we would bind an array size (in which case we would allow uint, long, or ulong).
count = GenerateConversionForAssignment(GetSpecialType(SpecialType.System_Int32, diagnostics, node), count, diagnostics);
if (!count.HasAnyErrors && IsNegativeConstantForArraySize(count))
count = BindValue(countSyntax, diagnostics, BindValueKind.RValue);
if (!count.HasAnyErrors)
{
Error(diagnostics, ErrorCode.ERR_NegativeStackAllocSize, countSyntax);
hasErrors = true;
// NOTE: this is different from how we would bind an array size (in which case we would allow uint, long, or ulong).
count = GenerateConversionForAssignment(GetSpecialType(SpecialType.System_Int32, diagnostics, node), count, diagnostics);
if (!count.HasAnyErrors && IsNegativeConstantForArraySize(count))
{
Error(diagnostics, ErrorCode.ERR_NegativeStackAllocSize, countSyntax);
hasErrors = true;
}
}
}
else if (node.Initializer == null)
{
// ERR_MissingArraySize is already reported
count = BadExpression(countSyntax);
hasErrors = true;
}

TypeSymbol type = null;
return node.Initializer == null
? new BoundStackAllocArrayCreation(node, elementType, count, initializerOpt: null, type, hasErrors: hasErrors)
: BindStackAllocWithInitializer(node, node.Initializer, type, elementType, count, diagnostics, hasErrors);
}

private bool ReportBadStackAllocPosition(SyntaxNode node, DiagnosticBag diagnostics)
{
Debug.Assert(node is StackAllocArrayCreationExpressionSyntax || node is ImplicitStackAllocArrayCreationExpressionSyntax);

var inLegalPosition = (IsInMethodBody || IsLocalFunctionsScopeBinder) && node.IsLegalSpanStackAllocPosition();
if (!inLegalPosition)
{
diagnostics.Add(
ErrorCode.ERR_InvalidExprTerm,
node.GetFirstToken().GetLocation(),
SyntaxFacts.GetText(SyntaxKind.StackAllocKeyword));
}

// Check if we're syntactically within a catch or finally clause.
if (this.Flags.IncludesAny(BinderFlags.InCatchBlock | BinderFlags.InCatchFilter | BinderFlags.InFinallyBlock))
{
Error(diagnostics, ErrorCode.ERR_StackallocInCatchFinally, node);
}

return inLegalPosition;
}

private TypeSymbol GetStackAllocType(SyntaxNode node, TypeSymbol elementType, DiagnosticBag diagnostics, out bool hasErrors)
{
var inLegalPosition = ReportBadStackAllocPosition(node, diagnostics);
hasErrors = !inLegalPosition;
if (inLegalPosition && !node.IsVariableDeclarationInitialization())
{
CheckFeatureAvailability(node, MessageID.IDS_FeatureRefStructs, diagnostics);

var spanType = GetWellKnownType(WellKnownType.System_Span_T, diagnostics, node);
if (!spanType.IsErrorType())
{
type = ConstructNamedType(
return ConstructNamedType(
type: spanType,
typeSyntax: node.Type,
typeSyntax: node.Kind() == SyntaxKind.StackAllocArrayCreationExpression
? ((StackAllocArrayCreationExpressionSyntax)node).Type
: node,
typeArgumentsSyntax: default,
typeArguments: ImmutableArray.Create(elementType),
basesBeingResolved: null,
diagnostics: diagnostics);
}
}

return new BoundStackAllocArrayCreation(node, elementType, count, type, hasErrors: hasErrors || typeHasErrors);
return null;
}

private BoundExpression BindStackAllocWithInitializer(
SyntaxNode node,
InitializerExpressionSyntax initSyntax,
TypeSymbol type,
TypeSymbol elementType,
BoundExpression sizeOpt,
DiagnosticBag diagnostics,
bool hasErrors,
ImmutableArray<BoundExpression> boundInitExprOpt = default)
{
if (boundInitExprOpt.IsDefault)
{
boundInitExprOpt = BindArrayInitializerExpressions(initSyntax, diagnostics, dimension: 1, rank: 1);
}

boundInitExprOpt = boundInitExprOpt.SelectAsArray((expr, t) => GenerateConversionForAssignment(t.elementType, expr, t.diagnostics), (elementType, diagnostics));

if (sizeOpt != null)
{
if (!sizeOpt.HasAnyErrors)
{
int? constantSizeOpt = GetIntegerConstantForArraySize(sizeOpt);
if (constantSizeOpt == null)
{
Error(diagnostics, ErrorCode.ERR_ConstantExpected, sizeOpt.Syntax);
hasErrors = true;
}
else if (boundInitExprOpt.Length != constantSizeOpt)
{
Error(diagnostics, ErrorCode.ERR_ArrayInitializerIncorrectLength, node, constantSizeOpt.Value);
hasErrors = true;
}
}
}
else
{
sizeOpt = new BoundLiteral(
node,
ConstantValue.Create(boundInitExprOpt.Length),
GetSpecialType(SpecialType.System_Int32, diagnostics, node))
{ WasCompilerGenerated = true };
}

return new BoundStackAllocArrayCreation(node, elementType, sizeOpt, new BoundArrayInitialization(initSyntax, boundInitExprOpt), type, hasErrors);
}

private static int? GetIntegerConstantForArraySize(BoundExpression expression)
Expand Down
3 changes: 2 additions & 1 deletion src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1449,7 +1449,8 @@

<Node Name="BoundStackAllocArrayCreation" Base="BoundExpression">
<Field Name="ElementType" Type="TypeSymbol" Null="disallow"/>
<Field Name="Count" Type="BoundExpression"/>
<Field Name="Count" Type="BoundExpression" Null="disallow" />
<Field Name="InitializerOpt" Type="BoundArrayInitialization" Null="allow"/>
</Node>

<Node Name="BoundConvertedStackAllocExpression" Base="BoundStackAllocArrayCreation">
Expand Down
9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/BoundTree/Expression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,17 @@ internal partial class BoundFixedLocalCollectionInitializer

internal partial class BoundStackAllocArrayCreation
{
protected override ImmutableArray<BoundNode> Children => ImmutableArray.Create<BoundNode>(this.Count);
internal static ImmutableArray<BoundExpression> GetChildInitializers(BoundArrayInitialization arrayInitializer)
{
return arrayInitializer?.Initializers ?? ImmutableArray<BoundExpression>.Empty;
}

protected override ImmutableArray<BoundNode> Children => StaticCast<BoundNode>.From(GetChildInitializers(this.InitializerOpt).Insert(0, this.Count));
}

internal partial class BoundConvertedStackAllocExpression
{
protected override ImmutableArray<BoundNode> Children => ImmutableArray.Create<BoundNode>(this.Count);
protected override ImmutableArray<BoundNode> Children => StaticCast<BoundNode>.From(GetChildInitializers(this.InitializerOpt).Insert(0, this.Count));
}

internal partial class BoundDynamicObjectCreationExpression
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/BoundTree/Formatting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public override object Display
internal partial class BoundStackAllocArrayCreation
{
public override object Display
=> FormattableStringFactory.Create("stackalloc {0}[{1}]", ElementType, Count.Syntax.ToString());
=> FormattableStringFactory.Create("stackalloc {0}[{1}]", ElementType, Count.WasCompilerGenerated ? null : Count.Syntax.ToString());
}

internal partial class BoundPassByCopy
Expand Down
18 changes: 18 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -5297,4 +5297,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_ConWithUnmanagedCon" xml:space="preserve">
<value>Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}'</value>
</data>
<data name="IDS_FeatureStackAllocInitializer" xml:space="preserve">
<value>stackalloc initializer</value>
</data>
<data name="ERR_InvalidStackAllocArray" xml:space="preserve">
<value>"Invalid rank specifier: expected ']'</value>
</data>
</root>
17 changes: 17 additions & 0 deletions src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,23 @@ private void EmitConvertedStackAllocExpression(BoundConvertedStackAllocExpressio
{
_builder.EmitOpCode(ILOpCode.Localloc);
}

var initializer = expression.InitializerOpt;
if (initializer != null)
{
if (used)
{
EmitStackAllocInitializers(expression.Type, initializer);
}
else
{
// If not used, just emit initializer elements to preserve possible sideeffects
foreach (var init in initializer.Initializers)
{
EmitExpression(init, used: false);
}
}
}
}

private void EmitObjectCreationExpression(BoundObjectCreationExpression expression, bool used)
Expand Down
Loading