{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/68627671","id":68627671,"diff_hunk":"@@ -0,0 +1,1013 @@\n+﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.\n+\n+using System;\n+using System.Collections.Generic;\n+using System.Collections.Immutable;\n+using System.Diagnostics;\n+using System.Linq;\n+using System.Text;\n+using System.Threading;\n+using System.Threading.Tasks;\n+using Microsoft.CodeAnalysis.CSharp.Symbols;\n+using Microsoft.CodeAnalysis.CSharp.Syntax;\n+using Roslyn.Utilities;\n+\n+namespace Microsoft.CodeAnalysis.CSharp\n+{\n+    partial class BoundPatternSwitchStatement\n+    {\n+        private ImmutableArray<Diagnostic> _decisionTreeDiagnostics;\n+        private DecisionTree _decisionTree;\n+        private ImmutableArray<LocalSymbol> _temps;\n+\n+        public ImmutableArray<Diagnostic> DecisionTreeDiagnostics\n+        {\n+            get\n+            {\n+                EnsureDecisionTree();\n+                Debug.Assert(_decisionTree != null);\n+                return _decisionTreeDiagnostics;\n+            }\n+        }\n+\n+        public DecisionTree DecisionTree\n+        {\n+            get\n+            {\n+                EnsureDecisionTree();\n+                Debug.Assert(_decisionTree != null);\n+                return _decisionTree;\n+            }\n+        }\n+\n+        public ImmutableArray<LocalSymbol> Temps\n+        {\n+            get\n+            {\n+                EnsureDecisionTree();\n+                if (_temps.IsDefault)\n+                {\n+                    ImmutableInterlocked.InterlockedInitialize(ref _temps, ComputeTemps(_decisionTree));\n+                }\n+                Debug.Assert(!_temps.IsDefault);\n+                return _temps;\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Compute the set of temps needed for the whole decision tree.\n+        /// </summary>\n+        private ImmutableArray<LocalSymbol> ComputeTemps(DecisionTree decisionTree)\n+        {\n+            var builder = ArrayBuilder<LocalSymbol>.GetInstance();\n+            AddTemps(decisionTree, builder);\n+            return builder.ToImmutableAndFree();\n+        }\n+\n+        private void AddTemps(DecisionTree decisionTree, ArrayBuilder<LocalSymbol> builder)\n+        {\n+            if (decisionTree == null) return;\n+            switch (decisionTree.Kind)\n+            {\n+                case DecisionTree.DecisionKind.ByType:\n+                    {\n+                        var byType = (DecisionTree.ByType)decisionTree;\n+                        AddTemps(byType.WhenNull, builder);\n+                        foreach (var td in byType.TypeAndDecision)\n+                        {\n+                            AddTemps(td.Value, builder);\n+                        }\n+                        AddTemps(byType.Default, builder);\n+                        return;\n+                    }\n+                case DecisionTree.DecisionKind.ByValue:\n+                    {\n+                        var byValue = (DecisionTree.ByValue)decisionTree;\n+                        foreach (var vd in byValue.ValueAndDecision)\n+                        {\n+                            AddTemps(vd.Value, builder);\n+                        }\n+                        AddTemps(byValue.Default, builder);\n+                        return;\n+                    }\n+                case DecisionTree.DecisionKind.Guarded:\n+                    {\n+                        var guarded = (DecisionTree.Guarded)decisionTree;\n+                        ComputeTemps(guarded.Default);\n+                        return;\n+                    }\n+                default:\n+                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);\n+            }\n+        }\n+\n+        /// <summary>\n+        /// If the target branch is computed at compile-time, the corresponding label. Otherwise null.\n+        /// </summary>\n+        public LabelSymbol ConstantTargetOpt\n+        {\n+            get\n+            {\n+                EnsureDecisionTree();\n+\n+                // Switch expression might be a constant expression.\n+                // For this scenario we can determine the target label of the switch statement\n+                // at compile time.\n+                if (!SwitchSections.Any())\n+                {\n+                    // empty switch block, set the break label as target\n+                    return this.BreakLabel;\n+                }\n+\n+                return BindConstantTarget(_decisionTree);\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Used to compute the only target label when it can be computed at compile-time.\n+        /// This does not use the same logic as handling \"goto case n\" because that\n+        /// always goes to \"case n\" even if there is a preceding \"case n when something\".\n+        /// However, the initial dispatch always obeys the switch statement sequentual\n+        /// semantics. We simulate that here.\n+        /// </summary>\n+        private LabelSymbol BindConstantTarget(DecisionTree decisionTree)\n+        {\n+            var expression = decisionTree.Expression;\n+\n+            switch (decisionTree.Kind)\n+            {\n+                case DecisionTree.DecisionKind.ByType:\n+                    {\n+                        var byType = (DecisionTree.ByType)decisionTree;\n+                        if (expression.ConstantValue?.IsNull == true)\n+                        {\n+                            if (byType.WhenNull != null) return BindConstantTarget(byType.WhenNull);\n+                        }\n+                        if (expression.ConstantValue?.IsNull != true)\n+                        {\n+                            foreach (var td in byType.TypeAndDecision)\n+                            {\n+                                var type = td.Key;\n+                                var decision = td.Value;\n+                                switch (Binder.Conversions.ExpressionOfTypeMatchesPatternType(expression.Type.TupleUnderlyingTypeOrSelf(), type))\n+                                {\n+                                    case null:\n+                                        return null; // we don't know if this matches the input\n+                                    case true:\n+                                        if (expression.Type.CanBeAssignedNull() && expression.ConstantValue == null)\n+                                        {\n+                                            return null; // we don't know if the input is null; unknown result\n+                                        }\n+                                        else\n+                                        {\n+                                            return BindConstantTarget(decision);\n+                                        }\n+                                    case false:\n+                                        continue;\n+                                }\n+                            }\n+                        }\n+                        return (byType.Default != null) ? BindConstantTarget(byType.Default) : null;\n+                    }\n+                case DecisionTree.DecisionKind.ByValue:\n+                    {\n+                        var byValue = (DecisionTree.ByValue)decisionTree;\n+                        var byValueConstant = byValue.Expression.ConstantValue;\n+                        if (byValueConstant == null)\n+                        {\n+                            if (byValue.ValueAndDecision.Count != 0) return null; // can't tell which decision to take\n+                        }\n+                        else\n+                        {\n+                            var input = byValueConstant.Value;\n+                            foreach (var vd in byValue.ValueAndDecision)\n+                            {\n+                                var value = vd.Key;\n+                                var decision = vd.Value;\n+                                if (Equals(input, value)) return BindConstantTarget(decision);\n+                            }\n+                        }\n+                        return (byValue.Default != null) ? BindConstantTarget(byValue.Default) : null;\n+                    }\n+                case DecisionTree.DecisionKind.Guarded:\n+                    {\n+                        var guarded = (DecisionTree.Guarded)decisionTree;\n+                        return (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? guarded.Label.Label : null;\n+                    }\n+                default:\n+                    throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);\n+            }\n+        }\n+\n+        private void EnsureDecisionTree()\n+        {\n+            if (_decisionTree == null)\n+            {\n+                // it is not a problem if this is done concurrently by multiple threads, as they\n+                // should all compute semantically equivalent diagnostics.\n+                var diagnostics = DiagnosticBag.GetInstance();\n+                var decisionTree = ComputeDecisionTree(diagnostics);\n+                this._decisionTreeDiagnostics = diagnostics.ToReadOnlyAndFree();\n+                Interlocked.CompareExchange(ref _decisionTree, decisionTree, null);\n+            }\n+        }\n+\n+        private DecisionTree ComputeDecisionTree(DiagnosticBag diagnostics)\n+        {\n+            DecisionTreeComputer decisionTreeComputer = new DecisionTreeComputer(\n+                this.Binder.ContainingMemberOrLambda, diagnostics, this, this.Binder.Conversions);\n+            return decisionTreeComputer.ComputeDecisionTree();\n+        }\n+    }\n+\n+    internal class DecisionTreeComputer\n+    {\n+        private readonly Symbol _enclosingSymbol;\n+        private readonly DiagnosticBag _diagnostics;\n+        private readonly BoundPatternSwitchStatement _switchStatement;\n+        private readonly Conversions _conversions;\n+\n+        private CSharpSyntaxNode _syntax;\n+\n+        public DecisionTreeComputer(\n+            Symbol enclosingSymbol,\n+            DiagnosticBag diagnostics,\n+            BoundPatternSwitchStatement switchStatement,\n+            Conversions conversions)\n+        {\n+            this._enclosingSymbol = enclosingSymbol;\n+            this._diagnostics = diagnostics;\n+            this._switchStatement = switchStatement;\n+            this._conversions = conversions;\n+        }\n+\n+        internal DecisionTree ComputeDecisionTree()\n+        {\n+            var expression = _switchStatement.Expression;\n+            var expressionCouldBeNull = Binder.ExpressionIsNull(expression) != false;\n+            if (expression.ConstantValue == null && expression.Kind != BoundKind.Local)\n+            {\n+                // unless the expression is simple enough, copy it into a local\n+                var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, expression.Type, SynthesizedLocalKind.PatternMatchingTemp, _switchStatement.Syntax, false, RefKind.None);\n+                expression = new BoundLocal(expression.Syntax, localSymbol, null, expression.Type);\n+            }\n+            var result = DecisionTree.Create(_switchStatement.Expression, _switchStatement.Expression.Type);\n+            BoundPatternSwitchLabel defaultLabel = null;\n+            foreach (var section in _switchStatement.SwitchSections)\n+            {\n+                foreach (var label in section.SwitchLabels)\n+                {\n+                    if (label.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel)\n+                    {\n+                        if (defaultLabel != null)\n+                        {\n+                            // duplicate switch label will have been reported during initial binding.\n+                        }\n+                        else\n+                        {\n+                            defaultLabel = label;\n+                        }\n+                    }\n+                    else\n+                    {\n+                        this._syntax = label.Syntax;\n+                        var subsumedErrorCode = CheckSubsumed(label.Pattern, result, expressionCouldBeNull);\n+                        if (subsumedErrorCode != 0 && subsumedErrorCode != ErrorCode.ERR_NoImplicitConvCast)\n+                        {\n+                            if (!label.HasErrors)\n+                            {\n+                                _diagnostics.Add(subsumedErrorCode, label.Pattern.Syntax.Location);\n+                            }\n+                        }\n+                        else\n+                        {\n+                            AddToDecisionTree(result, label);\n+                        }\n+                    }\n+                }\n+            }\n+\n+            if (defaultLabel != null)\n+            {\n+                Add(result, (e, t) => new DecisionTree.Guarded(_switchStatement.Expression, _switchStatement.Expression.Type, default(ImmutableArray<KeyValuePair<BoundExpression, LocalSymbol>>), null, defaultLabel));\n+            }\n+\n+            return result;\n+        }\n+\n+        private void AddToDecisionTree(DecisionTree decisionTree, BoundPatternSwitchLabel label)\n+        {\n+            var pattern = label.Pattern;\n+            var guard = label.Guard;\n+            if (guard?.ConstantValue == ConstantValue.False) return;\n+            switch (pattern.Kind)\n+            {\n+                case BoundKind.ConstantPattern:\n+                    {\n+                        var constantPattern = (BoundConstantPattern)pattern;\n+                        AddByValue(decisionTree, constantPattern.Value, (e, t) => new DecisionTree.Guarded(e, t, default(ImmutableArray<KeyValuePair<BoundExpression, LocalSymbol>>), guard, label), label.HasErrors);\n+                        break;\n+                    }\n+                case BoundKind.DeclarationPattern:\n+                    {\n+                        var declarationPattern = (BoundDeclarationPattern)pattern;\n+                        DecisionMaker maker = (e, t) => new DecisionTree.Guarded(e, t, ImmutableArray.Create(new KeyValuePair<BoundExpression, LocalSymbol>(e, declarationPattern.LocalSymbol)), guard, label);\n+                        if (declarationPattern.IsVar)\n+                        {\n+                            Add(decisionTree, maker);\n+                        }\n+                        else\n+                        {\n+                            AddByType(decisionTree, declarationPattern.DeclaredType.Type, maker);\n+                        }\n+                        break;\n+                    }\n+                case BoundKind.WildcardPattern:\n+                // We do not yet support a wildcard pattern syntax. It is used exclusively\n+                // to model the \"default:\" case, which is handled specially in the caller.\n+                default:\n+                    throw ExceptionUtilities.UnexpectedValue(pattern.Kind);\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Check if the pattern is subsumed by the decisions in the decision tree, given that the input could\n+        /// (or could not) be null based on the parameter <paramref name=\"inputCouldBeNull\"/>. If it is subsumed,\n+        /// returns an error code suitable for reporting the issue. If it is not subsumed, returns 0.\n+        /// </summary>\n+        private ErrorCode CheckSubsumed(BoundPattern pattern, DecisionTree decisionTree, bool inputCouldBeNull)\n+        {\n+            if (decisionTree.MatchIsComplete) return ErrorCode.ERR_PatternIsSubsumed;\n+            switch (pattern.Kind)\n+            {\n+                case BoundKind.ConstantPattern:\n+                    {\n+                        var constantPattern = (BoundConstantPattern)pattern;\n+                        if (constantPattern.Value.HasErrors || constantPattern.Value.ConstantValue == null)\n+                        {\n+                            // since this will have been reported earlier, we use ErrorCode.ERR_NoImplicitConvCast\n+                            // as a flag to suppress errors in subsumption analysis.\n+                            return ErrorCode.ERR_NoImplicitConvCast;\n+                        }\n+                        bool isNull = constantPattern.Value.ConstantValue.IsNull;\n+\n+                        // If null inputs have been handled by previous patterns, then\n+                        // the input can no longer be null. In that case a null pattern is subsumed.\n+                        if (isNull && !inputCouldBeNull) return ErrorCode.ERR_PatternIsSubsumed;\n+\n+                        switch (decisionTree.Kind)\n+                        {\n+                            case DecisionTree.DecisionKind.ByValue:\n+                                {\n+                                    var byValue = (DecisionTree.ByValue)decisionTree;\n+                                    if (isNull) return 0; // null must be handled at a type test\n+                                    DecisionTree decision;\n+                                    if (byValue.ValueAndDecision.TryGetValue(constantPattern.Value.ConstantValue.Value, out decision))\n+                                    {\n+                                        var error = CheckSubsumed(pattern, decision, inputCouldBeNull);\n+                                        if (error != 0) return error;\n+                                    }\n+                                    if (byValue.Default != null)\n+                                    {\n+                                        return CheckSubsumed(pattern, byValue.Default, inputCouldBeNull);\n+                                    }\n+                                    return 0;\n+                                }\n+                            case DecisionTree.DecisionKind.ByType:\n+                                {\n+                                    var byType = (DecisionTree.ByType)decisionTree;\n+                                    if (isNull)\n+                                    {\n+                                        if (byType.WhenNull != null)\n+                                        {\n+                                            var result = CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull);\n+                                            if (result != 0) return result;\n+                                        }\n+                                    }\n+                                    else\n+                                    {\n+                                        foreach (var td in byType.TypeAndDecision)\n+                                        {\n+                                            var type = td.Key;\n+                                            var decision = td.Value;\n+                                            if (_conversions.ExpressionOfTypeMatchesPatternType(constantPattern.Value.Type, type) == true)\n+                                            {\n+                                                var error = CheckSubsumed(pattern, decision, false);\n+                                                if (error != 0) return error;\n+                                            }\n+                                        }\n+                                    }\n+                                    return (byType.Default != null) ? CheckSubsumed(pattern, byType.Default, inputCouldBeNull) : 0;\n+                                }\n+                            case DecisionTree.DecisionKind.Guarded:\n+                                {\n+                                    var guarded = (DecisionTree.Guarded)decisionTree;\n+                                    return\n+                                        (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :\n+                                        guarded.Default == null ? 0 : CheckSubsumed(pattern, guarded.Default, inputCouldBeNull);\n+                                }\n+                            default:\n+                                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);\n+                        }\n+                    }\n+                case BoundKind.DeclarationPattern:\n+                    {\n+                        var declarationPattern = (BoundDeclarationPattern)pattern;\n+                        switch (decisionTree.Kind)\n+                        {\n+                            case DecisionTree.DecisionKind.ByValue:\n+                                {\n+                                    // A declaration pattern is only subsumed by a value pattern if all of the values are accounted for.\n+                                    // For example, when switching on a bool, do we handle both true and false?\n+                                    // For now, we do not handle this case. Also, this provides compatibility with previous compilers.\n+                                    if (inputCouldBeNull) return 0; // null could never be handled by a value decision\n+                                    var byValue = (DecisionTree.ByValue)decisionTree;\n+                                    if (byValue.Default != null)\n+                                    {\n+                                        return CheckSubsumed(pattern, byValue.Default, false);\n+                                    }\n+                                    return 0;\n+                                }\n+                            case DecisionTree.DecisionKind.ByType:\n+                                {\n+                                    var byType = (DecisionTree.ByType)decisionTree;\n+                                    if (declarationPattern.IsVar && inputCouldBeNull && (byType.WhenNull == null || CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull) == 0) && (byType.Default == null || CheckSubsumed(pattern, byType.Default, inputCouldBeNull) == 0))\n+                                        return 0; // new pattern catches null if not caught by existing WhenNull or Default\n+                                    inputCouldBeNull = false;\n+                                    foreach (var td in byType.TypeAndDecision)\n+                                    {\n+                                        var type = td.Key;\n+                                        var decision = td.Value;\n+                                        if (_conversions.ExpressionOfTypeMatchesPatternType(declarationPattern.DeclaredType.Type.TupleUnderlyingTypeOrSelf(), type) == true)\n+                                        {\n+                                            var error = CheckSubsumed(pattern, decision, inputCouldBeNull);\n+                                            if (error != 0) return error;\n+                                        }\n+                                    }\n+                                    if (byType.Default != null)\n+                                    {\n+                                        return CheckSubsumed(pattern, byType.Default, inputCouldBeNull);\n+                                    }\n+                                    return 0;\n+                                }\n+                            case DecisionTree.DecisionKind.Guarded:\n+                                {\n+                                    var guarded = (DecisionTree.Guarded)decisionTree;\n+                                    return (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :\n+                                        guarded.Default != null ? CheckSubsumed(pattern, guarded.Default, inputCouldBeNull) : 0;\n+                                }\n+                            default:\n+                                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);\n+                        }\n+                    }\n+                case BoundKind.WildcardPattern:\n+                    {\n+                        switch (decisionTree.Kind)\n+                        {\n+                            case DecisionTree.DecisionKind.ByValue:\n+                                return 0; // a value pattern is always considered incomplete (even bool true and false)\n+                            case DecisionTree.DecisionKind.ByType:\n+                                {\n+                                    var byType = (DecisionTree.ByType)decisionTree;\n+                                    if (inputCouldBeNull &&\n+                                        (byType.WhenNull == null || CheckSubsumed(pattern, byType.WhenNull, inputCouldBeNull) == 0) &&\n+                                        (byType.Default == null || CheckSubsumed(pattern, byType.Default, inputCouldBeNull) == 0))\n+                                        return 0; // new pattern catches null if not caught by existing WhenNull or Default\n+                                    inputCouldBeNull = false;\n+                                    foreach (var td in byType.TypeAndDecision)\n+                                    {\n+                                        var type = td.Key;\n+                                        var decision = td.Value;\n+                                        if (_conversions.ExpressionOfTypeMatchesPatternType(decisionTree.Type, type) == true)\n+                                        {\n+                                            var error = CheckSubsumed(pattern, decision, inputCouldBeNull);\n+                                            if (error != 0) return error;\n+                                        }\n+                                    }\n+                                    if (byType.Default != null)\n+                                    {\n+                                        return CheckSubsumed(pattern, byType.Default, inputCouldBeNull);\n+                                    }\n+                                    return 0;\n+                                }\n+                            case DecisionTree.DecisionKind.Guarded:\n+                                {\n+                                    var guarded = (DecisionTree.Guarded)decisionTree;\n+                                    return (guarded.Guard == null || guarded.Guard.ConstantValue == ConstantValue.True) ? ErrorCode.ERR_PatternIsSubsumed :\n+                                        guarded.Default != null ? CheckSubsumed(pattern, guarded.Default, inputCouldBeNull) : 0;\n+                                }\n+                            default:\n+                                throw ExceptionUtilities.UnexpectedValue(decisionTree.Kind);\n+                        }\n+                    }\n+                default:\n+                    throw ExceptionUtilities.UnexpectedValue(pattern.Kind);\n+            }\n+        }\n+\n+        internal delegate DecisionTree DecisionMaker(\n+            BoundExpression expression,\n+            TypeSymbol type);","path":"src/Compilers/CSharp/Portable/BoundTree/DecisionTree.cs","position":510,"original_position":510,"commit_id":"efe03719df984177cc31cef5d56ae4e91ca3b98f","original_commit_id":"efe03719df984177cc31cef5d56ae4e91ca3b98f","user":{"login":"agocke","id":515774,"avatar_url":"https://avatars.githubusercontent.com/u/515774?v=3","gravatar_id":"","url":"https://api.github.com/users/agocke","html_url":"https://github.com/agocke","followers_url":"https://api.github.com/users/agocke/followers","following_url":"https://api.github.com/users/agocke/following{/other_user}","gists_url":"https://api.github.com/users/agocke/gists{/gist_id}","starred_url":"https://api.github.com/users/agocke/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/agocke/subscriptions","organizations_url":"https://api.github.com/users/agocke/orgs","repos_url":"https://api.github.com/users/agocke/repos","events_url":"https://api.github.com/users/agocke/events{/privacy}","received_events_url":"https://api.github.com/users/agocke/received_events","type":"User","site_admin":false},"body":"Is this `internal` for testing?","created_at":"2016-06-27T18:15:29Z","updated_at":"2016-06-27T18:15:29Z","html_url":"https://github.com/dotnet/roslyn/pull/11485#discussion_r68627671","pull_request_url":"https://api.github.com/repos/dotnet/roslyn/pulls/11485","_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/68627671"},"html":{"href":"https://github.com/dotnet/roslyn/pull/11485#discussion_r68627671"},"pull_request":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/11485"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/11485","id":70960061,"html_url":"https://github.com/dotnet/roslyn/pull/11485","diff_url":"https://github.com/dotnet/roslyn/pull/11485.diff","patch_url":"https://github.com/dotnet/roslyn/pull/11485.patch","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/11485","number":11485,"state":"open","locked":false,"title":"Decision tree implementation for pattern switch statement.","user":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"body":"Implements subsumption checking for pattern-matching.\r\nFixes #8823, #10487, #10601, #10632\r\n\r\n@AlekseyTs @agocke Please review\r\n/cc @dotnet/roslyn-compiler \r\nNote that this targets a feature branch, as there is much more testing needed before this goes into `future`.","created_at":"2016-05-21T20:51:56Z","updated_at":"2016-06-27T18:15:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"242742a5f47b62727e726ee290bb68816d7e2c73","assignee":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"assignees":[{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/dotnet/roslyn/milestones/15","html_url":"https://github.com/dotnet/roslyn/milestones/2.0%20(RC)","labels_url":"https://api.github.com/repos/dotnet/roslyn/milestones/15/labels","id":1571383,"number":15,"title":"2.0 (RC)","description":"","creator":{"login":"davkean","id":1103906,"avatar_url":"https://avatars.githubusercontent.com/u/1103906?v=3","gravatar_id":"","url":"https://api.github.com/users/davkean","html_url":"https://github.com/davkean","followers_url":"https://api.github.com/users/davkean/followers","following_url":"https://api.github.com/users/davkean/following{/other_user}","gists_url":"https://api.github.com/users/davkean/gists{/gist_id}","starred_url":"https://api.github.com/users/davkean/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davkean/subscriptions","organizations_url":"https://api.github.com/users/davkean/orgs","repos_url":"https://api.github.com/users/davkean/repos","events_url":"https://api.github.com/users/davkean/events{/privacy}","received_events_url":"https://api.github.com/users/davkean/received_events","type":"User","site_admin":false},"open_issues":1085,"closed_issues":125,"state":"open","created_at":"2016-02-08T21:53:59Z","updated_at":"2016-06-27T17:54:43Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/dotnet/roslyn/pulls/11485/commits","review_comments_url":"https://api.github.com/repos/dotnet/roslyn/pulls/11485/comments","review_comment_url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/11485/comments","statuses_url":"https://api.github.com/repos/dotnet/roslyn/statuses/efe03719df984177cc31cef5d56ae4e91ca3b98f","head":{"label":"gafter:patterns-decision02","ref":"patterns-decision02","sha":"efe03719df984177cc31cef5d56ae4e91ca3b98f","user":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"repo":{"id":30125216,"name":"roslyn","full_name":"gafter/roslyn","owner":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/gafter/roslyn","description":"The .NET Compiler Platform (\"Roslyn\") provides open-source C# and Visual Basic compilers with rich code analysis APIs.","fork":true,"url":"https://api.github.com/repos/gafter/roslyn","forks_url":"https://api.github.com/repos/gafter/roslyn/forks","keys_url":"https://api.github.com/repos/gafter/roslyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gafter/roslyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gafter/roslyn/teams","hooks_url":"https://api.github.com/repos/gafter/roslyn/hooks","issue_events_url":"https://api.github.com/repos/gafter/roslyn/issues/events{/number}","events_url":"https://api.github.com/repos/gafter/roslyn/events","assignees_url":"https://api.github.com/repos/gafter/roslyn/assignees{/user}","branches_url":"https://api.github.com/repos/gafter/roslyn/branches{/branch}","tags_url":"https://api.github.com/repos/gafter/roslyn/tags","blobs_url":"https://api.github.com/repos/gafter/roslyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gafter/roslyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gafter/roslyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/gafter/roslyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gafter/roslyn/statuses/{sha}","languages_url":"https://api.github.com/repos/gafter/roslyn/languages","stargazers_url":"https://api.github.com/repos/gafter/roslyn/stargazers","contributors_url":"https://api.github.com/repos/gafter/roslyn/contributors","subscribers_url":"https://api.github.com/repos/gafter/roslyn/subscribers","subscription_url":"https://api.github.com/repos/gafter/roslyn/subscription","commits_url":"https://api.github.com/repos/gafter/roslyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/gafter/roslyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/gafter/roslyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/gafter/roslyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/gafter/roslyn/contents/{+path}","compare_url":"https://api.github.com/repos/gafter/roslyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gafter/roslyn/merges","archive_url":"https://api.github.com/repos/gafter/roslyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gafter/roslyn/downloads","issues_url":"https://api.github.com/repos/gafter/roslyn/issues{/number}","pulls_url":"https://api.github.com/repos/gafter/roslyn/pulls{/number}","milestones_url":"https://api.github.com/repos/gafter/roslyn/milestones{/number}","notifications_url":"https://api.github.com/repos/gafter/roslyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gafter/roslyn/labels{/name}","releases_url":"https://api.github.com/repos/gafter/roslyn/releases{/id}","deployments_url":"https://api.github.com/repos/gafter/roslyn/deployments","created_at":"2015-01-31T20:26:12Z","updated_at":"2016-02-18T04:08:14Z","pushed_at":"2016-06-27T17:29:18Z","git_url":"git://github.com/gafter/roslyn.git","ssh_url":"git@github.com:gafter/roslyn.git","clone_url":"https://github.com/gafter/roslyn.git","svn_url":"https://github.com/gafter/roslyn","homepage":"","size":164444,"stargazers_count":1,"watchers_count":1,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"features/patterns"}},"base":{"label":"dotnet:features/typeswitch","ref":"features/typeswitch","sha":"f5b839aa1035bd77fc4558c084599c2fcf09af9c","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":29078997,"name":"roslyn","full_name":"dotnet/roslyn","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/roslyn","description":"The .NET Compiler Platform (\"Roslyn\") provides open-source C# and Visual Basic compilers with rich code analysis APIs.","fork":false,"url":"https://api.github.com/repos/dotnet/roslyn","forks_url":"https://api.github.com/repos/dotnet/roslyn/forks","keys_url":"https://api.github.com/repos/dotnet/roslyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/roslyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/roslyn/teams","hooks_url":"https://api.github.com/repos/dotnet/roslyn/hooks","issue_events_url":"https://api.github.com/repos/dotnet/roslyn/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/roslyn/events","assignees_url":"https://api.github.com/repos/dotnet/roslyn/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/roslyn/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/roslyn/tags","blobs_url":"https://api.github.com/repos/dotnet/roslyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/roslyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/roslyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/roslyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/roslyn/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/roslyn/languages","stargazers_url":"https://api.github.com/repos/dotnet/roslyn/stargazers","contributors_url":"https://api.github.com/repos/dotnet/roslyn/contributors","subscribers_url":"https://api.github.com/repos/dotnet/roslyn/subscribers","subscription_url":"https://api.github.com/repos/dotnet/roslyn/subscription","commits_url":"https://api.github.com/repos/dotnet/roslyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/roslyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/roslyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/roslyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/roslyn/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/roslyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/roslyn/merges","archive_url":"https://api.github.com/repos/dotnet/roslyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/roslyn/downloads","issues_url":"https://api.github.com/repos/dotnet/roslyn/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/roslyn/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/roslyn/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/roslyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/roslyn/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/roslyn/releases{/id}","deployments_url":"https://api.github.com/repos/dotnet/roslyn/deployments","created_at":"2015-01-11T02:39:03Z","updated_at":"2016-06-27T17:05:52Z","pushed_at":"2016-06-27T18:12:16Z","git_url":"git://github.com/dotnet/roslyn.git","ssh_url":"git@github.com:dotnet/roslyn.git","clone_url":"https://github.com/dotnet/roslyn.git","svn_url":"https://github.com/dotnet/roslyn","homepage":"","size":308107,"stargazers_count":5651,"watchers_count":5651,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1355,"mirror_url":null,"open_issues_count":2957,"forks":1355,"open_issues":2957,"watchers":5651,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/11485"},"html":{"href":"https://github.com/dotnet/roslyn/pull/11485"},"issue":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/11485"},"comments":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/11485/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/11485/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/11485/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/roslyn/statuses/efe03719df984177cc31cef5d56ae4e91ca3b98f"}}}}
{"actor":{"display_login":"agocke"}}