| File: Binder\DecisionDagBuilder_ListPatterns.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp { internal sealed partial class DecisionDagBuilder { private Tests MakeTestsAndBindingsForListPattern(TestInputOutputInfo inputInfo, BoundListPattern list, out TestInputOutputInfo outputInfo, ArrayBuilder<BoundPatternBinding> bindings) { #if DEBUG TypeSymbol inputType = inputInfo.GetInputType(); Debug.Assert(inputType.IsErrorType() || list.HasErrors || list.InputType.IsErrorType() || inputType.Equals(list.InputType, TypeCompareKind.AllIgnoreOptions) && inputType.StrippedType().Equals(list.NarrowedType, TypeCompareKind.ConsiderEverything) && list.Subpatterns.Count(p => p.Kind == BoundKind.SlicePattern) == (list.HasSlice ? 1 : 0) && list.LengthAccess is not null); #endif var syntax = list.Syntax; var subpatterns = list.Subpatterns; var tests = ArrayBuilder<Tests>.GetInstance(4 + subpatterns.Length * 2); inputInfo = MakeConvertToType(inputInfo, list.Syntax, list.NarrowedType, isExplicitTest: false, tests); if (list.HasErrors) { BoundDagTemp input = PrepareForUnionValuePropertyMatching(ref inputInfo, tests); tests.Add(new Tests.One(new BoundDagTypeTest(list.Syntax, ErrorType(), input, hasErrors: true))); } else if (list.HasSlice && subpatterns.Length == 1 && subpatterns[0] is BoundSlicePattern { Pattern: null }) { // If `..` is the only pattern in the list, bail. This is a no-op and we don't need to match anything further. } else { BoundDagTemp input = PrepareForUnionValuePropertyMatching(ref inputInfo, tests); Debug.Assert(list.LengthAccess is not null); var lengthProperty = Binder.GetPropertySymbol(list.LengthAccess, out _, out _); Debug.Assert(lengthProperty is not null); var lengthEvaluation = new BoundDagPropertyEvaluation(syntax, lengthProperty, isLengthOrCount: true, input); tests.Add(new Tests.One(lengthEvaluation)); var lengthTemp = lengthEvaluation.MakeResultTemp(); tests.Add(new Tests.One(list.HasSlice ? new BoundDagRelationalTest(syntax, BinaryOperatorKind.IntGreaterThanOrEqual, ConstantValue.Create(subpatterns.Length - 1), lengthTemp) : new BoundDagValueTest(syntax, ConstantValue.Create(subpatterns.Length), lengthTemp))); int index = 0; foreach (BoundPattern subpattern in subpatterns) { if (subpattern is BoundSlicePattern slice) { int startIndex = index; index -= subpatterns.Length - 1; if (slice.Pattern is BoundPattern slicePattern) { Debug.Assert(slice.IndexerAccess is not null); Debug.Assert(index <= 0); Debug.Assert(slice.ReceiverPlaceholder is not null); Debug.Assert(slice.ArgumentPlaceholder is not null); var sliceEvaluation = new BoundDagSliceEvaluation(slicePattern.Syntax, slicePattern.InputType, lengthTemp, startIndex: startIndex, endIndex: index, slice.IndexerAccess, slice.ReceiverPlaceholder, slice.ArgumentPlaceholder, input); tests.Add(new Tests.One(sliceEvaluation)); var sliceTemp = sliceEvaluation.MakeResultTemp(); tests.Add(MakeTestsAndBindings(sliceTemp, slicePattern, bindings)); } continue; } Debug.Assert(list.IndexerAccess is not null); Debug.Assert(list.ReceiverPlaceholder is not null); Debug.Assert(list.ArgumentPlaceholder is not null); var indexEvaluation = new BoundDagIndexerEvaluation(subpattern.Syntax, subpattern.InputType, lengthTemp, index++, list.IndexerAccess, list.ReceiverPlaceholder, list.ArgumentPlaceholder, input); tests.Add(new Tests.One(indexEvaluation)); var indexTemp = indexEvaluation.MakeResultTemp(); tests.Add(MakeTestsAndBindings(indexTemp, subpattern, bindings)); } } if (list.VariableAccess is not null) { BoundDagTemp input = PrepareForUnionValuePropertyMatching(ref inputInfo, tests); bindings.Add(new BoundPatternBinding(list.VariableAccess, input)); } outputInfo = inputInfo; return Tests.AndSequence.Create(tests); } } }