internal Conversion(ConversionKind kind, DeconstructionInfo deconstructionInfo, ImmutableArray <Conversion> nestedConversions) { Debug.Assert(kind == ConversionKind.Deconstruction); this._kind = kind; _uncommonData = new DeconstructionUncommonData(deconstructionInfo, nestedConversions); }
private ImmutableArray <BoundExpression> InvokeDeconstructMethod(DeconstructionInfo deconstruction, BoundExpression target, ArrayBuilder <BoundExpression> effects, ref ArrayBuilder <LocalSymbol> temps) { AddPlaceholderReplacement(deconstruction.InputPlaceholder, target); var outputPlaceholders = deconstruction.OutputPlaceholders; var outLocals = ArrayBuilder <BoundExpression> .GetInstance(outputPlaceholders.Length); foreach (var outputPlaceholder in outputPlaceholders) { var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, outputPlaceholder.Type, SynthesizedLocalKind.LoweringTemp); var localBound = new BoundLocal(target.Syntax, localSymbol, constantValueOpt: null, type: outputPlaceholder.Type) { WasCompilerGenerated = true }; temps.Add(localSymbol); AddPlaceholderReplacement(outputPlaceholder, localBound); outLocals.Add(localBound); } effects.Add(VisitExpression(deconstruction.Invocation)); RemovePlaceholderReplacement(deconstruction.InputPlaceholder); foreach (var outputPlaceholder in outputPlaceholders) { RemovePlaceholderReplacement(outputPlaceholder); } return(outLocals.ToImmutableAndFree()); }
internal DeconstructionUncommonData(DeconstructionInfo deconstructionInfoOpt, ImmutableArray <Conversion> nestedConversions) : base(false, false, default(UserDefinedConversionResult), null, nestedConversions) { Debug.Assert(!nestedConversions.IsDefaultOrEmpty); DeconstructionInfo = deconstructionInfoOpt; }
/// <summary> /// Recursively builds a Conversion object with Kind=Deconstruction including information about any necessary /// Deconstruct method and any element-wise conversion. /// /// Note that the variables may either be plain or nested variables. /// The variables may be updated with inferred types if they didn't have types initially. /// Returns false if there was an error. /// </summary> private bool MakeDeconstructionConversion( TypeSymbol type, SyntaxNode syntax, SyntaxNode rightSyntax, DiagnosticBag diagnostics, ArrayBuilder <DeconstructionVariable> variables, out Conversion conversion) { Debug.Assert(type != null); ImmutableArray <TypeSymbol> tupleOrDeconstructedTypes; conversion = Conversion.Deconstruction; // Figure out the deconstruct method (if one is required) and determine the types we get from the RHS at this level var deconstructInfo = default(DeconstructionInfo); if (type.IsTupleType) { // tuple literal such as `(1, 2)`, `(null, null)`, `(x.P, y.M())` tupleOrDeconstructedTypes = type.TupleElementTypes; SetInferredTypes(variables, tupleOrDeconstructedTypes, diagnostics); if (variables.Count != tupleOrDeconstructedTypes.Length) { Error(diagnostics, ErrorCode.ERR_DeconstructWrongCardinality, syntax, tupleOrDeconstructedTypes.Length, variables.Count); return(false); } } else { ImmutableArray <BoundDeconstructValuePlaceholder> outPlaceholders; var inputPlaceholder = new BoundDeconstructValuePlaceholder(syntax, type); var deconstructInvocation = MakeDeconstructInvocationExpression(variables.Count, inputPlaceholder, rightSyntax, diagnostics, out outPlaceholders); if (deconstructInvocation.HasAnyErrors) { return(false); } deconstructInfo = new DeconstructionInfo(deconstructInvocation, inputPlaceholder, outPlaceholders); tupleOrDeconstructedTypes = outPlaceholders.SelectAsArray(p => p.Type); SetInferredTypes(variables, tupleOrDeconstructedTypes, diagnostics); } // Figure out whether those types will need conversions, including further deconstructions bool hasErrors = false; int count = variables.Count; var nestedConversions = ArrayBuilder <Conversion> .GetInstance(count); for (int i = 0; i < count; i++) { var variable = variables[i]; Conversion nestedConversion; if (variable.HasNestedVariables) { var elementSyntax = syntax.Kind() == SyntaxKind.TupleExpression ? ((TupleExpressionSyntax)syntax).Arguments[i] : syntax; hasErrors |= !MakeDeconstructionConversion(tupleOrDeconstructedTypes[i], syntax, rightSyntax, diagnostics, variable.NestedVariables, out nestedConversion); } else { var single = variable.Single; HashSet <DiagnosticInfo> useSiteDiagnostics = null; nestedConversion = this.Conversions.ClassifyConversionFromType(tupleOrDeconstructedTypes[i], single.Type, ref useSiteDiagnostics); diagnostics.Add(single.Syntax, useSiteDiagnostics); if (!nestedConversion.IsImplicit) { hasErrors = true; GenerateImplicitConversionError(diagnostics, Compilation, single.Syntax, nestedConversion, tupleOrDeconstructedTypes[i], single.Type); } } nestedConversions.Add(nestedConversion); } conversion = new Conversion(ConversionKind.Deconstruction, deconstructInfo, nestedConversions.ToImmutableAndFree()); return(!hasErrors); }