{
var sn = expr as SimpleName;
if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
- throw new NotImplementedException ("var deconstruct");
+ var targets = new List<Expression> (arguments.Count);
+ var variables = new List<LocalVariable> (arguments.Count);
+ foreach (var arg in arguments) {
+ var arg_sn = arg.Expr as SimpleName;
+ if (arg_sn == null || arg_sn.Arity != 0) {
+ rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved");
+ return ErrorExpression.Instance;
+ }
+
+ var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
+ rc.CurrentBlock.AddLocalName (lv);
+ variables.Add (lv);
+
+ targets.Add (new LocalVariableReference (lv, arg_sn.Location));
+ }
+
+ var res = new TupleDeconstruct (targets, variables, right_side, loc);
+ return res.Resolve (rc);
}
return base.DoResolveLValue (rc, right_side);
}
}
- class TupleDeconstruct : ExpressionStatement
+ class TupleDeconstruct : ExpressionStatement, IAssignMethod
{
Expression source;
List<Expression> targetExprs;
+ List<LocalVariable> variablesToInfer;
+ Expression instance;
public TupleDeconstruct (List<Expression> targetExprs, Expression source, Location loc)
{
this.loc = loc;
}
+ public TupleDeconstruct (List<Expression> targetExprs, List<LocalVariable> variables, Expression source, Location loc)
+ : this (targetExprs, source, loc)
+ {
+ this.variablesToInfer = variables;
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
return null;
}
- var tupleLiteral = src as TupleLiteral;
- if (tupleLiteral != null) {
- if (tupleLiteral.Elements.Count != targetExprs.Count) {
- rc.Report.Error (8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{0}' variables",
- tupleLiteral.Elements.Count.ToString (), targetExprs.Count.ToString ());
+ var src_type = src.Type;
+
+ if (src_type.IsTupleType) {
+ if (src_type.Arity != targetExprs.Count) {
+ rc.Report.Error (8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{1}' variables",
+ src_type.Arity.ToString (), targetExprs.Count.ToString ());
return null;
}
+ var tupleLiteral = src as TupleLiteral;
+ if (tupleLiteral == null && !ExpressionAnalyzer.IsInexpensiveLoad (src)) {
+ var expr_variable = LocalVariable.CreateCompilerGenerated (source.Type, rc.CurrentBlock, loc);
+ source = new CompilerAssign (expr_variable.CreateReferenceExpression (rc, loc), source, loc);
+ instance = expr_variable.CreateReferenceExpression (rc, loc);
+ }
+
for (int i = 0; i < targetExprs.Count; ++i) {
- targetExprs [i] = new SimpleAssign (targetExprs [i], tupleLiteral.Elements [i].Expr).Resolve (rc);
+ var tle = src_type.TypeArguments [i];
+
+ var lv = variablesToInfer? [i];
+ if (lv != null) {
+ if (InternalType.HasNoType (tle)) {
+ rc.Report.Error (8130, Location, "Cannot infer the type of implicitly-typed deconstruction variable `{0}'", lv.Name);
+ lv.Type = InternalType.ErrorType;
+ continue;
+ }
+
+ lv.Type = tle;
+ lv.PrepareAssignmentAnalysis ((BlockContext) rc);
+ }
+
+
+ var element_src = tupleLiteral == null ? new MemberAccess (instance, NamedTupleSpec.GetElementPropertyName (i)) : tupleLiteral.Elements [i].Expr;
+ targetExprs [i] = new SimpleAssign (targetExprs [i], element_src).Resolve (rc);
}
eclass = ExprClass.Value;
return this;
}
- if (src.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
+ if (src_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
rc.Report.Error (8133, loc, "Cannot deconstruct dynamic objects");
return null;
}
- throw new NotImplementedException ("Deconstruct assignment");
+ /*
+ var args = new Arguments (targetExprs.Count);
+ foreach (var t in targetExprs) {
+ args.Add (new Argument (t, Argument.AType.Out));
+ }
+
+ var invocation = new Invocation (new MemberAccess (src, "Deconstruct"), args);
+ var res = invocation.Resolve (rc);
+ */
+
+ throw new NotImplementedException ("Custom deconstruct");
}
public override void Emit (EmitContext ec)
public override void EmitStatement (EmitContext ec)
{
+ if (instance != null)
+ ((ExpressionStatement) source).EmitStatement (ec);
+
foreach (ExpressionStatement expr in targetExprs)
expr.EmitStatement (ec);
}
+ public void Emit (EmitContext ec, bool leave_copy)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
+ {
+ if (leave_copy)
+ throw new NotImplementedException ();
+
+ foreach (var lv in variablesToInfer)
+ lv.CreateBuilder (ec);
+
+ EmitStatement (ec);
+ }
+
public override void FlowAnalysis (FlowAnalysisContext fc)
{
foreach (var expr in targetExprs)
expr.FlowAnalysis (fc);
}
+
+ public void SetGeneratedFieldAssigned (FlowAnalysisContext fc)
+ {
+ if (variablesToInfer == null)
+ return;
+
+ foreach (var lv in variablesToInfer)
+ fc.SetVariableAssigned (lv.VariableInfo);
+ }
}
}
\ No newline at end of file