提交 d710efa2 编写于 作者: N Neal Gafter 提交者: GitHub

Merge pull request #13750 from dotnet/features/throwexpr

Merge the feature 'throw expressions' into master
Fixes #13745.
......@@ -6,26 +6,27 @@ This document reflects the status, and planned work, for the compiler team. It
| Feature | Branch | State | Owners | LDM Champ |
| ------- | ------ | ----- | ------ | --------- |
| Address of Static | none | Feature Specification | | [jaredpar](https://github.com/jaredpar) |
| [Binary Literals](https://github.com/dotnet/roslyn/issues/215) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | | [gafter](https://github.com/gafter) |
| [Digit Separators](https://github.com/dotnet/roslyn/issues/216) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | | [gafter](https://github.com/gafter) |
| [Local Functions](https://github.com/dotnet/roslyn/blob/master/docs/features/local-functions.md) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [agocke](https://github.com/agocke), [jaredpar](https://github.com/jaredpar), [vsadov](https://github.com/vsadov) | [gafter](https://github.com/gafter) |
| [Type switch](https://github.com/dotnet/roslyn/blob/master/docs/features/patterns.md) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [gafter](https://github.com/gafter), [alekseyts](https://github.com/alekseyts), [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) |
| [Local Functions](features/local-functions.md) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [agocke](https://github.com/agocke), [jaredpar](https://github.com/jaredpar), [vsadov](https://github.com/vsadov) | [gafter](https://github.com/gafter) |
| [Type switch](features/patterns.md) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [gafter](https://github.com/gafter), [alekseyts](https://github.com/alekseyts), [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) |
| [Ref Returns](https://github.com/dotnet/roslyn/issues/118) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [vsadov](https://github.com/vsadov), [agocke](https://github.com/agocke), [jaredpar](https://github.com/jaredpar) | [vsadov](https://github.com/vsadov) |
| [Tuples](https://github.com/dotnet/roslyn/issues/347) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [vsadov](https://github.com/vsadov), [jcouv](https://github.com/jcouv) | [madstorgersen](https://github.com/MadsTorgersen) |
| [Out var](https://github.com/dotnet/roslyn/blob/features/outvar/docs/features/outvar.md) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [alekseyts](https://github.com/alekseyts) | [gafter](https://github.com/gafter) |
| [Out var](features/outvar.md) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [alekseyts](https://github.com/alekseyts) | [gafter](https://github.com/gafter) |
| [ValueTask<T>](https://github.com/ljw1004/roslyn/blob/features/async-return/docs/specs/feature%20-%20arbitrary%20async%20returns.md) | [master](https://github.com/dotnet/roslyn/tree/master) | Finishing | [alekseyts](https://github.com/alekseyts) | [lucian](https://github.com/ljw1004) |
| [Throw Expr](features/throwexpr.md) | [features/throwexpr](https://github.com/dotnet/roslyn/tree/features/throwexpr) | Prototyping | [gafter](https://github.com/gafter), [agocke](https://github.com/agocke), [tyoverby](https://github.com/tyoverby) | [gafter](https://github.com/gafter) |
| [Expression-Bodied Everything](https://github.com/dotnet/roslyn/issues/7881) | [features/exprbody](https://github.com/dotnet/roslyn/tree/features/exprbody) | Prototyping | [MgSam](https://github.com/MgSam), [gafter](https://github.com/gafter) | [madstorgersen](https://github.com/MadsTorgersen) |
## (C# 7.0 and VB 15) + 1
| Feature | Branch | State | Owners | LDM Champ |
| ------- | ------ | ----- | ------ | --------- |
| Address of Static | none | Feature Specification | | [jaredpar](https://github.com/jaredpar) |
| [Async Main](https://github.com/dotnet/roslyn/issues/7476) | none | Feature Specification | [tyoverby](https://github.com/tyoverby), [agocke](https://github.com/agocke) | [stephentoub](https://github.com/stephentoub) |
| [Source Generation](https://github.com/dotnet/roslyn/blob/master/docs/features/generators.md) | [master](https://github.com/dotnet/roslyn/tree/features/generators) | Prototyping | [cston](https://github.com/cston), [vsadov](https://github.com/vsadov), [agocke](https://github.com/agocke) | [mattwar](https://github.com/mattwar) |
| [Throw Expr](https://github.com/dotnet/roslyn/blob/features/patterns/docs/features/patterns.md) | [features/patterns](https://github.com/dotnet/roslyn/tree/features/patterns) | Prototyping | [agocke](https://github.com/agocke), [tyoverby](https://github.com/tyoverby), [gafter](https://github.com/gafter) | [gafter](https://github.com/gafter) |
| [private protected](https://github.com/dotnet/roslyn/blob/features/privateProtected/docs/features/private-protected.md) | [features/privateProtected](https://github.com/dotnet/roslyn/tree/features/privateProtected) | Prototyping | | [gafter](https://github.com/gafter) |
| [Non-null Ref Types](https://github.com/dotnet/roslyn/blob/features/NullableReferenceTypes/docs/features/NullableReferenceTypes/Nullable%20reference%20types.md) | [features/NullableReferenceTypes](https://github.com/dotnet/roslyn/tree/features/NullableReferenceTypes) | Prototyping | [alekseyts](https://github.com/alekseyts) | [mattwar](https://github.com/mattwar) |
| [Better Betterness](https://github.com/dotnet/roslyn/issues/250) | none | Feature Specification | | [gafter](https://github.com/gafter) |
| [Bestest Betterness](https://github.com/dotnet/roslyn/issues/250) | none | Feature Specification | | [gafter](https://github.com/gafter) |
| [Records](https://github.com/dotnet/roslyn/blob/features/records/docs/features/records.md) | [features/records](https://github.com/dotnet/roslyn/tree/features/records) | Feature Specification | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) |
| [With Exprs](https://github.com/dotnet/roslyn/blob/features/records/docs/features/records.md) | [features/records](https://github.com/dotnet/roslyn/tree/features/records) | Feature Specification | [gafter](https://github.com/gafter) | [gafter](https://github.com/gafter) |
| [Pattern Matching](https://github.com/dotnet/roslyn/blob/features/patterns/docs/features/patterns.md) | [features/patterns](https://github.com/dotnet/roslyn/tree/features/patterns) | Prototyping | [gafter](https://github.com/gafter), [alekseyts](https://github.com/alekseyts), [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) |
......@@ -35,4 +36,4 @@ This document reflects the status, and planned work, for the compiler team. It
- **Is target version a guarantee?**: No. It's explicitly not a guarantee. This is just the planned and ongoing work to the best of our knowledge at this time.
- **Where are these State values defined?**: Take a look at the [Developing a Language Feature](contributing/Developing a Language Feature.md) document.
Updated 2016-07-27
\ No newline at end of file
Updated 2016-08-29
\ No newline at end of file
## Throw expression
We extend the set of expression forms to include
```antlr
throw_expression
: 'throw' null_coalescing_expression
;
null_coalescing_expression
: throw_expression
;
```
The type rules are as follows:
- A *throw_expression* has no type.
- A *throw_expression* is convertible to every type by an implicit conversion.
The flow-analysis rules are as follows:
- For every variable *v*, *v* is definitely assigned before the *null_coalescing_expression* of a *throw_expression* iff it is definitely assigned before the *throw_expression*.
- For every variable *v*, *v* is definitely assigned after *throw_expression*.
A *throw expression* is permitted in only the following syntactic contexts:
- As the second or third operand of a ternary conditional operator `?:`
- As the second operand of a null coalescing operator `??`
- As the body of an expression-bodied lambda or method.
> Note: the rest of the semantics of the throw expression are identical to the semantics of the *throw_statement* in the current language specification.
......@@ -628,6 +628,9 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic
case SyntaxKind.TupleExpression:
return BindTupleExpression((TupleExpressionSyntax)node, diagnostics);
case SyntaxKind.ThrowExpression:
return BindThrowExpression((ThrowExpressionSyntax)node, diagnostics);
case SyntaxKind.RefType:
{
var firstToken = node.GetFirstToken();
......@@ -653,6 +656,53 @@ private BoundExpression BindExpressionInternal(ExpressionSyntax node, Diagnostic
}
}
private BoundExpression BindThrowExpression(ThrowExpressionSyntax node, DiagnosticBag diagnostics)
{
bool hasErrors = node.HasErrors;
if (!IsThrowExpressionInProperContext(node))
{
diagnostics.Add(ErrorCode.ERR_ThrowMisplaced, node.ThrowKeyword.GetLocation());
hasErrors = true;
}
var thrownExpression = BindThrownExpression(node.Expression, diagnostics, ref hasErrors);
return new BoundThrowExpression(node, thrownExpression, null, hasErrors);
}
private static bool IsThrowExpressionInProperContext(ThrowExpressionSyntax node)
{
var parent = node.Parent;
if (parent == null || node.HasErrors)
{
return true;
}
switch (node.Parent.Kind())
{
case SyntaxKind.ConditionalExpression: // ?:
{
var conditionalParent = (ConditionalExpressionSyntax)parent;
return node == conditionalParent.WhenTrue || node == conditionalParent.WhenFalse;
}
case SyntaxKind.CoalesceExpression: // ??
{
var binaryParent = (BinaryExpressionSyntax)parent;
return node == binaryParent.Right;
}
case SyntaxKind.ArrowExpressionClause: // =>
{
var arrowClauseParent = (ArrowExpressionClauseSyntax)parent;
return node == arrowClauseParent.Expression;
}
// We do not support && and || because
// 1. The precedence would not syntactically allow it
// 2. It isn't clear what the semantics should be
// 3. It isn't clear what use cases would motivate us to change the precedence to support it
default:
return false;
}
}
private BoundExpression BindTupleExpression(TupleExpressionSyntax node, DiagnosticBag diagnostics)
{
SeparatedSyntaxList<ArgumentSyntax> arguments = node.Arguments;
......
......@@ -3575,10 +3575,10 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr
// If the return type is void then the expression is required to be a legal
// statement expression.
Debug.Assert(expressionSyntax != null || !IsValidStatementExpression(expression.Syntax, expression));
Debug.Assert(expressionSyntax != null || !IsValidExpressionBody(expressionSyntax, expression));
bool errors = false;
if (expressionSyntax == null || !IsValidStatementExpression(expressionSyntax, expression))
if (expressionSyntax == null || !IsValidExpressionBody(expressionSyntax, expression))
{
Error(diagnostics, ErrorCode.ERR_IllegalStatement, syntax);
errors = true;
......@@ -3609,6 +3609,11 @@ internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableAr
return new BoundBlock(node, locals, ImmutableArray.Create(statement)) { WasCompilerGenerated = node.Kind() != SyntaxKind.ArrowExpressionClause };
}
private static bool IsValidExpressionBody(SyntaxNode expressionSyntax, BoundExpression expression)
{
return IsValidStatementExpression(expressionSyntax, expression) || expressionSyntax.Kind() == SyntaxKind.ThrowExpression;
}
/// <summary>
/// Binds an expression-bodied member with expression e as either { return e;} or { e; }.
/// </summary>
......
......@@ -156,6 +156,7 @@ private static void AssertTrivialConversion(ConversionKind kind)
case ConversionKind.ImplicitNumeric:
case ConversionKind.ImplicitReference:
case ConversionKind.ImplicitEnumeration:
case ConversionKind.ImplicitThrow:
case ConversionKind.AnonymousFunction:
case ConversionKind.Boxing:
case ConversionKind.NullLiteral:
......@@ -195,6 +196,7 @@ internal static Conversion GetTrivialConversion(ConversionKind kind)
internal static Conversion ImplicitNumeric => new Conversion(ConversionKind.ImplicitNumeric);
internal static Conversion ImplicitReference => new Conversion(ConversionKind.ImplicitReference);
internal static Conversion ImplicitEnumeration => new Conversion(ConversionKind.ImplicitEnumeration);
internal static Conversion ImplicitThrow => new Conversion(ConversionKind.ImplicitThrow);
internal static Conversion AnonymousFunction => new Conversion(ConversionKind.AnonymousFunction);
internal static Conversion Boxing => new Conversion(ConversionKind.Boxing);
internal static Conversion NullLiteral => new Conversion(ConversionKind.NullLiteral);
......@@ -441,6 +443,17 @@ public bool IsEnumeration
}
}
/// <summary>
/// Returns true if the conversion is an implicit throw conversion.
/// </summary>
public bool IsThrow
{
get
{
return Kind == ConversionKind.ImplicitThrow;
}
}
// TODO: update the language reference section number below.
/// <summary>
/// Returns true if the conversion is an interpolated string conversion.
......
......@@ -12,6 +12,7 @@ internal enum ConversionKind : byte
Identity,
ImplicitNumeric,
ImplicitEnumeration,
ImplicitThrow,
ImplicitTupleLiteral,
ImplicitTuple,
ExplicitTupleLiteral,
......
......@@ -28,6 +28,7 @@ public static bool IsImplicitConversion(this ConversionKind conversionKind)
case ConversionKind.ImplicitTupleLiteral:
case ConversionKind.ImplicitTuple:
case ConversionKind.ImplicitEnumeration:
case ConversionKind.ImplicitThrow:
case ConversionKind.ImplicitNullable:
case ConversionKind.NullLiteral:
case ConversionKind.ImplicitReference:
......
......@@ -837,6 +837,9 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi
return interpolatedStringConversion;
}
break;
case BoundKind.ThrowExpression:
return Conversion.ImplicitThrow;
}
return Conversion.NoConversion;
......
......@@ -600,6 +600,7 @@ private static bool IsEncompassingImplicitConversionKind(ConversionKind kind)
// Added for C# 7.
case ConversionKind.ImplicitTupleLiteral:
case ConversionKind.ImplicitTuple:
case ConversionKind.ImplicitThrow:
return true;
case ConversionKind.ExplicitTupleLiteral:
......
......@@ -1581,6 +1581,10 @@
<Node Name="BoundWildcardPattern" Base="BoundPattern">
</Node>
<Node Name="BoundThrowExpression" Base="BoundExpression">
<Field Name="Expression" Type="BoundExpression" Null="disallow"/>
</Node>
<!-- The node is transformed into BoundLocal or BoundFieldAccess after inference -->
<Node Name="OutVariablePendingInference" Base="BoundExpression">
<!-- Type is not significant for this node type; always null -->
......
......@@ -725,6 +725,7 @@ Semantics.ConversionKind IConversionExpression.ConversionKind
case CSharp.ConversionKind.ImplicitDynamic:
case CSharp.ConversionKind.ExplicitEnumeration:
case CSharp.ConversionKind.ImplicitEnumeration:
case CSharp.ConversionKind.ImplicitThrow:
case CSharp.ConversionKind.ImplicitTupleLiteral:
case CSharp.ConversionKind.ImplicitTuple:
case CSharp.ConversionKind.ExplicitTupleLiteral:
......@@ -3017,6 +3018,24 @@ protected override OperationKind ExpressionKind
}
}
partial class BoundThrowExpression
{
public override void Accept(OperationVisitor visitor)
{
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
visitor.VisitNoneOperation(this);
}
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
return visitor.VisitNoneOperation(this, argument);
}
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
protected override OperationKind ExpressionKind => OperationKind.None;
}
internal partial class BoundDeclarationPattern
{
public BoundDeclarationPattern(SyntaxNode syntax, LocalSymbol localSymbol, BoundTypeExpression declaredType, bool isVar, bool hasErrors = false)
......
......@@ -61,6 +61,14 @@ public override object Display
}
}
internal sealed partial class BoundThrowExpression
{
public override object Display
{
get { return MessageID.IDS_ThrowExpression.Localize(); }
}
}
internal partial class BoundTupleExpression
{
public override object Display
......
......@@ -8755,6 +8755,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to A throw expression is not allowed in this context..
/// </summary>
internal static string ERR_ThrowMisplaced {
get {
return ResourceManager.GetString("ERR_ThrowMisplaced", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Catch clauses cannot follow the general catch clause of a try statement.
/// </summary>
......@@ -9998,6 +10007,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to throw expression.
/// </summary>
internal static string IDS_FeatureThrowExpression {
get {
return ResourceManager.GetString("IDS_FeatureThrowExpression", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to tuples.
/// </summary>
......
......@@ -120,6 +120,9 @@
<data name="IDS_NULL" xml:space="preserve">
<value>&lt;null&gt;</value>
</data>
<data name="IDS_ThrowExpression" xml:space="preserve">
<value>&lt;throw expression&gt;</value>
</data>
<data name="IDS_RELATEDERROR" xml:space="preserve">
<value>(Location of symbol related to previous error)</value>
</data>
......@@ -210,6 +213,9 @@
<data name="IDS_FeaturePatternMatching" xml:space="preserve">
<value>pattern matching</value>
</data>
<data name="IDS_FeatureThrowExpression" xml:space="preserve">
<value>throw expression</value>
</data>
<data name="IDS_FeatureImplicitArray" xml:space="preserve">
<value>implicitly typed array</value>
</data>
......@@ -4953,4 +4959,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_ExpressionVariableInConstructorOrFieldInitializer" xml:space="preserve">
<value>Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers.</value>
</data>
<data name="ERR_ThrowMisplaced" xml:space="preserve">
<value>A throw expression is not allowed in this context.</value>
</data>
</root>
\ No newline at end of file
......@@ -75,6 +75,7 @@ private void EmitConversion(BoundConversion conversion)
case ConversionKind.ExplicitTuple:
case ConversionKind.ImplicitDynamic:
case ConversionKind.ExplicitDynamic:
case ConversionKind.ImplicitThrow:
// None of these things should reach codegen (yet? maybe?)
throw ExceptionUtilities.UnexpectedValue(conversion.ConversionKind);
case ConversionKind.PointerToVoid:
......
......@@ -302,6 +302,10 @@ private void EmitExpressionCore(BoundExpression expression, bool used)
EmitPseudoVariableValue((BoundPseudoVariable)expression, used);
break;
case BoundKind.ThrowExpression:
EmitThrowExpression((BoundThrowExpression)expression, used);
break;
case BoundKind.Void:
Debug.Assert(!used);
break;
......@@ -315,6 +319,14 @@ private void EmitExpressionCore(BoundExpression expression, bool used)
}
}
private void EmitThrowExpression(BoundThrowExpression node, bool used)
{
this.EmitThrow(node.Expression);
// to satisfy invariants, we push a default value to pretend to adjust the stack height
EmitDefaultValue(node.Type, used, node.Syntax);
}
private void EmitComplexConditionalReceiver(BoundComplexConditionalReceiver expression, bool used)
{
Debug.Assert(!expression.Type.IsReferenceType);
......
......@@ -140,20 +140,24 @@ private void EmitNoOpStatement(BoundNoOpStatement statement)
private void EmitThrowStatement(BoundThrowStatement node)
{
BoundExpression expr = node.ExpressionOpt;
if (expr != null)
EmitThrow(node.ExpressionOpt);
}
private void EmitThrow(BoundExpression thrown)
{
if (thrown != null)
{
this.EmitExpression(expr, true);
this.EmitExpression(thrown, true);
var exprType = expr.Type;
var exprType = thrown.Type;
// Expression type will be null for "throw null;".
if (exprType?.TypeKind == TypeKind.TypeParameter)
{
this.EmitBox(exprType, expr.Syntax);
this.EmitBox(exprType, thrown.Syntax);
}
}
_builder.EmitThrow(isRethrow: expr == null);
_builder.EmitThrow(isRethrow: thrown == null);
}
private void EmitConditionalGoto(BoundConditionalGoto boundConditionalGoto)
......
......@@ -1354,6 +1354,7 @@ internal enum ErrorCode
// Available = 8112, 8113, 8114, 8115
#region diagnostics for pattern-matching introduced in C# 7
ERR_ThrowMisplaced = 8115,
ERR_PatternNullableType = 8116,
ERR_BadIsPatternExpression = 8117,
ERR_SwitchExpressionValueExpected = 8119,
......
......@@ -56,6 +56,7 @@ internal enum MessageID
IDS_FeatureNullable = MessageBase + 12528,
IDS_Lambda = MessageBase + 12531,
IDS_FeaturePatternMatching = MessageBase + 12532,
IDS_FeatureThrowExpression = MessageBase + 12533,
IDS_FeatureImplicitArray = MessageBase + 12557,
IDS_FeatureImplicitLocal = MessageBase + 12558,
......@@ -122,6 +123,7 @@ internal enum MessageID
IDS_FeatureOutVar = MessageBase + 12713,
IDS_FeatureIOperation = MessageBase + 12714,
IDS_ThrowExpression = MessageBase + 12715,
}
// Message IDs may refer to strings that need to be localized.
......@@ -184,6 +186,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureLocalFunctions:
case MessageID.IDS_FeatureRefLocalsReturns:
case MessageID.IDS_FeaturePatternMatching:
case MessageID.IDS_FeatureThrowExpression:
case MessageID.IDS_FeatureTuples:
case MessageID.IDS_FeatureOutVar:
return LanguageVersion.CSharp7;
......
......@@ -923,6 +923,13 @@ public override BoundNode VisitAttribute(BoundAttribute node)
return null;
}
public override BoundNode VisitThrowExpression(BoundThrowExpression node)
{
VisitRvalue(node.Expression);
SetUnreachable();
return node;
}
public override BoundNode VisitIsPatternExpression(BoundIsPatternExpression node)
{
VisitRvalue(node.Expression);
......
......@@ -1109,6 +1109,13 @@ public override BoundNode VisitSequence(BoundSequence node)
return builder.Update(value);
}
public override BoundNode VisitThrowExpression(BoundThrowExpression node)
{
BoundSpillSequenceBuilder builder = null;
BoundExpression operand = VisitExpression(ref builder, node.Expression);
return UpdateExpression(builder, node.Update(operand, node.Type));
}
/// <summary>
/// If an expression node that declares synthesized short-lived locals (currently only sequence) contains an await, these locals become long-lived since their
/// values may be read by code that follows the await. We promote these variables to long-lived of kind <see cref="SynthesizedLocalKind.AwaitSpill"/>.
......
......@@ -328,6 +328,7 @@ private static bool IsSafeForReordering(BoundExpression expression, RefKind kind
// expression trees rewrite this later.
// it is a kind of user defined conversions on IntPtr and in some cases can fail
case ConversionKind.IntPtr:
case ConversionKind.ImplicitThrow:
return false;
default:
......
......@@ -235,6 +235,13 @@ private static bool IsFloatPointExpressionOfUnknownPrecision(BoundExpression rew
return rewrittenOperand;
}
case ConversionKind.ImplicitThrow:
{
// the operand must be a bound throw expression
var operand = (BoundThrowExpression)rewrittenOperand;
return _factory.ThrowExpression(operand.Expression, rewrittenType);
}
case ConversionKind.ImplicitEnumeration:
// A conversion from constant zero to nullable is actually classified as an
// implicit enumeration conversion, not an implicit nullable conversion.
......
......@@ -941,6 +941,11 @@ public BoundStatement ThrowNull()
return Throw(Null(Compilation.GetWellKnownType(Microsoft.CodeAnalysis.WellKnownType.System_Exception)));
}
public BoundExpression ThrowExpression(BoundExpression thrown, TypeSymbol type)
{
return new BoundThrowExpression(thrown.Syntax, thrown, type) { WasCompilerGenerated = true };
}
public BoundExpression Null(TypeSymbol type)
{
BoundExpression nullLiteral = new BoundLiteral(Syntax, ConstantValue.Null, type) { WasCompilerGenerated = true };
......
......@@ -8986,6 +8986,7 @@ private bool IsPossibleExpression()
case SyntaxKind.NewKeyword:
case SyntaxKind.DelegateKeyword:
case SyntaxKind.ColonColonToken: // bad aliased name
case SyntaxKind.ThrowKeyword:
return true;
case SyntaxKind.IdentifierToken:
// Specifically allow the from contextual keyword, because it can always be the start of an
......@@ -9279,6 +9280,13 @@ private ExpressionSyntax ParseSubExpressionCore(Precedence precedence)
skipped = this.AddError(skipped, ErrorCode.ERR_InvalidExprTerm, this.CurrentToken.Text);
leftOperand = AddTrailingSkippedSyntax(this.CreateMissingIdentifierName(), skipped);
}
else if (tk == SyntaxKind.ThrowKeyword)
{
var result = ParseThrowExpression();
// we parse a throw expression even at the wrong precedence for better recovery
return (precedence <= Precedence.Coalescing) ? result :
this.AddError(result, ErrorCode.ERR_InvalidExprTerm, SyntaxFacts.GetText(tk));
}
else
{
// Not a unary operator - get a primary expression.
......@@ -9404,6 +9412,14 @@ private ExpressionSyntax ParseSubExpressionCore(Precedence precedence)
return leftOperand;
}
private ExpressionSyntax ParseThrowExpression()
{
var throwToken = this.EatToken(SyntaxKind.ThrowKeyword);
var thrown = this.ParseSubExpression(Precedence.Coalescing);
var result = _syntaxFactory.ThrowExpression(throwToken, thrown);
return CheckFeatureAvailability(result, MessageID.IDS_FeatureThrowExpression);
}
private ExpressionSyntax ParseIsExpression(ExpressionSyntax leftOperand, SyntaxToken opToken)
{
var node = this.ParseTypeOrPattern();
......
......@@ -5,6 +5,7 @@
*REMOVED*override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode.SerializeTo(System.IO.Stream stream, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> void
Microsoft.CodeAnalysis.CSharp.CSharpParseOptions.CSharpParseOptions(Microsoft.CodeAnalysis.CSharp.LanguageVersion languageVersion = Microsoft.CodeAnalysis.CSharp.LanguageVersion.Default, Microsoft.CodeAnalysis.DocumentationMode documentationMode = Microsoft.CodeAnalysis.DocumentationMode.Parse, Microsoft.CodeAnalysis.SourceCodeKind kind = Microsoft.CodeAnalysis.SourceCodeKind.Regular, System.Collections.Generic.IEnumerable<string> preprocessorSymbols = null) -> void
Microsoft.CodeAnalysis.CSharp.CSharpParseOptions.SpecifiedLanguageVersion.get -> Microsoft.CodeAnalysis.CSharp.LanguageVersion
Microsoft.CodeAnalysis.CSharp.Conversion.IsThrow.get -> bool
Microsoft.CodeAnalysis.CSharp.Conversion.IsTupleConversion.get -> bool
Microsoft.CodeAnalysis.CSharp.Conversion.IsTupleLiteralConversion.get -> bool
Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp7 = 7 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion
......@@ -123,6 +124,12 @@ Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax.Identifier.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax.WithIdentifier(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax.Expression.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax.ThrowKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken throwKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax.WithThrowKeyword(Microsoft.CodeAnalysis.SyntaxToken throwKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax.Name.get -> Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax.Type.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax
......@@ -182,6 +189,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.ParenthesizedVariableDesignation = 8931
Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefExpression = 9050 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.RefType = 9051 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleVariableDesignation = 8930 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.ThrowExpression = 9052 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleElement = 8926 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleExpression = 8927 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleType = 8925 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
......@@ -207,6 +215,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitParenthesizedVa
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitRefType(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitSingleVariableDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitThrowExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitTupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitTupleExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitTupleType(Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode
......@@ -253,6 +262,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Accept(Microsoft.Cod
override Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
override Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax.Accept<TResult>(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult> visitor) -> TResult
override Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void
......@@ -296,6 +307,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefExpression(Microsoft.CodeA
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SingleVariableDesignation(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ThrowExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ThrowExpression(Microsoft.CodeAnalysis.SyntaxToken throwKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax name) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TupleExpression(Microsoft.CodeAnalysis.SeparatedSyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax> arguments = default(Microsoft.CodeAnalysis.SeparatedSyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax>)) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax
......@@ -320,6 +333,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitParenthesizedVari
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefType(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitSingleVariableDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitThrowExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax node) -> void
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleType(Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax node) -> void
......@@ -339,6 +353,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitParenthe
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitRefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitRefType(Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitSingleVariableDesignation(Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitThrowExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitTupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitTupleExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax node) -> TResult
virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor<TResult>.VisitTupleType(Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax node) -> TResult
......
......@@ -1693,6 +1693,13 @@
<summary>Creates an IsPatternExpressionSyntax node.</summary>
</FactoryComment>
</Node>
<Node Name="ThrowExpressionSyntax" Base="ExpressionSyntax">
<Kind Name="ThrowExpression" />
<Field Name="ThrowKeyword" Type="SyntaxToken" Optional="false">
<Kind Name="ThrowKeyword"/>
</Field>
<Field Name="Expression" Type="ExpressionSyntax" Optional="false"/>
</Node>
<Node Name="WhenClauseSyntax" Base="CSharpSyntaxNode">
<Kind Name="WhenClause" />
<Field Name="WhenKeyword" Type="SyntaxToken">
......
......@@ -561,5 +561,6 @@ public enum SyntaxKind : ushort
DeclarationExpression = 9040,
RefExpression = 9050,
RefType = 9051,
ThrowExpression = 9052,
}
}
......@@ -14713,5 +14713,223 @@ public static void Main()
Diagnostic(ErrorCode.ERR_BadUnaryOp, "(1, null) is Program").WithArguments("is", "(int, <null>)").WithLocation(6, 13)
);
}
[Fact]
public void ThrowExpressionForParameterValidation()
{
var source =
@"using System;
class Program
{
public static void Main(string[] args)
{
foreach (var s in new[] { ""0123"", ""foo"" })
{
Console.Write(s + "" "");
try
{
Console.WriteLine(Ver(s));
}
catch (ArgumentException)
{
Console.WriteLine(""throws"");
}
}
}
static int Ver(string s)
{
var result = int.TryParse(s, out int k) ? k : throw new ArgumentException(nameof(s));
return k; // definitely assigned!
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput:
@"0123 123
foo throws");
}
[Fact]
public void ThrowExpressionWithNullable01()
{
var source =
@"using System;
class Program
{
public static void Main(string[] args)
{
Console.WriteLine(M(1));
try
{
Console.WriteLine(M(null));
}
catch (Exception)
{
Console.WriteLine(""thrown"");
}
}
static int M(int? data)
{
return data ?? throw null;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput:
@"1
thrown");
}
[Fact]
public void ThrowExpressionWithNullable02()
{
var source =
@"using System;
class Program
{
public static void Main(string[] args)
{
Console.WriteLine(M(1));
try
{
Console.WriteLine(M(null));
}
catch (Exception)
{
Console.WriteLine(""thrown"");
}
}
static string M(object data)
{
return data?.ToString() ?? throw null;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput:
@"1
thrown");
}
[Fact]
public void ThrowExpressionWithNullable03()
{
var source =
@"using System;
using System.Threading.Tasks;
class Program
{
public static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
foreach (var i in new[] { 1, 2 })
{
try
{
var used = (await Foo(i))?.ToString() ?? throw await Bar(i);
}
catch (Exception ex)
{
Console.WriteLine(""thrown "" + ex.Message);
}
}
}
static async Task<object> Foo(int i)
{
await Task.Yield();
return (i == 1) ? i : (object)null;
}
static async Task<Exception> Bar(int i)
{
await Task.Yield();
Console.WriteLine(""making exception "" + i);
return new Exception(i.ToString());
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.DebugExe,
references: new[] { MscorlibRef_v4_0_30316_17626, SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929 });
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput:
@"making exception 2
thrown 2");
}
[Fact]
public void ThrowExpressionPrecedence01()
{
var source =
@"using System;
class Program
{
public static void Main(string[] args)
{
Exception ex = null;
try
{
// The ?? operator is right-associative, even under 'throw'
ex = ex ?? throw ex ?? throw new ArgumentException(""blue"");
}
catch (ArgumentException x)
{
Console.WriteLine(x.Message);
}
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput:
@"blue");
}
[Fact]
public void ThrowExpressionPrecedence02()
{
var source =
@"using System;
class Program
{
public static void Main(string[] args)
{
MyException ex = null;
try
{
// Throw expression binds looser than +
ex = ex ?? throw ex + 1;
}
catch (MyException x)
{
Console.WriteLine(x.Message);
}
}
}
class MyException : Exception
{
public MyException(string message) : base(message) {}
public static MyException operator +(MyException left, int right)
{
return new MyException(""green"");
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput:
@"green");
}
}
}
......@@ -7,7 +7,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
[CompilerTrait(CompilerFeature.Patterns)]
public class PatternParsingTexts : CSharpTestBase
public class PatternParsingTexts : ParsingTests
{
[Fact]
public void CasePatternVersusFeatureFlag()
......@@ -42,5 +42,163 @@ public static void Main(string[] args)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "args[0] is string s").WithArguments("pattern matching", "7").WithLocation(15, 18)
);
}
[Fact]
public void ThrowExpression_Good()
{
var test = @"using System;
class C
{
public static void Sample(bool b, string s)
{
void NeverReturnsFunction() => throw new NullReferenceException();
int x = b ? throw new NullReferenceException() : 1;
x = b ? 2 : throw new NullReferenceException();
s = s ?? throw new NullReferenceException();
NeverReturnsFunction();
throw new NullReferenceException() ?? throw new NullReferenceException() ?? throw null;
}
public static void NeverReturns() => throw new NullReferenceException();
}";
CreateCompilationWithMscorlib(test).VerifyDiagnostics();
CreateCompilationWithMscorlib(test, parseOptions: TestOptions.Regular6).VerifyDiagnostics(
// (6,14): error CS8059: Feature 'local functions' is not available in C# 6. Please use language version 7 or greater.
// void NeverReturnsFunction() => throw new NullReferenceException();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "NeverReturnsFunction").WithArguments("local functions", "7").WithLocation(6, 14),
// (6,40): error CS8059: Feature 'throw expression' is not available in C# 6. Please use language version 7 or greater.
// void NeverReturnsFunction() => throw new NullReferenceException();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "throw new NullReferenceException()").WithArguments("throw expression", "7").WithLocation(6, 40),
// (7,21): error CS8059: Feature 'throw expression' is not available in C# 6. Please use language version 7 or greater.
// int x = b ? throw new NullReferenceException() : 1;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "throw new NullReferenceException()").WithArguments("throw expression", "7").WithLocation(7, 21),
// (8,21): error CS8059: Feature 'throw expression' is not available in C# 6. Please use language version 7 or greater.
// x = b ? 2 : throw new NullReferenceException();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "throw new NullReferenceException()").WithArguments("throw expression", "7").WithLocation(8, 21),
// (9,18): error CS8059: Feature 'throw expression' is not available in C# 6. Please use language version 7 or greater.
// s = s ?? throw new NullReferenceException();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "throw new NullReferenceException()").WithArguments("throw expression", "7").WithLocation(9, 18),
// (11,47): error CS8059: Feature 'throw expression' is not available in C# 6. Please use language version 7 or greater.
// throw new NullReferenceException() ?? throw new NullReferenceException() ?? throw null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "throw new NullReferenceException() ?? throw null").WithArguments("throw expression", "7").WithLocation(11, 47),
// (11,85): error CS8059: Feature 'throw expression' is not available in C# 6. Please use language version 7 or greater.
// throw new NullReferenceException() ?? throw new NullReferenceException() ?? throw null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "throw null").WithArguments("throw expression", "7").WithLocation(11, 85),
// (13,42): error CS8059: Feature 'throw expression' is not available in C# 6. Please use language version 7 or greater.
// public static void NeverReturns() => throw new NullReferenceException();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "throw new NullReferenceException()").WithArguments("throw expression", "7").WithLocation(13, 42)
);
}
[Fact]
public void ThrowExpression_Bad()
{
var test = @"using System;
class C
{
public static void Sample(bool b, string s)
{
// throw expression at wrong precedence
s = s + throw new NullReferenceException();
if (b || throw new NullReferenceException()) { }
// throw expression where not permitted
var z = from x in throw new NullReferenceException() select x;
M(throw new NullReferenceException());
throw throw null;
(int, int) w = (1, throw null);
return throw null;
}
static void M(string s) {}
}";
CreateCompilationWithMscorlib(test).VerifyDiagnostics(
// (7,17): error CS1525: Invalid expression term 'throw'
// s = s + throw new NullReferenceException();
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "throw new NullReferenceException()").WithArguments("throw").WithLocation(7, 17),
// (8,18): error CS1525: Invalid expression term 'throw'
// if (b || throw new NullReferenceException()) { }
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "throw new NullReferenceException()").WithArguments("throw").WithLocation(8, 18),
// (11,27): error CS8115: A throw expression is not allowed in this context.
// var z = from x in throw new NullReferenceException() select x;
Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(11, 27),
// (12,11): error CS8115: A throw expression is not allowed in this context.
// M(throw new NullReferenceException());
Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(12, 11),
// (13,15): error CS8115: A throw expression is not allowed in this context.
// throw throw null;
Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(13, 15),
// (14,9): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported
// (int, int) w = (1, throw null);
Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(int, int)").WithArguments("System.ValueTuple`2").WithLocation(14, 9),
// (14,28): error CS8115: A throw expression is not allowed in this context.
// (int, int) w = (1, throw null);
Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(14, 28),
// (14,24): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported
// (int, int) w = (1, throw null);
Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(1, throw null)").WithArguments("System.ValueTuple`2").WithLocation(14, 24),
// (15,16): error CS8115: A throw expression is not allowed in this context.
// return throw null;
Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(15, 16),
// (14,9): warning CS0162: Unreachable code detected
// (int, int) w = (1, throw null);
Diagnostic(ErrorCode.WRN_UnreachableCode, "(").WithLocation(14, 9)
);
}
[Fact]
public void ThrowExpression()
{
var tree = UsingTree(@"
class C
{
int x = y ?? throw null;
}", options: TestOptions.Regular);
N(SyntaxKind.CompilationUnit);
{
N(SyntaxKind.ClassDeclaration);
{
N(SyntaxKind.ClassKeyword);
N(SyntaxKind.IdentifierToken);
N(SyntaxKind.OpenBraceToken);
N(SyntaxKind.FieldDeclaration);
{
N(SyntaxKind.VariableDeclaration);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.IntKeyword);
}
N(SyntaxKind.VariableDeclarator);
{
N(SyntaxKind.IdentifierToken);
N(SyntaxKind.EqualsValueClause);
{
N(SyntaxKind.EqualsToken);
N(SyntaxKind.CoalesceExpression);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken);
}
N(SyntaxKind.QuestionQuestionToken);
N(SyntaxKind.ThrowExpression);
{
N(SyntaxKind.ThrowKeyword);
N(SyntaxKind.NullLiteralExpression);
{
N(SyntaxKind.NullKeyword);
}
}
}
}
}
}
N(SyntaxKind.SemicolonToken);
}
N(SyntaxKind.CloseBraceToken);
}
N(SyntaxKind.EndOfFileToken);
}
EOF();
}
}
}
......@@ -4348,8 +4348,7 @@ class C
expr: "throw new System.Exception()",
resultProperties: out resultProperties,
error: out error);
Assert.Equal("error CS1525: Invalid expression term 'throw'", error);
Assert.Equal("error CS8115: A throw expression is not allowed in this context.", error);
}
[WorkItem(1016555, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1016555")]
......
......@@ -331,6 +331,7 @@ namespace My
{
++i;
if (i is int q) continue;
void LocalFcn() => throw null;
break;
}
do
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册