Пример #1
0
        private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, Binder sectionBinder, DiagnosticBag diagnostics)
        {
            var switchGoverningType = GetSwitchGoverningType(diagnostics);
            BoundExpression boundLabelExpressionOpt = null;

            SourceLabelSymbol boundLabelSymbol = null;
            ConstantValue labelExpressionConstant = null;
            List<SourceLabelSymbol> matchedLabelSymbols;

            // Prevent cascading diagnostics
            bool hasErrors = node.HasErrors;

            switch (node.Kind())
            {
                case SyntaxKind.CaseSwitchLabel:
                var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
                // Bind the label case expression
                boundLabelExpressionOpt = sectionBinder.BindValue(caseLabelSyntax.Value, diagnostics, BindValueKind.RValue);

                boundLabelExpressionOpt = ConvertCaseExpression(switchGoverningType, caseLabelSyntax, boundLabelExpressionOpt, sectionBinder, ref labelExpressionConstant, diagnostics);

                // Check for bind errors
                hasErrors = hasErrors || boundLabelExpressionOpt.HasAnyErrors;


                // SPEC:    The constant expression of each case label must denote a value that
                // SPEC:    is implicitly convertible (§6.1) to the governing type of the switch statement.

                // Prevent cascading diagnostics
                if (!hasErrors && labelExpressionConstant == null)
                {
                    diagnostics.Add(ErrorCode.ERR_ConstantExpected, caseLabelSyntax.Location);
                    hasErrors = true;
                }

                // LabelSymbols for all the switch case labels are created by BuildLabels().
                // Fetch the matching switch case label symbols
                matchedLabelSymbols = FindMatchingSwitchCaseLabels(labelExpressionConstant, caseLabelSyntax);
                    break;
                case SyntaxKind.CasePatternSwitchLabel:
                    // pattern matching in case is not yet implemented.
                    if (!node.HasErrors)
                    {
                        Error(diagnostics, ErrorCode.ERR_FeatureIsUnimplemented, node, MessageID.IDS_FeaturePatternMatching.Localize());
                        hasErrors = true;
                    }
                    matchedLabelSymbols = new List<SourceLabelSymbol>();
                    break;
                case SyntaxKind.DefaultSwitchLabel:
                matchedLabelSymbols = GetDefaultLabels();
                    break;
                default:
                    throw ExceptionUtilities.Unreachable;
            }

            // Get the corresponding matching label symbol created during BuildLabels()
            // and also check for duplicate case labels.

            Debug.Assert(hasErrors || !matchedLabelSymbols.IsEmpty());
            bool first = true;
            bool hasDuplicateErrors = false;
            foreach (SourceLabelSymbol label in matchedLabelSymbols)
            {
                if (node.Equals(label.IdentifierNodeOrToken.AsNode()))
                {
                    // we must have exactly one matching label created during BuildLabels()
                    boundLabelSymbol = label;

                    // SPEC:    A compile-time error occurs if two or more case labels
                    // SPEC:    in the same switch statement specify the same constant value.

                    if (!hasErrors && !first)
                    {
                        // Skipping the first label symbol ensures that the errors (if any),
                        // are reported on all but the first duplicate case label.
                        diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location,
                            label.SwitchCaseLabelConstant?.Value ?? label.Name);
                        hasDuplicateErrors = true;
                    }
                    break;
                }
                first = false;
            }

            if ((object)boundLabelSymbol == null)
            {
                Debug.Assert(hasErrors);
                boundLabelSymbol = new SourceLabelSymbol((MethodSymbol)this.ContainingMemberOrLambda, node, labelExpressionConstant);
            }

            return new BoundSwitchLabel(
                syntax: node,
                label: boundLabelSymbol,
                expressionOpt: boundLabelExpressionOpt,
                hasErrors: hasErrors || hasDuplicateErrors);
        }
Пример #2
0
        private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, DiagnosticBag diagnostics)
        {
            var switchGoverningType = GetSwitchGoverningType(diagnostics);
            BoundExpression boundLabelExpressionOpt = null;

            SourceLabelSymbol boundLabelSymbol = null;
            ConstantValue labelExpressionConstant = null;
            List<SourceLabelSymbol> matchedLabelSymbols;

            // Prevent cascading diagnostics
            bool hasErrors = node.HasErrors;

            if (node.Value != null)
            {
                Debug.Assert(node.Kind == SyntaxKind.CaseSwitchLabel);

                // Bind the label case expression
                boundLabelExpressionOpt = BindValue(node.Value, diagnostics, BindValueKind.RValue);

                boundLabelExpressionOpt = ConvertCaseExpression(switchGoverningType, node, boundLabelExpressionOpt, ref labelExpressionConstant, diagnostics);

                // Check for bind errors
                hasErrors = hasErrors || boundLabelExpressionOpt.HasAnyErrors;


                // SPEC:    The constant expression of each case label must denote a value that
                // SPEC:    is implicitly convertible (§6.1) to the governing type of the switch statement.

                // Prevent cascading diagnostics
                if (!hasErrors && labelExpressionConstant == null)
                {
                    diagnostics.Add(ErrorCode.ERR_ConstantExpected, node.Location);
                    hasErrors = true;
                }

                // LabelSymbols for all the switch case labels are created by BuildLabels().
                // Fetch the matching switch case label symbols
                matchedLabelSymbols = FindMatchingSwitchCaseLabels(labelExpressionConstant, node);
            }
            else
            {
                Debug.Assert(node.Kind == SyntaxKind.DefaultSwitchLabel);
                matchedLabelSymbols = GetDefaultLabels();
            }

            // Get the corresponding matching label symbol created during BuildLabels()
            // and also check for duplicate case labels.

            Debug.Assert(!matchedLabelSymbols.IsEmpty());
            bool first = true;
            bool hasDuplicateErrors = false;
            foreach (SourceLabelSymbol label in matchedLabelSymbols)
            {
                if (node.Equals(label.IdentifierNodeOrToken.AsNode()))
                {
                    // we must have exactly one matching label created during BuildLabels()
                    boundLabelSymbol = label;

                    // SPEC:    A compile-time error occurs if two or more case labels
                    // SPEC:    in the same switch statement specify the same constant value.

                    if (!hasErrors && !first)
                    {
                        // Skipping the first label symbol ensures that the errors (if any),
                        // are reported on all but the first duplicate case label.
                        diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location,
                            label.SwitchCaseLabelConstant == null ? label.Name : label.SwitchCaseLabelConstant.Value);
                        hasDuplicateErrors = true;
                    }
                    break;
                }
                first = false;
            }

            if ((object)boundLabelSymbol == null)
            {
                Debug.Assert(hasErrors);
                boundLabelSymbol = new SourceLabelSymbol(this.Owner, node, labelExpressionConstant);
            }

            return new BoundSwitchLabel(
                syntax: node,
                label: boundLabelSymbol,
                expressionOpt: boundLabelExpressionOpt,
                hasErrors: hasErrors || hasDuplicateErrors);
        }