コード例 #1
0
 internal SubsumptionDiagnosticBuilder(Symbol enclosingSymbol,
                                        Conversions conversions,
                                        BoundExpression expression)
     : base(enclosingSymbol, conversions)
 {
     _subsumptionTree = DecisionTree.Create(expression, expression.Type, enclosingSymbol);
 }
コード例 #2
0
 /// <summary>
 /// Lower the given decision tree into the given statement builder.
 /// </summary>
 public void LowerDecisionTree(BoundExpression expression, DecisionTree decisionTree, ArrayBuilder<BoundStatement> loweredDecisionTree)
 {
     var oldLoweredDecisionTree = this._loweredDecisionTree;
     this._loweredDecisionTree = loweredDecisionTree;
     LowerDecisionTree(expression, decisionTree);
     this._loweredDecisionTree = oldLoweredDecisionTree;
 }
コード例 #3
0
        protected DecisionTree AddToDecisionTree(DecisionTree decisionTree, SyntaxNode sectionSyntax, BoundPatternSwitchLabel label)
        {
            var pattern = label.Pattern;
            var guard = label.Guard;
            if (guard?.ConstantValue == ConstantValue.False)
            {
                return null;
            }

            switch (pattern.Kind)
            {
                case BoundKind.ConstantPattern:
                    {
                        var constantPattern = (BoundConstantPattern)pattern;
                        DecisionMaker makeDecision = (e, t) => new DecisionTree.Guarded(e, t, default(ImmutableArray<KeyValuePair<BoundExpression, BoundExpression>>), sectionSyntax, guard, label);
                        if (constantPattern.ConstantValue == ConstantValue.Null)
                        {
                            return AddByNull(decisionTree, makeDecision);
                        }
                        else
                        {
                            return AddByValue(decisionTree, constantPattern, makeDecision);
                        }
                    }
                case BoundKind.DeclarationPattern:
                    {
                        var declarationPattern = (BoundDeclarationPattern)pattern;
                        DecisionMaker maker =
                            (e, t) => new DecisionTree.Guarded(e, t, ImmutableArray.Create(new KeyValuePair<BoundExpression, BoundExpression>(e, declarationPattern.VariableAccess)), sectionSyntax, guard, label);
                        if (declarationPattern.IsVar)
                        {
                            return Add(decisionTree, maker);
                        }
                        else
                        {
                            return AddByType(decisionTree, declarationPattern.DeclaredType.Type, maker);
                        }
                    }
                case BoundKind.WildcardPattern:
                // We do not yet support a wildcard pattern syntax. It is used exclusively
                // to model the "default:" case, which is handled specially in the caller.
                default:
                    throw ExceptionUtilities.UnexpectedValue(pattern.Kind);
            }
        }
コード例 #4
0
            private DecisionTree LowerToDecisionTree(
                BoundExpression loweredExpression,
                BoundPatternSwitchStatement node)
            {
                var loweredDecisionTree = DecisionTree.Create(loweredExpression, loweredExpression.Type, _enclosingSymbol);
                BoundPatternSwitchLabel defaultLabel = null;
                SyntaxNode defaultSection            = null;

                foreach (var section in node.SwitchSections)
                {
                    var sectionSyntax = (SyntaxNode)section.Syntax;
                    foreach (var label in section.SwitchLabels)
                    {
                        var loweredLabel = LowerSwitchLabel(label);
                        if (loweredLabel.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel)
                        {
                            if (defaultLabel != null)
                            {
                                // duplicate switch label will have been reported during initial binding.
                            }
                            else
                            {
                                defaultLabel   = loweredLabel;
                                defaultSection = sectionSyntax;
                            }
                        }
                        else
                        {
                            Syntax = label.Syntax;
                            AddToDecisionTree(loweredDecisionTree, sectionSyntax, loweredLabel);
                        }
                    }
                }

                if (defaultLabel != null && !loweredDecisionTree.MatchIsComplete)
                {
                    Add(loweredDecisionTree, (e, t) => new DecisionTree.Guarded(loweredExpression, loweredExpression.Type, default(ImmutableArray <KeyValuePair <BoundExpression, BoundExpression> >), defaultSection, null, defaultLabel));
                }

                // We discard use-site diagnostics, as they have been reported during initial binding.
                _useSiteDiagnostics.Clear();
                return(loweredDecisionTree);
            }
コード例 #5
0
ファイル: DecisionTree.cs プロジェクト: tvsonar/roslyn
        private void AddTemps(DecisionTree decisionTree, ArrayBuilder<LocalSymbol> builder)
        {
            if (decisionTree == null)
            {
                return;
            }

            switch (decisionTree.Kind)
            {
                case DecisionTree.DecisionKind.ByType:
                    {
                        var byType = (DecisionTree.ByType)decisionTree;
                        AddTemps(byType.WhenNull, builder);
                        foreach (var td in byType.TypeAndDecision)
                        {
                            AddTemps(td.Value, builder);
                        }

                        AddTemps(byType.Default, builder);
                        return;
                    }
                case DecisionTree.DecisionKind.ByValue:
                    {
                        var byValue = (DecisionTree.ByValue)decisionTree;
                        foreach (var vd in byValue.ValueAndDecision)
                        {
                            AddTemps(vd.Value, builder);
                        }

                        AddTemps(byValue.Default, builder);
                        return;
                    }
                case DecisionTree.DecisionKind.Guarded:
                    {
                        var guarded = (DecisionTree.Guarded)decisionTree;
                        ComputeTemps(guarded.Default);
                        return;
                    }
                default:
                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
            }
        }
