Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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;
                    }
                }
            }

            // if the last type is the type we need, add to it
            DecisionTree result = null;

            if (byType.TypeAndDecision.Count != 0)
            {
                var lastTypeAndDecision = byType.TypeAndDecision.Last();
                if (lastTypeAndDecision.Key.Equals(type, TypeCompareKind.IgnoreDynamicAndTupleNames))
                {
                    result = Add(lastTypeAndDecision.Value, makeDecision);
                }
            }

            if (result == null)
            {
                var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatching, Syntax, false, RefKind.None);
                var expression  = new BoundLocal(Syntax, localSymbol, null, type);
                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);
        }
Ejemplo n.º 3
0
        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;
                    }
                }
            }

            // if the last type is the type we need, add to it
            DecisionTree result = null;

            if (byType.TypeAndDecision.Count != 0)
            {
                var lastTypeAndDecision = byType.TypeAndDecision.Last();
                if (lastTypeAndDecision.Key.Equals(type, TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes))
                {
                    result = Add(lastTypeAndDecision.Value, makeDecision);
                }
            }

            if (result == null)
            {
                var expression = GetBoundPatternMatchingLocal(type);
                result = makeDecision(expression, type);
                Debug.Assert(result.Temp == null);
                result.Temp = expression.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);
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
 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;
         }
     }
 }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        private DecisionTree AddByNull(DecisionTree.ByType byType, DecisionMaker makeDecision)
        {
            // these tree cannot be complete, as if that were so we would have considered this decision subsumed.
            Debug.Assert(byType.WhenNull?.MatchIsComplete != true);
            Debug.Assert(byType.Default?.MatchIsComplete != true);

            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);
        }
Ejemplo n.º 8
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));
        }
Ejemplo n.º 9
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.CanContainNull())
                    {
                        // first test for null
                        var             notNullLabel    = _factory.GenerateLabel("notNull");
                        var             inputExpression = byType.Expression;
                        var             objectType      = _factory.SpecialType(SpecialType.System_Object);
                        var             nullValue       = _factory.Null(objectType);
                        BoundExpression notNull         = byType.Type.IsNullableType()
                            ? _localRewriter.RewriteNullableNullEquality(_factory.Syntax, BinaryOperatorKind.NullableNullNotEqual, byType.Expression, nullValue, _factory.SpecialType(SpecialType.System_Boolean))
                            : _factory.ObjectNotEqual(nullValue, _factory.Convert(objectType, byType.Expression));
                        _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);
                }
            }
Ejemplo n.º 10
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));
        }
Ejemplo n.º 11
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));
        }