--- /dev/null
+// CS0128: A local variable named `s' is already defined in this scope
+// Line: 12
+
+class C
+{
+ public static void Main ()
+ {
+ object o = null;
+
+ var x1 = o is string s;
+ var x2 = o is string s;
+ }
+}
--- /dev/null
+// CS0136: A local variable named `s' cannot be declared in this scope because it would give a different meaning to `s', which is already used in a `parent or current' scope to denote something else
+// Line: 10
+
+internal class Program
+{
+ public static void Main ()
+ {
+ object o = null;
+ if (o is string s) {
+ int s = 1;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS0165: Use of unassigned local variable `s'
+// Line: 12
+
+class X
+{
+ static string Foo (object arg)
+ {
+ if (arg is string s) {
+
+ }
+
+ return s;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS1644: Feature `pattern matching' cannot be used because it is not part of the C# 6.0 language specification
+// Line: 9
+// Compiler options: -langversion:6
+
+class Class
+{
+ static void Foo (object arg)
+ {
+ if (arg is Type v) {
+ return;
+ }
+ }
+}
--- /dev/null
+// CS8116: The nullable type `byte?' pattern matching is not allowed. Consider using underlying type `byte'
+// Line: 11
+
+using System;
+
+class C
+{
+ public static void Main ()
+ {
+ object o2 = null;
+ bool r2 = o2 is Nullable<byte> t3;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8117: Cannot use null as pattern matching operand
+// Line: 8
+
+class C
+{
+ static object Test ()
+ {
+ return null is object res;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8122: An expression tree cannot contain a pattern matching operator
+// Line: 12
+
+using System;
+using System.Linq.Expressions;
+
+class X
+{
+ public static void Main ()
+ {
+ object o = 1;
+ Expression<Func<bool>> e = () => o is int y;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers
+// Line: 8
+
+using System;
+
+public class C
+{
+ event Action H = Foo (out var res);
+
+ static Action Foo (out int arg)
+ {
+ arg = 2;
+ return null;
+ }
+}
--- /dev/null
+// CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers
+// Line: 6
+
+public class C
+{
+ bool res = Foo () is string s;
+
+ static object Foo ()
+ {
+ return null;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers
+// Line: 6
+
+class X
+{
+ public static bool Test { get; } = Foo () is bool x;
+
+ static object Foo ()
+ {
+ return false;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8208: The type `dynamic' pattern matching is not allowed
+// Line: 9
+
+static class Program
+{
+ public static void Main ()
+ {
+ object o = null;
+ if (o is dynamic res) {
+ }
+ }
+}
variable.SetAssigned (DefiniteAssignment, generatedAssignment);
}
+ public void SetVariableAssigned (VariableInfo variable, DefiniteAssignmentBitSet da)
+ {
+ variable.SetAssigned (da, false);
+ }
+
public void SetStructFieldAssigned (VariableInfo variable, string name)
{
variable.SetStructFieldAssigned (DefiniteAssignment, name);
$$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), null);
lbag.AddLocation ($$, GetLocation ($1));
}
- | COMMA IDENTIFIER ASSIGN
- {
- ++lexer.parsing_block;
- }
- event_variable_initializer
+ | COMMA IDENTIFIER ASSIGN event_variable_initializer
{
- --lexer.parsing_block;
var lt = (LocatedToken) $2;
- $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), (Expression) $5);
+ $$ = new FieldDeclarator (new SimpleMemberName (lt.Value, lt.Location), (Expression) $4);
lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3));
}
;
if ((current_event_field.ModFlags & Modifiers.ABSTRACT) != 0) {
report.Error (74, lexer.Location, "`{0}': abstract event cannot have an initializer",
current_event_field.GetSignatureForError ());
- }
+ }
+
+ ++lexer.parsing_block;
+ current_local_parameters = ParametersCompiled.EmptyReadOnlyParameters;
+ start_block (lexer.Location);
}
variable_initializer
{
$$ = $2;
+
+ --lexer.parsing_block;
+ end_block (lexer.Location);
+ current_local_parameters = null;
}
;
{
var is_expr = new Is ((Expression) $1, (Expression) $3, GetLocation ($2));
if ($4 != null) {
- if (lang_version != LanguageVersion.Experimental)
- FeatureIsNotAvailable (GetLocation ($4), "type pattern matching");
+ if (lang_version < LanguageVersion.V_7)
+ FeatureIsNotAvailable (GetLocation ($4), "pattern matching");
var lt = (LocatedToken) $4;
- is_expr.Variable = new LocalVariable (current_block, lt.Value, lt.Location);
- current_block.AddLocalName (is_expr.Variable);
+ var lv = new LocalVariable (current_block, lt.Value, lt.Location);
+ is_expr.Variable = lv;
+ current_block.AddLocalName (lv);
}
$$ = is_expr;
}
}
-Block
-end_block (Location loc)
+Block end_block (Location loc)
{
Block retval = current_block.Explicit;
retval.SetEndLocation (loc);
return null;
}
+ protected void CheckExpressionVariable (ResolveContext rc)
+ {
+ if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
+ rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
+ } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
+ rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
+ }
+ }
+
public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
{
rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
ec.Emit (OpCodes.Pop);
}
+ public virtual void EmitPrepare (EmitContext ec)
+ {
+ }
+
//
// Emits the expression into temporary field variable. The method
// should be used for await expressions only
expr.EmitSideEffect (ec);
}
+ public override void EmitPrepare (EmitContext ec)
+ {
+ expr.EmitPrepare (ec);
+ }
+
public override void FlowAnalysis (FlowAnalysisContext fc)
{
expr.FlowAnalysis (fc);
public override Expression CreateExpressionTree (ResolveContext ec)
{
if (Variable != null)
- throw new NotSupportedException ();
+ ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator");
Arguments args = Arguments.CreateForExpressionTree (ec, null,
expr.CreateExpressionTree (ec),
ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
}
+ public override void EmitPrepare (EmitContext ec)
+ {
+ base.EmitPrepare (ec);
+
+ if (Variable != null)
+ Variable.CreateBuilder (ec);
+ }
+
void EmitPatternMatch (EmitContext ec)
{
var no_match = ec.DefineLabel ();
value_on_stack = false;
}
- Variable.CreateBuilder (ec);
+ //
+ // It's ok to have variable builder create out of order. It simplified emit
+ // of statements like while (condition) { }
+ //
+ if (!Variable.Created)
+ Variable.CreateBuilder (ec);
+
Variable.EmitAssign (ec);
if (expr_unwrap != null) {
fc.SetVariableAssigned (Variable.VariableInfo, true);
}
+ public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+ {
+ if (Variable == null) {
+ base.FlowAnalysisConditional (fc);
+ return;
+ }
+
+ expr.FlowAnalysis (fc);
+
+ fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
+ fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
+
+ fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
+ }
+
protected override void ResolveProbeType (ResolveContext rc)
{
if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
Expression ResolveResultExpression (ResolveContext ec)
{
+ if (Variable != null) {
+ if (expr is NullLiteral) {
+ ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
+ return this;
+ }
+
+ CheckExpressionVariable (ec);
+ }
+
TypeSpec d = expr.Type;
bool d_is_nullable = false;
// If E is a method group or the null literal, or if the type of E is a reference
// type or a nullable type and the value of E is null, the result is false
//
- if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
+ if (expr.IsNull)
return CreateConstantResult (ec, false);
if (d.IsNullableType) {
TypeSpec t = probe_type_expr;
bool t_is_nullable = false;
if (t.IsNullableType) {
+ if (Variable != null) {
+ ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
+ t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
+ }
+
var ut = Nullable.NullableInfo.GetUnderlyingType (t);
if (!ut.IsGenericParameter) {
t = ut;
return ResolveGenericParameter (ec, d, tps);
if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
- ec.Report.Warning (1981, 3, loc,
- "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
- OperatorName, t.GetSignatureForError ());
+ if (Variable != null) {
+ ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
+ } else {
+ ec.Report.Warning (1981, 3, loc,
+ "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
+ OperatorName, t.GetSignatureForError ());
+ }
}
if (TypeManager.IsGenericParameter (d))
bool DoResolveCommon (ResolveContext rc)
{
- if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
- rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
- } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
- rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
- }
+ CheckExpressionVariable (rc);
var var_expr = VariableType as VarExpr;
if (var_expr != null) {
ec.Emit (OpCodes.Br, ec.LoopBegin);
ec.MarkLabel (while_loop);
+ expr.EmitPrepare (ec);
+
Statement.Emit (ec);
ec.MarkLabel (ec.LoopBegin);
}
}
+ public bool Created {
+ get {
+ return builder != null;
+ }
+ }
+
public bool IsDeclared {
get {
return type != null;
# csXXXX.cs IGNORE : adds test to ignore list
gtest-230.cs
+test-pattern-02.cs
-// Compiler options: -langversion:experimental
-
using System;
class TypePattern
{
object o = 3;
bool r = o is System.String t1;
- if (t1 != null)
- return 1;
-
if (r)
return 2;
if (o is string t2)
return 3;
- if (t2 != null)
- return 4;
-
- object o2 = (int?) 4;
- bool r2 = o2 is byte? t3;
-
- if (t3 != null)
- return 5;
-
- if (r2)
- return 6;
-
long? l = 5;
bool r3 = l is long t4;
- if (t4 != 5)
- return 7;
if (!r3)
return 8;
Console.WriteLine ("ok");
return 0;
}
+
+ static void Test1 (object arg)
+ {
+ while (arg is int b) {
+ b = 2;
+ }
+ }
+
+ static string Test2 (object arg)
+ {
+ if (arg is string s) {
+ return s;
+ } else {
+ s = "";
+ }
+
+ return s;
+ }
}
\ No newline at end of file
object o4 = (byte?)255;
var ggg = o4 is 255;
- if (!ggg)
+ if (ggg)
return 8;
if (o4 is null)
return 9;
object o5 = (double)-255;
- if (!(o5 is -byte.MaxValue))
+ if (o5 is -byte.MaxValue)
return 10;
object o6 = MyEnum.V_4;
<test name="test-pattern-01.cs">
<type name="TypePattern">
<method name="Int32 Main()" attrs="150">
- <size>227</size>
- </method>
- <method name="Void .ctor()" attrs="6278">
- <size>7</size>
- </method>
- </type>
- </test>
- <test name="test-pattern-02.cs">
- <type name="ConstantPattern">
- <method name="Int32 Main()" attrs="150">
- <size>609</size>
+ <size>118</size>
</method>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
- </type>
- <type name="<PatternMatchingHelper>">
- <method name="Boolean NumberMatcher(System.Object, System.Object, Boolean)" attrs="150">
- <size>69</size>
+ <method name="Void Test1(System.Object)" attrs="145">
+ <size>24</size>
</method>
- </type>
- <type name="ConstantPattern">
- <method name="Boolean Generic[T](T)" attrs="145">
- <size>28</size>
+ <method name="System.String Test2(System.Object)" attrs="145">
+ <size>39</size>
</method>
</type>
</test>