--- /dev/null
+// CS0411: The type arguments for method `C.Foo<T>(out T)' cannot be inferred from the usage. Try specifying the type arguments explicitly
+// Line: 8
+
+public class C
+{
+ public static void Main ()
+ {
+ Foo (out var y);
+ }
+
+ static void Foo<T> (out T t)
+ {
+ t = default (T);
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS0815: An implicitly typed local variable declaration cannot be initialized with `void'
+// Line: 8
+
+class X
+{
+ public static void Main ()
+ {
+ Foo (out var x = Main ());
+ }
+
+ static void Foo (out int i)
+ {
+ i = 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS0841: A local variable `x' cannot be used before it is declared
+// Line: 8
+
+class X
+{
+ public static void Main ()
+ {
+ Foo (x, out var x);
+ }
+
+ static void Foo (int arg, out int value)
+ {
+ value = 3;
+ }
+}
\ No newline at end of file
// CS1501: No overload for method `Bar' takes `2' arguments
-// Line: 25
+// Line: 19
using System;
{
}
- static void Mismatch (string s)
- {
- }
-
- public static void Main ()
- {
- }
-
void Bar ()
{
Foo (arg: 1, a: () => {
--- /dev/null
+// CS1501: Argument `#1' cannot convert `ref string' expression to type `ref int'
+// Line: 8
+
+class C
+{
+ public static void Main ()
+ {
+ Foo (ref var x = "");
+ }
+
+ static void Foo (ref int i)
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS1615: Argument `#1' does not require `out' modifier. Consider removing `out' modifier
+// Line: 8
+
+public class C
+{
+ public static void Main ()
+ {
+ Foo (out var y);
+ }
+
+ static void Foo (int x)
+ {
+ }
+
+ static void Foo (string x)
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS1644: Feature `declaration expression' cannot be used because it is not part of the C# 5.0 language specification
+// Line: 12
+// Compiler options: -langversion:5
+
+class C
+{
+ public static void Main ()
+ {
+ int.TryParse ("0", out var v);
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8046: An expression tree cannot contain a declaration expression
+// Line: 11
+
+using System;
+using System.Linq.Expressions;
+
+class C
+{
+ static void Main()
+ {
+ Expression<Func<bool>> e = () => Out (out int x);
+ }
+
+ static bool Out (out int value)
+ {
+ value = 3;
+ return true;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8047: Declaration expression cannot be used in this context
+// Line: 8
+
+public class C
+{
+ public static void Main ()
+ {
+ dynamic target = 3;
+ var x = new Test (target, out var y);
+ }
+}
+
+class Test
+{
+ public Test (int x, out int y)
+ {
+ y = 0;
+ }
+}
\ No newline at end of file
;
named_argument
- : identifier_inside_body COLON opt_named_modifier expression_or_error
+ : identifier_inside_body COLON opt_named_modifier named_argument_expr
{
if (lang_version <= LanguageVersion.V_3)
FeatureIsNotAvailable (GetLocation ($1), "named argument");
lbag.AddLocation ($$, GetLocation($2));
}
;
+
+named_argument_expr
+ : expression_or_error
+ | declaration_expression
+ ;
opt_named_modifier
: /* empty */ { $$ = null; }
$$ = new Argument ((Expression) $2, Argument.AType.Ref);
lbag.AddLocation ($$, GetLocation ($1));
}
+ | REF declaration_expression
+ {
+ $$ = new Argument ((Expression) $2, Argument.AType.Ref);
+ }
| OUT variable_reference
{
$$ = new Argument ((Expression) $2, Argument.AType.Out);
lbag.AddLocation ($$, GetLocation ($1));
}
+ | OUT declaration_expression
+ {
+ $$ = new Argument ((Expression) $2, Argument.AType.Out);
+ }
| ARGLIST OPEN_PARENS argument_list CLOSE_PARENS
{
$$ = new Argument (new Arglist ((Arguments) $3, GetLocation ($1)));
}
;
+declaration_expression
+ : OPEN_PARENS declaration_expression CLOSE_PARENS
+ {
+ $$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1));
+ lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3));
+ }
+/*
+ | CHECKED open_parens_any declaration_expression CLOSE_PARENS
+ {
+ $$ = new CheckedExpr ((Expression) $3, GetLocation ($1));
+ lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4));
+ }
+ | UNCHECKED open_parens_any declaration_expression CLOSE_PARENS
+ {
+ $$ = new UnCheckedExpr ((Expression) $3, GetLocation ($1));
+ lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4));
+ }
+*/
+ | variable_type identifier_inside_body
+ {
+ if (lang_version < LanguageVersion.V_6)
+ FeatureIsNotAvailable (GetLocation ($1), "declaration expression");
+
+ var lt = (LocatedToken) $2;
+ var lv = new LocalVariable (current_block, lt.Value, lt.Location);
+ current_block.AddLocalName (lv);
+ $$ = new DeclarationExpression ((FullNamedExpression) $1, lv);
+ }
+ | variable_type identifier_inside_body ASSIGN expression
+ {
+ if (lang_version < LanguageVersion.V_6)
+ FeatureIsNotAvailable (GetLocation ($1), "declaration expression");
+
+ var lt = (LocatedToken) $2;
+ var lv = new LocalVariable (current_block, lt.Value, lt.Location);
+ current_block.AddLocalName (lv);
+ $$ = new DeclarationExpression ((FullNamedExpression) $1, lv) {
+ Initializer = (Expression) $4
+ };
+ }
+ ;
+
variable_reference
: expression
;
protected bool DoResolveCore (ResolveContext rc)
{
+ foreach (var arg in arguments) {
+ if (arg.Type == InternalType.VarOutType) {
+ // Should be special error message about dynamic dispatch
+ rc.Report.Error (8047, arg.Expr.Location, "Declaration expression cannot be used in this context");
+ }
+ }
+
if (rc.CurrentTypeParameters != null && rc.CurrentTypeParameters[0].IsMethodTypeParameter)
context_mvars = rc.CurrentTypeParameters;
// is used and argument is not of dynamic type
//
if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
- if (argument.Type != parameter) {
+ var arg_type = argument.Type;
+
+ if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
+ //
+ // Using dynamic for ref/out parameter can still succeed at runtime
+ //
+ if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
+ return -1;
+
+ return 1;
+ }
+
+ if (arg_type != parameter) {
+ if (arg_type == InternalType.VarOutType)
+ return 0;
+
//
// Do full equality check after quick path
//
- if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
+ if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
//
// Using dynamic for ref/out parameter can still succeed at runtime
//
- if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
+ if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
return -1;
return 2;
}
}
- if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
- //
- // Using dynamic for ref/out parameter can still succeed at runtime
- //
- if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
- return -1;
-
- return 1;
- }
-
} else {
if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
return -1;
if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
break;
- if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
+ var arg_type = a.Type;
+ if (arg_type == pt)
continue;
- break;
+ if (arg_type == InternalType.VarOutType) {
+ //
+ // Set underlying variable type based on parameter type
+ //
+ ((DeclarationExpression)a.Expr).Variable.Type = pt;
+ continue;
+ }
+
+ if (!TypeSpecComparer.IsEqual (arg_type, pt))
+ break;
}
NamedArgument na = a as NamedArgument;
}
if (a_idx != arg_count) {
+ //
+ // Convert all var out argument to error type for less confusing error reporting
+ // when no matching overload is found
+ //
+ for (; a_idx < arg_count; a_idx++) {
+ var arg = args [a_idx];
+ if (arg == null)
+ continue;
+
+ if (arg.Type == InternalType.VarOutType) {
+ ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
+ }
+ }
+
ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
return false;
}
return expr;
}
}
+
+ public class DeclarationExpression : Expression, IMemoryLocation
+ {
+ LocalVariableReference lvr;
+
+ public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
+ {
+ VariableType = variableType;
+ Variable = variable;
+ this.loc = variable.Location;
+ }
+
+ public LocalVariable Variable { get; set; }
+ public Expression Initializer { get; set; }
+ public FullNamedExpression VariableType { get; set; }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ Variable.CreateBuilder (ec);
+
+ if (Initializer != null) {
+ lvr.EmitAssign (ec, Initializer, false, false);
+ }
+
+ lvr.AddressOf (ec, mode);
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Expression t)
+ {
+ var target = (DeclarationExpression) t;
+
+ target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
+
+ if (Initializer != null)
+ target.Initializer = Initializer.Clone (clonectx);
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext rc)
+ {
+ rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
+ return null;
+ }
+
+ bool DoResolveCommon (ResolveContext rc)
+ {
+ var var_expr = VariableType as VarExpr;
+ if (var_expr != null) {
+ type = InternalType.VarOutType;
+ } else {
+ type = VariableType.ResolveAsType (rc);
+ if (type == null)
+ return false;
+ }
+
+ if (Initializer != null) {
+ Initializer = Initializer.Resolve (rc);
+
+ if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
+ type = var_expr.Type;
+ }
+ }
+
+ Variable.Type = type;
+ lvr = new LocalVariableReference (Variable, loc);
+
+ eclass = ExprClass.Variable;
+ return true;
+ }
+
+ protected override Expression DoResolve (ResolveContext rc)
+ {
+ if (DoResolveCommon (rc))
+ lvr.Resolve (rc);
+
+ return this;
+ }
+
+ public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
+ {
+ if (lvr == null && DoResolveCommon (rc))
+ lvr.ResolveLValue (rc, right_side);
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new NotImplementedException ();
+ }
+ }
//
// C# 2.0 Default value expression
void DoResolveBase (ResolveContext ec)
{
+ eclass = ExprClass.Variable;
+ type = local_info.Type;
+
//
// If we are referencing a variable from the external block
// flag it for capturing
storey.CaptureLocalVariable (ec, local_info);
}
}
-
- eclass = ExprClass.Variable;
- type = local_info.Type;
}
protected override Expression DoResolve (ResolveContext ec)
local_info.SetIsUsed ();
DoResolveBase (ec);
+
+ if (local_info.Type == InternalType.VarOutType) {
+ ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
+ GetSignatureForError ());
+
+ type = InternalType.ErrorType;
+ }
+
return this;
}
// Some types cannot be used as type arguments
//
if ((bound.Type.Kind == MemberKind.Void && !voidAllowed) || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType ||
- bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod)
+ bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod || bound.Type == InternalType.VarOutType)
return;
var a = bounds [index];
public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
public static readonly InternalType Namespace = new InternalType ("<namespace>");
public static readonly InternalType ErrorType = new InternalType ("<error>");
+ public static readonly InternalType VarOutType = new InternalType ("var out");
readonly string name;
--- /dev/null
+using System;
+
+class DeclarationExpression
+{
+ public static int Main ()
+ {
+ Out (out int o);
+ if (o != 3)
+ return 1;
+
+ if (Out (out int o1)) {
+ if (o1 != 3)
+ return 2;
+ }
+
+ Out (out int o2 = 2);
+ if (o2 != 3)
+ return 3;
+
+ Out (out var o3);
+ if (o3 != 3)
+ return 4;
+
+ Ref (ref int r = 2);
+ if (r != 7)
+ return 5;
+
+ Ref (ref ((var r2 = 3)));
+ if (r2 != 8)
+ return 6;
+
+ Out2 (str: "b", v: out var o5);
+ if (o5 != 9)
+ return 7;
+
+ Out3 (out var o6 = 9m);
+ if (o6.GetType () != typeof (decimal))
+ return 8;
+
+ Console.WriteLine ("ok");
+ return 0;
+ }
+
+ static bool Out (out int value)
+ {
+ value = 3;
+ return true;
+ }
+
+ static bool Out2 (out int v, string str)
+ {
+ v = 9;
+ return true;
+ }
+
+ static void Out3<T> (out T t)
+ {
+ t = default (T);
+ }
+
+ static void Ref (ref int arg)
+ {
+ arg += 5;
+ }
+}
\ No newline at end of file
</method>\r
</type>\r
</test>\r
+ <test name="test-decl-expr-01.cs">\r
+ <type name="DeclarationExpression">\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>252</size>\r
+ </method>\r
+ <method name="Boolean Out(Int32 ByRef)" attrs="145">\r
+ <size>13</size>\r
+ </method>\r
+ <method name="Boolean Out2(Int32 ByRef, System.String)" attrs="145">\r
+ <size>14</size>\r
+ </method>\r
+ <method name="Void Out3[T](T ByRef)" attrs="145">\r
+ <size>17</size>\r
+ </method>\r
+ <method name="Void Ref(Int32 ByRef)" attrs="145">\r
+ <size>8</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
<test name="test-dictinit-01.cs">\r
<type name="Program">\r
<method name="Int32 Main()" attrs="145">\r