提交 6f2e0b6d 编写于 作者: V VSadov

Implementation of conditional access operators - ?. and ?[]

 Change Description:

     Implementation of conditional access operators ( ?. and ?[] )

     The grammar roughly looks like:

     expr ::= | ...
              | expr ? tail

     tail ::= | tailopt . id
     tail ::= | tailopt .$ id                        <---   this is NYI in this change
              | tailopt [ expr-args ]
              | tail ( expr-args )

     Note that the tail isn’t optional for invocation: there is no ?(…) operator.

     Interesting implementation points:

     == Parsing/syntax

     Syntax tree is right associative – it has the same topology as in the grammar. However I did not create special variants for all the kinds of syntax that could be produced by the parsing of the tail of accessors.
     I just use regular syntax nodes with exception of the topmost node that is the conditional access operator itself and the lower-leftmost node that textually starts the accessor tail.

     The root node looks like –

     ConditionalAccessExpression
     {
        ExpressionSyntax Expression;
        SyntaxToken OperatorToken;                  // always “?”
        ExpressionSyntax WhenNotNull;              // by analogy with conditional expression which uses WhenTrue
     }

     WhenNotNull is an ExpressionSyntax that represent the sequence of postfix operations conditionally applied to the Expression. These are regular InvocationExpressions, MemberAccesses, ElementAcesses – whatever postfix operators we have.

     The only special part about WhenNotNull is that the low-leftmost expression child is one of 2 special “binding” nodes – MemberBindingExpression, ElementBindingExpression.

     Binding expressions are entities which can start the chain of WhenNotNull . Textually they look like  -  “ .SimpleName“ ,  “[argList]” or “$Name” (when $ accessor is supported).
     Note that there is no InvocationBinding, since we do not allow () to start the chain of applications – you cannot do “a?(arg)”.
     The binding expression syntaxes are basically versions of corresponding member/element/dollar access expressions without receivers.

     R?.a.b(x).c

     Would parse as

         ConditionalAccess
       /         |         \
     R           ?          MemberAccess
                                 /    |   \
                       Invocation     .     c
                      /           \
                MemberAccess       ArgList{( x )}
               /        |    \
     MemberBinding      .      b
         |      \
         .       a

     The advantage of using regular syntax nodes on the right side is that semantical analysis “just works”.  Naturally, because of the topology, the API cannot ask nonsensical questions like - what is the type of subexpression “R?.a.b” ?
     Since “R?.a.b” is not a subexpression, there is no way to ask such question.
     It is however possible to interrogate member accesses – they are just regular member accesses (in both syntax and bound trees) so they naturally know their types etc…

     == Binding

     Binding of the tree above is fairly simple – I only had to add binding support for the left-lowermost binding nodes. And what comes out is really just regular access expressions with placeholder receiver.
     I cannot refer to the actual receiver since we are not evaluating it again.

     In terms of schema - Bound tree actually needed even fewer changes than syntax tree – the bound tree for the above expression is just a regular bound tree. It is isomorphic to the syntax.
     The only new bound nodes are the root BoundConditionalAccess and the left-lowermost placeholder receiver – BoundConditionalReceiver.

         BoundConditionalAccess
          /                  \
     <BoundExpr>         BoundMemberAccess {c}
                              /
                        BoundCall {b}
                       /          \
      BoundMemberAccess {a}        List<Args>{ x }
                    /
     BoundConditionalReceiver

     == Dataflow

     Dataflow considers BoundConditionalReceiver always assigned. However the whole WhenNotNull is reachable conditionally  - i.e. assignedVariables state is forked when going into WhenNotNull.
     “receiver is a const” situation is handled trivially. That is similar to the ?? operator but somewhat inverted.

     == Emit

     There are two ways to emit this :
     - In complex cases (nullables, async, expr trees) we lower the conditional access into a ternary with consequence being rewritten as0is with just BoundConditionalReceiver replaced by a temp for the receiver value.
     - In simple case (all reference types), we do not lower the node, emit of BoundConditionalAccess dups the receiver (thus avoiding an IL temp) , checks it for null and conditionally executes the the access expression.
     BoundConditionalReceiver is handled by emit by not emitting anything since it represents receiver value and that is on the stack already.
 (changeset 1249636)
