protected void EmitConditionalAccess(EmitContext ec) { var a_expr = arguments [0].Expr; var des = a_expr as DynamicExpressionStatement; if (des != null) { des.EmitConditionalAccess(ec); } if (HasConditionalAccess()) { var NullOperatorLabel = ec.DefineLabel(); if (ExpressionAnalyzer.IsInexpensiveLoad(a_expr)) { a_expr.Emit(ec); } else { var lt = new LocalTemporary(a_expr.Type); lt.EmitAssign(ec, a_expr, true, false); Arguments [0].Expr = lt; } ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel); if (!ec.ConditionalAccess.Statement) { if (ec.ConditionalAccess.Type.IsNullableType) { Nullable.LiftedNull.Create(ec.ConditionalAccess.Type, Location.Null).Emit(ec); } else { ec.EmitNull(); } } ec.Emit(OpCodes.Br, ec.ConditionalAccess.EndLabel); ec.MarkLabel(NullOperatorLabel); return; } if (a_expr.HasConditionalAccess()) { var lt = new LocalTemporary(a_expr.Type); lt.EmitAssign(ec, a_expr, false, false); Arguments [0].Expr = lt; } }
protected override Expression DoResolve(ResolveContext rc) { var src = source.Resolve(rc); if (src == null) { return(null); } if (InternalType.HasNoType(src.Type)) { rc.Report.Error(8131, source.Location, "Deconstruct assignment requires an expression with a type on the right-hand-side"); return(null); } 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) { 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; // TODO: The type is same only if there is no target element conversion // var res = (/*byte*/ b, /*short*/ s) = (2, 4); type = src.Type; return(this); } if (src_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { rc.Report.Error(8133, loc, "Cannot deconstruct dynamic objects"); return(null); } /* * 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 void Emit(EmitContext ec, bool conditionalAccess) { Label NullOperatorLabel; Nullable.Unwrap unwrap; if (conditionalAccess && Expression.IsNeverNull(instance)) { conditionalAccess = false; } if (conditionalAccess) { NullOperatorLabel = ec.DefineLabel(); unwrap = instance as Nullable.Unwrap; } else { NullOperatorLabel = new Label(); unwrap = null; } IMemoryLocation instance_address = null; bool conditional_access_dup = false; if (unwrap != null) { unwrap.Store(ec); unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel); } else { if (conditionalAccess && addressRequired) { // // Don't allocate temp variable when instance load is cheap and load and load-address // operate on same memory // instance_address = instance as VariableReference; if (instance_address == null) { instance_address = instance as LocalTemporary; } if (instance_address == null) { EmitLoad(ec, false); ec.Emit(OpCodes.Dup); ec.EmitLoadFromPtr(instance.Type); conditional_access_dup = true; } else { instance.Emit(ec); } } else { EmitLoad(ec, !conditionalAccess); if (conditionalAccess) { conditional_access_dup = !ExpressionAnalyzer.IsInexpensiveLoad(instance); if (conditional_access_dup) { ec.Emit(OpCodes.Dup); } } } if (conditionalAccess) { if (instance.Type.Kind == MemberKind.TypeParameter) { ec.Emit(OpCodes.Box, instance.Type); } ec.Emit(OpCodes.Brtrue_S, NullOperatorLabel); if (conditional_access_dup) { ec.Emit(OpCodes.Pop); } } } if (conditionalAccess) { if (!ec.ConditionalAccess.Statement) { var t = ec.ConditionalAccess.Type; if (t.IsNullableType) { Nullable.LiftedNull.Create(t, Location.Null).Emit(ec); } else { ec.EmitNull(); if (t.IsGenericParameter) { ec.Emit(OpCodes.Unbox_Any, t); } } } ec.Emit(OpCodes.Br, ec.ConditionalAccess.EndLabel); ec.MarkLabel(NullOperatorLabel); if (instance_address != null) { instance_address.AddressOf(ec, AddressOp.Load); } else if (unwrap != null) { unwrap.Emit(ec); if (addressRequired) { var tmp = ec.GetTemporaryLocal(unwrap.Type); ec.Emit(OpCodes.Stloc, tmp); ec.Emit(OpCodes.Ldloca, tmp); ec.FreeTemporaryLocal(tmp, unwrap.Type); } } else if (!conditional_access_dup) { instance.Emit(ec); } } }
protected override Expression DoResolve(ResolveContext rc) { var src = source.Resolve(rc); if (src == null) { return(null); } if (InternalType.HasNoType(src.Type)) { rc.Report.Error(8131, source.Location, "Deconstruct assignment requires an expression with a type on the right-hand-side"); return(null); } var src_type = src.Type; if (src_type.IsTupleType) { int target_count; if (targetExprs == null) { target_count = variables.Count; targetExprs = new List <Expression> (target_count); } else { target_count = targetExprs.Count; } if (src_type.Arity != target_count) { rc.Report.Error(8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{1}' variables", src_type.Arity.ToString(CultureInfo.InvariantCulture), target_count.ToString(CultureInfo.InvariantCulture)); 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); } var element_srcs = new List <Expression> (); var src_names = new List <string> (); for (int i = 0; i < target_count; ++i) { var element_src = tupleLiteral == null ? new MemberAccess(instance, NamedTupleSpec.GetElementPropertyName(i)) : tupleLiteral.Elements [i].Expr; element_srcs.Add(element_src); if (element_src is VariableReference) { src_names.Add((element_src as VariableReference)?.Name); } } for (int i = 0; i < target_count; ++i) { var tle = src_type.TypeArguments [i]; if (variables != null) { var variable = variables [i].Variable; if (variable.Type == InternalType.Discard) { variables [i] = null; targetExprs.Add(EmptyExpressionStatement.Instance); continue; } var variable_type = variables [i].TypeExpression; targetExprs.Add(new LocalVariableReference(variable, variable.Location)); if (variable_type is VarExpr) { if (InternalType.HasNoType(tle)) { rc.Report.Error(8130, Location, "Cannot infer the type of implicitly-typed deconstruction variable `{0}'", variable.Name); tle = InternalType.ErrorType; } variable.Type = tle; } else { variable.Type = variable_type.ResolveAsType(rc); } variable.PrepareAssignmentAnalysis((BlockContext)rc); } var element_target = (targetExprs [i] as SimpleName)?.LookupNameExpression(rc, MemberLookupRestrictions.None); if (element_target != null && src_names.Contains((element_target as VariableReference)?.Name)) { var tempType = element_target.Resolve(rc).Type; var temp = new LocalTemporary(tempType); tempExprs.Add(new SimpleAssign(temp, element_srcs [i]).Resolve(rc)); targetExprs [i] = new SimpleAssign(targetExprs [i], temp).Resolve(rc); } else { targetExprs [i] = new SimpleAssign(targetExprs [i], element_srcs [i]).Resolve(rc); } } eclass = ExprClass.Value; // TODO: The type is same only if there is no target element conversion // var res = (/*byte*/ b, /*short*/ s) = (2, 4); type = src.Type; return(this); } if (src_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { rc.Report.Error(8133, loc, "Cannot deconstruct dynamic objects"); return(null); } /* * 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"); }