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