上级 4cd3b58b
......@@ -634,13 +634,9 @@
</Node>
<Node Name="BoundSwitchStatement" Base="BoundStatement">
<!-- Locals declared by the switch expression, should be moved into an outer block by the local rewriter. -->
<Field Name="OuterLocals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="BoundExpression" Type="BoundExpression"/>
<Field Name="ConstantTargetOpt" Type="LabelSymbol" Null= "allow"/>
<!-- Locals declared immediately within the switch block. -->
<Field Name="InnerLocalsOpt" Type="ImmutableArray&lt;LocalSymbol&gt;" Null="allow"/>
<Field Name="LocalsOpt" Type="ImmutableArray&lt;LocalSymbol&gt;" Null="allow"/>
<Field Name="SwitchSections" Type="ImmutableArray&lt;BoundSwitchSection&gt;"/>
<Field Name="BreakLabel" Type="GeneratedLabelSymbol"/>
<!-- Well-known member populated during lowering -->
......@@ -665,7 +661,6 @@
</Node>
<Node Name="BoundIfStatement" Base="BoundStatement">
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Condition" Type="BoundExpression"/>
<Field Name="Consequence" Type="BoundStatement"/>
<Field Name="AlternativeOpt" Type="BoundStatement" Null="allow"/>
......@@ -677,37 +672,24 @@
</AbstractNode>
<Node Name="BoundDoStatement" Base="BoundLoopStatement">
<!-- InnerLocals are the locals declared within Condition.
They are in scope in the Body. -->
<Field Name="InnerLocals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Condition" Type="BoundExpression"/>
<Field Name="Body" Type="BoundStatement"/>
</Node>
<Node Name="BoundWhileStatement" Base="BoundLoopStatement">
<!-- InnerLocals are the locals declared within Condition.
They are in scope in the Body. -->
<Field Name="InnerLocals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Condition" Type="BoundExpression"/>
<Field Name="Body" Type="BoundStatement"/>
</Node>
<Node Name="BoundForStatement" Base="BoundLoopStatement">
<!-- OuterLocals are the locals declared within the loop statement and are in scope throughout the whole loop statement, including the Initializer -->
<Field Name="OuterLocals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Initializer" Type="BoundStatement" Null="allow"/>
<!-- InnerLocals are the locals declared within Condition and Increment.
They are in scope in the Body, but not in a loop initialization. -->
<Field Name="InnerLocals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Condition" Type="BoundExpression" Null="allow"/>
<Field Name="Increment" Type="BoundStatement" Null="allow"/>
<Field Name="Body" Type="BoundStatement"/>
</Node>
<Node Name="BoundForEachStatement" Base="BoundLoopStatement">
<!-- OuterLocals are the locals declared within the loop statement and are in scope throughout the whole loop statement, including the Expression -->
<Field Name="OuterLocals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<!-- Extracted information -->
<Field Name="EnumeratorInfoOpt" Type="ForEachEnumeratorInfo" Null="allow"/>
<Field Name="ElementConversion" Type="Conversion"/>
......@@ -716,6 +698,7 @@
<!-- This is so the binding API can find produce semantic info if the type is "var". -->
<Field Name="IterationVariableType" Type="BoundTypeExpression"/>
<Field Name="IterationVariable" Type="LocalSymbol"/>
<!-- If this node does not have errors, then this is the foreach expression wrapped
in a conversion to the collection type used by the foreach loop. The conversion
is here so that the binding API can return the correct ConvertedType in semantic
......@@ -729,7 +712,7 @@
<Node Name="BoundUsingStatement" Base="BoundStatement">
<!-- DeclarationsOpt and ExpressionOpt cannot both be non-null. -->
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="LocalsOpt" Type="ImmutableArray&lt;LocalSymbol&gt;" Null="allow"/>
<Field Name="DeclarationsOpt" Type="BoundMultipleLocalDeclarations" Null="allow"/>
<Field Name="ExpressionOpt" Type="BoundExpression" Null="allow"/>
<Field Name="IDisposableConversion" Type="Conversion" />
......@@ -784,13 +767,14 @@
<Node Name="BoundCatchBlock" Base="BoundNode">
<!--
Local symbols owned by the catch block.
Exception variable (if present) and variables declared in filter via Declaration Expressions.
In the initial bound tree the exception variable (if present) is the first variable in the array.
After the node is lowered it might be another variable.
Local symbol owned by the catch block.
Null if the catch syntax doesn't declare a local variable.
In the initial bound tree this is the exception variable (if present).
After the node is lowered it might be another variable or null.
-->
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="LocalOpt" Type="LocalSymbol" Null="allow"/>
<!--
Refers to the location where the exception object is stored.
The expression is a local or a BoundSequence, whose last expression refers to the location of the exception object
......@@ -846,33 +830,6 @@
<Field Name="ConstantValueOpt" Type="ConstantValue" Null="allow"/>
</Node>
<!--
Bound node that represents a single declaration expression:
int x = Foo()
NOTE: The node does NOT introduce the referenced local into surrounding scope.
A local must be explicitly declared in a BoundBlock to be usable inside it.
NOTE: In an error recovery scenario we might have a local declaration parsed as
int x[123] - This is an error commonly made by C++ developers who come to
C#. We will give a good error about it at parse time, but we should preserve
the semantic analysis of the argument list in the bound tree.
-->
<Node Name="BoundDeclarationExpression" Base="BoundExpression">
<Field Name="LocalSymbol" Type="LocalSymbol"/>
<Field Name="DeclaredType" Type="BoundTypeExpression"/>
<Field Name="InitializerOpt" Type="BoundExpression" Null="allow"/>
<Field Name="ArgumentsOpt" Type="ImmutableArray&lt;BoundExpression&gt;" Null="allow"/>
</Node>
<!-- The node is transformed into BoundDeclarationExpression after successful inference -->
<Node Name="UninitializedVarDeclarationExpression" Base="BoundExpression">
<!-- Type is not significant for this node type; always null -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="always"/>
<Field Name="LocalSymbol" Type="LocalSymbol"/>
<Field Name="ArgumentsOpt" Type="ImmutableArray&lt;BoundExpression&gt;" Null="allow"/>
</Node>
<Node Name="BoundRangeVariable" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
......@@ -1307,10 +1264,4 @@
<Field Name="Binder" Type="Binder" Null="disallow" />
</Node>
<!--
Special node to encapsulate initializers added into a constructor.
Helps to do special optimizations in lowering, doesn't survive the lowering.
-->
<Node Name="BoundTypeOrInstanceInitializers" Base="BoundStatementList">
</Node>
</Tree>
</Tree>
\ No newline at end of file
......@@ -113,7 +113,6 @@
<Compile Include="Binder\ConstantFieldsInProgressBinder.cs" />
<Compile Include="Binder\ContextualAttributeBinder.cs" />
<Compile Include="Binder\EarlyWellKnownAttributeBinder.cs" />
<Compile Include="Binder\EmbeddedStatementBinder.cs" />
<Compile Include="Binder\ExecutableCodeBinder.cs" />
<Compile Include="Binder\ExtensionMethodScope.cs" />
<Compile Include="Binder\FixedStatementBinder.cs" />
......@@ -121,7 +120,6 @@
<Compile Include="Binder\ForEachLoopBinder.cs" />
<Compile Include="Binder\ForLoopBinder.cs" />
<Compile Include="Binder\HostObjectModeBinder.cs" />
<Compile Include="Binder\IfBinder.cs" />
<Compile Include="Binder\ImplicitlyTypedFieldBinder.cs" />
<Compile Include="Binder\ImplicitlyTypedLocalBinder.cs" />
<Compile Include="Binder\Imports.cs" />
......@@ -140,7 +138,6 @@
<Compile Include="Binder\LoopBinderContext.cs" />
<Compile Include="Binder\MethodGroupResolution.cs" />
<Compile Include="Binder\NamespaceOrTypeAndUsingDirective.cs" />
<Compile Include="Binder\ScopedExpressionBinder.cs" />
<Compile Include="Binder\Semantics\AccessCheck.cs" />
<Compile Include="Binder\Semantics\BestTypeInferrer.cs" />
<Compile Include="Binder\Semantics\Conversions\Conversion.cs" />
......@@ -193,7 +190,6 @@
<Compile Include="Binder\WithLambdaParametersBinder.cs" />
<Compile Include="Binder\WithMethodTypeParametersBinder.cs" />
<Compile Include="Binder\WithParametersBinder.cs" />
<Compile Include="Binder\WithPrimaryConstructorParametersBinder.cs" />
<Compile Include="Binder\WithTypeParametersBinder.cs" />
<Compile Include="BoundTree\BoundExpression.cs" />
<Compile Include="BoundTree\BoundExpressionExtensions.cs" />
......@@ -212,7 +208,6 @@
<Compile Include="BoundTree\Formatting.cs" />
<Compile Include="BoundTree\NoOpStatementFlavor.cs" />
<Compile Include="BoundTree\UnboundLambda.cs" />
<Compile Include="BoundTree\UninitializedVarDeclarationExpression.cs" />
<Compile Include="CodeGen\CodeGenerator.cs" />
<Compile Include="CodeGen\EmitAddress.cs" />
<Compile Include="CodeGen\EmitArrayInitializer.cs" />
......@@ -253,7 +248,6 @@
<Compile Include="Compiler\MethodCompiler.cs" />
<Compile Include="Compiler\MethodBodySynthesizer.cs" />
<Compile Include="Compiler\MethodBodySynthesizer.Lowered.cs" />
<Compile Include="Compiler\ModuleCompilationState.cs" />
<Compile Include="Compiler\NamespaceScopeBuilder.cs" />
<Compile Include="Compiler\SynthesizedMetadataCompiler.cs" />
<Compile Include="Compiler\TypeCompilationState.cs" />
......@@ -647,7 +641,6 @@
<Compile Include="Symbols\Source\SourceNamespaceSymbol_Completion.cs" />
<Compile Include="Symbols\Source\SourceParameterSymbol.cs" />
<Compile Include="Symbols\Source\SourceParameterSymbolBase.cs" />
<Compile Include="Symbols\Source\SourcePrimaryConstructorParameterSymbolWithBackingField.cs" />
<Compile Include="Symbols\Source\SourcePropertyAccessorSymbol.cs" />
<Compile Include="Symbols\Source\SourcePropertySymbol.cs" />
<Compile Include="Symbols\Source\SourceSimpleParameterSymbol.cs" />
......@@ -719,8 +712,8 @@
<Compile Include="Syntax\ArrayRankSpecifierSyntax.cs" />
<Compile Include="Syntax\AttributeSyntax.cs" />
<Compile Include="Syntax\AttributeTargetSpecifierSyntax.cs" />
<Compile Include="Syntax\BaseMethodDeclarationSyntax.cs" />
<Compile Include="Syntax\BaseSyntaxNodeExtensions.cs" />
<Compile Include="Syntax\ClassDeclarationSyntax.cs" />
<Compile Include="Syntax\CompilationUnitSyntax.cs" />
<Compile Include="Syntax\CSharpLineDirectiveMap.cs" />
<Compile Include="Syntax\CSharpPragmaWarningStateMap.cs" />
......@@ -776,13 +769,11 @@
<Compile Include="Syntax\NamespaceDeclarationSyntax.cs" />
<Compile Include="Syntax\NamespaceDeclarationSyntaxReference.cs" />
<Compile Include="Syntax\NameSyntax.cs" />
<Compile Include="Syntax\ParameterListSyntax.cs" />
<Compile Include="Syntax\ParameterSyntax.cs" />
<Compile Include="Syntax\QualifiedNameSyntax.cs" />
<Compile Include="Syntax\SeparatedSyntaxListBuilder.cs" />
<Compile Include="Syntax\SimpleNameSyntax.cs" />
<Compile Include="Syntax\SimpleSyntaxReference.cs" />
<Compile Include="Syntax\StructDeclarationSyntax.cs" />
<Compile Include="Syntax\StructuredTriviaSyntax.cs" />
<Compile Include="Syntax\SyntaxEquivalence.cs" />
<Compile Include="Syntax\SyntaxExtensions.cs" />
......
......@@ -1219,9 +1219,8 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
{
Debug.Assert(node.OuterLocals.IsEmpty);
Debug.Assert(this.evalStack == 0);
DeclareLocals(node.InnerLocalsOpt, 0);
DeclareLocals(node.LocalsOpt, 0);
var origStack = this.evalStack;
......@@ -1237,7 +1236,7 @@ public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
EnsureOnlyEvalStack();
ImmutableArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections);
var result = node.Update(node.OuterLocals, boundExpression, node.ConstantTargetOpt, node.InnerLocalsOpt, switchSections, node.BreakLabel, node.StringEquality);
var result = node.Update(boundExpression, node.ConstantTargetOpt, node.LocalsOpt, switchSections, node.BreakLabel, node.StringEquality);
// implicit control flow
EnsureOnlyEvalStack();
......@@ -1278,10 +1277,13 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
EnsureOnlyEvalStack();
var locals = node.Locals;
var local = node.LocalOpt;
var exceptionSourceOpt = node.ExceptionSourceOpt;
DeclareLocals(locals, stack: 0);
if ((object)local != null)
{
DeclareLocal(local, stack: 0);
}
if (exceptionSourceOpt != null)
{
......@@ -1326,7 +1328,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
var boundBlock = (BoundBlock)this.Visit(node.Body);
var exceptionTypeOpt = this.VisitType(node.ExceptionTypeOpt);
return node.Update(locals, exceptionSourceOpt, exceptionTypeOpt, boundFilter, boundBlock);
return node.Update(local, exceptionSourceOpt, exceptionTypeOpt, boundFilter, boundBlock);
}
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node)
......@@ -1713,7 +1715,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
var locals = node.Locals;
var local = node.LocalOpt;
var exceptionSource = node.ExceptionSourceOpt;
var type = node.ExceptionTypeOpt;
var filter = node.ExceptionFilterOpt;
......@@ -1756,7 +1758,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
body = (BoundBlock)this.Visit(body);
type = this.VisitType(type);
return node.Update(locals, exceptionSource, type, filter, body);
return node.Update(local, exceptionSource, type, filter, body);
}
}
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
......@@ -160,39 +160,6 @@ private Binder GetEnclosingBinder(CSharpSyntaxNode node, int position)
if (LookupPosition.IsInStatementScope(position, stmt))
{
binder = rootBinder.GetBinder(current);
if (binder != null)
{
switch (stmt.CSharpKind())
{
case SyntaxKind.ForEachStatement:
var forEachStmt = (ForEachStatementSyntax)stmt;
if (LookupPosition.IsBetweenTokens(position, forEachStmt.InKeyword, forEachStmt.CloseParenToken))
{
binder = binder.Next;
Debug.Assert(binder is ScopedExpressionBinder);
}
break;
case SyntaxKind.ForStatement:
var forStmt = (ForStatementSyntax)stmt;
if (LookupPosition.IsBetweenTokens(position, forStmt.OpenParenToken, forStmt.FirstSemicolonToken))
{
binder = binder.Next;
Debug.Assert(binder is ForLoopInitializationBinder);
}
break;
case SyntaxKind.SwitchStatement:
var switchStmt = (SwitchStatementSyntax)stmt;
if (LookupPosition.IsBetweenTokens(position, switchStmt.OpenParenToken, switchStmt.CloseParenToken))
{
binder = binder.Next;
Debug.Assert(binder is ScopedExpressionBinder);
}
break;
}
}
}
}
else if (current.Kind == SyntaxKind.CatchClause)
......@@ -444,12 +411,6 @@ public override IMethodSymbol GetDeclaredSymbol(BaseMethodDeclarationSyntax decl
return null;
}
public override IMethodSymbol GetDeclaredConstructorSymbol(TypeDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
{
// Can't define type inside a member.
return null;
}
public override ISymbol GetDeclaredSymbol(BasePropertyDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
{
// Can't define property inside member.
......@@ -1466,12 +1427,6 @@ internal protected virtual CSharpSyntaxNode GetBindableSyntaxNode(CSharpSyntaxNo
return GetBindableSyntaxNode(parent);
case SyntaxKind.VariableDeclarator: // declarators are mapped in SyntaxBinder
if (parent.Kind == SyntaxKind.DeclarationExpression)
{
return GetBindableSyntaxNode(parent);
}
// When a local variable declaration contains a single declarator, the bound node
// is associated with the declaration, rather than with the declarator. If we
// used the declarator here, we would have enough context to bind it, but we wouldn't
......@@ -1677,18 +1632,6 @@ public override BoundStatement BindStatement(StatementSyntax node, DiagnosticBag
return (BoundStatement)boundNodes[0];
}
}
internal override Binder WithPrimaryConstructorParametersIfNecessary(NamedTypeSymbol containingType, bool shadowBackingFields)
{
Binder result = base.WithPrimaryConstructorParametersIfNecessary(containingType, shadowBackingFields);
if (result != this)
{
result = new IncrementalBinder(this.semanticModel, result);
}
return result;
}
}
}
}
......@@ -382,33 +382,6 @@ protected ImmutableArray<ParameterSymbol> MethodParameters
}
}
/// <summary>
/// If we are not in primary constructor and primary constructor parameters are in scope,
/// return them. Returns an empty array otherwise.
/// </summary>
protected ImmutableArray<ParameterSymbol> PrimaryConstructorParameters
{
get
{
if ((object)member != null)
{
var container = (member.Kind == SymbolKind.NamedType ? member : member.ContainingType) as SourceMemberContainerTypeSymbol;
if ((object)container != null && (object)container.PrimaryCtor != null && (object)container.PrimaryCtor != (object)member)
{
var sourceMethod = member as SourceMethodSymbol;
if ((object)sourceMethod == null || !sourceMethod.IsPrimaryCtor)
{
return container.PrimaryCtor.Parameters;
}
}
}
return ImmutableArray<ParameterSymbol>.Empty;
}
}
/// <summary>
/// If a method is currently being analyzed returns its 'this' parameter, returns null
/// otherwise.
......@@ -513,7 +486,6 @@ protected void VisitLvalue(BoundExpression node)
case BoundKind.Local:
case BoundKind.ThisReference:
case BoundKind.BaseReference:
case BoundKind.DeclarationExpression:
// no need for it to be previously assigned: it is on the left.
break;
......@@ -985,15 +957,6 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node)
return null;
}
public override BoundNode VisitDeclarationExpression(BoundDeclarationExpression node)
{
if (node.InitializerOpt != null)
{
VisitRvalue(node.InitializerOpt); // analyze the expression
}
return null;
}
public override BoundNode VisitBlock(BoundBlock node)
{
foreach (var statement in node.Statements)
......@@ -1986,11 +1949,6 @@ public override BoundNode VisitSequencePointWithSpan(BoundSequencePointWithSpan
}
public override BoundNode VisitStatementList(BoundStatementList node)
{
return VisitStatementListWorker(node);
}
private BoundNode VisitStatementListWorker(BoundStatementList node)
{
foreach (var statement in node.Statements)
{
......@@ -2000,11 +1958,6 @@ private BoundNode VisitStatementListWorker(BoundStatementList node)
return null;
}
public override BoundNode VisitTypeOrInstanceInitializers(BoundTypeOrInstanceInitializers node)
{
return VisitStatementListWorker(node);
}
public override BoundNode VisitUnboundLambda(UnboundLambda node)
{
// The presence of this node suggests an error was detected in an earlier phase.
......
......@@ -302,86 +302,5 @@ public override BoundNode VisitRefTypeOperator(BoundRefTypeOperator node)
return node.Update(operand, getTypeFromHandle, type);
}
public override BoundNode VisitTypeOrInstanceInitializers(BoundTypeOrInstanceInitializers node)
{
ImmutableArray<BoundStatement> rewrittenStatements = (ImmutableArray<BoundStatement>)this.VisitList(node.Statements);
ImmutableArray<BoundStatement> optimizedStatements = ImmutableArray<BoundStatement>.Empty;
if (compilation.Options.Optimize)
{
// TODO: this part may conflict with InitializerRewriter.Rewrite in how it handles
// the first field initializer (see 'if (i == 0)'...) which seems suspicious
ArrayBuilder<BoundStatement> statements = ArrayBuilder<BoundStatement>.GetInstance();
bool anyNonDefault = false;
foreach (var initializer in rewrittenStatements)
{
if (ShouldOptimizeOutInitializer(initializer))
{
if (this.factory.CurrentMethod.IsStatic)
{
// NOTE: Dev11 removes static initializers if ONLY all of them are optimized out
statements.Add(initializer);
}
}
else
{
statements.Add(initializer);
anyNonDefault = true;
}
}
if (anyNonDefault)
{
optimizedStatements = statements.ToImmutableAndFree();
}
else
{
statements.Free();
}
}
else
{
optimizedStatements = rewrittenStatements;
}
return new BoundStatementList(node.Syntax, optimizedStatements, node.HasErrors);
}
/// <summary>
/// Returns true if the initializer is a field initializer which should be optimized out
/// </summary>
private static bool ShouldOptimizeOutInitializer(BoundStatement initializer)
{
BoundStatement statement = initializer;
if (initializer.Kind == BoundKind.SequencePointWithSpan)
{
statement = ((BoundSequencePointWithSpan)initializer).StatementOpt;
}
else if (initializer.Kind == BoundKind.SequencePoint)
{
statement = ((BoundSequencePoint)initializer).StatementOpt;
}
if (statement == null || statement.Kind != BoundKind.ExpressionStatement)
{
Debug.Assert(false, "initializer does not initialize a field?");
return false;
}
BoundAssignmentOperator assignment = ((BoundExpressionStatement)statement).Expression as BoundAssignmentOperator;
if (assignment == null)
{
Debug.Assert(false, "initializer does not initialize a field?");
return false;
}
Debug.Assert(assignment.Left.Kind == BoundKind.FieldAccess);
BoundExpression rhs = assignment.Right;
return rhs.IsDefaultValue();
}
}
}
\ No newline at end of file
......@@ -239,15 +239,6 @@
<summary>Creates an NullableTypeSyntax node.</summary>
</FactoryComment>
</Node>
<Node Name="BaseClassWithArgumentsSyntax" Base="TypeSyntax">
<Kind Name="BaseClassWithArguments"/>
<Field Name="BaseClass" Type="TypeSyntax"/>
<Field Name="ArgumentList" Type="ArgumentListSyntax">
<PropertyComment>
<summary>ArgumentListSyntax node representing the list of arguments acting as arguments to the base call of the primary constructor.</summary>
</PropertyComment>
</Field>
</Node>
<Node Name="OmittedTypeArgumentSyntax" Base="TypeSyntax">
<Kind Name="OmittedTypeArgument"/>
<Field Name="OmittedTypeArgumentToken" Type="SyntaxToken">
......@@ -2376,7 +2367,6 @@
<Kind Name="IdentifierToken"/>
</Field>
<Field Name="TypeParameterList" Type="TypeParameterListSyntax" Optional="true" Override="true"/>
<Field Name="ParameterList" Type="ParameterListSyntax" Optional="true"/>
<Field Name="BaseList" Type="BaseListSyntax" Optional="true" Override="true"/>
<Field Name="ConstraintClauses" Type="SyntaxList&lt;TypeParameterConstraintClauseSyntax&gt;" Override="true"/>
<Field Name="OpenBraceToken" Type="SyntaxToken" Override="true">
......@@ -2407,7 +2397,6 @@
<Kind Name="IdentifierToken"/>
</Field>
<Field Name="TypeParameterList" Type="TypeParameterListSyntax" Optional="true" Override="true"/>
<Field Name="ParameterList" Type="ParameterListSyntax" Optional="true"/>
<Field Name="BaseList" Type="BaseListSyntax" Optional="true" Override="true"/>
<Field Name="ConstraintClauses" Type="SyntaxList&lt;TypeParameterConstraintClauseSyntax&gt;" Override="true"/>
<Field Name="OpenBraceToken" Type="SyntaxToken" Override="true">
......@@ -3138,13 +3127,6 @@
</Field>
<Field Name="Type" Type="TypeSyntax" Optional="true"/>
</Node>
<Node Name="DeclarationExpressionSyntax" Base="ExpressionSyntax">
<Kind Name="DeclarationExpression"/>
<Field Name="Type" Type="TypeSyntax"/>
<Field Name="Variable" Type="VariableDeclaratorSyntax"/>
</Node>
<Node Name="SkippedTokensTriviaSyntax" Base="StructuredTriviaSyntax">
<Kind Name="SkippedTokensTrivia"/>
<Field Name="Tokens" Type="SyntaxList&lt;SyntaxToken&gt;"/>
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
......@@ -1265,7 +1265,7 @@ public static ParameterListSyntax ParseParameterList(string text, int offset = 0
using (var lexer = MakeLexer(text, offset, (CSharpParseOptions)options))
using (var parser = MakeParser(lexer))
{
var node = parser.ParseParenthesizedParameterList(allowThisKeyword: true, allowDefaults: true, allowAttributes: true, allowFieldModifiers: true);
var node = parser.ParseParenthesizedParameterList(allowThisKeyword: true, allowDefaults: true, allowAttributes: true);
if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node);
return (ParameterListSyntax)node.CreateRed();
}
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -289,7 +289,6 @@ public enum SyntaxKind : ushort
PointerType,
NullableType,
OmittedTypeArgument,
BaseClassWithArguments,
// expressions
ParenthesizedExpression,
......@@ -315,7 +314,6 @@ public enum SyntaxKind : ushort
ImplicitArrayCreationExpression,
StackAllocArrayCreationExpression,
OmittedArraySizeExpression,
DeclarationExpression,
// binary expressions
AddExpression,
......
......@@ -98,7 +98,6 @@
<Compile Include="Semantics\ColorColorTests.cs" />
<Compile Include="Semantics\ConditionalOperatorTests.cs" />
<Compile Include="Semantics\ConstantTests.cs" />
<Compile Include="Semantics\DeclarationExpressionsTests.cs" />
<Compile Include="Semantics\DynamicTests.cs" />
<Compile Include="Semantics\FieldInitializerBindingTests.cs" />
<Compile Include="Semantics\ForEachTests.cs" />
......
......@@ -19,14 +19,14 @@ public void DiagnosticAnalyzerAllInOne()
{
var source = TestResource.AllInOneCSharpCode;
var analyzer = new CSharpTrackingDiagnosticAnalyzer();
CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Experimental)).VerifyAnalyzerDiagnostics(new[] { analyzer });
CreateCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics(new[] { analyzer });
analyzer.VerifyAllInterfaceMembersWereCalled();
analyzer.VerifyAnalyzeSymbolCalledForAllSymbolKinds();
analyzer.VerifyAnalyzeNodeCalledForAllSyntaxKinds();
analyzer.VerifyOnCodeBlockCalledForAllSymbolAndMethodKinds();
analyzer = new CSharpTrackingDiagnosticAnalyzer();
CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Experimental)).VerifyAnalyzerDiagnostics3(new[] { analyzer });
CreateCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics3(new[] { analyzer });
analyzer.VerifyAllInterfaceMembersWereCalled();
analyzer.VerifyAnalyzeSymbolCalledForAllSymbolKinds();
analyzer.VerifyAnalyzeNodeCalledForAllSyntaxKinds();
......@@ -70,7 +70,7 @@ public class C
[Fact]
public void AnalyzerDriverIsSafeAgainstAnalyzerExceptions()
{
var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Experimental));
var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode);
ThrowingDiagnosticAnalyzer<SyntaxKind>.VerifyAnalyzerEngineIsSafeAgainstExceptions(analyzer =>
AnalyzerDriver.GetDiagnostics(compilation, new[] { analyzer }, CancellationToken.None), typeof(AnalyzerDriver).Name);
}
......
......@@ -12781,28 +12781,6 @@ public void CS1525ERR_InvalidExprTerm()
return 1;
}
}", parseOptions: Test.Utilities.TestOptions.Regular.WithLanguageVersion(LanguageVersion.Experimental))
.VerifyDiagnostics(
// (4,25): error CS1001: Identifier expected
// bool b = string is string;
Diagnostic(ErrorCode.ERR_IdentifierExpected, "is").WithLocation(4, 25),
// (4,18): error CS0165: Use of unassigned local variable ''
// bool b = string is string;
Diagnostic(ErrorCode.ERR_UseDefViolation, "string ").WithArguments("").WithLocation(4, 18)
);
}
[Fact]
public void CS1525ERR_InvalidExprTerm_NoDeclExpr()
{
CreateCompilationWithMscorlib(
@"public class MyClass {
public static int Main() {
bool b = string is string;
return 1;
}
}")
.VerifyDiagnostics(Diagnostic(ErrorCode.ERR_InvalidExprTerm, "string").WithArguments("string"));
}
......
......@@ -190,7 +190,6 @@
<Compile Include="Symbols\Source\LocationTests.cs" />
<Compile Include="Symbols\Source\MethodTests.cs" />
<Compile Include="Symbols\Source\ModifierTests.cs" />
<Compile Include="Symbols\Source\PrimaryConstructors.cs" />
<Compile Include="Symbols\Source\PropertyTests.cs" />
<Compile Include="Symbols\Source\SourcePlusMetadataTests.cs" />
<Compile Include="Symbols\Source\TypeMapTests.cs" />
......
......@@ -53,6 +53,7 @@
<Compile Include="CodeGen\CompilationTestData.cs" />
<Compile Include="CodeGen\DebugDocumentProvider.cs" />
<Compile Include="CodeGen\EmitState.cs" />
<Compile Include="CodeGen\ExternNamespace.cs" />
<Compile Include="CodeGen\FullLocalSlotManager.cs" />
<Compile Include="CodeGen\ILBuilder.cs" />
<Compile Include="CodeGen\ILBuilderConversions.cs" />
......@@ -63,6 +64,7 @@
<Compile Include="CodeGen\LabelInfo.cs" />
<Compile Include="CodeGen\LocalConstantDefinition.cs" />
<Compile Include="CodeGen\LocalDefinition.cs" />
<Compile Include="CodeGen\LocalScope.cs" />
<Compile Include="CodeGen\LocalScopeManager.cs" />
<Compile Include="CodeGen\LocalSlotManager.cs" />
<Compile Include="CodeGen\MetadataConstant.cs" />
......@@ -70,6 +72,7 @@
<Compile Include="CodeGen\MetadataNamedArgument.cs" />
<Compile Include="CodeGen\MetadataTypeOf.cs" />
<Compile Include="CodeGen\MethodBody.cs" />
<Compile Include="CodeGen\NamespaceScope.cs" />
<Compile Include="CodeGen\PermissionSetAttribute.cs" />
<Compile Include="CodeGen\PrivateImplementationDetails.cs" />
<Compile Include="CodeGen\RawSequencePoint.cs" />
......@@ -81,6 +84,7 @@
<Compile Include="CodeGen\SwitchIntegralJumpTableEmitter.SwitchBucket.cs" />
<Compile Include="CodeGen\SwitchStringJumpTableEmitter.cs" />
<Compile Include="CodeGen\TokenMap.cs" />
<Compile Include="CodeGen\UsedNamespaceOrType.cs" />
<Compile Include="CodeGen\Win32Res.cs" />
<Compile Include="Collections\ArrayBuilder.ArrayBuilderEnumerator.cs" />
<Compile Include="Collections\ArrayBuilder.cs" />
......@@ -183,7 +187,6 @@
<Compile Include="DocumentationMode.cs" />
<Compile Include="Emit\AnonymousTypeKey.cs" />
<Compile Include="Emit\AnonymousTypeValue.cs" />
<Compile Include="Compilation\CommonModuleCompilationState.cs" />
<Compile Include="Emit\Context.cs" />
<Compile Include="Emit\EditAndContinue\DefinitionMap.cs" />
<Compile Include="Emit\EditAndContinue\DeltaPeWriter.cs" />
......@@ -206,7 +209,7 @@
<Compile Include="Emit\NoPia\CommonEmbeddedTypeParameter.cs" />
<Compile Include="Emit\NoPia\EmbeddedTypesManager.cs" />
<Compile Include="Emit\NoPia\VtblGap.cs" />
<Compile Include="Emit\CommonPEModuleBuilder.cs" />
<Compile Include="Emit\PEModuleBuilder.cs" />
<Compile Include="Emit\SemanticEdit.cs" />
<Compile Include="Emit\TypeExport.cs" />
<Compile Include="EnumConstantHelper.cs" />
......@@ -359,7 +362,6 @@
<Compile Include="PEWriter\DirectoryEntry.cs" />
<Compile Include="PEWriter\ExceptionHandlerRegion.cs" />
<Compile Include="PEWriter\Expressions.cs" />
<Compile Include="PEWriter\ExternNamespace.cs" />
<Compile Include="PEWriter\FullPeWriter.cs" />
<Compile Include="PEWriter\ICustomAttribute.cs" />
<Compile Include="PEWriter\IFileReference.cs" />
......@@ -367,7 +369,6 @@
<Compile Include="PEWriter\InstructionOperandTypes.cs" />
<Compile Include="PEWriter\ISymbolWriter.cs" />
<Compile Include="PEWriter\ISymUnmanagedAsyncMethodPropertiesWriter.cs" />
<Compile Include="PEWriter\LocalScope.cs" />
<Compile Include="PEWriter\ManagedResource.cs" />
<Compile Include="PEWriter\MemberRefComparer.cs" />
<Compile Include="PEWriter\Members.cs" />
......@@ -376,11 +377,10 @@
<Compile Include="PEWriter\MethodSpecComparer.cs" />
<Compile Include="PEWriter\Miscellaneous.cs" />
<Compile Include="PEWriter\ModifiedTypeReference.cs" />
<Compile Include="PEWriter\NamespaceScope.cs" />
<Compile Include="PEWriter\NtHeader.cs" />
<Compile Include="PEWriter\PdbMetadataWrapper.cs" />
<Compile Include="PEWriter\PdbWriter.cs" />
<Compile Include="PEWriter\PeDebugDirectory.cs" />
<Compile Include="PEWriter\PdbWriterInterface.cs" />
<Compile Include="PEWriter\PeWriter.cs" />
<Compile Include="PEWriter\ReferenceIndexer.cs" />
<Compile Include="PEWriter\ReturnValueParameter.cs" />
......@@ -388,12 +388,12 @@
<Compile Include="PEWriter\SectionHeader.cs" />
<Compile Include="PEWriter\SecurityAction.cs" />
<Compile Include="PEWriter\SequencePoint.cs" />
<Compile Include="PEWriter\TempCCIParts.cs" />
<Compile Include="PEWriter\TypeLibTypeFlags.cs" />
<Compile Include="PEWriter\Types.cs" />
<Compile Include="PEWriter\TypeSpecComparer.cs" />
<Compile Include="PEWriter\UnitHelper.cs" />
<Compile Include="PEWriter\Units.cs" />
<Compile Include="PEWriter\UsedNamespaceOrType.cs" />
<Compile Include="PEWriter\UsedNamespaceOrTypeKind.cs" />
<Compile Include="PrimitiveTypeCodeExtensions.cs" />
<Compile Include="ReferenceManager\AssemblyData.cs" />
<Compile Include="ReferenceManager\AssemblyDataForAssemblyBeingBuilt.cs" />
......@@ -451,7 +451,6 @@
<Compile Include="SymbolDisplay\SymbolDisplayPropertyStyle.cs" />
<Compile Include="SymbolDisplay\SymbolDisplayTypeQualificationStyle.cs" />
<Compile Include="Symbols\Accessibility.cs" />
<Compile Include="Symbols\AnonymousTypes\CommonAnonymousTypeManager.cs" />
<Compile Include="Symbols\Attributes\AttributeDescription.cs" />
<Compile Include="Symbols\Attributes\AttributeUsageInfo.cs" />
<Compile Include="Symbols\Attributes\CommonAssemblyWellKnownAttributeData.cs" />
......
......@@ -378,9 +378,9 @@ public static SyntaxTree[] Parse(params string[] sources)
return sources.Select(src => Parse(src)).ToArray();
}
public static SyntaxTree ParseWithRoundTripCheck(string text, CSharpParseOptions options = null)
public static SyntaxTree ParseWithRoundTripCheck(string text)
{
var tree = Parse(text, options: options);
var tree = Parse(text);
var parsedText = tree.GetRoot();
// we validate the text roundtrips
Assert.Equal(text, parsedText.ToFullString());
......@@ -431,12 +431,11 @@ public static SyntaxTree ParseWithRoundTripCheck(string text, CSharpParseOptions
string source,
IEnumerable<MetadataReference> references = null,
CSharpCompilationOptions compOptions = null,
CSharpParseOptions parseOptions = null,
string sourceFileName = "",
string assemblyName = "")
{
return CreateCompilationWithMscorlib45(
new SyntaxTree[] { Parse(source, sourceFileName, parseOptions) },
new SyntaxTree[] { Parse(source, sourceFileName) },
references,
compOptions,
assemblyName);
......
......@@ -929,7 +929,6 @@
<Compile Include="Symbols\SymbolVisitor`1.vb" />
<Compile Include="Syntax\InternalSyntax\ChildSyntaxList.Enumerator.vb" />
<Compile Include="Syntax\InternalSyntax\ChildSyntaxList.vb" />
<Compile Include="Compilation\ModuleCompilationState.vb" />
<Content Include="Symbols\SymbolsAndNoPia.docx" />
<Content Include="UseSiteDiagnosticsCheckEnforcer\BaseLine.txt" />
<Content Include="UseSiteDiagnosticsCheckEnforcer\Run.bat" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册