diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index ac4f05fa8d197aae2e901991db13155c949815ce..2d3b9b6b200a8ecce83da676dd72a3dd82ade48c 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -143,7 +143,7 @@ - + @@ -273,7 +273,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -373,7 +373,7 @@ - + @@ -394,7 +394,7 @@ - + @@ -436,7 +436,7 @@ - + @@ -675,7 +675,7 @@ - + - + @@ -1810,7 +1810,7 @@ - + diff --git a/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs b/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs index 978d7751a42d02dff14e408a3edaaa2c4137e0d9..9e49e564e31b1ecaa6ffbf87b50be70678908683 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #nullable enable +using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; @@ -83,5 +84,38 @@ private BoundNode VisitBinaryOperatorBase(BoundBinaryOperatorBase binaryOperator return sym; } + + private ImmutableArray GetUpdatedArray(BoundNode expr, ImmutableArray symbols) where T : Symbol + { + if (symbols.IsDefaultOrEmpty) + { + return symbols; + } + + var builder = ArrayBuilder.GetInstance(symbols.Length); + bool foundUpdate = false; + foreach (var originalSymbol in symbols) + { + if (_updatedSymbols.TryGetValue((expr, originalSymbol), out var updatedSymbol)) + { + foundUpdate = true; + builder.Add((T)updatedSymbol); + } + else + { + builder.Add(originalSymbol); + } + } + + if (foundUpdate) + { + return builder.ToImmutableAndFree(); + } + else + { + builder.Free(); + return symbols; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 9c60386eccf17fbb4fdc54bc0366df083db1eae1..635d9c48853c629fd41a0ff73adb5b0d87d175a4 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -609,7 +609,7 @@ public BoundPassByCopy Update(BoundExpression expression, TypeSymbol? type) internal sealed partial class BoundBadExpression : BoundExpression { - public BoundBadExpression(SyntaxNode syntax, LookupResultKind resultKind, ImmutableArray symbols, ImmutableArray childBoundNodes, TypeSymbol? type, bool hasErrors = false) + public BoundBadExpression(SyntaxNode syntax, LookupResultKind resultKind, ImmutableArray symbols, ImmutableArray childBoundNodes, TypeSymbol? type, bool hasErrors = false) : base(BoundKind.BadExpression, syntax, type, hasErrors || childBoundNodes.HasErrors()) { @@ -625,13 +625,13 @@ public BoundBadExpression(SyntaxNode syntax, LookupResultKind resultKind, Immuta private readonly LookupResultKind _ResultKind; public override LookupResultKind ResultKind { get { return _ResultKind;} } - public ImmutableArray Symbols { get; } + public ImmutableArray Symbols { get; } public ImmutableArray ChildBoundNodes { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitBadExpression(this); - public BoundBadExpression Update(LookupResultKind resultKind, ImmutableArray symbols, ImmutableArray childBoundNodes, TypeSymbol? type) + public BoundBadExpression Update(LookupResultKind resultKind, ImmutableArray symbols, ImmutableArray childBoundNodes, TypeSymbol? type) { if (resultKind != this.ResultKind || symbols != this.Symbols || childBoundNodes != this.ChildBoundNodes || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { @@ -11092,12 +11092,12 @@ public NullabilityRewriter(ImmutableDictionary field.Type.TrimEnd('?') == "TypeSymbol"; - private static bool TypeIsSymbol(Field field) => field.Type.TrimEnd('?').EndsWith("Symbol"); + private static bool TypeIsSymbol(Field field) => TypeIsSymbol(field.Type); + private static bool TypeIsSymbol(string type) => type.TrimEnd('?').EndsWith("Symbol"); private string StripBound(string name) { @@ -1200,7 +1201,7 @@ private void WriteTreeDumperNodeProducer() Write("new TreeDumperNode(\"{0}\", null, new TreeDumperNode[] {{ Visit(node.{1}, null) }})", ToCamelCase(field.Name), field.Name); else if (IsListOfDerived("BoundNode", field.Type)) { - if (IsImmutableArray(field.Type) && FieldNullHandling(node, field.Name) == NullHandling.Disallow) + if (IsImmutableArray(field.Type, out _) && FieldNullHandling(node, field.Name) == NullHandling.Disallow) { Write("new TreeDumperNode(\"{0}\", null, from x in node.{1} select Visit(x, null))", ToCamelCase(field.Name), field.Name); } @@ -1499,7 +1500,11 @@ void writeUpdate(bool updatedType) allSpecifiableFields, field => { - if (IsDerivedOrListOfDerived("BoundNode", field.Type)) + if (SkipInNullabilityRewriter(field)) + { + return $"node.{field.Name}"; + } + else if (IsDerivedOrListOfDerived("BoundNode", field.Type)) { return ToCamelCase(field.Name); } @@ -1511,6 +1516,10 @@ void writeUpdate(bool updatedType) { return $"GetUpdatedSymbol(node, node.{field.Name})"; } + else if (IsImmutableArray(field.Type, out var elementType) && TypeIsSymbol(elementType) && typeIsUpdated(elementType)) + { + return $"GetUpdatedArray(node, node.{field.Name})"; + } else { return $"node.{field.Name}"; @@ -1529,7 +1538,12 @@ static bool symbolIsPotentiallyUpdated(Field f) if (f.Name == "Type") return false; - switch (f.Type.TrimEnd('?')) + return typeIsUpdated(f.Type); + } + + static bool typeIsUpdated(string type) + { + switch (type.TrimEnd('?')) { case "LocalSymbol": case "LabelSymbol": @@ -1563,17 +1577,23 @@ private bool IsListOfDerived(string baseType, string derivedType) return IsNodeList(derivedType) && IsDerivedType(baseType, GetElementType(derivedType)); } - private bool IsImmutableArray(string typeName) + private bool IsImmutableArray(string typeName, out string elementType) { - switch (_targetLang) + string immutableArrayPrefix = _targetLang switch { - case TargetLanguage.CSharp: - return typeName.StartsWith("ImmutableArray<", StringComparison.Ordinal); - case TargetLanguage.VB: - return typeName.StartsWith("ImmutableArray(Of", StringComparison.OrdinalIgnoreCase); - default: - throw new ArgumentException("Unexpected target language", nameof(_targetLang)); + TargetLanguage.CSharp => "ImmutableArray<", + TargetLanguage.VB => "ImmutableArray(Of ", + _ => throw new InvalidOperationException($"Unknown target language {_targetLang}") + }; + + if (typeName.StartsWith(immutableArrayPrefix, StringComparison.Ordinal)) + { + elementType = typeName[immutableArrayPrefix.Length..^1]; + return true; } + + elementType = null; + return false; } private bool IsNodeList(string typeName) @@ -1714,6 +1734,11 @@ private static bool SkipInNullabilityRewriter(Node n) return string.Compare(n.SkipInNullabilityRewriter, "true", true) == 0; } + private static bool SkipInNullabilityRewriter(Field f) + { + return string.Compare(f.SkipInNullabilityRewriter, "true", ignoreCase: true) == 0; + } + private string ToCamelCase(string name) { if (char.IsUpper(name[0])) diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/CompilersBoundTreeGenerator.csproj b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/CompilersBoundTreeGenerator.csproj index caa1cc2e9d1ecc6f021ec47052e69dbbc113fbff..121fcec79a4d88b4b501b3ff9d29faa9bdc50bc6 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/CompilersBoundTreeGenerator.csproj +++ b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/CompilersBoundTreeGenerator.csproj @@ -9,7 +9,7 @@ Roslyn.Compilers.Internal.BoundTreeGenerator BoundTreeGenerator True - netcoreapp2.1 + netcoreapp3.0 false diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/Model.cs b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/Model.cs index 7585b791751393194dfce0a0ec9d5519e65a2588..28c09758fd41e0a27b64e7a5a05a78cba94967e9 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/Model.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/Model.cs @@ -91,6 +91,9 @@ public class Field [XmlAttribute] public string SkipInVisitor; + + [XmlAttribute] + public string SkipInNullabilityRewriter; } public class EnumType : TreeType