コード例 #6
0
        private DecisionTree AddByNull(DecisionTree decision, DecisionMaker makeDecision)
        {
            // the decision tree cannot be complete, as if that were so we would have considered this decision subsumed.
            Debug.Assert(!decision.MatchIsComplete);

            switch (decision.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
                return(AddByNull((DecisionTree.ByType)decision, makeDecision));

            case DecisionTree.DecisionKind.ByValue:
                throw ExceptionUtilities.Unreachable;

            case DecisionTree.DecisionKind.Guarded:
                return(AddByNull((DecisionTree.Guarded)decision, makeDecision));

            default:
                throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #7
0
        protected DecisionTree Add(DecisionTree decision, DecisionMaker makeDecision)
        {
            // the decision tree cannot be complete, otherwise we would have given a subsumption error for this case.
            Debug.Assert(!decision.MatchIsComplete);

            switch (decision.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
                return(Add((DecisionTree.ByType)decision, makeDecision));

            case DecisionTree.DecisionKind.ByValue:
                return(Add((DecisionTree.ByValue)decision, makeDecision));

            case DecisionTree.DecisionKind.Guarded:
                return(Add((DecisionTree.Guarded)decision, makeDecision));

            default:
                throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #8
0
        protected DecisionTree AddToDecisionTree(DecisionTree decisionTree, SyntaxNode sectionSyntax, BoundPatternSwitchLabel label)
        {
            var pattern = label.Pattern;
            var guard   = label.Guard;

            if (guard?.ConstantValue == ConstantValue.False)
            {
                return(null);
            }

            switch (pattern.Kind)
            {
            case BoundKind.ConstantPattern:
            {
                var constantPattern = (BoundConstantPattern)pattern;
                return(AddByValue(decisionTree, constantPattern,
                                  (e, t) => new DecisionTree.Guarded(e, t, default(ImmutableArray <KeyValuePair <BoundExpression, BoundExpression> >), sectionSyntax, guard, label)));
            }

            case BoundKind.DeclarationPattern:
            {
                var           declarationPattern = (BoundDeclarationPattern)pattern;
                DecisionMaker maker =
                    (e, t) => new DecisionTree.Guarded(e, t, ImmutableArray.Create(new KeyValuePair <BoundExpression, BoundExpression>(e, declarationPattern.VariableAccess)), sectionSyntax, guard, label);
                if (declarationPattern.IsVar)
                {
                    return(Add(decisionTree, maker));
                }
                else
                {
                    return(AddByType(decisionTree, declarationPattern.DeclaredType.Type, maker));
                }
            }

            case BoundKind.WildcardPattern:
            // We do not yet support a wildcard pattern syntax. It is used exclusively
            // to model the "default:" case, which is handled specially in the caller.
            default:
                throw ExceptionUtilities.UnexpectedValue(pattern.Kind);
            }
        }
コード例 #9
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByValue(DecisionTree decision, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            if (decision.MatchIsComplete)
            {
                return null;
            }

            // Even if value.ConstantValue == null, we proceed here for error recovery, so that the case label isn't
            // dropped on the floor. That is useful, for example to suppress unreachable code warnings on bad case labels.
            switch (decision.Kind)
            {
                case DecisionTree.DecisionKind.ByType:
                    return AddByValue((DecisionTree.ByType)decision, value, makeDecision);
                case DecisionTree.DecisionKind.ByValue:
                    return AddByValue((DecisionTree.ByValue)decision, value, makeDecision);
                case DecisionTree.DecisionKind.Guarded:
                    return AddByValue((DecisionTree.Guarded)decision, value, makeDecision);
                default:
                    throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #10
0
        private DecisionTree AddByValue(DecisionTree decision, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            Debug.Assert(!decision.MatchIsComplete); // otherwise we would have given a subsumption error

            // Even if value.ConstantValue == null, we proceed here for error recovery, so that the case label isn't
            // dropped on the floor. That is useful, for example to suppress unreachable code warnings on bad case labels.
            switch (decision.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
                return(AddByValue((DecisionTree.ByType)decision, value, makeDecision));

            case DecisionTree.DecisionKind.ByValue:
                return(AddByValue((DecisionTree.ByValue)decision, value, makeDecision));

            case DecisionTree.DecisionKind.Guarded:
                return(AddByValue((DecisionTree.Guarded)decision, value, makeDecision));

            default:
                throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #11
0
        private DecisionTree AddByType(DecisionTree decision, TypeSymbol type, DecisionMaker makeDecision)
        {
            if (decision.MatchIsComplete || decision.Expression.ConstantValue?.IsNull == true)
            {
                return(null);
            }

            switch (decision.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
                return(AddByType((DecisionTree.ByType)decision, type, makeDecision));

            case DecisionTree.DecisionKind.ByValue:
            {
                var byValue = (DecisionTree.ByValue)decision;
                if (byValue.Default == null)
                {
                    byValue.Default = makeDecision(byValue.Expression, byValue.Type);
                    if (byValue.Default.MatchIsComplete)
                    {
                        byValue.MatchIsComplete = true;
                    }

                    return(byValue.Default);
                }
                else
                {
                    Debug.Assert(byValue.Default.Type == type);
                    return(Add(byValue.Default, makeDecision));
                }
            }

            case DecisionTree.DecisionKind.Guarded:
                return(AddByType((DecisionTree.Guarded)decision, type, makeDecision));

            default:
                throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #12
0
        protected DecisionTree Add(DecisionTree decision, DecisionMaker makeDecision)
        {
            if (decision.MatchIsComplete)
            {
                return(null);
            }

            switch (decision.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
                return(Add((DecisionTree.ByType)decision, makeDecision));

            case DecisionTree.DecisionKind.ByValue:
                return(Add((DecisionTree.ByValue)decision, makeDecision));

            case DecisionTree.DecisionKind.Guarded:
                return(Add((DecisionTree.Guarded)decision, makeDecision));

            default:
                throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #13
0
        private DecisionTree AddByValue(DecisionTree decision, BoundExpression value, DecisionMaker makeDecision, bool hasErrors)
        {
            if (decision.MatchIsComplete)
            {
                return(null);
            }

            // Even if value.ConstantValue == null, we proceed here for error recovery, so that the case label isn't
            // dropped on the floor. That is useful, for example to suppress unreachable code warnings on bad case labels.
            switch (decision.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
                return(AddByValue((DecisionTree.ByType)decision, value, makeDecision, hasErrors));

            case DecisionTree.DecisionKind.ByValue:
                return(AddByValue((DecisionTree.ByValue)decision, value, makeDecision, hasErrors));

            case DecisionTree.DecisionKind.Guarded:
                return(AddByValue((DecisionTree.Guarded)decision, value, makeDecision, hasErrors));

            default:
                throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #14
0
            private void LowerDecisionTree(DecisionTree.ByValue byValue)
            {
                if (byValue.Expression.ConstantValue != null)
                {
                    LowerConstantValueDecision(byValue);
                    return;
                }

                if (byValue.ValueAndDecision.Count == 0)
                {
                    LowerDecisionTree(byValue.Expression, byValue.Default);
                    return;
                }

                if (byValue.Type.SpecialType == SpecialType.System_Boolean)
                {
                    LowerBooleanSwitch(byValue);
                }
                else
                {
                    LowerBasicSwitch(byValue);
                }
            }
コード例 #15
0
ファイル: DecisionTree.cs プロジェクト: tvsonar/roslyn
 /// <summary>
 /// Compute the set of temps needed for the whole decision tree.
 /// </summary>
 private ImmutableArray<LocalSymbol> ComputeTemps(DecisionTree decisionTree)
 {
     var builder = ArrayBuilder<LocalSymbol>.GetInstance();
     AddTemps(decisionTree, builder);
     return builder.ToImmutableAndFree();
 }
コード例 #16
0
            private void LowerDecisionTree(DecisionTree.Guarded guarded)
            {
                var sectionBuilder = this._switchSections[guarded.SectionSyntax];
                var targetLabel = guarded.Label.Label;
                Debug.Assert(guarded.Guard?.ConstantValue != ConstantValue.False);
                if (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True)
                {
                    // unconditional
                    Debug.Assert(guarded.Default == null);
                    if (guarded.Bindings.IsDefaultOrEmpty)
                    {
                        _loweredDecisionTree.Add(_factory.Goto(targetLabel));
                    }
                    else
                    {
                        // with bindings
                        AddBindingsForCase(guarded.Bindings, sectionBuilder);
                        sectionBuilder.Add(_factory.Goto(targetLabel));
                    }
                }
                else
                {
                    AddBindingsForCase(guarded.Bindings, sectionBuilder);
                    var guardTest = _factory.ConditionalGoto(guarded.Guard, targetLabel, true);

                    // Only add instrumentation (such as a sequence point) if the node is not compiler-generated.
                    if (!guarded.Guard.WasCompilerGenerated && _localRewriter.Instrument)
                    {
                        guardTest = _localRewriter._instrumenter.InstrumentPatternSwitchWhenClauseConditionalGotoBody(guarded.Guard, guardTest);
                    }

                    sectionBuilder.Add(guardTest);

                    var guardFailed = _factory.GenerateLabel("guardFailed");
                    sectionBuilder.Add(_factory.Goto(guardFailed));
                    _loweredDecisionTree.Add(_factory.Label(guardFailed));

                    LowerDecisionTree(guarded.Expression, guarded.Default);
                }
            }
コード例 #17
0
        /// <summary>
        /// Check if the pattern is subsumed by the decisions in the decision tree, given that the input could
        /// (or could not) be null based on the parameter <paramref name="inputCouldBeNull"/>. If it is subsumed,
        /// returns an error code suitable for reporting the issue. If it is not subsumed, returns 0.
        /// </summary>
        private ErrorCode CheckSubsumed(BoundPattern pattern, DecisionTree decisionTree, bool inputCouldBeNull)
        {
            if (decisionTree.MatchIsComplete)
            {
                return(ErrorCode.ERR_PatternIsSubsumed);
            }

            switch (pattern.Kind)
            {
            case BoundKind.ConstantPattern:
            {
                var constantPattern = (BoundConstantPattern)pattern;
                if (constantPattern.Value.HasErrors || constantPattern.Value.ConstantValue == null || constantPattern.Value.ConstantValue.IsBad)
                {
                    // since this will have been reported earlier, we use ErrorCode.ERR_NoImplicitConvCast
                    // as a flag to suppress errors in subsumption analysis.
                    return(ErrorCode.ERR_NoImplicitConvCast);
                }

                bool isNull = constantPattern.Value.ConstantValue.IsNull;

                // If null inputs have been handled by previous patterns, then
                // the input can no longer be null. In that case a null pattern is subsumed.
                if (isNull && !inputCouldBeNull)
                {
                    return(ErrorCode.ERR_PatternIsSubsumed);
                }

                switch (decisionTree.Kind)
                {
                case DecisionTree.DecisionKind.ByValue:
                {
                    var byValue = (DecisionTree.ByValue)decisionTree;
                    if (isNull)
                    {
                        return(0);                // null must be handled at a type test
                    }

                    DecisionTree decision;
                    if (byValue.ValueAndDecision.TryGetValue(constantPattern.Value.ConstantValue.Value, out decision))
                    {
                        var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                        if (error != 0)
                        {
                            return(error);
                        }
                    }

                    if (byValue.Default != null)
                    {
                        return(CheckSubsumed(pattern, byValue.Default, inputCouldBeNull));
                    }

                    return(0);
                }

                case DecisionTree.DecisionKind.ByType:
                {
                    var byType = (DecisionTree.ByType)decisionTree;
                    if (isNull)
                    {
                        if (byType.WhenNull != null)
                        {
                            var result = CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull);
                            if (result != 0)
                            {
                                return(result);
                            }
                        }
                    }
                    else
                    {
                        foreach (var td in byType.TypeAndDecision)
                        {
                            var type     = td.Key;
                            var decision = td.Value;
                            if (ExpressionOfTypeMatchesPatternType(constantPattern.Value.Type, type, ref _useSiteDiagnostics) == true)
                            {
                                var error = CheckSubsumed(pattern, decision, false);
                                if (error != 0)
                                {
                                    return(error);
                                }
                            }
                        }
                    }
                    return((byType.Default != null) ? CheckSubsumed(pattern, byType.Default, inputCouldBeNull) : 0);
                }

                case DecisionTree.DecisionKind.Guarded:
                {
                    var guarded = (DecisionTree.Guarded)decisionTree;
                    return
                        ((guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :
                         guarded.Default == null ? 0 : CheckSubsumed(pattern, guarded.Default, inputCouldBeNull));
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                }
            }

            case BoundKind.DeclarationPattern:
            {
                var declarationPattern = (BoundDeclarationPattern)pattern;
                switch (decisionTree.Kind)
                {
                case DecisionTree.DecisionKind.ByValue:
                {
                    // A declaration pattern is only subsumed by a value pattern if all of the values are accounted for.
                    // For example, when switching on a bool, do we handle both true and false?
                    // For now, we do not handle this case. Also, this provides compatibility with previous compilers.
                    if (inputCouldBeNull)
                    {
                        return(0);                // null could never be handled by a value decision
                    }

                    var byValue = (DecisionTree.ByValue)decisionTree;
                    if (byValue.Default != null)
                    {
                        return(CheckSubsumed(pattern, byValue.Default, false));
                    }

                    return(0);
                }

                case DecisionTree.DecisionKind.ByType:
                {
                    var byType = (DecisionTree.ByType)decisionTree;
                    if (declarationPattern.IsVar &&
                        inputCouldBeNull &&
                        (byType.WhenNull == null || CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull) == 0) &&
                        (byType.Default == null || CheckSubsumed(pattern, byType.Default, inputCouldBeNull) == 0))
                    {
                        return(0);                // new pattern catches null if not caught by existing WhenNull or Default
                    }

                    inputCouldBeNull = false;
                    foreach (var td in byType.TypeAndDecision)
                    {
                        var type     = td.Key;
                        var decision = td.Value;
                        // if the pattern's type is already handled by the previous pattern
                        // or the previous pattern handles all of the (non-null) input data...
                        if (ExpressionOfTypeMatchesPatternType(
                                declarationPattern.DeclaredType.Type.TupleUnderlyingTypeOrSelf(), type, ref _useSiteDiagnostics) == true ||
                            ExpressionOfTypeMatchesPatternType(byType.Type, type, ref _useSiteDiagnostics) == true)
                        {
                            // then we check if the pattern is subsumed by the previous decision
                            var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                            if (error != 0)
                            {
                                return(error);
                            }
                        }
                    }

                    if (byType.Default != null)
                    {
                        return(CheckSubsumed(pattern, byType.Default, inputCouldBeNull));
                    }

                    return(0);
                }

                case DecisionTree.DecisionKind.Guarded:
                {
                    var guarded = (DecisionTree.Guarded)decisionTree;
                    return((guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :
                           guarded.Default != null?CheckSubsumed(pattern, guarded.Default, inputCouldBeNull) : 0);
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                }
            }

            case BoundKind.WildcardPattern:
            {
                switch (decisionTree.Kind)
                {
                case DecisionTree.DecisionKind.ByValue:
                    return(0);            // a value pattern is always considered incomplete (even bool true and false)

                case DecisionTree.DecisionKind.ByType:
                {
                    var byType = (DecisionTree.ByType)decisionTree;
                    if (inputCouldBeNull &&
                        (byType.WhenNull == null || CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull) == 0) &&
                        (byType.Default == null || CheckSubsumed(pattern, byType.Default, inputCouldBeNull) == 0))
                    {
                        return(0);                // new pattern catches null if not caught by existing WhenNull or Default
                    }

                    inputCouldBeNull = false;
                    foreach (var td in byType.TypeAndDecision)
                    {
                        var type     = td.Key;
                        var decision = td.Value;
                        if (ExpressionOfTypeMatchesPatternType(decisionTree.Type, type, ref _useSiteDiagnostics) == true)
                        {
                            var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                            if (error != 0)
                            {
                                return(error);
                            }
                        }
                    }

                    if (byType.Default != null)
                    {
                        return(CheckSubsumed(pattern, byType.Default, inputCouldBeNull));
                    }

                    return(0);
                }

                case DecisionTree.DecisionKind.Guarded:
                {
                    var guarded = (DecisionTree.Guarded)decisionTree;
                    return((guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :
                           guarded.Default != null?CheckSubsumed(pattern, guarded.Default, inputCouldBeNull) : 0);
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                }
            }

            default:
                throw ExceptionUtilities.UnexpectedValue(pattern.Kind);
            }
        }
コード例 #18
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByNull(DecisionTree.Guarded guarded, DecisionMaker makeDecision)
        {
            if (guarded.Default == null)
            {
                guarded.Default = new DecisionTree.ByType(guarded.Expression, guarded.Type, null);
            }

            var result = AddByNull(guarded.Default, makeDecision);
            if (guarded.Default.MatchIsComplete)
            {
                guarded.MatchIsComplete = true;
            }

            return result;
        }
コード例 #19
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private bool NonNullHandled(DecisionTree.ByType byType)
        {
            var inputType = byType.Type.StrippedType().TupleUnderlyingTypeOrSelf();
            foreach (var td in byType.TypeAndDecision)
            {
                var type = td.Key;
                var decision = td.Value;
                if (ExpressionOfTypeMatchesPatternType(inputType, type, ref _useSiteDiagnostics) == true &&
                    decision.MatchIsComplete)
                {
                    return true;
                }
            }

            return false;
        }
コード例 #20
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByNull(DecisionTree.ByType byType, DecisionMaker makeDecision)
        {
            if (byType.WhenNull?.MatchIsComplete == true || byType.Default?.MatchIsComplete == true)
            {
                return null;
            }

            if (byType.Default != null)
            {
                try
                {
                    return AddByNull(byType.Default, makeDecision);
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        byType.MatchIsComplete = true;
                    }
                }
            }
            DecisionTree result;
            if (byType.WhenNull == null)
            {
                result = byType.WhenNull = makeDecision(byType.Expression, byType.Type);
            }
            else
            {
                result = Add(byType.WhenNull, makeDecision);
            }

            if (byType.WhenNull.MatchIsComplete && NonNullHandled(byType))
            {
                byType.MatchIsComplete = true;
            }

            return result;
        }
コード例 #21
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByNull(DecisionTree decision, DecisionMaker makeDecision)
        {
            if (decision.MatchIsComplete)
            {
                return null;
            }

            switch (decision.Kind)
            {
                case DecisionTree.DecisionKind.ByType:
                    return AddByNull((DecisionTree.ByType)decision, makeDecision);
                case DecisionTree.DecisionKind.ByValue:
                    {
                        var byValue = (DecisionTree.ByValue)decision;
                        if (byValue.MatchIsComplete)
                        {
                            return null;
                        }

                        throw ExceptionUtilities.Unreachable;
                    }
                case DecisionTree.DecisionKind.Guarded:
                    return AddByNull((DecisionTree.Guarded)decision, makeDecision);
                default:
                    throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #22
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByType(DecisionTree.ByType byType, TypeSymbol type, DecisionMaker makeDecision)
        {
            if (byType.Default != null)
            {
                try
                {
                    return AddByType(byType.Default, type, makeDecision);
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        byType.MatchIsComplete = true;
                    }
                }
            }
            foreach (var kvp in byType.TypeAndDecision)
            {
                var MatchedType = kvp.Key;
                var Decision = kvp.Value;
                // See if matching Type matches this value
                switch (ExpressionOfTypeMatchesPatternType(type, MatchedType, ref _useSiteDiagnostics))
                {
                    case true:
                        if (Decision.MatchIsComplete)
                        {
                            return null;
                        }

                        continue;
                    case false:
                        continue;
                    case null:
                        continue;
                }
            }

            var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, Syntax, false, RefKind.None);
            var expression = new BoundLocal(Syntax, localSymbol, null, type);
            var result = makeDecision(expression, type);
            Debug.Assert(result.Temp == null);
            result.Temp = localSymbol;
            byType.TypeAndDecision.Add(new KeyValuePair<TypeSymbol, DecisionTree>(type, result));
            if (ExpressionOfTypeMatchesPatternType(byType.Type, type, ref _useSiteDiagnostics) == true &&
                result.MatchIsComplete &&
                byType.WhenNull?.MatchIsComplete == true)
            {
                byType.MatchIsComplete = true;
            }

            return result;
        }
コード例 #23
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByType(DecisionTree decision, TypeSymbol type, DecisionMaker makeDecision)
        {
            if (decision.MatchIsComplete || decision.Expression.ConstantValue?.IsNull == true)
            {
                return null;
            }

            switch (decision.Kind)
            {
                case DecisionTree.DecisionKind.ByType:
                    return AddByType((DecisionTree.ByType)decision, type, makeDecision);
                case DecisionTree.DecisionKind.ByValue:
                    {
                        var byValue = (DecisionTree.ByValue)decision;
                        if (byValue.Default == null)
                        {
                            byValue.Default = makeDecision(byValue.Expression, byValue.Type);
                            if (byValue.Default.MatchIsComplete)
                            {
                                byValue.MatchIsComplete = true;
                            }

                            return byValue.Default;
                        }
                        else
                        {
                            Debug.Assert(byValue.Default.Type == type);
                            return Add(byValue.Default, makeDecision);
                        }
                    }
                case DecisionTree.DecisionKind.Guarded:
                    return AddByType((DecisionTree.Guarded)decision, type, makeDecision);
                default:
                    throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #24
0
            private void LowerDecisionTree(DecisionTree.Guarded guarded)
            {
                var sectionBuilder = this.SwitchSections[guarded.Section];
                var targetLabel = guarded.Label.Label;
                Debug.Assert(guarded.Guard?.ConstantValue != ConstantValue.False);
                if (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True)
                {
                    // unconditional
                    Debug.Assert(guarded.Default == null);
                    if (guarded.Bindings.IsDefaultOrEmpty)
                    {
                        _loweredDecisionTree.Add(_factory.Goto(targetLabel));
                    }
                    else
                    {
                        // with bindings
                        var matched = _factory.GenerateLabel("matched");
                        _loweredDecisionTree.Add(_factory.Goto(matched));
                        sectionBuilder.Add(_factory.Label(matched));
                        AddBindings(sectionBuilder, guarded.Bindings);
                        sectionBuilder.Add(_factory.Goto(targetLabel));
                    }
                }
                else
                {
                    var checkGuard = _factory.GenerateLabel("checkGuard");
                    _loweredDecisionTree.Add(_factory.Goto(checkGuard));
                    sectionBuilder.Add(_factory.Label(checkGuard));
                    AddBindings(sectionBuilder, guarded.Bindings);
                    sectionBuilder.Add(_factory.ConditionalGoto(LocalRewriter.VisitExpression(guarded.Guard), targetLabel, true));
                    var guardFailed = _factory.GenerateLabel("guardFailed");
                    sectionBuilder.Add(_factory.Goto(guardFailed));
                    _loweredDecisionTree.Add(_factory.Label(guardFailed));

                    LowerDecisionTree(guarded.Expression, guarded.Default);
                }
            }
コード例 #25
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByValue(DecisionTree.ByType byType, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            if (byType.Default != null)
            {
                try
                {
                    return AddByValue(byType.Default, value, makeDecision);
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        byType.MatchIsComplete = true;
                    }
                }
            }

            if (value.ConstantValue == ConstantValue.Null)
            {
                return byType.Expression.ConstantValue?.IsNull == false
                    ? null : AddByNull((DecisionTree)byType, makeDecision);
            }

            foreach (var kvp in byType.TypeAndDecision)
            {
                var matchedType = kvp.Key;
                var decision = kvp.Value;

                // See if the test is already subsumed
                switch (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics))
                {
                    case true:
                        if (decision.MatchIsComplete)
                        {
                            return null;
                        }

                        continue;
                    case false:
                    case null:
                        continue;
                }
            }

            DecisionTree forType = null;

            // Find an existing decision tree for the expression's type. Since this new test
            // should logically be last, we look for the last one we can piggy-back it onto.
            for (int i = byType.TypeAndDecision.Count - 1; i >= 0 && forType == null; i--)
            {
                var kvp = byType.TypeAndDecision[i];
                var matchedType = kvp.Key;
                var decision = kvp.Value;
                if (matchedType.TupleUnderlyingTypeOrSelf() == value.Value.Type.TupleUnderlyingTypeOrSelf())
                {
                    forType = decision;
                    break;
                }
                else if (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics) != false)
                {
                    break;
                }
            }

            if (forType == null)
            {
                var type = value.Value.Type;
                var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, Syntax, false, RefKind.None);
                var narrowedExpression = new BoundLocal(Syntax, localSymbol, null, type);
                forType = new DecisionTree.ByValue(narrowedExpression, value.Value.Type.TupleUnderlyingTypeOrSelf(), localSymbol);
                byType.TypeAndDecision.Add(new KeyValuePair<TypeSymbol, DecisionTree>(value.Value.Type, forType));
            }

            return AddByValue(forType, value, makeDecision);
        }
コード例 #26
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        protected DecisionTree Add(DecisionTree decision, DecisionMaker makeDecision)
        {
            if (decision.MatchIsComplete)
            {
                return null;
            }

            switch (decision.Kind)
            {
                case DecisionTree.DecisionKind.ByType:
                    return Add((DecisionTree.ByType)decision, makeDecision);
                case DecisionTree.DecisionKind.ByValue:
                    return Add((DecisionTree.ByValue)decision, makeDecision);
                case DecisionTree.DecisionKind.Guarded:
                    return Add((DecisionTree.Guarded)decision, makeDecision);
                default:
                    throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #27
0
        private DecisionTree AddByValue(DecisionTree.ByType byType, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            if (byType.Default != null)
            {
                try
                {
                    return(AddByValue(byType.Default, value, makeDecision));
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        byType.MatchIsComplete = true;
                    }
                }
            }

            if (value.ConstantValue == ConstantValue.Null)
            {
                return(byType.Expression.ConstantValue?.IsNull == false
                    ? null : AddByNull((DecisionTree)byType, makeDecision));
            }

            foreach (var kvp in byType.TypeAndDecision)
            {
                var matchedType = kvp.Key;
                var decision    = kvp.Value;

                // See if the test is already subsumed
                switch (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics))
                {
                case true:
                    if (decision.MatchIsComplete)
                    {
                        return(null);
                    }

                    continue;

                case false:
                case null:
                    continue;
                }
            }

            DecisionTree forType = null;

            // Find an existing decision tree for the expression's type. Since this new test
            // should logically be last, we look for the last one we can piggy-back it onto.
            for (int i = byType.TypeAndDecision.Count - 1; i >= 0 && forType == null; i--)
            {
                var kvp         = byType.TypeAndDecision[i];
                var matchedType = kvp.Key;
                var decision    = kvp.Value;
                if (matchedType.TupleUnderlyingTypeOrSelf() == value.Value.Type.TupleUnderlyingTypeOrSelf())
                {
                    forType = decision;
                    break;
                }
                else if (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics) != false)
                {
                    break;
                }
            }

            if (forType == null)
            {
                var type               = value.Value.Type;
                var localSymbol        = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, Syntax, false, RefKind.None);
                var narrowedExpression = new BoundLocal(Syntax, localSymbol, null, type);
                forType = new DecisionTree.ByValue(narrowedExpression, value.Value.Type.TupleUnderlyingTypeOrSelf(), localSymbol);
                byType.TypeAndDecision.Add(new KeyValuePair <TypeSymbol, DecisionTree>(value.Value.Type, forType));
            }

            return(AddByValue(forType, value, makeDecision));
        }
コード例 #28
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree Add(DecisionTree.Guarded guarded, DecisionMaker makeDecision)
        {
            if (guarded.Default != null)
            {
                if (guarded.Default.MatchIsComplete)
                {
                    return null;
                }

                var result = Add(guarded.Default, makeDecision);
                if (guarded.Default.MatchIsComplete)
                {
                    guarded.MatchIsComplete = true;
                }

                return result;
            }
            else
            {
                var result = guarded.Default = makeDecision(guarded.Expression, guarded.Type);
                if (guarded.Default.MatchIsComplete)
                {
                    guarded.MatchIsComplete = true;
                }

                return result;
            }
        }
コード例 #29
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree Add(DecisionTree.ByValue byValue, DecisionMaker makeDecision)
        {
            DecisionTree result;
            if (byValue.Default != null)
            {
                result = Add(byValue.Default, makeDecision);
            }
            else
            {
                result = byValue.Default = makeDecision(byValue.Expression, byValue.Type);
            }
            if (byValue.Default.MatchIsComplete)
            {
                byValue.MatchIsComplete = true;
            }

            return result;
        }
コード例 #30
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
 private DecisionTree Add(DecisionTree.ByType byType, DecisionMaker makeDecision)
 {
     try
     {
         if (byType.Default == null)
         {
             byType.Default = makeDecision(byType.Expression, byType.Type);
             return byType.Default;
         }
         else
         {
             return Add(byType.Default, makeDecision);
         }
     }
     finally
     {
         if (byType.Default.MatchIsComplete)
         {
             byType.MatchIsComplete = true;
         }
     }
 }
コード例 #31
0
 /// <summary>
 /// Lower the given decision tree into the given statement builder.
 /// </summary>
 private void LowerDecisionTree(BoundExpression expression, DecisionTree decisionTree, ArrayBuilder<BoundStatement> loweredDecisionTree)
 {
     // build a decision tree to dispatch the switch statement
     var oldLoweredDecisionTree = this._loweredDecisionTree;
     this._loweredDecisionTree = loweredDecisionTree;
     LowerDecisionTree(expression, decisionTree);
     this._loweredDecisionTree = oldLoweredDecisionTree;
 }
コード例 #32
0
            private void LowerBooleanSwitch(DecisionTree.ByValue byValue)
            {
                switch (byValue.ValueAndDecision.Count)
                {
                    case 0:
                        {
                            // this should have been handled in the caller.
                            throw ExceptionUtilities.Unreachable;
                        }
                    case 1:
                        {
                            DecisionTree decision;
                            bool onBoolean = byValue.ValueAndDecision.TryGetValue(true, out decision);
                            if (!onBoolean)
                            {
                                byValue.ValueAndDecision.TryGetValue(false, out decision);
                            }

                            Debug.Assert(decision != null);
                            var onOther = _factory.GenerateLabel("on" + !onBoolean);
                            _loweredDecisionTree.Add(_factory.ConditionalGoto(byValue.Expression, onOther, !onBoolean));
                            LowerDecisionTree(byValue.Expression, decision);
                            // if we fall through here, that means the match was not complete and we invoke the default part
                            _loweredDecisionTree.Add(_factory.Label(onOther));
                            LowerDecisionTree(byValue.Expression, byValue.Default);
                            break;
                        }
                    case 2:
                        {
                            DecisionTree trueDecision, falseDecision;
                            bool hasTrue = byValue.ValueAndDecision.TryGetValue(true, out trueDecision);
                            bool hasFalse = byValue.ValueAndDecision.TryGetValue(false, out falseDecision);
                            Debug.Assert(hasTrue && hasFalse);
                            var tryAnother = _factory.GenerateLabel("tryAnother");
                            var onFalse = _factory.GenerateLabel("onFalse");
                            _loweredDecisionTree.Add(_factory.ConditionalGoto(byValue.Expression, onFalse, false));
                            LowerDecisionTree(byValue.Expression, trueDecision);
                            _loweredDecisionTree.Add(_factory.Goto(tryAnother));
                            _loweredDecisionTree.Add(_factory.Label(onFalse));
                            LowerDecisionTree(byValue.Expression, falseDecision);
                            _loweredDecisionTree.Add(_factory.Label(tryAnother));
                            // if both true and false (i.e. all values) are fully handled, there should be no default.
                            Debug.Assert(!trueDecision.MatchIsComplete || !falseDecision.MatchIsComplete || byValue.Default == null);
                            LowerDecisionTree(byValue.Expression, byValue.Default);
                            break;
                        }
                    default:
                        throw ExceptionUtilities.UnexpectedValue(byValue.ValueAndDecision.Count);
                }
            }
コード例 #33
0
        private DecisionTree AddByValue(DecisionTree.ByType byType, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            if (byType.Default != null)
            {
                try
                {
                    return(AddByValue(byType.Default, value, makeDecision));
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        // This code may be unreachable due to https://github.com/dotnet/roslyn/issues/16878
                        byType.MatchIsComplete = true;
                    }
                }
            }

            if (value.ConstantValue == ConstantValue.Null)
            {
                // This should not occur, as the caller will have invoked AddByNull instead.
                throw ExceptionUtilities.Unreachable;
            }

            if ((object)value.Value.Type == null)
            {
                return(null);
            }

            foreach (var kvp in byType.TypeAndDecision)
            {
                var matchedType = kvp.Key;
                var decision    = kvp.Value;

                // See if the test is already subsumed
                switch (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics))
                {
                case true:
                    if (decision.MatchIsComplete)
                    {
                        return(null);
                    }

                    continue;

                case false:
                case null:
                    continue;
                }
            }

            DecisionTree forType = null;

            // This new type test should logically be last. However it might be the same type as the one that is already
            // last. In that case we can produce better code by piggy-backing our new case on to the last decision.
            // Also, the last one might be a non-overlapping type, in which case we can piggy-back onto the second-last
            // type test.
            for (int i = byType.TypeAndDecision.Count - 1; i >= 0; i--)
            {
                var kvp         = byType.TypeAndDecision[i];
                var matchedType = kvp.Key;
                var decision    = kvp.Value;
                if (matchedType.Equals(value.Value.Type, TypeCompareKind.IgnoreDynamicAndTupleNames))
                {
                    forType = decision;
                    break;
                }
                else if (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics) != false)
                {
                    // because there is overlap, we cannot reuse some earlier entry
                    break;
                }
            }

            // if we did not piggy-back, then create a new decision tree node for the type.
            if (forType == null)
            {
                var type               = value.Value.Type;
                var localSymbol        = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatching, Syntax, false, RefKind.None);
                var narrowedExpression = new BoundLocal(Syntax, localSymbol, null, type);
                forType = new DecisionTree.ByValue(narrowedExpression, value.Value.Type.TupleUnderlyingTypeOrSelf(), localSymbol);
                byType.TypeAndDecision.Add(new KeyValuePair <TypeSymbol, DecisionTree>(value.Value.Type, forType));
            }

            return(AddByValue(forType, value, makeDecision));
        }
コード例 #34
0
        // Visit all the branches in the decision tree
        private void VisitDecisionTree(DecisionTree decisionTree)
        {
            if (decisionTree == null)
            {
                return;
            }

            switch (decisionTree.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
            {
                var byType        = (DecisionTree.ByType)decisionTree;
                var inputConstant = byType.Expression.ConstantValue;
                if (inputConstant != null)
                {
                    if (inputConstant.IsNull)
                    {
                        VisitDecisionTree(byType.WhenNull);
                    }
                    else
                    {
                        foreach (var kvp in byType.TypeAndDecision)
                        {
                            VisitDecisionTree(kvp.Value);
                            if (kvp.Value.MatchIsComplete)
                            {
                                return;
                            }
                        }

                        VisitDecisionTree(byType.Default);
                    }
                }
                else
                {
                    VisitDecisionTree(byType.WhenNull);
                    foreach (var kvp in byType.TypeAndDecision)
                    {
                        VisitDecisionTree(kvp.Value);
                    }

                    VisitDecisionTree(byType.Default);
                }
                return;
            }

            case DecisionTree.DecisionKind.ByValue:
            {
                var byValue       = (DecisionTree.ByValue)decisionTree;
                var inputConstant = byValue.Expression.ConstantValue;
                if (inputConstant != null)
                {
                    DecisionTree onValue;
                    if (byValue.ValueAndDecision.TryGetValue(inputConstant.Value, out onValue))
                    {
                        VisitDecisionTree(onValue);
                        if (!onValue.MatchIsComplete)
                        {
                            VisitDecisionTree(byValue.Default);
                        }
                    }
                    else
                    {
                        VisitDecisionTree(byValue.Default);
                    }
                }
                else
                {
                    foreach (var kvp in byValue.ValueAndDecision)
                    {
                        VisitDecisionTree(kvp.Value);
                    }

                    VisitDecisionTree(byValue.Default);
                }
                return;
            }

            case DecisionTree.DecisionKind.Guarded:
            {
                VisitGuardedDecisionTree((DecisionTree.Guarded)decisionTree);
                return;
            }

            default:
                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
            }
        }
コード例 #35
0
ファイル: DecisionTree.cs プロジェクト: tvsonar/roslyn
        private DecisionTree AddByValue(DecisionTree.Guarded guarded, BoundExpression value, DecisionMaker makeDecision, bool hasErrors)
        {
            if (guarded.Default != null)
            {
                if (guarded.Default.MatchIsComplete)
                {
                    return null;
                }
            }
            else
            {
                guarded.Default = new DecisionTree.ByValue(guarded.Expression, guarded.Type, null);
            }

            return AddByValue(guarded.Default, value, makeDecision, hasErrors);
        }
コード例 #36
0
        /// <summary>
        /// Check if the pattern is subsumed by the decisions in the decision tree, given that the input could
        /// (or could not) be null based on the parameter <paramref name="inputCouldBeNull"/>. If it is subsumed,
        /// returns an error code suitable for reporting the issue. If it is not subsumed, returns 0.
        /// </summary>
        private ErrorCode CheckSubsumed(BoundPattern pattern, DecisionTree decisionTree, bool inputCouldBeNull)
        {
            if (decisionTree.MatchIsComplete)
            {
                return ErrorCode.ERR_PatternIsSubsumed;
            }

            switch (pattern.Kind)
            {
                case BoundKind.ConstantPattern:
                    {
                        var constantPattern = (BoundConstantPattern)pattern;
                        if (constantPattern.Value.HasErrors || constantPattern.Value.ConstantValue == null)
                        {
                            // since this will have been reported earlier, we use ErrorCode.ERR_NoImplicitConvCast
                            // as a flag to suppress errors in subsumption analysis.
                            return ErrorCode.ERR_NoImplicitConvCast;
                        }

                        bool isNull = constantPattern.Value.ConstantValue.IsNull;

                        // If null inputs have been handled by previous patterns, then
                        // the input can no longer be null. In that case a null pattern is subsumed.
                        if (isNull && !inputCouldBeNull)
                        {
                            return ErrorCode.ERR_PatternIsSubsumed;
                        }

                        switch (decisionTree.Kind)
                        {
                            case DecisionTree.DecisionKind.ByValue:
                                {
                                    var byValue = (DecisionTree.ByValue)decisionTree;
                                    if (isNull)
                                    {
                                        return 0; // null must be handled at a type test
                                    }

                                    DecisionTree decision;
                                    if (byValue.ValueAndDecision.TryGetValue(constantPattern.Value.ConstantValue.Value, out decision))
                                    {
                                        var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                                        if (error != 0)
                                        {
                                            return error;
                                        }
                                    }

                                    if (byValue.Default != null)
                                    {
                                        return CheckSubsumed(pattern, byValue.Default, inputCouldBeNull);
                                    }

                                    return 0;
                                }
                            case DecisionTree.DecisionKind.ByType:
                                {
                                    var byType = (DecisionTree.ByType)decisionTree;
                                    if (isNull)
                                    {
                                        if (byType.WhenNull != null)
                                        {
                                            var result = CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull);
                                            if (result != 0)
                                            {
                                                return result;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        foreach (var td in byType.TypeAndDecision)
                                        {
                                            var type = td.Key;
                                            var decision = td.Value;
                                            if (ExpressionOfTypeMatchesPatternType(constantPattern.Value.Type, type, ref _useSiteDiagnostics) == true)
                                            {
                                                var error = CheckSubsumed(pattern, decision, false);
                                                if (error != 0)
                                                {
                                                    return error;
                                                }
                                            }
                                        }
                                    }
                                    return (byType.Default != null) ? CheckSubsumed(pattern, byType.Default, inputCouldBeNull) : 0;
                                }
                            case DecisionTree.DecisionKind.Guarded:
                                {
                                    var guarded = (DecisionTree.Guarded)decisionTree;
                                    return
                                        (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :
                                        guarded.Default == null ? 0 : CheckSubsumed(pattern, guarded.Default, inputCouldBeNull);
                                }
                            default:
                                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                        }
                    }
                case BoundKind.DeclarationPattern:
                    {
                        var declarationPattern = (BoundDeclarationPattern)pattern;
                        switch (decisionTree.Kind)
                        {
                            case DecisionTree.DecisionKind.ByValue:
                                {
                                    // A declaration pattern is only subsumed by a value pattern if all of the values are accounted for.
                                    // For example, when switching on a bool, do we handle both true and false?
                                    // For now, we do not handle this case. Also, this provides compatibility with previous compilers.
                                    if (inputCouldBeNull)
                                    {
                                        return 0; // null could never be handled by a value decision
                                    }

                                    var byValue = (DecisionTree.ByValue)decisionTree;
                                    if (byValue.Default != null)
                                    {
                                        return CheckSubsumed(pattern, byValue.Default, false);
                                    }

                                    return 0;
                                }
                            case DecisionTree.DecisionKind.ByType:
                                {
                                    var byType = (DecisionTree.ByType)decisionTree;
                                    if (declarationPattern.IsVar &&
                                        inputCouldBeNull &&
                                        (byType.WhenNull == null || CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull) == 0) &&
                                        (byType.Default == null || CheckSubsumed(pattern, byType.Default, inputCouldBeNull) == 0))
                                    {
                                        return 0; // new pattern catches null if not caught by existing WhenNull or Default
                                    }

                                    inputCouldBeNull = false;
                                    foreach (var td in byType.TypeAndDecision)
                                    {
                                        var type = td.Key;
                                        var decision = td.Value;
                                        if (ExpressionOfTypeMatchesPatternType(
                                                declarationPattern.DeclaredType.Type.TupleUnderlyingTypeOrSelf(), type, ref _useSiteDiagnostics) == true)
                                        {
                                            var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                                            if (error != 0)
                                            {
                                                return error;
                                            }
                                        }
                                    }

                                    if (byType.Default != null)
                                    {
                                        return CheckSubsumed(pattern, byType.Default, inputCouldBeNull);
                                    }

                                    return 0;
                                }
                            case DecisionTree.DecisionKind.Guarded:
                                {
                                    var guarded = (DecisionTree.Guarded)decisionTree;
                                    return (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :
                                        guarded.Default != null ? CheckSubsumed(pattern, guarded.Default, inputCouldBeNull) : 0;
                                }
                            default:
                                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                        }
                    }
                case BoundKind.WildcardPattern:
                    {
                        switch (decisionTree.Kind)
                        {
                            case DecisionTree.DecisionKind.ByValue:
                                return 0; // a value pattern is always considered incomplete (even bool true and false)
                            case DecisionTree.DecisionKind.ByType:
                                {
                                    var byType = (DecisionTree.ByType)decisionTree;
                                    if (inputCouldBeNull &&
                                        (byType.WhenNull == null || CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull) == 0) &&
                                        (byType.Default == null || CheckSubsumed(pattern, byType.Default, inputCouldBeNull) == 0))
                                    {
                                        return 0; // new pattern catches null if not caught by existing WhenNull or Default
                                    }

                                    inputCouldBeNull = false;
                                    foreach (var td in byType.TypeAndDecision)
                                    {
                                        var type = td.Key;
                                        var decision = td.Value;
                                        if (ExpressionOfTypeMatchesPatternType(decisionTree.Type, type, ref _useSiteDiagnostics) == true)
                                        {
                                            var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                                            if (error != 0)
                                            {
                                                return error;
                                            }
                                        }
                                    }

                                    if (byType.Default != null)
                                    {
                                        return CheckSubsumed(pattern, byType.Default, inputCouldBeNull);
                                    }

                                    return 0;
                                }
                            case DecisionTree.DecisionKind.Guarded:
                                {
                                    var guarded = (DecisionTree.Guarded)decisionTree;
                                    return (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :
                                        guarded.Default != null ? CheckSubsumed(pattern, guarded.Default, inputCouldBeNull) : 0;
                                }
                            default:
                                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                        }
                    }
                default:
                    throw ExceptionUtilities.UnexpectedValue(pattern.Kind);
            }
        }
コード例 #37
0
            private void LowerDecisionTree(DecisionTree.ByType byType)
            {
                var inputConstant = byType.Expression.ConstantValue;
                if (inputConstant != null)
                {
                    if (inputConstant.IsNull)
                    {
                        // input is the constant null
                        LowerDecisionTree(byType.Expression, byType.WhenNull);
                        if (byType.WhenNull?.MatchIsComplete != true)
                        {
                            LowerDecisionTree(byType.Expression, byType.Default);
                        }
                    }
                    else
                    {
                        // input is a non-null constant
                        foreach (var kvp in byType.TypeAndDecision)
                        {
                            LowerDecisionTree(byType.Expression, kvp.Value);
                            if (kvp.Value.MatchIsComplete)
                            {
                                return;
                            }
                        }

                        LowerDecisionTree(byType.Expression, byType.Default);
                    }
                }
                else
                {
                    var defaultLabel = _factory.GenerateLabel("byTypeDefault");

                    // input is not a constant
                    if (byType.Type.CanBeAssignedNull())
                    {
                        // first test for null
                        var notNullLabel = _factory.GenerateLabel("notNull");
                        var inputExpression = byType.Expression;
                        var nullValue = _factory.Null(byType.Type);
                        BoundExpression notNull = byType.Type.IsNullableType()
                            ? LocalRewriter.RewriteNullableNullEquality(_factory.Syntax, BinaryOperatorKind.NullableNullNotEqual, byType.Expression, nullValue, _factory.SpecialType(SpecialType.System_Boolean))
                            : _factory.ObjectNotEqual(byType.Expression, nullValue);
                        _loweredDecisionTree.Add(_factory.ConditionalGoto(notNull, notNullLabel, true));
                        LowerDecisionTree(byType.Expression, byType.WhenNull);
                        if (byType.WhenNull?.MatchIsComplete != true)
                        {
                            _loweredDecisionTree.Add(_factory.Goto(defaultLabel));
                        }

                        _loweredDecisionTree.Add(_factory.Label(notNullLabel));
                    }
                    else
                    {
                        Debug.Assert(byType.WhenNull == null);
                    }

                    foreach (var td in byType.TypeAndDecision)
                    {
                        // then test for each type, sequentially
                        var type = td.Key;
                        var decision = td.Value;
                        var failLabel = _factory.GenerateLabel("failedDecision");
                        var testAndCopy = TypeTestAndCopyToTemp(byType.Expression, decision.Expression);
                        _loweredDecisionTree.Add(_factory.ConditionalGoto(testAndCopy, failLabel, false));
                        LowerDecisionTree(decision.Expression, decision);
                        _loweredDecisionTree.Add(_factory.Label(failLabel));
                    }

                    // finally, the default for when no type matches
                    _loweredDecisionTree.Add(_factory.Label(defaultLabel));
                    LowerDecisionTree(byType.Expression, byType.Default);
                }
            }
コード例 #38
0
        private DecisionTree AddByValue(DecisionTree.ByType byType, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            if (byType.Default != null)
            {
                try
                {
                    return(AddByValue(byType.Default, value, makeDecision));
                }
                finally
                {
                    if (byType.Default.MatchIsComplete)
                    {
                        // This code may be unreachable due to https://github.com/dotnet/roslyn/issues/16878
                        byType.MatchIsComplete = true;
                    }
                }
            }

            if (value.ConstantValue == ConstantValue.Null)
            {
                // This should not occur, as the caller will have invoked AddByNull instead.
                throw ExceptionUtilities.Unreachable;
            }

            if ((object)value.Value.Type == null || value.ConstantValue == null)
            {
                return(null);
            }

            foreach (var kvp in byType.TypeAndDecision)
            {
                var matchedType = kvp.Key;
                var decision    = kvp.Value;

                // See if the test is already subsumed
                switch (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics))
                {
                case true:
                    if (decision.MatchIsComplete)
                    {
                        // Subsumed case have been eliminated by semantic analysis.
                        Debug.Assert(false);
                        return(null);
                    }

                    continue;

                case false:
                case null:
                    continue;
                }
            }

            DecisionTree forType = null;

            // This new type test should logically be last. However it might be the same type as the one that is already
            // last. In that case we can produce better code by piggy-backing our new case on to the last decision.
            // Also, the last one might be a non-overlapping type, in which case we can piggy-back onto the second-last
            // type test.
            for (int i = byType.TypeAndDecision.Count - 1; i >= 0; i--)
            {
                var kvp         = byType.TypeAndDecision[i];
                var matchedType = kvp.Key;
                var decision    = kvp.Value;
                if (matchedType.Equals(value.Value.Type, TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes))
                {
                    forType = decision;
                    break;
                }
                switch (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics))
                {
                case true:
                    if (decision.MatchIsComplete)
                    {
                        // we should have reported this case as subsumed already.
                        Debug.Assert(false);
                        return(null);
                    }
                    else
                    {
                        goto case null;
                    }

                case false:
                    continue;

                case null:
                    // because there is overlap, we cannot reuse some earlier entry
                    goto noReuse;
                }
            }
            noReuse :;

            // if we did not piggy-back, then create a new decision tree node for the type.
            if (forType == null)
            {
                var type = value.Value.Type;
                if (byType.Type.Equals(type, TypeCompareKind.AllIgnoreOptions))
                {
                    // reuse the input expression when we have an equivalent type to reduce the number of generated temps
                    forType = new DecisionTree.ByValue(byType.Expression, type.TupleUnderlyingTypeOrSelf(), null);
                }
                else
                {
                    var narrowedExpression = GetBoundPatternMatchingLocal(type);
                    forType = new DecisionTree.ByValue(narrowedExpression, type.TupleUnderlyingTypeOrSelf(), narrowedExpression.LocalSymbol);
                }

                byType.TypeAndDecision.Add(new KeyValuePair <TypeSymbol, DecisionTree>(type, forType));
            }

            return(AddByValue(forType, value, makeDecision));
        }
コード例 #39
0
            private void LowerConstantValueDecision(DecisionTree.ByValue byValue)
            {
                var value = byValue.Expression.ConstantValue.Value;
                Debug.Assert(value != null);
                DecisionTree onValue;
                if (byValue.ValueAndDecision.TryGetValue(value, out onValue))
                {
                    LowerDecisionTree(byValue.Expression, onValue);
                    if (onValue.MatchIsComplete)
                    {
                        return;
                    }
                }

                LowerDecisionTree(byValue.Expression, byValue.Default);
            }
コード例 #40
0
        /// <summary>
        /// Check if the pattern is subsumed by the decisions in the decision tree, given that the input could
        /// (or could not) be null based on the parameter <paramref name="inputCouldBeNull"/>. If it is subsumed,
        /// returns an error code suitable for reporting the issue. If it is not subsumed, returns 0.
        /// </summary>
        private ErrorCode CheckSubsumed(BoundPattern pattern, DecisionTree decisionTree, bool inputCouldBeNull)
        {
            if (decisionTree.MatchIsComplete)
            {
                return(ErrorCode.ERR_PatternIsSubsumed);
            }

            switch (pattern.Kind)
            {
            case BoundKind.ConstantPattern:
            {
                var constantPattern = (BoundConstantPattern)pattern;
                if (constantPattern.Value.HasErrors || constantPattern.Value.ConstantValue == null || constantPattern.Value.ConstantValue.IsBad)
                {
                    // since this will have been reported earlier, we use ErrorCode.ERR_NoImplicitConvCast
                    // as a flag to suppress errors in subsumption analysis.
                    return(ErrorCode.ERR_NoImplicitConvCast);
                }

                bool isNull = constantPattern.Value.ConstantValue.IsNull;

                // If null inputs have been handled by previous patterns, then
                // the input can no longer be null. In that case a null pattern is subsumed.
                if (isNull && !inputCouldBeNull)
                {
                    // Note: we do not have any test covering this. Is it reachable?
                    // Possibly not given the simple patterns types we support today.
                    return(ErrorCode.ERR_PatternIsSubsumed);
                }

                switch (decisionTree.Kind)
                {
                case DecisionTree.DecisionKind.ByValue:
                {
                    var byValue = (DecisionTree.ByValue)decisionTree;
                    if (isNull)
                    {
                        // This should not occur, as the decision tree should contain a handler for
                        // null earlier, for example in a type test.
                        throw ExceptionUtilities.Unreachable;
                    }

                    DecisionTree decision;
                    if (byValue.ValueAndDecision.TryGetValue(constantPattern.Value.ConstantValue.Value, out decision))
                    {
                        var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                        if (error != 0)
                        {
                            return(error);
                        }
                    }

                    if (byValue.Default != null)
                    {
                        // Note: we do not have any test covering this. Is it reachable?
                        // Possibly not given the simple patterns types we support today.
                        return(CheckSubsumed(pattern, byValue.Default, inputCouldBeNull));
                    }

                    return(0);
                }

                case DecisionTree.DecisionKind.ByType:
                {
                    var byType = (DecisionTree.ByType)decisionTree;
                    if (isNull)
                    {
                        if (byType.WhenNull != null)
                        {
                            var result = CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull);
                            if (result != 0)
                            {
                                return(result);
                            }
                        }
                    }
                    else
                    {
                        foreach (var td in byType.TypeAndDecision)
                        {
                            var type     = td.Key;
                            var decision = td.Value;
                            if (ExpressionOfTypeMatchesPatternType(constantPattern.Value.Type, type, ref _useSiteDiagnostics) == true)
                            {
                                var error = CheckSubsumed(pattern, decision, false);
                                if (error != 0)
                                {
                                    return(error);
                                }
                            }
                        }
                    }
                    return((byType.Default != null) ? CheckSubsumed(pattern, byType.Default, inputCouldBeNull) : 0);
                }

                case DecisionTree.DecisionKind.Guarded:
                {
                    // This is unreachable because the subsumption version of the decision tree
                    // never contains guarded decision trees that are not complete, or that have
                    // any guard other than `true`.
                    throw ExceptionUtilities.Unreachable;
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                }
            }

            case BoundKind.DeclarationPattern:
            {
                var declarationPattern = (BoundDeclarationPattern)pattern;
                switch (decisionTree.Kind)
                {
                case DecisionTree.DecisionKind.ByValue:
                {
                    // A declaration pattern is only subsumed by a value pattern if all of the values are accounted for.
                    // For example, when switching on a bool, do we handle both true and false?
                    // For now, we do not handle this case. Also, this provides compatibility with previous compilers.
                    if (inputCouldBeNull)
                    {
                        return(0);                // null could never be handled by a value decision
                    }

                    var byValue = (DecisionTree.ByValue)decisionTree;
                    if (byValue.Default != null)
                    {
                        // Note: we do not have any test covering this. Is it reachable?
                        // Possibly not given the simple patterns types we support today.
                        return(CheckSubsumed(pattern, byValue.Default, false));
                    }

                    return(0);
                }

                case DecisionTree.DecisionKind.ByType:
                {
                    var byType = (DecisionTree.ByType)decisionTree;
                    if (declarationPattern.IsVar &&
                        inputCouldBeNull &&
                        (byType.WhenNull == null || CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull) == 0) &&
                        (byType.Default == null || CheckSubsumed(pattern, byType.Default, inputCouldBeNull) == 0))
                    {
                        return(0);                // new pattern catches null if not caught by existing WhenNull or Default
                    }

                    inputCouldBeNull = false;
                    foreach (var td in byType.TypeAndDecision)
                    {
                        var type     = td.Key;
                        var decision = td.Value;
                        // if the pattern's type is already handled by the previous pattern
                        // or the previous pattern handles all of the (non-null) input data...
                        if (ExpressionOfTypeMatchesPatternType(
                                declarationPattern.DeclaredType.Type.TupleUnderlyingTypeOrSelf(), type, ref _useSiteDiagnostics) == true ||
                            ExpressionOfTypeMatchesPatternType(byType.Type, type, ref _useSiteDiagnostics) == true)
                        {
                            // then we check if the pattern is subsumed by the previous decision
                            var error = CheckSubsumed(pattern, decision, inputCouldBeNull);
                            if (error != 0)
                            {
                                return(error);
                            }
                        }
                    }

                    if (byType.Default != null)
                    {
                        // Note: we do not have any test covering this. Is it reachable?
                        // Possibly not given the simple patterns types we support today.
                        return(CheckSubsumed(pattern, byType.Default, inputCouldBeNull));
                    }

                    return(0);
                }

                case DecisionTree.DecisionKind.Guarded:
                {
                    // Because all guarded decision trees in the subsumption tree are
                    // complete, we should never get here.
                    throw ExceptionUtilities.Unreachable;
                }

                default:
                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                }
            }

            case BoundKind.WildcardPattern:
                // because we always handle `default:` last, and that is the only way to get a wildcard pattern,
                // we should never need to see if it subsumes something else.
                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);

            default:
                throw ExceptionUtilities.UnexpectedValue(pattern.Kind);
            }
        }
コード例 #41
0
            // For switch statements, we have an option of completely rewriting the switch header
            // and switch sections into simpler constructs, i.e. we can rewrite the switch header
            // using bound conditional goto statements and the rewrite the switch sections into
            // bound labeled statements.
            //
            // However, all the logic for emitting the switch jump tables is language agnostic
            // and includes IL optimizations. Hence we delay the switch jump table generation
            // till the emit phase. This way we also get additional benefit of sharing this code
            // between both VB and C# compilers.
            //
            // For string switch statements, we need to determine if we are generating a hash
            // table based jump table or a non hash jump table, i.e. linear string comparisons
            // with each case label. We use the Dev10 Heuristic to determine this
            // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
            // If we are generating a hash table based jump table, we use a simple
            // hash function to hash the string constants corresponding to the case labels.
            // See SwitchStringJumpTableEmitter.ComputeStringHash().
            // We need to emit this same function to compute the hash value into the compiler generated
            // <PrivateImplementationDetails> class.
            // If we have at least one string switch statement in a module that needs a
            // hash table based jump table, we generate a single public string hash synthesized method
            // that is shared across the module.
            private void LowerBasicSwitch(DecisionTree.ByValue byValue)
            {
                var switchSections = ArrayBuilder<BoundSwitchSection>.GetInstance();
                var noValueMatches = _factory.GenerateLabel("noValueMatches");
                var underlyingSwitchType = byValue.Type.IsEnumType() ? byValue.Type.GetEnumUnderlyingType() : byValue.Type;
                foreach (var vd in byValue.ValueAndDecision)
                {
                    var value = vd.Key;
                    var decision = vd.Value;
                    var constantValue = ConstantValue.Create(value, underlyingSwitchType.SpecialType);
                    var constantExpression = new BoundLiteral(_factory.Syntax, constantValue, underlyingSwitchType);
                    var label = _factory.GenerateLabel("case+" + value);
                    var switchLabel = new BoundSwitchLabel(_factory.Syntax, label, constantExpression, constantValue);
                    var forValue = ArrayBuilder<BoundStatement>.GetInstance();
                    LowerDecisionTree(byValue.Expression, decision, forValue);
                    if (!decision.MatchIsComplete)
                    {
                        forValue.Add(_factory.Goto(noValueMatches));
                    }

                    var section = new BoundSwitchSection(_factory.Syntax, ImmutableArray.Create(switchLabel), forValue.ToImmutableAndFree());
                    switchSections.Add(section);
                }

                var rewrittenSections = switchSections.ToImmutableAndFree();
                MethodSymbol stringEquality = null;
                if (underlyingSwitchType.SpecialType == SpecialType.System_String)
                {
                    LocalRewriter.EnsureStringHashFunction(rewrittenSections, _factory.Syntax);
                    stringEquality = LocalRewriter.GetSpecialTypeMethod(_factory.Syntax, SpecialMember.System_String__op_Equality);
                }

                // The BoundSwitchStatement requires a constant target when there are no sections, so we accomodate that here.
                var constantTarget = rewrittenSections.IsEmpty ? noValueMatches : null;
                var switchStatement = new BoundSwitchStatement(
                    _factory.Syntax, null, _factory.Convert(underlyingSwitchType, byValue.Expression),
                    constantTarget,
                    ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty,
                    rewrittenSections, noValueMatches, stringEquality);
                // The bound switch statement implicitly defines the label noValueMatches at the end, so we do not add it explicitly.

                switch (underlyingSwitchType.SpecialType)
                {
                    case SpecialType.System_Boolean:
                        // boolean switch is handled in LowerBooleanSwitch, not here.
                        throw ExceptionUtilities.Unreachable;

                    case SpecialType.System_String:
                    case SpecialType.System_Byte:
                    case SpecialType.System_Char:
                    case SpecialType.System_Int16:
                    case SpecialType.System_Int32:
                    case SpecialType.System_Int64:
                    case SpecialType.System_SByte:
                    case SpecialType.System_UInt16:
                    case SpecialType.System_UInt32:
                    case SpecialType.System_UInt64:
                        {
                            // emit knows how to efficiently generate code for these kinds of switches.
                            _loweredDecisionTree.Add(switchStatement);
                            break;
                        }

                    default:
                        {
                            // other types, such as float, double, and decimal, are not currently
                            // handled by emit and must be lowered here.
                            _loweredDecisionTree.Add(LowerNonprimitiveSwitch(switchStatement));
                            break;
                        }
                }

                LowerDecisionTree(byValue.Expression, byValue.Default);
            }
コード例 #42
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByValue(DecisionTree.ByValue byValue, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            Debug.Assert(value.Value.Type == byValue.Type);
            if (byValue.Default != null)
            {
                return AddByValue(byValue.Default, value, makeDecision);
            }

            // For error recovery, to avoid "unreachable code" diagnostics when there is a bad case
            // label, we use the case label itself as the value key.
            object valueKey = value.ConstantValue?.Value ?? value;
            DecisionTree valueDecision;
            if (byValue.ValueAndDecision.TryGetValue(valueKey, out valueDecision))
            {
                valueDecision = Add(valueDecision, makeDecision);
            }
            else
            {
                valueDecision = makeDecision(byValue.Expression, byValue.Type);
                byValue.ValueAndDecision.Add(valueKey, valueDecision);
            }

            if (byValue.Type.SpecialType == SpecialType.System_Boolean &&
                byValue.ValueAndDecision.Count == 2 &&
                byValue.ValueAndDecision.Values.All(d => d.MatchIsComplete))
            {
                byValue.MatchIsComplete = true;
            }

            return valueDecision;
        }
コード例 #43
0
            private void LowerDecisionTree(BoundExpression expression, DecisionTree decisionTree)
            {
                if (decisionTree == null)
                {
                    return;
                }

                // If the input expression was a constant or a simple read of a local, then that is the
                // decision tree's expression. Otherwise it is a newly created temp, to which we must
                // assign the switch expression.
                if (decisionTree.Temp != null)
                {
                    // Store the input expression into a temp
                    if (decisionTree.Expression != expression)
                    {
                        _loweredDecisionTree.Add(_factory.Assignment(decisionTree.Expression, expression));
                    }

                    if (DeclaredTempSet.Add(decisionTree.Temp))
                    {
                        DeclaredTemps.Add(decisionTree.Temp);
                    }
                    else
                    {
                        // we should only attempt to declare each temp once.
                        throw ExceptionUtilities.Unreachable;
                    }
                }

                switch (decisionTree.Kind)
                {
                    case DecisionTree.DecisionKind.ByType:
                        {
                            LowerDecisionTree((DecisionTree.ByType)decisionTree);
                            return;
                        }
                    case DecisionTree.DecisionKind.ByValue:
                        {
                            LowerDecisionTree((DecisionTree.ByValue)decisionTree);
                            return;
                        }
                    case DecisionTree.DecisionKind.Guarded:
                        {
                            LowerDecisionTree((DecisionTree.Guarded)decisionTree);
                            return;
                        }
                    default:
                        throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);
                }
            }
コード例 #44
0
ファイル: DecisionTreeBuilder.cs プロジェクト: genlu/roslyn
        private DecisionTree AddByValue(DecisionTree.Guarded guarded, BoundConstantPattern value, DecisionMaker makeDecision)
        {
            if (guarded.Default != null)
            {
                if (guarded.Default.MatchIsComplete)
                {
                    return null;
                }
            }
            else
            {
                guarded.Default = new DecisionTree.ByValue(guarded.Expression, guarded.Type, null);
            }

            return AddByValue(guarded.Default, value, makeDecision);
        }
コード例 #45
0
        private bool FullyHandlesItsInput(DecisionTree decision)
        {
            if (decision == null)
            {
                return(false);
            }

            if (decision.MatchIsComplete)
            {
                return(true);
            }

            // We check for completeness based on value. Other cases were handled in the construction of the decision tree.
            if (decision.Expression.ConstantValue == null)
            {
                return(false);
            }

            var value = decision.Expression.ConstantValue;

            switch (decision.Kind)
            {
            case DecisionTree.DecisionKind.ByType:
            {
                var byType = (DecisionTree.ByType)decision;
                if (value.IsNull)
                {
                    return(FullyHandlesItsInput(byType.WhenNull));
                }

                foreach (var kv in byType.TypeAndDecision)
                {
                    // the only types that should appear in the decision tree are those
                    // that can accept the input constant. Other types should have been
                    // removed when the decision tree was produced. This depends on the
                    // fact that all constants are of sealed types.
                    if (FullyHandlesItsInput(kv.Value))
                    {
                        return(true);
                    }
                }

                return(FullyHandlesItsInput(byType.Default));
            }

            case DecisionTree.DecisionKind.ByValue:
            {
                var byValue = (DecisionTree.ByValue)decision;
                if (value.IsNull)
                {
                    return(false);
                }

                DecisionTree onValue;
                return
                    (byValue.ValueAndDecision.TryGetValue(value.Value, out onValue) && FullyHandlesItsInput(onValue) ||
                     byValue.Default != null && FullyHandlesItsInput(byValue.Default));
            }

            case DecisionTree.DecisionKind.Guarded:
            {
                return(decision.MatchIsComplete);
            }

            default:
                throw ExceptionUtilities.UnexpectedValue(decision.Kind);
            }
        }
コード例 #46
0
ファイル: DecisionTree.cs プロジェクト: kusl/roslyn-1
        internal DecisionTree ComputeDecisionTree()
        {
            Debug.Assert(_section == null);
            var expression = _switchStatement.Expression;

            if (expression.ConstantValue == null && expression.Kind != BoundKind.Local)
            {
                // unless the expression is simple enough, copy it into a local
                var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, expression.Type, SynthesizedLocalKind.PatternMatchingTemp, _switchStatement.Syntax, false, RefKind.None);
                expression = new BoundLocal(expression.Syntax, localSymbol, null, expression.Type);
            }

            var result          = DecisionTree.Create(_switchStatement.Expression, _switchStatement.Expression.Type, _enclosingSymbol);
            var subsumptionTree = DecisionTree.Create(_switchStatement.Expression, _switchStatement.Expression.Type, _enclosingSymbol);
            BoundPatternSwitchLabel   defaultLabel   = null;
            BoundPatternSwitchSection defaultSection = null;

            foreach (var section in _switchStatement.SwitchSections)
            {
                this._section = section;
                foreach (var label in section.SwitchLabels)
                {
                    if (label.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel)
                    {
                        if (defaultLabel != null)
                        {
                            // duplicate switch label will have been reported during initial binding.
                        }
                        else
                        {
                            defaultLabel   = label;
                            defaultSection = section;
                        }
                    }
                    else
                    {
                        this._syntax = label.Syntax;
                        // For purposes of subsumption, we do not take into consideration the value
                        // of the input expression. Therefore we consider null possible if the type permits.
                        var subsumedErrorCode = CheckSubsumed(label.Pattern, subsumptionTree, inputCouldBeNull: true);
                        if (subsumedErrorCode != 0 && subsumedErrorCode != ErrorCode.ERR_NoImplicitConvCast)
                        {
                            if (!label.HasErrors)
                            {
                                _diagnostics.Add(subsumedErrorCode, label.Pattern.Syntax.Location);
                            }
                        }
                        else
                        {
                            AddToDecisionTree(result, label);
                            if (label.Guard == null || label.Guard.ConstantValue == ConstantValue.True)
                            {
                                // Only unconditional switch labels contribute to subsumption
                                AddToDecisionTree(subsumptionTree, label);
                            }
                        }
                    }
                }
            }

            if (defaultLabel != null)
            {
                Add(result, (e, t) => new DecisionTree.Guarded(_switchStatement.Expression, _switchStatement.Expression.Type, default(ImmutableArray <KeyValuePair <BoundExpression, BoundExpression> >), defaultSection, null, defaultLabel));
            }

            return(result);
        }