Beispiel #1
0
        /// <summary>
        /// Find any deconstruction locals that are still pending inference and fail their inference.
        /// </summary>
        private void FailRemainingInferences(ArrayBuilder <DeconstructionVariable> variables, DiagnosticBag diagnostics)
        {
            int count = variables.Count;

            for (int i = 0; i < count; i++)
            {
                var variable = variables[i];
                if (variable.HasNestedVariables)
                {
                    FailRemainingInferences(variable.NestedVariables, diagnostics);
                }
                else
                {
                    switch (variable.Single.Kind)
                    {
                    case BoundKind.DeconstructionVariablePendingInference:
                        BoundExpression local = ((DeconstructionVariablePendingInference)variable.Single).FailInference(this, diagnostics);
                        variables[i] = new DeconstructionVariable(local, local.Syntax);
                        break;

                    case BoundKind.DiscardExpression:
                        var pending = (BoundDiscardExpression)variable.Single;
                        if ((object)pending.Type == null)
                        {
                            Error(diagnostics, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, pending.Syntax, "_");
                            variables[i] = new DeconstructionVariable(pending.FailInference(this, diagnostics), pending.Syntax);
                        }
                        break;
                    }

                    // at this point we expect to have a type for every lvalue
                    Debug.Assert((object)variables[i].Single.Type != null);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Prepares locals corresponding to the variables of the declaration.
        /// The locals are kept in a tree which captures the nesting of variables.
        /// Each local is either a simple local (when its type is known) or a deconstruction local pending inference.
        /// The caller is responsible for releasing the nested ArrayBuilders.
        /// </summary>
        private ArrayBuilder <DeconstructionVariable> BindDeconstructionDeclarationLocals(VariableDeclarationSyntax node, TypeSyntax closestTypeSyntax, DiagnosticBag diagnostics)
        {
            Debug.Assert(node.IsDeconstructionDeclaration);
            SeparatedSyntaxList <VariableDeclarationSyntax> variables = node.Deconstruction.Variables;

            // There are four cases for VariableDeclaration:
            // - type and declarators are set, but deconstruction is null. This could represent `int x`, which is a single variable.
            // - type is null, declarators are set, but deconstruction is null. This could represent `x`, which is a single variable.
            // - type is set to 'var', declarators are null, and deconstruction is set. This could represent `var (...)`
            // - type and declarators are null, but deconstruction is set. This could represent `(int x, ...)`

            var localsBuilder = ArrayBuilder <DeconstructionVariable> .GetInstance(variables.Count);

            foreach (var variable in variables)
            {
                TypeSyntax typeSyntax = variable.Type ?? closestTypeSyntax;

                DeconstructionVariable local;
                if (variable.IsDeconstructionDeclaration)
                {
                    local = new DeconstructionVariable(BindDeconstructionDeclarationLocals(variable, typeSyntax, diagnostics), variable.Deconstruction);
                }
                else
                {
                    local = new DeconstructionVariable(BindDeconstructionDeclarationLocal(variable, typeSyntax, diagnostics), variable);
                }

                localsBuilder.Add(local);
            }

            return(localsBuilder);
        }
        /// <summary>
        /// Inform the variables about found types.
        /// </summary>
        private void SetInferredTypes(ArrayBuilder <DeconstructionVariable> variables, ImmutableArray <TypeSymbol> foundTypes, DiagnosticBag diagnostics)
        {
            var matchCount = Math.Min(variables.Count, foundTypes.Length);

            for (int i = 0; i < matchCount; i++)
            {
                var variable = variables[i];
                if (!variable.HasNestedVariables)
                {
                    switch (variable.Single.Kind)
                    {
                    case BoundKind.DeconstructionVariablePendingInference:
                    {
                        var             pending = (DeconstructionVariablePendingInference)variable.Single;
                        BoundExpression local   = pending.SetInferredType(foundTypes[i], this, diagnostics);
                        variables[i] = new DeconstructionVariable(local, local.Syntax);
                    }
                    break;

                    case BoundKind.DiscardedExpression:
                    {
                        var pending = (BoundDiscardedExpression)variable.Single;
                        if ((object)pending.Type == null)
                        {
                            variables[i] = new DeconstructionVariable(pending.SetInferredType(foundTypes[i]), pending.Syntax);
                        }
                    }
                    break;
                    }
                }
            }
        }
        /// <summary>
        /// Bind a deconstruction assignment.
        /// </summary>
        /// <param name="deconstruction">The deconstruction operation</param>
        /// <param name="left">The left (tuple) operand</param>
        /// <param name="right">The right (deconstructable) operand</param>
        /// <param name="diagnostics">Where to report diagnostics</param>
        /// <param name="declaration">A variable set to the first variable declaration found in the left</param>
        /// <param name="expression">A variable set to the first expression in the left that isn't a declaration or discard</param>
        /// <param name="resultIsUsedOverride">The expression evaluator needs to bind deconstructions (both assignments and declarations) as expression-statements
        ///     and still access the returned value</param>
        /// <param name="rightPlaceholder"></param>
        /// <returns></returns>
        internal BoundDeconstructionAssignmentOperator BindDeconstruction(
            CSharpSyntaxNode deconstruction,
            ExpressionSyntax left,
            ExpressionSyntax right,
            DiagnosticBag diagnostics,
            ref DeclarationExpressionSyntax declaration,
            ref ExpressionSyntax expression,
            bool resultIsUsedOverride = false,
            BoundDeconstructValuePlaceholder rightPlaceholder = null)
        {
            DeconstructionVariable locals = BindDeconstructionVariables(left, diagnostics, ref declaration, ref expression);

            Debug.Assert(locals.HasNestedVariables);

            var             deconstructionDiagnostics = new DiagnosticBag();
            BoundExpression boundRight = rightPlaceholder ?? BindValue(right, deconstructionDiagnostics, BindValueKind.RValue);

            boundRight = FixTupleLiteral(locals.NestedVariables, boundRight, deconstruction, deconstructionDiagnostics);

            bool resultIsUsed = resultIsUsedOverride || IsDeconstructionResultUsed(left);
            var  assignment   = BindDeconstructionAssignment(deconstruction, left, boundRight, locals.NestedVariables, resultIsUsed, deconstructionDiagnostics);

            DeconstructionVariable.FreeDeconstructionVariables(locals.NestedVariables);

            diagnostics.AddRange(deconstructionDiagnostics);
            return(assignment);
        }
Beispiel #5
0
        internal BoundDeconstructionAssignmentOperator BindDeconstructionDeclaration(CSharpSyntaxNode node, VariableComponentSyntax declaration, ExpressionSyntax right, DiagnosticBag diagnostics, BoundDeconstructValuePlaceholder rightPlaceholder = null)
        {
            DeconstructionVariable locals = BindDeconstructionDeclarationLocals(declaration, diagnostics);

            Debug.Assert(locals.HasNestedVariables);
            var result = BindDeconstructionAssignment(node, right, locals.NestedVariables, diagnostics, isDeclaration: true, rhsPlaceholder: rightPlaceholder);

            FreeDeconstructionVariables(locals.NestedVariables);
            return(result);
        }
Beispiel #6
0
        /// <summary>
        /// Inform the variables about found types.
        /// </summary>
        private static void SetInferredTypes(ArrayBuilder <DeconstructionVariable> variables, ImmutableArray <TypeSymbol> foundTypes)
        {
            var matchCount = Math.Min(variables.Count, foundTypes.Length);

            for (int i = 0; i < matchCount; i++)
            {
                var variable = variables[i];
                if (!variable.HasNestedVariables && variable.Single.Kind == BoundKind.DeconstructionLocalPendingInference)
                {
                    BoundLocal local = ((DeconstructionLocalPendingInference)variable.Single).SetInferredType(foundTypes[i], success: true);
                    variables[i] = new DeconstructionVariable(local, local.Syntax);
                }
            }
        }
        /// <summary>
        /// Inform the variables about found types.
        /// </summary>
        private void SetInferredTypes(ArrayBuilder <DeconstructionVariable> variables, ImmutableArray <TypeSymbol> foundTypes, DiagnosticBag diagnostics)
        {
            var matchCount = Math.Min(variables.Count, foundTypes.Length);

            for (int i = 0; i < matchCount; i++)
            {
                var variable = variables[i];
                if (!variable.HasNestedVariables && variable.Single.Kind == BoundKind.DeconstructionVariablePendingInference)
                {
                    BoundExpression local = ((DeconstructionVariablePendingInference)variable.Single).SetInferredType(foundTypes[i], this, diagnostics);
                    variables[i] = new DeconstructionVariable(local, local.Syntax);
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Bind a deconstruction assignment.
        /// </summary>
        /// <param name="deconstruction">The deconstruction operation</param>
        /// <param name="left">The left (tuple) operand</param>
        /// <param name="right">The right (deconstrucible) operand</param>
        /// <param name="diagnostics">Where to report diagnostics</param>
        /// <param name="declaration">A variable set to the first variable declaration found in the left</param>
        /// <param name="expression">A variable set to the first expression in the left that isn't a declaration or discard</param>
        /// <param name="rightPlaceholder"></param>
        /// <returns></returns>
        internal BoundDeconstructionAssignmentOperator BindDeconstruction(
            CSharpSyntaxNode deconstruction,
            ExpressionSyntax left,
            ExpressionSyntax right,
            DiagnosticBag diagnostics,
            ref DeclarationExpressionSyntax declaration,
            ref ExpressionSyntax expression,
            BoundDeconstructValuePlaceholder rightPlaceholder = null)
        {
            DeconstructionVariable locals = BindDeconstructionVariables(left, diagnostics, ref declaration, ref expression);

            Debug.Assert(locals.HasNestedVariables);
            var result = BindDeconstructionAssignment(deconstruction, left, right, locals.NestedVariables, diagnostics, rhsPlaceholder: rightPlaceholder);

            FreeDeconstructionVariables(locals.NestedVariables);
            return(result);
        }
Beispiel #9
0
        private void FailRemainingInferencesAndSetValEscape(ArrayBuilder <DeconstructionVariable> variables, DiagnosticBag diagnostics,
                                                            uint rhsValEscape)
        {
            int count = variables.Count;

            for (int i = 0; i < count; i++)
            {
                var variable = variables[i];
                if (variable.NestedVariables is object)
                {
                    FailRemainingInferencesAndSetValEscape(variable.NestedVariables, diagnostics, rhsValEscape);
                }
                else
                {
                    Debug.Assert(variable.Single is object);
                    switch (variable.Single.Kind)
                    {
                    case BoundKind.Local:
                        var local = (BoundLocal)variable.Single;
                        if (local.DeclarationKind != BoundLocalDeclarationKind.None)
                        {
                            ((SourceLocalSymbol)local.LocalSymbol).SetValEscape(rhsValEscape);
                        }
                        break;

                    case BoundKind.DeconstructionVariablePendingInference:
                        BoundExpression errorLocal = ((DeconstructionVariablePendingInference)variable.Single).FailInference(this, diagnostics);
                        variables[i] = new DeconstructionVariable(errorLocal, errorLocal.Syntax);
                        break;

                    case BoundKind.DiscardExpression:
                        var pending = (BoundDiscardExpression)variable.Single;
                        if ((object?)pending.Type == null)
                        {
                            Error(diagnostics, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, pending.Syntax, "_");
                            variables[i] = new DeconstructionVariable(pending.FailInference(this, diagnostics), pending.Syntax);
                        }
                        break;
                    }

                    // at this point we expect to have a type for every lvalue
                    Debug.Assert((object?)variables[i].Single !.Type != null);
                }
            }
        }
Beispiel #10
0
        private void SetInferredTypes(ArrayBuilder <DeconstructionVariable> variables, ImmutableArray <TypeSymbol> foundTypes, DiagnosticBag diagnostics)
        {
            var matchCount = Math.Min(variables.Count, foundTypes.Length);

            for (int i = 0; i < matchCount; i++)
            {
                var variable = variables[i];
                if (variable.Single is { } pending)
                {
                    if ((object?)pending.Type != null)
                    {
                        continue;
                    }

                    variables[i] = new DeconstructionVariable(SetInferredType(pending, foundTypes[i], diagnostics), variable.Syntax);
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// Find any deconstruction locals that are still pending inference and fail their inference.
        /// </summary>
        private void FailRemainingInferences(ArrayBuilder <DeconstructionVariable> variables, DiagnosticBag diagnostics)
        {
            var count = variables.Count;

            for (int i = 0; i < count; i++)
            {
                var variable = variables[i];
                if (variable.HasNestedVariables)
                {
                    FailRemainingInferences(variable.NestedVariables, diagnostics);
                }
                else
                {
                    if (variable.Single.Kind == BoundKind.DeconstructionLocalPendingInference)
                    {
                        var local = ((DeconstructionLocalPendingInference)variable.Single).FailInference(this);
                        variables[i] = new DeconstructionVariable(local, local.Syntax);
                    }
                }
            }
        }
Beispiel #12
0
        /// <summary>
        /// Inform the variables about found types.
        /// </summary>
        private void SetInferredTypes(ArrayBuilder<DeconstructionVariable> variables, ImmutableArray<TypeSymbol> foundTypes, DiagnosticBag diagnostics)
        {
            var matchCount = Math.Min(variables.Count, foundTypes.Length);
            for (int i = 0; i < matchCount; i++)
            {
                var variable = variables[i];
                if (!variable.HasNestedVariables)
                {
                    var pending = variable.Single;
                    if ((object)pending.Type != null)
                    {
                        continue;
                    }

                    variables[i] = new DeconstructionVariable(SetInferredType(pending, foundTypes[i], diagnostics), pending.Syntax);
                }
            }
        }
Beispiel #13
0
 /// <summary>
 /// Find any deconstruction locals that are still pending inference and fail their inference.
 /// </summary>
 private void FailRemainingInferences(ArrayBuilder<DeconstructionVariable> variables, DiagnosticBag diagnostics)
 {
     var count = variables.Count;
     for (int i = 0; i < count; i++)
     {
         var variable = variables[i];
         if (variable.HasNestedVariables)
         {
             FailRemainingInferences(variable.NestedVariables, diagnostics);
         }
         else
         {
             if (variable.Single.Kind == BoundKind.DeconstructionLocalPendingInference)
             {
                 var local = ((DeconstructionLocalPendingInference)variable.Single).FailInference(this);
                 variables[i] = new DeconstructionVariable(local, local.Syntax);
             }
         }
     }
 }
Beispiel #14
0
        /// <summary>
        /// Prepares locals corresponding to the variables of the declaration.
        /// The locals are kept in a tree which captures the nesting of variables.
        /// Each local is either a simple local (when its type is known) or a deconstruction local pending inference.
        /// The caller is responsible for releasing the nested ArrayBuilders.
        /// </summary>
        private ArrayBuilder<DeconstructionVariable> BindDeconstructionDeclarationLocals(VariableDeclarationSyntax node, TypeSyntax closestTypeSyntax, DiagnosticBag diagnostics)
        {
            Debug.Assert(node.IsDeconstructionDeclaration);
            SeparatedSyntaxList<VariableDeclarationSyntax> variables = node.Deconstruction.Variables;

            // There are four cases for VariableDeclaration:
            // - type and declarators are set, but deconstruction is null. This could represent `int x`, which is a single variable.
            // - type is null, declarators are set, but deconstruction is null. This could represent `x`, which is a single variable.
            // - type is set to 'var', declarators are null, and deconstruction is set. This could represent `var (...)`
            // - type and declarators are null, but deconstruction is set. This could represent `(int x, ...)`

            var localsBuilder = ArrayBuilder<DeconstructionVariable>.GetInstance(variables.Count);
            foreach (var variable in variables)
            {
                TypeSyntax typeSyntax = variable.Type ?? closestTypeSyntax;

                DeconstructionVariable local;
                if (variable.IsDeconstructionDeclaration)
                {
                    local = new DeconstructionVariable(BindDeconstructionDeclarationLocals(variable, typeSyntax, diagnostics), node.Deconstruction);
                }
                else
                {
                    local = new DeconstructionVariable(BindDeconstructionDeclarationLocal(variable, typeSyntax, diagnostics));
                }

                localsBuilder.Add(local);
            }

            return localsBuilder;
        }
Beispiel #15
0
 /// <summary>
 /// Inform the variables about found types.
 /// </summary>
 private void SetInferredTypes(ArrayBuilder<DeconstructionVariable> variables, ImmutableArray<TypeSymbol> foundTypes, DiagnosticBag diagnostics)
 {
     var matchCount = Math.Min(variables.Count, foundTypes.Length);
     for (int i = 0; i < matchCount; i++)
     {
         var variable = variables[i];
         if (!variable.HasNestedVariables && variable.Single.Kind == BoundKind.DeconstructionVariablePendingInference)
         {
             BoundExpression local = ((DeconstructionVariablePendingInference)variable.Single).SetInferredType(foundTypes[i], this, diagnostics);
             variables[i] = new DeconstructionVariable(local, local.Syntax);
         }
     }
 }
Beispiel #16
0
        /// <summary>
        /// Find any deconstruction locals that are still pending inference and fail their inference.
        /// </summary>
        private void FailRemainingInferences(ArrayBuilder<DeconstructionVariable> variables, DiagnosticBag diagnostics)
        {
            int count = variables.Count;
            for (int i = 0; i < count; i++)
            {
                var variable = variables[i];
                if (variable.HasNestedVariables)
                {
                    FailRemainingInferences(variable.NestedVariables, diagnostics);
                }
                else
                {
                    switch (variable.Single.Kind)
                    {
                        case BoundKind.DeconstructionVariablePendingInference:
                            BoundExpression local = ((DeconstructionVariablePendingInference)variable.Single).FailInference(this, diagnostics);
                            variables[i] = new DeconstructionVariable(local, local.Syntax);
                            break;
                        case BoundKind.DiscardExpression:
                            var pending = (BoundDiscardExpression)variable.Single;
                            if ((object)pending.Type == null)
                            {
                                Error(diagnostics, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, pending.Syntax, "_");
                                variables[i] = new DeconstructionVariable(pending.FailInference(this, diagnostics), pending.Syntax);
                            }
                            break;
                    }

                    // at this point we expect to have a type for every lvalue
                    Debug.Assert((object)variables[i].Single.Type != null);
                }
            }
        }
Beispiel #17
0
 /// <summary>
 /// Inform the variables about found types.
 /// </summary>
 private static void SetInferredTypes(ArrayBuilder<DeconstructionVariable> variables, ImmutableArray<TypeSymbol> foundTypes)
 {
     var matchCount = Math.Min(variables.Count, foundTypes.Length);
     for (int i = 0; i < matchCount; i++)
     {
         var variable = variables[i];
         if (!variable.HasNestedVariables && variable.Single.Kind == BoundKind.DeconstructionLocalPendingInference)
         {
             BoundLocal local = ((DeconstructionLocalPendingInference)variable.Single).SetInferredType(foundTypes[i], success: true);
             variables[i] = new DeconstructionVariable(local, local.Syntax);
         }
     }
 }
Beispiel #18
0
 /// <summary>
 /// Inform the variables about found types.
 /// </summary>
 private void SetInferredTypes(ArrayBuilder<DeconstructionVariable> variables, ImmutableArray<TypeSymbol> foundTypes, DiagnosticBag diagnostics)
 {
     var matchCount = Math.Min(variables.Count, foundTypes.Length);
     for (int i = 0; i < matchCount; i++)
     {
         var variable = variables[i];
         if (!variable.HasNestedVariables)
         {
             switch (variable.Single.Kind)
             {
                 case BoundKind.DeconstructionVariablePendingInference:
                     {
                         var pending = (DeconstructionVariablePendingInference)variable.Single;
                         BoundExpression local = pending.SetInferredType(foundTypes[i], this, diagnostics);
                         variables[i] = new DeconstructionVariable(local, local.Syntax);
                     }
                     break;
                 case BoundKind.DiscardedExpression:
                     {
                         var pending = (BoundDiscardedExpression)variable.Single;
                         if ((object)pending.Type == null)
                         {
                             variables[i] = new DeconstructionVariable(pending.SetInferredType(foundTypes[i]), pending.Syntax);
                         }
                     }
                     break;
             }
         }
     }
 }