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); } }
private BoundExpression MakeIsConstantPattern(BoundConstantPattern loweredPattern, BoundExpression loweredInput) { return CompareWithConstant(loweredInput, loweredPattern.Value); }
private BoundExpression LowerConstantPattern(BoundConstantPattern pattern, BoundExpression input) { return CompareWithConstant(input, VisitExpression(pattern.Value)); }
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); }
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); }
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; }