提交 fd7c3295 编写于 作者: K Kevin Halverson 提交者: unknown

Prefer System.Linq over System.Core...

When we optimistically load a "LINQ library", prefer to load System.Linq (and then fall back to System.Core if that fails).
上级 02a4fa0b
......@@ -551,16 +551,18 @@ internal override bool HasDuplicateTypesOrAssemblies(Diagnostic diagnostic)
}
}
internal override ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentities(Diagnostic diagnostic)
internal override ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentities(Diagnostic diagnostic, AssemblyIdentity linqLibrary)
{
return GetMissingAssemblyIdentitiesHelper((ErrorCode)diagnostic.Code, diagnostic.Arguments);
return GetMissingAssemblyIdentitiesHelper((ErrorCode)diagnostic.Code, diagnostic.Arguments, linqLibrary);
}
/// <remarks>
/// Internal for testing.
/// </remarks>
internal static ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentitiesHelper(ErrorCode code, IReadOnlyList<object> arguments)
internal static ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentitiesHelper(ErrorCode code, IReadOnlyList<object> arguments, AssemblyIdentity linqLibrary)
{
Debug.Assert(linqLibrary != null);
switch (code)
{
case ErrorCode.ERR_NoTypeDef:
......@@ -598,7 +600,7 @@ internal static ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentitiesHel
// MSDN says these might come from System.Dynamic.Runtime
case ErrorCode.ERR_QueryNoProviderStandard:
case ErrorCode.ERR_ExtensionAttrNotFound: // Probably can't happen.
return ImmutableArray.Create(SystemCoreIdentity);
return ImmutableArray.Create(linqLibrary);
case ErrorCode.ERR_BadAwaitArg_NeedSystem:
Debug.Assert(false, "Roslyn no longer produces ERR_BadAwaitArg_NeedSystem");
break;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
......@@ -572,43 +573,43 @@ static void M(Windows.UI.Colors c)
Assert.Equal(expectedMissingAssemblyIdentity, actualMissingAssemblyIdentities.Single());
}
[WorkItem(1154988)]
[Fact]
[WorkItem(1154988)]
[Fact]
public void CompileWithRetrySameErrorReported()
{
{
var source = @"
class C
{
void M()
{
}
}";
var comp = CreateCompilationWithMscorlib(source);
var runtime = CreateRuntimeInstance(comp);
var context = CreateMethodContext(runtime, "C.M");
var missingModule = runtime.Modules.First();
var missingIdentity = missingModule.MetadataReader.ReadAssemblyIdentityOrThrow();
var numRetries = 0;
}";
var comp = CreateCompilationWithMscorlib(source);
var runtime = CreateRuntimeInstance(comp);
var context = CreateMethodContext(runtime, "C.M");
var missingModule = runtime.Modules.First();
var missingIdentity = missingModule.MetadataReader.ReadAssemblyIdentityOrThrow();
var numRetries = 0;
string errorMessage;
ExpressionCompilerTestHelpers.CompileExpressionWithRetry(
runtime.Modules.Select(m => m.MetadataBlock).ToImmutableArray(),
context,
(_, diagnostics) =>
ExpressionCompilerTestHelpers.CompileExpressionWithRetry(
runtime.Modules.Select(m => m.MetadataBlock).ToImmutableArray(),
context,
(_, diagnostics) =>
{
numRetries++;
Assert.InRange(numRetries, 0, 2); // We don't want to loop forever...
diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_NoTypeDef, "MissingType", missingIdentity), Location.None));
return null;
},
(AssemblyIdentity assemblyIdentity, out uint uSize) =>
{
uSize = (uint)missingModule.MetadataLength;
return missingModule.MetadataAddress;
},
out errorMessage);
return null;
},
(AssemblyIdentity assemblyIdentity, out uint uSize) =>
{
uSize = (uint)missingModule.MetadataLength;
return missingModule.MetadataAddress;
},
out errorMessage);
Assert.Equal(2, numRetries); // Ensure that we actually retried and that we bailed out on the second retry if the same identity was seen in the diagnostics.
Assert.Equal($"error CS0012: The type 'MissingType' is defined in an assembly that is not referenced. You must add a reference to assembly '{missingIdentity}'.", errorMessage);
}
......@@ -660,6 +661,66 @@ void M()
Assert.Null(errorMessage);
}
[WorkItem(2547)]
[Fact]
public void TryDifferentLinqLibraryOnRetry()
{
var source = @"
using System.Linq;
class C
{
void M(string[] args)
{
}
}
class UseLinq
{
bool b = Enumerable.Any<int>(null);
}";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
byte[] exeBytes, pdbBytes;
ImmutableArray<MetadataReference> references;
compilation.EmitAndGetReferences(out exeBytes, out pdbBytes, out references);
var systemCore = SystemCoreRef.ToModuleInstance(fullImage: null, symReader: null);
var referencesWithoutSystemCore = references.Where(r => r != SystemCoreRef).ToImmutableArray();
var runtime = CreateRuntimeInstance(ExpressionCompilerUtilities.GenerateUniqueName(), referencesWithoutSystemCore.AddIntrinsicAssembly(), exeBytes, symReader: null);
var context = CreateMethodContext(runtime, "C.M");
var fakeSystemLinq = CreateCompilationWithMscorlib45("", assemblyName: "System.Linq").EmitToImageReference().ToModuleInstance(fullImage: null, symReader: null);
string errorMessage;
CompilationTestData testData;
int retryCount = 0;
var compileResult = ExpressionCompilerTestHelpers.CompileExpressionWithRetry(
runtime.Modules.Select(m => m.MetadataBlock).ToImmutableArray(),
"args.Where(a => a.Length > 0)",
(_1, _2) => context, // ignore new blocks and just keep using the same failed context...
(AssemblyIdentity assemblyIdentity, out uint uSize) =>
{
retryCount++;
MetadataBlock block;
switch (retryCount)
{
case 1:
Assert.Equal(EvaluationContextBase.SystemLinqIdentity, assemblyIdentity);
block = fakeSystemLinq.MetadataBlock;
break;
case 2:
Assert.Equal(EvaluationContextBase.SystemCoreIdentity, assemblyIdentity);
block = systemCore.MetadataBlock;
break;
default:
throw ExceptionUtilities.Unreachable;
}
uSize = (uint)block.Size;
return block.Pointer;
},
errorMessage: out errorMessage,
testData: out testData);
Assert.Equal(2, retryCount);
}
private sealed class TestCompileResult : CompileResult
{
public static readonly CompileResult Instance = new TestCompileResult();
......@@ -694,7 +755,7 @@ private EvaluationContext CreateMethodContextWithReferences(Compilation comp, st
private static AssemblyIdentity GetMissingAssemblyIdentity(ErrorCode code, params object[] arguments)
{
var missingAssemblyIdentities = EvaluationContext.GetMissingAssemblyIdentitiesHelper(code, arguments);
var missingAssemblyIdentities = EvaluationContext.GetMissingAssemblyIdentitiesHelper(code, arguments, EvaluationContextBase.SystemCoreIdentity);
return missingAssemblyIdentities.IsDefault ? null : missingAssemblyIdentities.Single();
}
......
......@@ -17,6 +17,7 @@ internal abstract class EvaluationContextBase
{
internal static readonly AssemblyIdentity SystemIdentity = new AssemblyIdentity("System");
internal static readonly AssemblyIdentity SystemCoreIdentity = new AssemblyIdentity("System.Core");
internal static readonly AssemblyIdentity SystemLinqIdentity = new AssemblyIdentity("System.Linq");
internal static readonly AssemblyIdentity SystemXmlIdentity = new AssemblyIdentity("System.Xml");
internal static readonly AssemblyIdentity SystemXmlLinqIdentity = new AssemblyIdentity("System.Xml.Linq");
internal static readonly AssemblyIdentity MicrosoftVisualBasicIdentity = new AssemblyIdentity("Microsoft.VisualBasic");
......@@ -45,12 +46,12 @@ internal abstract class EvaluationContextBase
out string typeName,
CompilationTestData testData);
internal string GetErrorMessageAndMissingAssemblyIdentities(DiagnosticBag diagnostics, DiagnosticFormatter formatter, CultureInfo preferredUICulture, out bool useReferencedModulesOnly, out ImmutableArray<AssemblyIdentity> missingAssemblyIdentities)
internal string GetErrorMessageAndMissingAssemblyIdentities(DiagnosticBag diagnostics, DiagnosticFormatter formatter, CultureInfo preferredUICulture, AssemblyIdentity linqLibrary, out bool useReferencedModulesOnly, out ImmutableArray<AssemblyIdentity> missingAssemblyIdentities)
{
var errors = diagnostics.AsEnumerable().Where(d => d.Severity == DiagnosticSeverity.Error);
foreach (var error in errors)
{
missingAssemblyIdentities = this.GetMissingAssemblyIdentities(error);
missingAssemblyIdentities = this.GetMissingAssemblyIdentities(error, linqLibrary);
if (!missingAssemblyIdentities.IsDefault)
{
break;
......@@ -75,7 +76,7 @@ internal string GetErrorMessageAndMissingAssemblyIdentities(DiagnosticBag diagno
internal abstract bool HasDuplicateTypesOrAssemblies(Diagnostic diagnostic);
internal abstract ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentities(Diagnostic diagnostic);
internal abstract ImmutableArray<AssemblyIdentity> GetMissingAssemblyIdentities(Diagnostic diagnostic, AssemblyIdentity linqLibrary);
// ILOffset == 0xffffffff indicates an instruction outside of IL.
// Treat such values as the beginning of the IL.
......
......@@ -322,6 +322,7 @@ void IDkmModuleModifiedNotification.OnModuleModified(DkmModuleInstance moduleIns
PooledHashSet<AssemblyIdentity> assembliesLoadedInRetryLoop = null;
bool tryAgain;
var linqLibrary = EvaluationContextBase.SystemLinqIdentity;
do
{
errorMessage = null;
......@@ -338,8 +339,13 @@ void IDkmModuleModifiedNotification.OnModuleModified(DkmModuleInstance moduleIns
diagnostics,
formatter,
preferredUICulture: null,
linqLibrary: linqLibrary,
useReferencedModulesOnly: out useReferencedModulesOnly,
missingAssemblyIdentities: out missingAssemblyIdentities);
// If there were LINQ-related errors, we'll initially add System.Linq (set above).
// If that doesn't work, we'll fall back to System.Core for subsequent retries.
linqLibrary = EvaluationContextBase.SystemCoreIdentity;
if (useReferencedModulesOnly)
{
Debug.Assert(missingAssemblyIdentities.IsEmpty);
......
......@@ -108,7 +108,7 @@ internal static class ExpressionCompilerTestHelpers
if (diagnostics.HasAnyErrors())
{
bool useReferencedModulesOnly;
error = context.GetErrorMessageAndMissingAssemblyIdentities(diagnostics, formatter, preferredUICulture, out useReferencedModulesOnly, out missingAssemblyIdentities);
error = context.GetErrorMessageAndMissingAssemblyIdentities(diagnostics, formatter, preferredUICulture, EvaluationContextBase.SystemCoreIdentity, out useReferencedModulesOnly, out missingAssemblyIdentities);
}
else
{
......@@ -222,7 +222,7 @@ internal static class ExpressionCompilerTestHelpers
if (diagnostics.HasAnyErrors())
{
bool useReferencedModulesOnly;
error = evaluationContext.GetErrorMessageAndMissingAssemblyIdentities(diagnostics, formatter, preferredUICulture, out useReferencedModulesOnly, out missingAssemblyIdentities);
error = evaluationContext.GetErrorMessageAndMissingAssemblyIdentities(diagnostics, formatter, preferredUICulture, EvaluationContextBase.SystemCoreIdentity, out useReferencedModulesOnly, out missingAssemblyIdentities);
}
else
{
......
......@@ -626,14 +626,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
End Select
End Function
Friend Overrides Function GetMissingAssemblyIdentities(diagnostic As Diagnostic) As ImmutableArray(Of AssemblyIdentity)
Return GetMissingAssemblyIdentitiesHelper(CType(diagnostic.Code, ERRID), diagnostic.Arguments, Me.Compilation.GlobalNamespace)
Friend Overrides Function GetMissingAssemblyIdentities(diagnostic As Diagnostic, linqLibrary As AssemblyIdentity) As ImmutableArray(Of AssemblyIdentity)
Return GetMissingAssemblyIdentitiesHelper(CType(diagnostic.Code, ERRID), diagnostic.Arguments, Me.Compilation.GlobalNamespace, linqLibrary)
End Function
''' <remarks>
''' Friend for testing.
''' </remarks>
Friend Shared Function GetMissingAssemblyIdentitiesHelper(code As ERRID, arguments As IReadOnlyList(Of Object), globalNamespace As NamespaceSymbol) As ImmutableArray(Of AssemblyIdentity)
Friend Shared Function GetMissingAssemblyIdentitiesHelper(code As ERRID, arguments As IReadOnlyList(Of Object), globalNamespace As NamespaceSymbol, linqLibrary As AssemblyIdentity) As ImmutableArray(Of AssemblyIdentity)
Debug.Assert(linqLibrary IsNot Nothing)
Select Case code
Case ERRID.ERR_UnreferencedAssemblyEvent3, ERRID.ERR_UnreferencedAssembly3
For Each argument As Object In arguments
......@@ -659,8 +661,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim identity = New AssemblyIdentity($"{containingNamespace.ToDisplayString}.{namespaceName}", contentType:=AssemblyContentType.WindowsRuntime)
Return ImmutableArray.Create(identity)
Else
' Maybe it's a missing Linq extension method. Let's try adding System.Core and see if that helps.
Return ImmutableArray.Create(SystemCoreIdentity)
' Maybe it's a missing LINQ extension method. Let's try adding the "LINQ library" to see if that helps.
Return ImmutableArray.Create(linqLibrary)
End If
End If
Case ERRID.ERR_UndefinedType1
......@@ -696,7 +698,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
End If
End If
Case ERRID.ERR_XmlFeaturesNotAvailable
Return ImmutableArray.Create(SystemIdentity, SystemCoreIdentity, SystemXmlIdentity, SystemXmlLinqIdentity)
Return ImmutableArray.Create(SystemIdentity, linqLibrary, SystemXmlIdentity, SystemXmlLinqIdentity)
Case ERRID.ERR_MissingRuntimeHelper
Return ImmutableArray.Create(MicrosoftVisualBasicIdentity)
End Select
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.CodeGen
Imports Microsoft.CodeAnalysis.ExpressionEvaluator
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
......@@ -250,23 +251,23 @@ End Class
Dim expectedIdentity = New AssemblyIdentity("Windows.Storage", contentType:=Reflection.AssemblyContentType.WindowsRuntime)
Dim actualIdentity = EvaluationContext.GetMissingAssemblyIdentitiesHelper(ERRID.ERR_UndefinedType1, {"Windows.Storage"}, globalNamespace).Single()
Dim actualIdentity = GetMissingAssemblyIdentities(ERRID.ERR_UndefinedType1, {"Windows.Storage"}, globalNamespace).Single()
Assert.Equal(expectedIdentity, actualIdentity)
actualIdentity = EvaluationContext.GetMissingAssemblyIdentitiesHelper(ERRID.ERR_UndefinedType1, {"Global.Windows.Storage"}, globalNamespace).Single()
actualIdentity = GetMissingAssemblyIdentities(ERRID.ERR_UndefinedType1, {"Global.Windows.Storage"}, globalNamespace).Single()
Assert.Equal(expectedIdentity, actualIdentity)
actualIdentity = EvaluationContext.GetMissingAssemblyIdentitiesHelper(ERRID.ERR_UndefinedType1, {"Global.Windows.Storage.Additional"}, globalNamespace).Single()
actualIdentity = GetMissingAssemblyIdentities(ERRID.ERR_UndefinedType1, {"Global.Windows.Storage.Additional"}, globalNamespace).Single()
Assert.Equal(expectedIdentity, actualIdentity)
expectedIdentity = New AssemblyIdentity("Windows.UI.Xaml", contentType:=Reflection.AssemblyContentType.WindowsRuntime)
actualIdentity = EvaluationContext.GetMissingAssemblyIdentitiesHelper(ERRID.ERR_UndefinedType1, {"Windows.UI.Xaml"}, globalNamespace).Single()
actualIdentity = GetMissingAssemblyIdentities(ERRID.ERR_UndefinedType1, {"Windows.UI.Xaml"}, globalNamespace).Single()
Assert.Equal(expectedIdentity, actualIdentity)
Assert.True(EvaluationContext.GetMissingAssemblyIdentitiesHelper(ERRID.ERR_UndefinedType1, {"Windows.UI.Xaml(Of T)"}, globalNamespace).IsDefault)
Assert.True(GetMissingAssemblyIdentities(ERRID.ERR_UndefinedType1, {"Windows.UI.Xaml(Of T)"}, globalNamespace).IsDefault)
End Sub
<WorkItem(1151888, "DevDiv")>
......@@ -514,6 +515,58 @@ End Class
Assert.Equal($"error BC30652: Reference required to assembly '{missingIdentity}' containing the type 'MissingType'. Add one to your project.", errorMessage)
End Sub
<WorkItem(2547)>
<Fact>
Public Sub TryDifferentLinqLibraryOnRetry()
Dim source = "
Imports System.Linq
Class C
Shared Sub Main(args() As String)
End Sub
End Class
Class UseLinq
Dim b = Enumerable.Any(Of Integer)(Nothing)
End Class"
Dim compilation = CreateCompilationWithMscorlib({source}, references:={SystemCoreRef})
Dim exeBytes() As Byte = Nothing, pdbBytes() As Byte = Nothing
Dim references As ImmutableArray(Of MetadataReference) = Nothing
compilation.EmitAndGetReferences(exeBytes, pdbBytes, references)
Dim systemCore = SystemCoreRef.ToModuleInstance(fullImage:=Nothing, symReader:=Nothing)
Dim referencesWithoutSystemCore = references.Where(Function(r) r IsNot SystemCoreRef).ToImmutableArray()
Dim runtime = CreateRuntimeInstance(ExpressionCompilerUtilities.GenerateUniqueName(), referencesWithoutSystemCore.AddIntrinsicAssembly(), exeBytes, symReader:=Nothing)
Dim context = CreateMethodContext(runtime, "C.Main")
Dim fakeSystemLinq = CreateCompilationWithMscorlib({""}, options:=TestOptions.ReleaseDll, assemblyName:="System.Linq").EmitToImageReference().ToModuleInstance(fullImage:=Nothing, symReader:=Nothing)
Dim errorMessage As String = Nothing
Dim testData As CompilationTestData = Nothing
Dim retryCount = 0
Dim compileResult = ExpressionCompilerTestHelpers.CompileExpressionWithRetry(
runtime.Modules.Select(Function(m) m.MetadataBlock).ToImmutableArray(),
"args.Where(Function(a) a.Length > 0)",
Function(_1, _2) context, ' ignore new blocks and just keep using the same failed context...
Function(assemblyIdentity As AssemblyIdentity, ByRef uSize As UInteger)
retryCount += 1
Dim block As MetadataBlock
Select Case retryCount
Case 1
Assert.Equal(EvaluationContextBase.SystemLinqIdentity, assemblyIdentity)
block = fakeSystemLinq.MetadataBlock
Case 2
Assert.Equal(EvaluationContextBase.SystemCoreIdentity, assemblyIdentity)
block = systemCore.MetadataBlock
Case Else
Throw ExceptionUtilities.Unreachable
End Select
uSize = CUInt(block.Size)
Return block.Pointer
End Function,
errorMessage:=errorMessage,
testData:=testData)
Assert.Equal(2, retryCount)
End Sub
Private Function CreateMethodContextWithReferences(comp As Compilation, methodName As String, ParamArray references As MetadataReference()) As EvaluationContext
Return CreateMethodContextWithReferences(comp, methodName, ImmutableArray.CreateRange(references))
End Function
......@@ -529,8 +582,13 @@ End Class
Return CreateMethodContext(runtime, methodName)
End Function
Private Shared Function GetMissingAssemblyIdentities(code As ERRID, ParamArray arguments As Object()) As ImmutableArray(Of AssemblyIdentity)
Return EvaluationContext.GetMissingAssemblyIdentitiesHelper(code, arguments, globalNamespace:=Nothing)
Private Shared Function GetMissingAssemblyIdentities(code As ERRID, ParamArray arguments() As Object) As ImmutableArray(Of AssemblyIdentity)
Return GetMissingAssemblyIdentities(code, arguments, globalNamespace:=Nothing)
End Function
Private Shared Function GetMissingAssemblyIdentities(code As ERRID, arguments() As Object, globalNamespace As NamespaceSymbol) As ImmutableArray(Of AssemblyIdentity)
Return EvaluationContext.GetMissingAssemblyIdentitiesHelper(code, arguments, globalNamespace, linqLibrary:=EvaluationContextBase.SystemCoreIdentity)
End Function
End Class
End Namespace
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册