/// <summary> /// Learn from any constant null patterns appearing in the pattern. /// </summary> /// <param name="inputType">Type type of the input expression (before nullable analysis). /// Used to determine which types can contain null.</param> /// <returns>true if there is a top-level explicit null check</returns> private void LearnFromAnyNullPatterns( int inputSlot, TypeSymbol inputType, BoundPattern pattern) { if (inputSlot <= 0) { return; } switch (pattern) { case BoundConstantPattern cp: bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null; if (isExplicitNullCheck) { LearnFromNullTest(inputSlot, inputType, ref this.State); } break; case BoundDeclarationPattern _: case BoundDiscardPattern _: case BoundITuplePattern _: break; // nothing to learn case BoundRecursivePattern rp: { // for positional part: we only learn from tuples (not Deconstruct) if (rp.DeconstructMethod is null && !rp.Deconstruction.IsDefault) { var elements = inputType.TupleElements; for (int i = 0, n = Math.Min(rp.Deconstruction.Length, elements.IsDefault ? 0 : elements.Length); i < n; i++) { BoundSubpattern item = rp.Deconstruction[i]; FieldSymbol element = elements[i]; LearnFromAnyNullPatterns(GetOrCreateSlot(element, inputSlot), element.Type, item.Pattern); } } // for property part if (!rp.Properties.IsDefault) { for (int i = 0, n = rp.Properties.Length; i < n; i++) { BoundSubpattern item = rp.Properties[i]; Symbol symbol = item.Symbol; if (symbol?.ContainingType.Equals(inputType, TypeCompareKind.AllIgnoreOptions) == true) { LearnFromAnyNullPatterns(GetOrCreateSlot(symbol, inputSlot), symbol.GetTypeOrReturnType().Type, item.Pattern); } } } } break; default: throw ExceptionUtilities.UnexpectedValue(pattern); } }
public override BoundNode VisitSubpattern(BoundSubpattern node) { Visit(node.Pattern); return(null); }
/// <summary> /// Learn from any constant null patterns appearing in the pattern. /// </summary> /// <param name="inputType">Type type of the input expression (before nullable analysis). /// Used to determine which types can contain null.</param> private void LearnFromAnyNullPatterns( int inputSlot, TypeSymbol inputType, BoundPattern pattern) { if (inputSlot <= 0) { return; } // https://github.com/dotnet/roslyn/issues/35041 We only need to do this when we're rewriting, so we // can get information for any nodes in the pattern. VisitPatternForRewriting(pattern); switch (pattern) { case BoundConstantPattern cp: bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null; if (isExplicitNullCheck) { // Since we're not branching on this null test here, we just infer the top level // nullability. We'll branch on it later. LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false); } break; case BoundDeclarationPattern _: case BoundDiscardPattern _: case BoundITuplePattern _: break; // nothing to learn case BoundRecursivePattern rp: { if (rp.IsExplicitNotNullTest) { LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false); } // for positional part: we only learn from tuples (not Deconstruct) if (rp.DeconstructMethod is null && !rp.Deconstruction.IsDefault) { var elements = inputType.TupleElements; for (int i = 0, n = Math.Min(rp.Deconstruction.Length, elements.IsDefault ? 0 : elements.Length); i < n; i++) { BoundSubpattern item = rp.Deconstruction[i]; FieldSymbol element = elements[i]; LearnFromAnyNullPatterns(GetOrCreateSlot(element, inputSlot), element.Type, item.Pattern); } } // for property part if (!rp.Properties.IsDefault) { for (int i = 0, n = rp.Properties.Length; i < n; i++) { BoundSubpattern item = rp.Properties[i]; Symbol symbol = item.Symbol; if (symbol?.ContainingType.Equals(inputType, TypeCompareKind.AllIgnoreOptions) == true) { LearnFromAnyNullPatterns(GetOrCreateSlot(symbol, inputSlot), symbol.GetTypeOrReturnType().Type, item.Pattern); } } } } break; default: throw ExceptionUtilities.UnexpectedValue(pattern); } }
private void LearnFromAnyNullPatterns( int inputSlot, TypeSymbol inputType, BoundPattern pattern) { if (inputSlot <= 0) { return; } // https://github.com/dotnet/roslyn/issues/35041 We only need to do this when we're rewriting, so we // can get information for any nodes in the pattern. VisitPatternForRewriting(pattern); switch (pattern) { case BoundConstantPattern cp: bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null; if (isExplicitNullCheck) { // Since we're not branching on this null test here, we just infer the top level // nullability. We'll branch on it later. LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false); } break; case BoundDeclarationPattern _: case BoundDiscardPattern _: case BoundITuplePattern _: case BoundRelationalPattern _: break; // nothing to learn case BoundTypePattern tp: if (tp.IsExplicitNotNullTest) { LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false); } break; case BoundRecursivePattern rp: { if (rp.IsExplicitNotNullTest) { LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false); } // for positional part: we only learn from tuples (not Deconstruct) if (rp.DeconstructMethod is null && !rp.Deconstruction.IsDefault) { var elements = inputType.TupleElements; for (int i = 0, n = Math.Min(rp.Deconstruction.Length, elements.IsDefault ? 0 : elements.Length); i < n; i++) { BoundSubpattern item = rp.Deconstruction[i]; FieldSymbol element = elements[i]; LearnFromAnyNullPatterns(GetOrCreateSlot(element, inputSlot), element.Type, item.Pattern); } } // for property part if (!rp.Properties.IsDefault) { foreach (BoundPropertySubpattern subpattern in rp.Properties) { if (subpattern.Member is BoundPropertySubpatternMember member) { LearnFromAnyNullPatterns(getExtendedPropertySlot(member, inputSlot), member.Type, subpattern.Pattern); } } } } break; case BoundNegatedPattern p: LearnFromAnyNullPatterns(inputSlot, inputType, p.Negated); break; case BoundBinaryPattern p: LearnFromAnyNullPatterns(inputSlot, inputType, p.Left); LearnFromAnyNullPatterns(inputSlot, inputType, p.Right); break; default: throw ExceptionUtilities.UnexpectedValue(pattern); } int getExtendedPropertySlot(BoundPropertySubpatternMember member, int inputSlot) { if (member.Symbol is null) { return(-1); } if (member.Receiver is not null) { inputSlot = getExtendedPropertySlot(member.Receiver, inputSlot); } if (inputSlot < 0) { return(inputSlot); } return(GetOrCreateSlot(member.Symbol, inputSlot)); } }