示例#1
0
        internal Conversion(ConversionKind kind, DeconstructionInfo deconstructionInfo, ImmutableArray <Conversion> nestedConversions)
        {
            Debug.Assert(kind == ConversionKind.Deconstruction);

            this._kind    = kind;
            _uncommonData = new DeconstructionUncommonData(deconstructionInfo, nestedConversions);
        }
示例#2
0
        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());
        }
示例#3
0
 internal DeconstructionUncommonData(DeconstructionInfo deconstructionInfoOpt, ImmutableArray <Conversion> nestedConversions)
     : base(false, false, default(UserDefinedConversionResult), null, nestedConversions)
 {
     Debug.Assert(!nestedConversions.IsDefaultOrEmpty);
     DeconstructionInfo = deconstructionInfoOpt;
 }
示例#4
0
        /// <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);
        }