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); }
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); }