提交 609b6409 编写于 作者: B Brett V. Forsgren

Merge remote-tracking branch 'upstream/master' into...

Merge remote-tracking branch 'upstream/master' into merges/master-to-features/ioperation-20170808-070019
......@@ -22,6 +22,7 @@
<RoslynPortableTargetFrameworks>net46;netcoreapp2.0</RoslynPortableTargetFrameworks>
<Features>strict,IOperation</Features>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<SignAssembly>true</SignAssembly>
<!-- The new SDK introduced a GenerateAssemblyInfo target, which is disabled by GenerateAssemblyInfo=false.
......
......@@ -347,6 +347,10 @@ function Test-XUnit() {
# Exclude out the multi-targetted netcore app projects
$dlls = $dlls | ?{ -not ($_.FullName -match ".*netcoreapp.*") }
# Exclude out the ref assemblies
$dlls = $dlls | ?{ -not ($_.FullName -match ".*\\ref\\.*") }
$dlls = $dlls | ?{ -not ($_.FullName -match ".*/ref/.*") }
if ($cibuild) {
# Use a 50 minute timeout on CI
$args += " -xml -timeout:50"
......
......@@ -61,7 +61,7 @@ public override IEnumerable<string> PreprocessorSymbolNames
LanguageVersion languageVersion,
DocumentationMode documentationMode,
SourceCodeKind kind,
IEnumerable<string> preprocessorSymbols,
ImmutableArray<string> preprocessorSymbols,
IReadOnlyDictionary<string, string> features)
: base(kind, documentationMode)
{
......
......@@ -66,7 +66,7 @@ internal MethodWithBody(MethodSymbol method, BoundStatement body, ImportChain im
public readonly CSharpCompilation Compilation;
public LambdaFrame StaticLambdaFrame;
public ClosureEnvironment StaticLambdaFrame;
/// <summary>
/// A graph of method->method references for this(...) constructor initializers.
......
......@@ -183,16 +183,13 @@ internal override bool TryGetPropertyHandle(Cci.IPropertyDefinition def, out Pro
awaiterSlotCount = maxAwaiterSlotIndex + 1;
}
protected override ImmutableArray<EncLocalInfo> TryGetLocalSlotMapFromMetadata(MethodDefinitionHandle handle, EditAndContinueMethodDebugInformation debugInfo)
protected override ImmutableArray<EncLocalInfo> GetLocalSlotMapFromMetadata(StandaloneSignatureHandle handle, EditAndContinueMethodDebugInformation debugInfo)
{
ImmutableArray<LocalInfo<TypeSymbol>> slotMetadata;
if (!_metadataDecoder.TryGetLocals(handle, out slotMetadata))
{
return default(ImmutableArray<EncLocalInfo>);
}
Debug.Assert(!handle.IsNil);
var result = CreateLocalSlotMap(debugInfo, slotMetadata);
Debug.Assert(result.Length == slotMetadata.Length);
var localInfos = _metadataDecoder.GetLocalsOrThrow(handle);
var result = CreateLocalSlotMap(debugInfo, localInfos);
Debug.Assert(result.Length == localInfos.Length);
return result;
}
......
......@@ -31,7 +31,7 @@ private LambdaCapturedVariable(SynthesizedContainer frame, TypeSymbol type, stri
_isThis = isThisParameter;
}
public static LambdaCapturedVariable Create(LambdaFrame frame, Symbol captured, ref int uniqueId)
public static LambdaCapturedVariable Create(ClosureEnvironment frame, Symbol captured, ref int uniqueId)
{
Debug.Assert(captured is LocalSymbol || captured is ParameterSymbol);
......@@ -87,7 +87,7 @@ private static TypeSymbol GetCapturedVariableFieldType(SynthesizedContainer fram
if ((object)local != null)
{
// if we're capturing a generic frame pointer, construct it with the new frame's type parameters
var lambdaFrame = local.Type.OriginalDefinition as LambdaFrame;
var lambdaFrame = local.Type.OriginalDefinition as ClosureEnvironment;
if ((object)lambdaFrame != null)
{
// lambdaFrame may have less generic type parameters than frame, so trim them down (the first N will always match)
......
// 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 System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
/// <summary>
/// A class that represents the set of variables in a scope that have been
/// captured by lambdas within that scope.
/// captured by nested functions within that scope.
/// </summary>
internal sealed class LambdaFrame : SynthesizedContainer, ISynthesizedMethodBodyImplementationSymbol
internal sealed class ClosureEnvironment : SynthesizedContainer, ISynthesizedMethodBodyImplementationSymbol
{
private readonly TypeKind _typeKind;
private readonly MethodSymbol _topLevelMethod;
private readonly MethodSymbol _containingMethod;
private readonly MethodSymbol _constructor;
private readonly MethodSymbol _staticConstructor;
private readonly FieldSymbol _singletonCache;
internal readonly SyntaxNode ScopeSyntaxOpt;
internal readonly int ClosureOrdinal;
internal LambdaFrame(MethodSymbol topLevelMethod, MethodSymbol containingMethod, bool isStruct, SyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId)
/// <summary>
/// The closest method/lambda that this frame is originally from. Null if nongeneric static closure.
/// Useful because this frame's type parameters are constructed from this method and all methods containing this method.
/// </summary>
internal readonly MethodSymbol OriginalContainingMethodOpt;
internal readonly FieldSymbol SingletonCache;
internal readonly MethodSymbol StaticConstructor;
public readonly IEnumerable<Symbol> CapturedVariables;
public override TypeKind TypeKind { get; }
internal override MethodSymbol Constructor { get; }
internal ClosureEnvironment(
IEnumerable<Symbol> capturedVariables,
MethodSymbol topLevelMethod,
MethodSymbol containingMethod,
bool isStruct,
SyntaxNode scopeSyntaxOpt,
DebugId methodId,
DebugId closureId)
: base(MakeName(scopeSyntaxOpt, methodId, closureId), containingMethod)
{
_typeKind = isStruct ? TypeKind.Struct : TypeKind.Class;
CapturedVariables = capturedVariables;
TypeKind = isStruct ? TypeKind.Struct : TypeKind.Class;
_topLevelMethod = topLevelMethod;
_containingMethod = containingMethod;
_constructor = isStruct ? null : new LambdaFrameConstructor(this);
OriginalContainingMethodOpt = containingMethod;
Constructor = isStruct ? null : new LambdaFrameConstructor(this);
this.ClosureOrdinal = closureId.Ordinal;
// static lambdas technically have the class scope so the scope syntax is null
if (scopeSyntaxOpt == null)
{
_staticConstructor = new SynthesizedStaticConstructor(this);
StaticConstructor = new SynthesizedStaticConstructor(this);
var cacheVariableName = GeneratedNames.MakeCachedFrameInstanceFieldName();
_singletonCache = new SynthesizedLambdaCacheFieldSymbol(this, this, cacheVariableName, topLevelMethod, isReadOnly: true, isStatic: true);
SingletonCache = new SynthesizedLambdaCacheFieldSymbol(this, this, cacheVariableName, topLevelMethod, isReadOnly: true, isStatic: true);
}
AssertIsClosureScopeSyntax(scopeSyntaxOpt);
......@@ -77,69 +91,25 @@ private static void AssertIsClosureScopeSyntax(SyntaxNode syntaxOpt)
throw ExceptionUtilities.UnexpectedValue(syntaxOpt.Kind());
}
public override TypeKind TypeKind
{
get { return _typeKind; }
}
internal override MethodSymbol Constructor
{
get { return _constructor; }
}
internal MethodSymbol StaticConstructor
{
get { return _staticConstructor; }
}
/// <summary>
/// The closest method/lambda that this frame is originally from. Null if nongeneric static closure.
/// Useful because this frame's type parameters are constructed from this method and all methods containing this method.
/// </summary>
internal MethodSymbol ContainingMethod
{
get { return _containingMethod; }
}
public override ImmutableArray<Symbol> GetMembers()
{
var members = base.GetMembers();
if ((object)_staticConstructor != null)
if ((object)StaticConstructor != null)
{
members = ImmutableArray.Create<Symbol>(_staticConstructor, _singletonCache).AddRange(members);
members = ImmutableArray.Create<Symbol>(StaticConstructor, SingletonCache).AddRange(members);
}
return members;
}
internal FieldSymbol SingletonCache
{
get { return _singletonCache; }
}
// display classes for static lambdas do not have any data and can be serialized.
internal override bool IsSerializable
{
get { return (object)_singletonCache != null; }
}
internal override bool IsSerializable => (object)SingletonCache != null;
public override Symbol ContainingSymbol
{
get { return _topLevelMethod.ContainingSymbol; }
}
public override Symbol ContainingSymbol => _topLevelMethod.ContainingSymbol;
bool ISynthesizedMethodBodyImplementationSymbol.HasMethodBodyDependency
{
get
{
// the lambda method contains user code from the lambda:
return true;
}
}
// The lambda method contains user code from the lambda
bool ISynthesizedMethodBodyImplementationSymbol.HasMethodBodyDependency => true;
IMethodSymbol ISynthesizedMethodBodyImplementationSymbol.Method
{
get { return _topLevelMethod; }
}
IMethodSymbol ISynthesizedMethodBodyImplementationSymbol.Method => _topLevelMethod;
}
}
......@@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed class LambdaFrameConstructor : SynthesizedInstanceConstructor, ISynthesizedMethodBodyImplementationSymbol
{
internal LambdaFrameConstructor(LambdaFrame frame)
internal LambdaFrameConstructor(ClosureEnvironment frame)
: base(frame)
{
}
......
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
......@@ -25,14 +26,14 @@ internal sealed partial class Analysis : BoundTreeWalkerWithStackGuardWithoutRec
[DebuggerDisplay("{ToString(), nq}")]
public sealed class Scope
{
public Scope Parent { get; }
public readonly Scope Parent;
public ArrayBuilder<Scope> NestedScopes { get; } = ArrayBuilder<Scope>.GetInstance();
public readonly ArrayBuilder<Scope> NestedScopes = ArrayBuilder<Scope>.GetInstance();
/// <summary>
/// A list of all closures (all lambdas and local functions) declared in this scope.
/// </summary>
public ArrayBuilder<Closure> Closures { get; } = ArrayBuilder<Closure>.GetInstance();
public readonly ArrayBuilder<Closure> Closures = ArrayBuilder<Closure>.GetInstance();
/// <summary>
/// A list of all locals or parameters that were declared in this scope and captured
......@@ -45,7 +46,7 @@ public sealed class Scope
/// non-deterministic compilation, and if we generate duplicate proxies we'll generate
/// wasteful code in the best case and incorrect code in the worst.
/// </remarks>
public SetWithInsertionOrder<Symbol> DeclaredVariables { get; } = new SetWithInsertionOrder<Symbol>();
public readonly SetWithInsertionOrder<Symbol> DeclaredVariables = new SetWithInsertionOrder<Symbol>();
/// <summary>
/// The bound node representing this scope. This roughly corresponds to the bound
......@@ -53,13 +54,19 @@ public sealed class Scope
/// methods/closures are introduced into their Body's scope and do not get their
/// own scope.
/// </summary>
public BoundNode BoundNode { get; }
public readonly BoundNode BoundNode;
/// <summary>
/// The closure that this scope is nested inside. Null if this scope is not nested
/// inside a closure.
/// </summary>
public Closure ContainingClosureOpt { get; }
public readonly Closure ContainingClosureOpt;
/// <summary>
/// Environments created in this scope to hold <see cref="DeclaredVariables"/>.
/// </summary>
public readonly ArrayBuilder<ClosureEnvironment> DeclaredEnvironments
= ArrayBuilder<ClosureEnvironment>.GetInstance();
public Scope(Scope parent, BoundNode boundNode, Closure containingClosure)
{
......@@ -83,6 +90,7 @@ public void Free()
closure.Free();
}
Closures.Free();
DeclaredEnvironments.Free();
}
public override string ToString() => BoundNode.Syntax.GetText().ToString();
......@@ -102,9 +110,14 @@ public sealed class Closure
/// <summary>
/// The method symbol for the original lambda or local function.
/// </summary>
public MethodSymbol OriginalMethodSymbol { get; }
public readonly MethodSymbol OriginalMethodSymbol;
public readonly PooledHashSet<Symbol> CapturedVariables = PooledHashSet<Symbol>.GetInstance();
public PooledHashSet<Symbol> CapturedVariables { get; } = PooledHashSet<Symbol>.GetInstance();
public readonly ArrayBuilder<ClosureEnvironment> CapturedEnvironments
= ArrayBuilder<ClosureEnvironment>.GetInstance();
public ClosureEnvironment ContainingEnvironmentOpt;
public Closure(MethodSymbol symbol)
{
......@@ -115,6 +128,7 @@ public Closure(MethodSymbol symbol)
public void Free()
{
CapturedVariables.Free();
CapturedEnvironments.Free();
}
}
......@@ -164,17 +178,36 @@ private void RemoveUnneededReferences(ParameterSymbol thisParam)
}
}
// True if there are any closures in the tree which
// capture 'this' and another variable
bool captureMoreThanThis = false;
VisitClosures(ScopeTree, (scope, closure) =>
{
if (!capturesVariable.Contains(closure.OriginalMethodSymbol))
{
closure.CapturedVariables.Clear();
}
if (capturesThis.Contains(closure.OriginalMethodSymbol))
{
closure.CapturedVariables.Add(thisParam);
if (closure.CapturedVariables.Count > 1)
{
captureMoreThanThis |= true;
}
}
});
if (!captureMoreThanThis && capturesThis.Count > 0)
{
// If we have closures which capture 'this', and nothing else, we can
// remove 'this' from the declared variables list, since we don't need
// to create an environment to hold 'this' (since we can emit the
// lowered methods directly onto the containing class)
bool removed = ScopeTree.DeclaredVariables.Remove(thisParam);
Debug.Assert(removed);
}
}
/// <summary>
......@@ -193,6 +226,19 @@ public static void VisitClosures(Scope scope, Action<Scope, Closure> action)
}
}
/// <summary>
/// Visit the tree with the given root and run the <paramref name="action"/>
/// </summary>
public static void VisitScopeTree(Scope treeRoot, Action<Scope> action)
{
action(treeRoot);
foreach (var nested in treeRoot.NestedScopes)
{
VisitScopeTree(nested, action);
}
}
/// <summary>
/// Builds a tree of <see cref="Scope"/> nodes corresponding to a given method.
/// <see cref="Build(BoundNode, MethodSymbol, HashSet{MethodSymbol}, DiagnosticBag)"/>
......@@ -267,6 +313,12 @@ private void Build()
{
// Set up the current method locals
DeclareLocals(_currentScope, _topLevelMethod.Parameters);
// Treat 'this' as a formal parameter of the top-level method
if (_topLevelMethod.TryGetThisParameter(out var thisParam))
{
DeclareLocals(_currentScope, ImmutableArray.Create<Symbol>(thisParam));
}
Visit(_currentScope.BoundNode);
}
......@@ -468,12 +520,6 @@ private void AddIfCaptured(Symbol symbol, SyntaxNode syntax)
return;
}
// The 'this' parameter isn't declared in method scope
if (symbol is ParameterSymbol param && param.IsThis)
{
return;
}
if (_localToScope.TryGetValue(symbol, out var declScope))
{
declScope.DeclaredVariables.Add(symbol);
......
// 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 System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
......@@ -29,12 +32,6 @@ internal sealed partial class Analysis
// We can't rewrite delegate signatures
|| MethodsConvertedToDelegates.Contains(closure));
/// <summary>
/// Any scope that a method that <see cref="CanTakeRefParameters(MethodSymbol)"/> doesn't close over.
/// If a scope is in this set, don't use a struct closure.
/// </summary>
public readonly PooledHashSet<BoundNode> ScopesThatCantBeStructs = PooledHashSet<BoundNode>.GetInstance();
/// <summary>
/// Blocks that are positioned between a block declaring some lifted variables
/// and a block that contains the lambda that lifts said variables.
......@@ -44,29 +41,44 @@ internal sealed partial class Analysis
/// </summary>
public readonly PooledHashSet<BoundNode> NeedsParentFrame = PooledHashSet<BoundNode>.GetInstance();
/// <summary>
/// Optimized locations of lambdas.
///
/// Lambda does not need to be placed in a frame that corresponds to its lexical scope if lambda does not reference any local state in that scope.
/// It is advantageous to place lambdas higher in the scope tree, ideally in the innermost scope of all scopes that contain variables captured by a given lambda.
/// Doing so reduces indirections needed when captured locals are accessed. For example locals from the innermost scope can be accessed with no indirection at all.
/// <see cref="ComputeLambdaScopesAndFrameCaptures"/> needs to be called to compute this.
/// </summary>
public readonly SmallDictionary<MethodSymbol, BoundNode> LambdaScopes =
new SmallDictionary<MethodSymbol, BoundNode>(ReferenceEqualityComparer.Instance);
/// <summary>
/// The root of the scope tree for this method.
/// </summary>
public readonly Scope ScopeTree;
private Analysis(Scope scopeTree, PooledHashSet<MethodSymbol> methodsConvertedToDelegates)
private readonly MethodSymbol _topLevelMethod;
private readonly int _topLevelMethodOrdinal;
private readonly MethodSymbol _substitutedSourceMethod;
private readonly VariableSlotAllocator _slotAllocatorOpt;
private readonly TypeCompilationState _compilationState;
private Analysis(
Scope scopeTree,
PooledHashSet<MethodSymbol> methodsConvertedToDelegates,
MethodSymbol topLevelMethod,
int topLevelMethodOrdinal,
MethodSymbol substitutedSourceMethod,
VariableSlotAllocator slotAllocatorOpt,
TypeCompilationState compilationState)
{
ScopeTree = scopeTree;
MethodsConvertedToDelegates = methodsConvertedToDelegates;
_topLevelMethod = topLevelMethod;
_topLevelMethodOrdinal = topLevelMethodOrdinal;
_substitutedSourceMethod = substitutedSourceMethod;
_slotAllocatorOpt = slotAllocatorOpt;
_compilationState = compilationState;
}
public static Analysis Analyze(BoundNode node, MethodSymbol method, DiagnosticBag diagnostics)
public static Analysis Analyze(
BoundNode node,
MethodSymbol method,
int topLevelMethodOrdinal,
MethodSymbol substitutedSourceMethod,
VariableSlotAllocator slotAllocatorOpt,
TypeCompilationState compilationState,
ArrayBuilder<ClosureDebugInfo> closureDebugInfo,
DiagnosticBag diagnostics)
{
var methodsConvertedToDelegates = PooledHashSet<MethodSymbol>.GetInstance();
var scopeTree = ScopeTreeBuilder.Build(
......@@ -74,7 +86,21 @@ public static Analysis Analyze(BoundNode node, MethodSymbol method, DiagnosticBa
method,
methodsConvertedToDelegates,
diagnostics);
return new Analysis(scopeTree, methodsConvertedToDelegates);
Debug.Assert(scopeTree != null);
var analysis = new Analysis(
scopeTree,
methodsConvertedToDelegates,
method,
topLevelMethodOrdinal,
substitutedSourceMethod,
slotAllocatorOpt,
compilationState);
analysis.RemoveUnneededReferences(method.ThisParameter);
analysis.MakeAndAssignEnvironments(closureDebugInfo);
analysis.ComputeLambdaScopesAndFrameCaptures(method.ThisParameter);
return analysis;
}
private static BoundNode FindNodeToAnalyze(BoundNode node)
......@@ -107,12 +133,17 @@ private static BoundNode FindNodeToAnalyze(BoundNode node)
}
/// <summary>
/// Create the optimized plan for the location of lambda methods and whether scopes need access to parent scopes
/// </summary>
internal void ComputeLambdaScopesAndFrameCaptures(ParameterSymbol thisParam)
/// Must be called only after <see cref="Closure.CapturedEnvironments"/>
/// has been calculated.
///
/// Finds the most optimal capture environment to place a closure in.
/// This roughly corresponds to the 'highest' Scope in the tree where all
/// the captured variables for this closure are in scope. This minimizes
/// the number of indirections we may have to traverse to access captured
/// variables.
/// </summary>
private void ComputeLambdaScopesAndFrameCaptures(ParameterSymbol thisParam)
{
RemoveUnneededReferences(thisParam);
VisitClosures(ScopeTree, (scope, closure) =>
{
if (closure.CapturedVariables.Count > 0)
......@@ -124,6 +155,15 @@ internal void ComputeLambdaScopesAndFrameCaptures(ParameterSymbol thisParam)
(Scope innermost, Scope outermost) FindLambdaScopeRange(Closure closure, Scope closureScope)
{
// If the closure only captures this, put the method directly in the
// top-level method's containing type
if (closure.CapturedVariables.Count == 1 &&
closure.CapturedVariables.Single() is ParameterSymbol param &&
param.IsThis)
{
return (null, null);
}
Scope innermost = null;
Scope outermost = null;
......@@ -149,8 +189,8 @@ internal void ComputeLambdaScopesAndFrameCaptures(ParameterSymbol thisParam)
curScope != null && capturedVars.Count > 0;
curScope = curScope.Parent)
{
if (!(capturedVars.Overlaps(curScope.DeclaredVariables) ||
capturedVars.Overlaps(curScope.Closures.Select(c => c.OriginalMethodSymbol))))
if (!(capturedVars.RemoveAll(curScope.DeclaredVariables) ||
capturedVars.RemoveAll(curScope.Closures.Select(c => c.OriginalMethodSymbol))))
{
continue;
}
......@@ -160,9 +200,6 @@ internal void ComputeLambdaScopesAndFrameCaptures(ParameterSymbol thisParam)
{
innermost = curScope;
}
capturedVars.RemoveAll(curScope.DeclaredVariables);
capturedVars.RemoveAll(curScope.Closures.Select(c => c.OriginalMethodSymbol));
}
// If any captured variables are left, they're captured above method scope
......@@ -183,33 +220,119 @@ void RecordClosureScope(Scope innermost, Scope outermost, Closure closure)
//
// Example:
// if a lambda captures a method's parameter and `this`,
// its innermost scope depth is 0 (method locals and parameters)
// and outermost scope is -1
// its innermost scope is the root Scope (method locals and parameters)
// and outermost Scope is null
// Such lambda will be placed in a closure frame that corresponds to the method's outer block
// and this frame will also lift original `this` as a field when created by its parent.
// Note that it is completely irrelevant how deeply the lexical scope of the lambda was originally nested.
if (innermost != null)
{
LambdaScopes.Add(closure.OriginalMethodSymbol, innermost.BoundNode);
// Disable struct closures on methods converted to delegates, as well as on async and iterator methods.
var markAsNoStruct = !CanTakeRefParameters(closure.OriginalMethodSymbol);
if (markAsNoStruct)
{
ScopesThatCantBeStructs.Add(innermost.BoundNode);
}
closure.ContainingEnvironmentOpt = innermost.DeclaredEnvironments[0];
while (innermost != outermost)
{
NeedsParentFrame.Add(innermost.BoundNode);
innermost = innermost.Parent;
if (markAsNoStruct && innermost != null)
}
}
}
}
private void MakeAndAssignEnvironments(ArrayBuilder<ClosureDebugInfo> closureDebugInfo)
{
VisitScopeTree(ScopeTree, scope =>
{
if (scope.DeclaredVariables.Count > 0)
{
// First walk the nested scopes to find all closures which
// capture variables from this scope. They all need to capture
// this environment. This includes closures which captured local
// functions that capture those variables, so multiple passes may
// be needed. This will also decide if the environment is a struct
// or a class.
bool isStruct = true;
var closures = new SetWithInsertionOrder<Closure>();
bool addedItem;
do
{
addedItem = false;
VisitClosures(scope, (closureScope, closure) =>
{
ScopesThatCantBeStructs.Add(innermost.BoundNode);
}
if (!closures.Contains(closure) &&
(closure.CapturedVariables.Overlaps(scope.DeclaredVariables) ||
closure.CapturedVariables.Overlaps(closures.Select(c => c.OriginalMethodSymbol))))
{
closures.Add(closure);
addedItem = true;
isStruct &= CanTakeRefParameters(closure.OriginalMethodSymbol);
}
});
} while (addedItem == true);
// Next create the environment and add it to the declaration scope
// Currently all variables declared in the same scope are added
// to the same closure environment
var env = MakeEnvironment(scope, scope.DeclaredVariables, isStruct);
scope.DeclaredEnvironments.Add(env);
foreach (var closure in closures)
{
closure.CapturedEnvironments.Add(env);
}
}
});
ClosureEnvironment MakeEnvironment(Scope scope, IEnumerable<Symbol> capturedVariables, bool isStruct)
{
var scopeBoundNode = scope.BoundNode;
var syntax = scopeBoundNode.Syntax;
Debug.Assert(syntax != null);
DebugId methodId = GetTopLevelMethodId();
DebugId closureId = GetClosureId(syntax, closureDebugInfo);
var containingMethod = scope.ContainingClosureOpt?.OriginalMethodSymbol ?? _topLevelMethod;
if ((object)_substitutedSourceMethod != null && containingMethod == _topLevelMethod)
{
containingMethod = _substitutedSourceMethod;
}
return new ClosureEnvironment(
capturedVariables,
_topLevelMethod,
containingMethod,
isStruct,
syntax,
methodId,
closureId);
}
}
internal DebugId GetTopLevelMethodId()
{
return _slotAllocatorOpt?.MethodId ?? new DebugId(_topLevelMethodOrdinal, _compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal);
}
private DebugId GetClosureId(SyntaxNode syntax, ArrayBuilder<ClosureDebugInfo> closureDebugInfo)
{
Debug.Assert(syntax != null);
DebugId closureId;
DebugId previousClosureId;
if (_slotAllocatorOpt != null && _slotAllocatorOpt.TryGetPreviousClosure(syntax, out previousClosureId))
{
closureId = previousClosureId;
}
else
{
closureId = new DebugId(closureDebugInfo.Count, _compilationState.ModuleBuilderOpt.CurrentGenerationOrdinal);
}
int syntaxOffset = _topLevelMethod.CalculateLocalSyntaxOffset(syntax.SpanStart, syntax.SyntaxTree);
closureDebugInfo.Add(new ClosureDebugInfo(syntaxOffset, closureId));
return closureId;
}
/// <summary>
......@@ -347,7 +470,6 @@ Closure Helper(Scope scope)
public void Free()
{
MethodsConvertedToDelegates.Free();
ScopesThatCantBeStructs.Free();
NeedsParentFrame.Free();
ScopeTree.Free();
}
......
......@@ -140,7 +140,7 @@ public BoundStatement RewriteLocalFunctionReferences(BoundStatement loweredBody)
_framePointers.TryGetValue(synthesizedLambda.ContainingType, out _innermostFramePointer);
}
var containerAsFrame = synthesizedLambda.ContainingType as LambdaFrame;
var containerAsFrame = synthesizedLambda.ContainingType as ClosureEnvironment;
// Includes type parameters from the containing type iff
// the containing type is a frame. If it is a frame then
......@@ -201,11 +201,11 @@ public BoundStatement RewriteLocalFunctionReferences(BoundStatement loweredBody)
// will always be a LambdaFrame, it's always a capture frame
var frameType = (NamedTypeSymbol)loweredSymbol.Parameters[i].Type.OriginalDefinition;
Debug.Assert(frameType is LambdaFrame);
Debug.Assert(frameType is ClosureEnvironment);
if (frameType.Arity > 0)
{
var typeParameters = ((LambdaFrame)frameType).ConstructedFromTypeParameters;
var typeParameters = ((ClosureEnvironment)frameType).ConstructedFromTypeParameters;
Debug.Assert(typeParameters.Length == frameType.Arity);
var subst = this.TypeMap.SubstituteTypeParameters(typeParameters);
frameType = frameType.Construct(subst);
......
......@@ -15,11 +15,11 @@ namespace Microsoft.CodeAnalysis.CSharp
internal sealed class SynthesizedLambdaMethod : SynthesizedMethodBaseSymbol, ISynthesizedMethodBodyImplementationSymbol
{
private readonly MethodSymbol _topLevelMethod;
private readonly ImmutableArray<TypeSymbol> _structClosures;
private readonly ImmutableArray<NamedTypeSymbol> _structEnvironments;
internal SynthesizedLambdaMethod(
NamedTypeSymbol containingType,
ImmutableArray<TypeSymbol> structClosures,
ImmutableArray<ClosureEnvironment> structEnvironments,
ClosureKind closureKind,
MethodSymbol topLevelMethod,
DebugId topLevelMethodId,
......@@ -43,15 +43,15 @@ internal sealed class SynthesizedLambdaMethod : SynthesizedMethodBaseSymbol, ISy
TypeMap typeMap;
ImmutableArray<TypeParameterSymbol> typeParameters;
ImmutableArray<TypeParameterSymbol> constructedFromTypeParameters;
LambdaFrame lambdaFrame;
ClosureEnvironment lambdaFrame;
lambdaFrame = this.ContainingType as LambdaFrame;
lambdaFrame = this.ContainingType as ClosureEnvironment;
switch (closureKind)
{
case ClosureKind.Singleton: // all type parameters on method (except the top level method's)
case ClosureKind.General: // only lambda's type parameters on method (rest on class)
Debug.Assert(lambdaFrame != null);
typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, lambdaFrame.ContainingMethod);
typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, out constructedFromTypeParameters, lambdaFrame.OriginalContainingMethodOpt);
break;
case ClosureKind.ThisOnly: // all type parameters on method
case ClosureKind.Static:
......@@ -62,28 +62,30 @@ internal sealed class SynthesizedLambdaMethod : SynthesizedMethodBaseSymbol, ISy
throw ExceptionUtilities.UnexpectedValue(closureKind);
}
if (!structClosures.IsDefaultOrEmpty && typeParameters.Length != 0)
if (!structEnvironments.IsDefaultOrEmpty && typeParameters.Length != 0)
{
var constructedStructClosures = ArrayBuilder<TypeSymbol>.GetInstance();
foreach (var closure in structClosures)
var constructedStructClosures = ArrayBuilder<NamedTypeSymbol>.GetInstance();
foreach (var env in structEnvironments)
{
var frame = (LambdaFrame)closure;
NamedTypeSymbol constructed;
if (frame.Arity == 0)
if (env.Arity == 0)
{
constructed = frame;
constructed = env;
}
else
{
var originals = frame.ConstructedFromTypeParameters;
var originals = env.ConstructedFromTypeParameters;
var newArgs = typeMap.SubstituteTypeParameters(originals);
constructed = frame.Construct(newArgs);
constructed = env.Construct(newArgs);
}
constructedStructClosures.Add(constructed);
}
structClosures = constructedStructClosures.ToImmutableAndFree();
_structEnvironments = constructedStructClosures.ToImmutableAndFree();
}
else
{
_structEnvironments = ImmutableArray<NamedTypeSymbol>.CastUp(structEnvironments);
}
_structClosures = structClosures;
AssignTypeMapAndTypeParameters(typeMap, typeParameters);
}
......@@ -125,8 +127,9 @@ private static string MakeName(string topLevelMethodName, DebugId topLevelMethod
// UNDONE: names from the delegate. Does it really matter?
protected override ImmutableArray<ParameterSymbol> BaseMethodParameters => this.BaseMethod.Parameters;
protected override ImmutableArray<TypeSymbol> ExtraSynthesizedRefParameters => _structClosures;
internal int ExtraSynthesizedParameterCount => this._structClosures.IsDefault ? 0 : this._structClosures.Length;
protected override ImmutableArray<TypeSymbol> ExtraSynthesizedRefParameters
=> ImmutableArray<TypeSymbol>.CastUp(_structEnvironments);
internal int ExtraSynthesizedParameterCount => this._structEnvironments.IsDefault ? 0 : this._structEnvironments.Length;
internal override bool GenerateDebugInfo => !this.IsAsync;
internal override bool IsExpressionBodied => false;
......
......@@ -1015,17 +1015,17 @@ static void Main()
{
// Code size 131 (0x83)
.maxstack 3
.locals init (Program.<>c__DisplayClass1_2<T> V_0, //CS$<>8__locals0
Program.<>c__DisplayClass1_1<T> V_1, //CS$<>8__locals1
.locals init (Program.<>c__DisplayClass1_1<T> V_0, //CS$<>8__locals0
Program.<>c__DisplayClass1_2<T> V_1, //CS$<>8__locals1
T V_2)
IL_0000: newobj ""Program.<>c__DisplayClass1_2<T>..ctor()""
IL_0000: newobj ""Program.<>c__DisplayClass1_1<T>..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld ""Program.<>c__DisplayClass1_0<T> Program.<>c__DisplayClass1_2<T>.CS$<>8__locals1""
IL_0008: stfld ""Program.<>c__DisplayClass1_0<T> Program.<>c__DisplayClass1_1<T>.CS$<>8__locals1""
IL_000d: ldloc.0
IL_000e: ldstr ""y""
IL_0013: stfld ""string Program.<>c__DisplayClass1_2<T>.y""
IL_0013: stfld ""string Program.<>c__DisplayClass1_1<T>.y""
.try
{
IL_0018: ldstr ""xy""
......@@ -1041,17 +1041,17 @@ .maxstack 3
IL_002c: ldc.i4.0
IL_002d: br.s IL_005d
IL_002f: unbox.any ""T""
IL_0034: newobj ""Program.<>c__DisplayClass1_1<T>..ctor()""
IL_0034: newobj ""Program.<>c__DisplayClass1_2<T>..ctor()""
IL_0039: stloc.1
IL_003a: ldloc.1
IL_003b: ldloc.0
IL_003c: stfld ""Program.<>c__DisplayClass1_2<T> Program.<>c__DisplayClass1_1<T>.CS$<>8__locals2""
IL_003c: stfld ""Program.<>c__DisplayClass1_1<T> Program.<>c__DisplayClass1_2<T>.CS$<>8__locals2""
IL_0041: stloc.2
IL_0042: ldloc.1
IL_0043: ldloc.2
IL_0044: stfld ""T Program.<>c__DisplayClass1_1<T>.e""
IL_0044: stfld ""T Program.<>c__DisplayClass1_2<T>.e""
IL_0049: ldloc.1
IL_004a: ldftn ""bool Program.<>c__DisplayClass1_1<T>.<F>b__1()""
IL_004a: ldftn ""bool Program.<>c__DisplayClass1_2<T>.<F>b__1()""
IL_0050: newobj ""System.Func<bool>..ctor(object, System.IntPtr)""
IL_0055: callvirt ""bool System.Func<bool>.Invoke()""
IL_005a: ldc.i4.0
......@@ -1064,8 +1064,8 @@ .maxstack 3
IL_0065: ldarg.0
IL_0066: ldfld ""string Program.<>c__DisplayClass1_0<T>.x""
IL_006b: ldloc.1
IL_006c: ldfld ""Program.<>c__DisplayClass1_2<T> Program.<>c__DisplayClass1_1<T>.CS$<>8__locals2""
IL_0071: ldfld ""string Program.<>c__DisplayClass1_2<T>.y""
IL_006c: ldfld ""Program.<>c__DisplayClass1_1<T> Program.<>c__DisplayClass1_2<T>.CS$<>8__locals2""
IL_0071: ldfld ""string Program.<>c__DisplayClass1_1<T>.y""
IL_0076: call ""string string.Concat(string, string, string)""
IL_007b: call ""void System.Console.Write(string)""
IL_0080: leave.s IL_0082
......@@ -3646,12 +3646,12 @@ private bool T()
{
// Code size 89 (0x59)
.maxstack 2
.locals init (Program.c1.<>c__DisplayClass1_1 V_0) //CS$<>8__locals0
IL_0000: newobj ""Program.c1.<>c__DisplayClass1_1..ctor()""
.locals init (Program.c1.<>c__DisplayClass1_0 V_0) //CS$<>8__locals0
IL_0000: newobj ""Program.c1.<>c__DisplayClass1_0..ctor()""
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld ""Program.c1 Program.c1.<>c__DisplayClass1_1.<>4__this""
IL_0008: stfld ""Program.c1 Program.c1.<>c__DisplayClass1_0.<>4__this""
IL_000d: ldarg.0
IL_000e: call ""bool Program.c1.T()""
IL_0013: brfalse.s IL_002e
......@@ -3664,12 +3664,12 @@ .maxstack 2
IL_002d: ret
IL_002e: ldloc.0
IL_002f: ldc.i4.s 42
IL_0031: stfld ""int Program.c1.<>c__DisplayClass1_1.aaa""
IL_0031: stfld ""int Program.c1.<>c__DisplayClass1_0.aaa""
IL_0036: ldarg.0
IL_0037: call ""bool Program.c1.T()""
IL_003c: brfalse.s IL_0057
IL_003e: ldloc.0
IL_003f: ldftn ""bool Program.c1.<>c__DisplayClass1_1.<Test>b__2(int)""
IL_003f: ldftn ""bool Program.c1.<>c__DisplayClass1_0.<Test>b__2(int)""
IL_0045: newobj ""System.Func<int, bool>..ctor(object, System.IntPtr)""
IL_004a: ldc.i4.s 42
IL_004c: callvirt ""bool System.Func<int, bool>.Invoke(int)""
......
......@@ -76,6 +76,28 @@ void L5()
}", expectedOutput:
@"0
1");
verifier.VerifyIL("C.M()", @"
{
// Code size 46 (0x2e)
.maxstack 2
.locals init (C.<>c__DisplayClass2_0 V_0) //CS$<>8__locals0
IL_0000: ldloca.s V_0
IL_0002: ldarg.0
IL_0003: stfld ""C C.<>c__DisplayClass2_0.<>4__this""
IL_0008: ldloca.s V_0
IL_000a: ldc.i4.0
IL_000b: stfld ""int C.<>c__DisplayClass2_0.var1""
IL_0010: ldarg.0
IL_0011: ldfld ""int C._x""
IL_0016: call ""void System.Console.WriteLine(int)""
IL_001b: ldloca.s V_0
IL_001d: call ""void C.<M>g__L12_0(ref C.<>c__DisplayClass2_0)""
IL_0022: ldarg.0
IL_0023: ldfld ""int C._x""
IL_0028: call ""void System.Console.WriteLine(int)""
IL_002d: ret
}");
// L1
verifier.VerifyIL("C.<M>g__L12_0(ref C.<>c__DisplayClass2_0)", @"
{
......
......@@ -2900,7 +2900,7 @@ public void M()
);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
[WorkItem(16947, "https://github.com/dotnet/roslyn/issues/16947")]
public void Dynamic003()
{
......@@ -2930,13 +2930,12 @@ public void M()
";
CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics(
// (14,28): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// (14,26): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref G(ref d.Length);
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d.Length").WithLocation(14, 28),
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d.Length").WithLocation(14, 26),
// (14,20): error CS8164: Cannot return by reference a result of 'C.G(ref dynamic)' because the argument passed to parameter 'd' cannot be returned by reference
// return ref G(ref d.Length);
Diagnostic(ErrorCode.ERR_RefReturnCall, "G(ref d.Length)").WithArguments("C.G(ref dynamic)", "d").WithLocation(14, 20)
);
}
......
......@@ -81,7 +81,7 @@ .maxstack 1
");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
public void TestRethrowImplicit()
{
var source = @"
......@@ -91,6 +91,7 @@ static void Main()
{
try
{
System.Console.WriteLine();
}
catch
{
......@@ -101,28 +102,24 @@ static void Main()
var compilation = CompileAndVerify(source);
compilation.VerifyIL("C.Main", @"{
// Code size 11 (0xb)
// Code size 11 (0xb)
.maxstack 1
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: nop
IL_0003: leave.s IL_0009
} // end .try
catch [mscorlib]System.Object
IL_0000: call ""void System.Console.WriteLine()""
IL_0005: leave.s IL_000a
}
catch object
{
IL_0005: pop
IL_0006: nop
IL_0007: rethrow
} // end handler
IL_0009: nop
IL_000a: ret
IL_0007: pop
IL_0008: rethrow
}
IL_000a: ret
}
");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
public void TestRethrowTyped()
{
var source = @"
......@@ -142,28 +139,52 @@ static void Main()
var compilation = CompileAndVerify(source);
compilation.VerifyIL("C.Main", @"{
// Code size 11 (0xb)
// Code size 1 (0x1)
.maxstack 0
IL_0000: ret
}
");
}
[Fact]
public void TestRethrowTyped2()
{
var source = @"
class C
{
static void Main()
{
try
{
System.Console.WriteLine();
}
catch (System.Exception)
{
throw;
}
}
}";
var compilation = CompileAndVerify(source);
compilation.VerifyIL("C.Main", @"{
// Code size 11 (0xb)
.maxstack 1
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: nop
IL_0003: leave.s IL_0009
} // end .try
catch [mscorlib]System.Exception
IL_0000: call ""void System.Console.WriteLine()""
IL_0005: leave.s IL_000a
}
catch System.Exception
{
IL_0005: pop
IL_0006: nop
IL_0007: rethrow
} // end handler
IL_0009: nop
IL_000a: ret
IL_0007: pop
IL_0008: rethrow
}
IL_000a: ret
}
");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
public void TestRethrowNamed()
{
var source = @"
......@@ -183,23 +204,47 @@ static void Main()
var compilation = CompileAndVerify(source);
compilation.VerifyIL("C.Main", @"{
// Code size 11 (0xb)
// Code size 1 (0x1)
.maxstack 0
IL_0000: ret
}
");
}
[Fact]
public void TestRethrowNamed2()
{
var source = @"
class C
{
static void Main()
{
try
{
System.Console.WriteLine();
}
catch (System.Exception e)
{
throw;
}
}
}";
var compilation = CompileAndVerify(source);
compilation.VerifyIL("C.Main", @"{
// Code size 11 (0xb)
.maxstack 1
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: nop
IL_0003: leave.s IL_0009
} // end .try
catch [mscorlib]System.Exception
IL_0000: call ""void System.Console.WriteLine()""
IL_0005: leave.s IL_000a
}
catch System.Exception
{
IL_0005: stloc.0
IL_0006: nop
IL_0007: rethrow
} // end handler
IL_0009: nop
IL_000a: ret
IL_0007: pop
IL_0008: rethrow
}
IL_000a: ret
}
");
}
......
......@@ -271,8 +271,8 @@ int F(int a)
// no new synthesized members generated (with #1 in names):
diff1.VerifySynthesizedMembers(
"C: {<>c__DisplayClass0_0}",
"C.<>c__DisplayClass0_0: {a, <>4__this, <F>b__0}");
"C.<>c__DisplayClass0_0: {<>4__this, a, <F>b__0}",
"C: {<>c__DisplayClass0_0}");
var md1 = diff1.GetMetadata();
var reader1 = md1.Reader;
......
......@@ -1128,11 +1128,11 @@ void F()
</encLocalSlotMap>
<encLambdaMap>
<methodOrdinal>1</methodOrdinal>
<closure offset=""102"" />
<closure offset=""41"" />
<lambda offset=""149"" closure=""0"" />
<lambda offset=""73"" closure=""1"" />
<lambda offset=""87"" closure=""1"" />
<closure offset=""102"" />
<lambda offset=""149"" closure=""1"" />
<lambda offset=""73"" closure=""0"" />
<lambda offset=""87"" closure=""0"" />
</encLambdaMap>
</customDebugInfo>
<sequencePoints>
......
......@@ -2948,12 +2948,12 @@ class Student : Person { public double GPA; }
</encLocalSlotMap>
<encLambdaMap>
<methodOrdinal>2</methodOrdinal>
<closure offset=""383"" />
<closure offset=""0"" />
<lambda offset=""109"" closure=""0"" />
<lambda offset=""202"" closure=""0"" />
<lambda offset=""295"" closure=""0"" />
<lambda offset=""383"" closure=""1"" />
<closure offset=""383"" />
<lambda offset=""109"" closure=""1"" />
<lambda offset=""202"" closure=""1"" />
<lambda offset=""295"" closure=""1"" />
<lambda offset=""383"" closure=""0"" />
</encLambdaMap>
</customDebugInfo>
<sequencePoints>
......@@ -6795,32 +6795,32 @@ static void M()
#region Patterns
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
public void SyntaxOffset_Pattern()
{
var source = @"class C { bool F(object o) => o is int i && o is 3 && o is bool; }";
var c = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.DebugDll);
c.VerifyPdb("C.F", @"<symbols>
<methods>
<method containingType=""C"" name=""F"" parameterNames=""o"">
<customDebugInfo>
<using>
<namespace usingCount=""0"" />
</using>
<encLocalSlotMap>
<slot kind=""0"" offset=""12"" />
<slot kind=""temp"" />
</encLocalSlotMap>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""1"" startColumn=""31"" endLine=""1"" endColumn=""64"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x38"">
<local name=""i"" il_index=""0"" il_start=""0x0"" il_end=""0x38"" attributes=""0"" />
</scope>
</method>
</methods>
</symbols>");
<methods>
<method containingType=""C"" name=""F"" parameterNames=""o"">
<customDebugInfo>
<using>
<namespace usingCount=""0"" />
</using>
<encLocalSlotMap>
<slot kind=""0"" offset=""12"" />
<slot kind=""temp"" />
</encLocalSlotMap>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""1"" startColumn=""31"" endLine=""1"" endColumn=""64"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x35"">
<local name=""i"" il_index=""0"" il_start=""0x0"" il_end=""0x35"" attributes=""0"" />
</scope>
</method>
</methods>
</symbols>");
}
#endregion
......
......@@ -166,7 +166,7 @@ static void M1()
VerifyOperationTreeAndDiagnosticsForTest<InvocationExpressionSyntax>(source, expectedOperationTree, expectedDiagnostics);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
public void NamedArgumentInParameterOrderWithDefaultValue()
{
string source = @"
......@@ -188,7 +188,7 @@ static void M1()
IArgument (ArgumentKind.Explicit, Matching Parameter: z) (OperationKind.Argument) (Syntax: '2')
ILiteralExpression (Text: 2) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 2) (Syntax: '2')
IArgument (ArgumentKind.DefaultValue, Matching Parameter: x) (OperationKind.Argument) (Syntax: 'M2(y: 0, z: 2)')
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: 'M2(y: 0, z: 2)')
ILiteralExpression (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: 'M2(y: 0, z: 2)')
";
var expectedDiagnostics = DiagnosticDescription.None;
......
......@@ -1852,7 +1852,7 @@ public void TestFromOrderByDescendingSelect()
Assert.Null(qs.Body.Continuation);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
public void TestFromGroupBy()
{
var text = "from a in A group b by c";
......@@ -1864,10 +1864,9 @@ public void TestFromGroupBy()
Assert.Equal(0, expr.Errors().Length);
var qs = (QueryExpressionSyntax)expr;
Assert.Equal(1, qs.Body.Clauses.Count);
Assert.Equal(SyntaxKind.FromClause, qs.Body.Clauses[0].Kind());
Assert.Equal(0, qs.Body.Clauses.Count);
var fs = (FromClauseSyntax)qs.Body.Clauses[0];
var fs = qs.FromClause;
Assert.NotNull(fs.FromKeyword);
Assert.False(fs.FromKeyword.IsMissing);
Assert.Null(fs.Type);
......@@ -1892,7 +1891,7 @@ public void TestFromGroupBy()
Assert.Null(qs.Body.Continuation);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/21079")]
[Fact]
public void TestFromGroupByIntoSelect()
{
var text = "from a in A group b by c into d select e";
......@@ -1904,10 +1903,9 @@ public void TestFromGroupByIntoSelect()
Assert.Equal(0, expr.Errors().Length);
var qs = (QueryExpressionSyntax)expr;
Assert.Equal(1, qs.Body.Clauses.Count);
Assert.Equal(SyntaxKind.FromClause, qs.Body.Clauses[0].Kind());
Assert.Equal(0, qs.Body.Clauses.Count);
var fs = (FromClauseSyntax)qs.Body.Clauses[0];
var fs = qs.FromClause;
Assert.NotNull(fs.FromKeyword);
Assert.False(fs.FromKeyword.IsMissing);
Assert.Null(fs.Type);
......
......@@ -12,9 +12,10 @@ namespace Microsoft.CodeAnalysis.UnitTests.Emit
public class EmitBaselineTests
{
[Fact]
public void CreateInitialBaseline()
public void CreateInitialBaseline_Errors()
{
var provider = new Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation>(_ => default(EditAndContinueMethodDebugInformation));
var debugInfoProvider = new Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation>(_ => default);
var localSigProvider = new Func<MethodDefinitionHandle, StandaloneSignatureHandle>(_ => default);
var peModule = ModuleMetadata.CreateFromImage(TestResources.Basic.Members);
var peReader = peModule.Module.PEReaderOpt;
......@@ -22,9 +23,14 @@ public void CreateInitialBaseline()
var mdBytesHandle = GCHandle.Alloc(mdBytes.DangerousGetUnderlyingArray(), GCHandleType.Pinned);
var mdModule = ModuleMetadata.CreateFromMetadata(mdBytesHandle.AddrOfPinnedObject(), mdBytes.Length);
Assert.Throws<ArgumentNullException>(() => EmitBaseline.CreateInitialBaseline(null, provider));
Assert.Throws<ArgumentNullException>(() => EmitBaseline.CreateInitialBaseline(null, debugInfoProvider));
Assert.Throws<ArgumentNullException>(() => EmitBaseline.CreateInitialBaseline(peModule, null));
Assert.Throws<ArgumentException>(() => EmitBaseline.CreateInitialBaseline(mdModule, provider));
Assert.Throws<ArgumentException>(() => EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider));
Assert.Throws<ArgumentNullException>(() => EmitBaseline.CreateInitialBaseline(null, debugInfoProvider, localSigProvider, true));
Assert.Throws<ArgumentNullException>(() => EmitBaseline.CreateInitialBaseline(peModule, null, localSigProvider, true));
Assert.Throws<ArgumentNullException>(() => EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider, null, true));
Assert.NotNull(EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider, localSigProvider, true));
}
}
}
......@@ -151,14 +151,14 @@ private bool TryGetMethodHandle(EmitBaseline baseline, Cci.IMethodDefinition def
out IReadOnlyDictionary<Cci.ITypeReference, int> awaiterMap,
out int awaiterSlotCount);
protected abstract ImmutableArray<EncLocalInfo> TryGetLocalSlotMapFromMetadata(MethodDefinitionHandle handle, EditAndContinueMethodDebugInformation debugInfo);
protected abstract ImmutableArray<EncLocalInfo> GetLocalSlotMapFromMetadata(StandaloneSignatureHandle handle, EditAndContinueMethodDebugInformation debugInfo);
protected abstract ITypeSymbol TryGetStateMachineType(EntityHandle methodHandle);
internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline baseline, Compilation compilation, IMethodSymbolInternal method, IMethodSymbol topLevelMethod, DiagnosticBag diagnostics)
{
// Top-level methods are always included in the semantic edit list. Lambda methods are not.
MappedMethod mappedMethod;
if (!this.mappedMethods.TryGetValue(topLevelMethod, out mappedMethod))
if (!mappedMethods.TryGetValue(topLevelMethod, out mappedMethod))
{
return null;
}
......@@ -167,7 +167,7 @@ internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline basel
// Handle cases when the previous method doesn't exist.
MethodDefinitionHandle previousHandle;
if (!this.TryGetMethodHandle(baseline, (Cci.IMethodDefinition)method, out previousHandle))
if (!TryGetMethodHandle(baseline, (Cci.IMethodDefinition)method, out previousHandle))
{
// Unrecognized method. Must have been added in the current compilation.
return null;
......@@ -227,11 +227,13 @@ internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline basel
// Method has not changed since initial generation. Generate a map
// using the local names provided with the initial metadata.
EditAndContinueMethodDebugInformation debugInfo;
StandaloneSignatureHandle localSignature;
try
{
debugInfo = baseline.DebugInformationProvider(previousHandle);
localSignature = baseline.LocalSignatureProvider(previousHandle);
}
catch (InvalidDataException)
catch (Exception e) when (e is InvalidDataException || e is IOException)
{
diagnostics.Add(MessageProvider.CreateDiagnostic(
MessageProvider.ERR_InvalidDebugInfo,
......@@ -292,10 +294,21 @@ internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline basel
}
}
previousLocals = TryGetLocalSlotMapFromMetadata(previousHandle, debugInfo);
if (previousLocals.IsDefault)
try
{
// TODO: Report error that metadata is not supported.
previousLocals = localSignature.IsNil ? ImmutableArray<EncLocalInfo>.Empty :
GetLocalSlotMapFromMetadata(localSignature, debugInfo);
}
catch (Exception e) when (e is UnsupportedSignatureContent || e is BadImageFormatException || e is IOException)
{
diagnostics.Add(MessageProvider.CreateDiagnostic(
MessageProvider.ERR_InvalidDebugInfo,
method.Locations.First(),
method,
MetadataTokens.GetToken(localSignature),
method.ContainingAssembly
));
return null;
}
}
......
......@@ -134,8 +134,6 @@ private ImmutableArray<int> GetDeltaTableSizes(ImmutableArray<int> rowCounts)
internal EmitBaseline GetDelta(EmitBaseline baseline, Compilation compilation, Guid encId, MetadataSizes metadataSizes)
{
var moduleBuilder = (CommonPEModuleBuilder)this.module;
var addedOrChangedMethodsByIndex = new Dictionary<int, AddedOrChangedMethodInfo>();
foreach (var pair in _addedOrChangedMethods)
{
......@@ -143,7 +141,7 @@ internal EmitBaseline GetDelta(EmitBaseline baseline, Compilation compilation, G
}
var previousTableSizes = _previousGeneration.TableEntriesAdded;
var deltaTableSizes = this.GetDeltaTableSizes(metadataSizes.RowCounts);
var deltaTableSizes = GetDeltaTableSizes(metadataSizes.RowCounts);
var tableSizes = new int[MetadataTokens.TableCount];
for (int i = 0; i < tableSizes.Length; i++)
......@@ -153,11 +151,11 @@ internal EmitBaseline GetDelta(EmitBaseline baseline, Compilation compilation, G
// If the previous generation is 0 (metadata) get the synthesized members from the current compilation's builder,
// otherwise members from the current compilation have already been merged into the baseline.
var synthesizedMembers = (baseline.Ordinal == 0) ? moduleBuilder.GetSynthesizedMembers() : baseline.SynthesizedMembers;
var synthesizedMembers = (baseline.Ordinal == 0) ? module.GetSynthesizedMembers() : baseline.SynthesizedMembers;
return baseline.With(
compilation,
moduleBuilder,
module,
baseline.Ordinal + 1,
encId,
typesAdded: AddRange(_previousGeneration.TypesAdded, _typeDefs.GetAdded()),
......@@ -177,10 +175,11 @@ internal EmitBaseline GetDelta(EmitBaseline baseline, Compilation compilation, G
userStringStreamLengthAdded: metadataSizes.GetAlignedHeapSize(HeapIndex.UserString) + _previousGeneration.UserStringStreamLengthAdded,
// Guid stream accumulates on the GUID heap unlike other heaps, so the previous generations are already included.
guidStreamLengthAdded: metadataSizes.HeapSizes[(int)HeapIndex.Guid],
anonymousTypeMap: ((IPEDeltaAssemblyBuilder)moduleBuilder).GetAnonymousTypeMap(),
anonymousTypeMap: ((IPEDeltaAssemblyBuilder)module).GetAnonymousTypeMap(),
synthesizedMembers: synthesizedMembers,
addedOrChangedMethods: AddRange(_previousGeneration.AddedOrChangedMethods, addedOrChangedMethodsByIndex, replace: true),
debugInformationProvider: baseline.DebugInformationProvider);
debugInformationProvider: baseline.DebugInformationProvider,
localSignatureProvider: baseline.LocalSignatureProvider);
}
private static IReadOnlyDictionary<K, V> AddRange<K, V>(IReadOnlyDictionary<K, V> previous, IReadOnlyDictionary<K, V> current, bool replace = false)
......
......@@ -89,8 +89,62 @@ public MetadataSymbols(IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue>
/// <param name="module">The metadata of the module before editing.</param>
/// <param name="debugInformationProvider">
/// A function that for a method handle returns Edit and Continue debug information emitted by the compiler into the PDB.
/// The function shall throw <see cref="System.IO.InvalidDataException"/> if the debug information can't be read for the specified method.
/// This exception is caught and converted to an emit diagnostic. Other exceptions are passed through.
/// The function shall throw <see cref="InvalidDataException"/> if the debug information can't be read for the specified method.
/// This exception and <see cref="IOException"/> are caught and converted to an emit diagnostic. Other exceptions are passed through.
/// </param>
/// <returns>An <see cref="EmitBaseline"/> for the module.</returns>
/// <exception cref="ArgumentException"><paramref name="module"/> is not a PE image.</exception>
/// <exception cref="ArgumentNullException"><paramref name="module"/> is null.</exception>
/// <exception cref="ArgumentNullException"><paramref name="debugInformationProvider"/> is null.</exception>
/// <exception cref="IOException">Error reading module metadata.</exception>
/// <exception cref="BadImageFormatException">Module metadata is invalid.</exception>
/// <exception cref="ObjectDisposedException">Module has been disposed.</exception>
public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation> debugInformationProvider)
{
if (module == null)
{
throw new ArgumentNullException(nameof(module));
}
if (!module.Module.HasIL)
{
throw new ArgumentException(CodeAnalysisResources.PEImageNotAvailable, nameof(module));
}
var hasPortablePdb = module.Module.PEReaderOpt.ReadDebugDirectory().Any(entry => entry.IsPortableCodeView);
var localSigProvider = new Func<MethodDefinitionHandle, StandaloneSignatureHandle>(methodHandle =>
{
try
{
return module.Module.GetMethodBodyOrThrow(methodHandle)?.LocalSignature ?? default;
}
catch (Exception e) when (e is BadImageFormatException || e is IOException)
{
throw new InvalidDataException(e.Message, e);
}
});
return CreateInitialBaseline(module, debugInformationProvider, localSigProvider, hasPortablePdb);
}
/// <summary>
/// Creates an <see cref="EmitBaseline"/> from the metadata of the module before editing
/// and from a function that maps from a method to an array of local names.
/// </summary>
/// <param name="module">The metadata of the module before editing.</param>
/// <param name="debugInformationProvider">
/// A function that for a method handle returns Edit and Continue debug information emitted by the compiler into the PDB.
/// The function shall throw <see cref="InvalidDataException"/> if the debug information can't be read for the specified method.
/// This exception and <see cref="IOException"/> are caught and converted to an emit diagnostic. Other exceptions are passed through.
/// </param>
/// <param name="localSignatureProvider">
/// A function that for a method handle returns the signature of its local variables.
/// The function shall throw <see cref="InvalidDataException"/> if the information can't be read for the specified method.
/// This exception and <see cref="IOException"/> are caught and converted to an emit diagnostic. Other exceptions are passed through.
/// </param>
/// <param name="hasPortableDebugInformation">
/// True if the baseline PDB is portable.
/// </param>
/// <returns>An <see cref="EmitBaseline"/> for the module.</returns>
/// <remarks>
......@@ -109,45 +163,44 @@ public MetadataSymbols(IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue>
/// The slot ordering thus no longer matches the syntax ordering. It is therefore necessary to pass <see cref="EmitDifferenceResult.Baseline"/>
/// to the next generation (rather than e.g. create new <see cref="EmitBaseline"/>s from scratch based on metadata produced by subsequent compilations).
/// </remarks>
/// <exception cref="ArgumentException"><paramref name="module"/> is not a PE image.</exception>
/// <exception cref="ArgumentNullException"><paramref name="module"/> is null.</exception>
/// <exception cref="ArgumentNullException"><paramref name="debugInformationProvider"/> is null.</exception>
/// <exception cref="ArgumentNullException"><paramref name="localSignatureProvider"/> is null.</exception>
/// <exception cref="IOException">Error reading module metadata.</exception>
/// <exception cref="BadImageFormatException">Module metadata is invalid.</exception>
/// <exception cref="ObjectDisposedException">Module has been disposed.</exception>
public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation> debugInformationProvider)
internal static EmitBaseline CreateInitialBaseline(
ModuleMetadata module,
Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation> debugInformationProvider,
Func<MethodDefinitionHandle, StandaloneSignatureHandle> localSignatureProvider,
bool hasPortableDebugInformation)
{
if (module == null)
{
throw new ArgumentNullException(nameof(module));
}
if (!module.Module.HasIL)
{
throw new ArgumentException(CodeAnalysisResources.PEImageNotAvailable, nameof(module));
}
if (debugInformationProvider == null)
{
throw new ArgumentNullException(nameof(debugInformationProvider));
}
// module has IL as checked above and hence a PE reader:
Debug.Assert(module.Module.PEReaderOpt != null);
if (localSignatureProvider == null)
{
throw new ArgumentNullException(nameof(localSignatureProvider));
}
var reader = module.MetadataReader;
var moduleVersionId = module.GetModuleVersionId();
var hasPortablePdb = module.Module.PEReaderOpt.ReadDebugDirectory().Any(entry => entry.IsPortableCodeView);
return new EmitBaseline(
null,
module,
compilation: null,
moduleBuilder: null,
moduleVersionId: moduleVersionId,
moduleVersionId: module.GetModuleVersionId(),
ordinal: 0,
encId: default(Guid),
hasPortablePdb: hasPortablePdb,
encId: default,
hasPortablePdb: hasPortableDebugInformation,
typesAdded: new Dictionary<Cci.ITypeDefinition, int>(),
eventsAdded: new Dictionary<Cci.IEventDefinition, int>(),
fieldsAdded: new Dictionary<Cci.IFieldDefinition, int>(),
......@@ -165,6 +218,7 @@ public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<Met
synthesizedMembers: ImmutableDictionary<Cci.ITypeDefinition, ImmutableArray<Cci.ITypeDefinitionMember>>.Empty,
methodsAddedOrChanged: new Dictionary<int, AddedOrChangedMethodInfo>(),
debugInformationProvider: debugInformationProvider,
localSignatureProvider: localSignatureProvider,
typeToEventMap: CalculateTypeEventMap(reader),
typeToPropertyMap: CalculateTypePropertyMap(reader),
methodImpls: CalculateMethodImpls(reader));
......@@ -220,11 +274,22 @@ public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<Met
/// <summary>
/// Reads EnC debug information of a method from the initial baseline PDB.
/// The function shall throw <see cref="System.IO.InvalidDataException"/> if the debug information can't be read for the specified method.
/// This exception is caught and converted to an emit diagnostic. Other exceptions are passed through.
/// The function shall throw <see cref="InvalidDataException"/> if the debug information can't be read for the specified method.
/// This exception and <see cref="IOException"/> are caught and converted to an emit diagnostic. Other exceptions are passed through.
/// The function shall return an empty <see cref="EditAndContinueMethodDebugInformation"/> if the method that corresponds to the specified handle
/// has no debug information.
/// </summary>
internal readonly Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation> DebugInformationProvider;
/// <summary>
/// A function that for a method handle returns the signature of its local variables.
/// The function shall throw <see cref="InvalidDataException"/> if the information can't be read for the specified method.
/// This exception and <see cref="IOException"/> are caught and converted to an emit diagnostic. Other exceptions are passed through.
/// The function shall return a nil <see cref="StandaloneSignatureHandle"/> if the method that corresponds to the specified handle
/// has no local variables.
/// </summary>
internal readonly Func<MethodDefinitionHandle, StandaloneSignatureHandle> LocalSignatureProvider;
internal readonly ImmutableArray<int> TableSizes;
internal readonly IReadOnlyDictionary<int, int> TypeToEventMap;
internal readonly IReadOnlyDictionary<int, int> TypeToPropertyMap;
......@@ -258,18 +323,20 @@ public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<Met
ImmutableDictionary<Cci.ITypeDefinition, ImmutableArray<Cci.ITypeDefinitionMember>> synthesizedMembers,
IReadOnlyDictionary<int, AddedOrChangedMethodInfo> methodsAddedOrChanged,
Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation> debugInformationProvider,
Func<MethodDefinitionHandle, StandaloneSignatureHandle> localSignatureProvider,
IReadOnlyDictionary<int, int> typeToEventMap,
IReadOnlyDictionary<int, int> typeToPropertyMap,
IReadOnlyDictionary<MethodImplKey, int> methodImpls)
{
Debug.Assert(module != null);
Debug.Assert((ordinal == 0) == (encId == default(Guid)));
Debug.Assert((ordinal == 0) == (encId == default));
Debug.Assert((ordinal == 0) == (initialBaseline == null));
Debug.Assert(encId != module.GetModuleVersionId());
Debug.Assert(debugInformationProvider != null);
Debug.Assert(localSignatureProvider != null);
Debug.Assert(typeToEventMap != null);
Debug.Assert(typeToPropertyMap != null);
Debug.Assert(moduleVersionId != default(Guid));
Debug.Assert(moduleVersionId != default);
Debug.Assert(moduleVersionId == module.GetModuleVersionId());
Debug.Assert(synthesizedMembers != null);
......@@ -289,37 +356,38 @@ public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<Met
var reader = module.Module.MetadataReader;
this.InitialBaseline = initialBaseline ?? this;
this.OriginalMetadata = module;
this.Compilation = compilation;
this.PEModuleBuilder = moduleBuilder;
this.ModuleVersionId = moduleVersionId;
this.Ordinal = ordinal;
this.EncId = encId;
this.HasPortablePdb = hasPortablePdb;
this.TypesAdded = typesAdded;
this.EventsAdded = eventsAdded;
this.FieldsAdded = fieldsAdded;
this.MethodsAdded = methodsAdded;
this.PropertiesAdded = propertiesAdded;
this.EventMapAdded = eventMapAdded;
this.PropertyMapAdded = propertyMapAdded;
this.MethodImplsAdded = methodImplsAdded;
this.TableEntriesAdded = tableEntriesAdded;
this.BlobStreamLengthAdded = blobStreamLengthAdded;
this.StringStreamLengthAdded = stringStreamLengthAdded;
this.UserStringStreamLengthAdded = userStringStreamLengthAdded;
this.GuidStreamLengthAdded = guidStreamLengthAdded;
InitialBaseline = initialBaseline ?? this;
OriginalMetadata = module;
Compilation = compilation;
PEModuleBuilder = moduleBuilder;
ModuleVersionId = moduleVersionId;
Ordinal = ordinal;
EncId = encId;
HasPortablePdb = hasPortablePdb;
TypesAdded = typesAdded;
EventsAdded = eventsAdded;
FieldsAdded = fieldsAdded;
MethodsAdded = methodsAdded;
PropertiesAdded = propertiesAdded;
EventMapAdded = eventMapAdded;
PropertyMapAdded = propertyMapAdded;
MethodImplsAdded = methodImplsAdded;
TableEntriesAdded = tableEntriesAdded;
BlobStreamLengthAdded = blobStreamLengthAdded;
StringStreamLengthAdded = stringStreamLengthAdded;
UserStringStreamLengthAdded = userStringStreamLengthAdded;
GuidStreamLengthAdded = guidStreamLengthAdded;
_anonymousTypeMap = anonymousTypeMap;
this.SynthesizedMembers = synthesizedMembers;
this.AddedOrChangedMethods = methodsAddedOrChanged;
this.DebugInformationProvider = debugInformationProvider;
this.TableSizes = CalculateTableSizes(reader, this.TableEntriesAdded);
this.TypeToEventMap = typeToEventMap;
this.TypeToPropertyMap = typeToPropertyMap;
this.MethodImpls = methodImpls;
SynthesizedMembers = synthesizedMembers;
AddedOrChangedMethods = methodsAddedOrChanged;
DebugInformationProvider = debugInformationProvider;
LocalSignatureProvider = localSignatureProvider;
TableSizes = CalculateTableSizes(reader, TableEntriesAdded);
TypeToEventMap = typeToEventMap;
TypeToPropertyMap = typeToPropertyMap;
MethodImpls = methodImpls;
}
internal EmitBaseline With(
......@@ -343,7 +411,8 @@ public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<Met
IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue> anonymousTypeMap,
ImmutableDictionary<Cci.ITypeDefinition, ImmutableArray<Cci.ITypeDefinitionMember>> synthesizedMembers,
IReadOnlyDictionary<int, AddedOrChangedMethodInfo> addedOrChangedMethods,
Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation> debugInformationProvider)
Func<MethodDefinitionHandle, EditAndContinueMethodDebugInformation> debugInformationProvider,
Func<MethodDefinitionHandle, StandaloneSignatureHandle> localSignatureProvider)
{
Debug.Assert(_anonymousTypeMap == null || anonymousTypeMap != null);
Debug.Assert(_anonymousTypeMap == null || anonymousTypeMap.Count >= _anonymousTypeMap.Count);
......@@ -374,6 +443,7 @@ public static EmitBaseline CreateInitialBaseline(ModuleMetadata module, Func<Met
synthesizedMembers: synthesizedMembers,
methodsAddedOrChanged: addedOrChangedMethods,
debugInformationProvider: debugInformationProvider,
localSignatureProvider: localSignatureProvider,
typeToEventMap: TypeToEventMap,
typeToPropertyMap: TypeToPropertyMap,
methodImpls: MethodImpls);
......
......@@ -43,10 +43,11 @@ internal abstract class SymbolMatcher
stringStreamLengthAdded: baseline.StringStreamLengthAdded,
userStringStreamLengthAdded: baseline.UserStringStreamLengthAdded,
guidStreamLengthAdded: baseline.GuidStreamLengthAdded,
anonymousTypeMap: this.MapAnonymousTypes(baseline.AnonymousTypeMap),
anonymousTypeMap: MapAnonymousTypes(baseline.AnonymousTypeMap),
synthesizedMembers: mappedSynthesizedMembers,
addedOrChangedMethods: this.MapAddedOrChangedMethods(baseline.AddedOrChangedMethods),
debugInformationProvider: baseline.DebugInformationProvider);
addedOrChangedMethods: MapAddedOrChangedMethods(baseline.AddedOrChangedMethods),
debugInformationProvider: baseline.DebugInformationProvider,
localSignatureProvider: baseline.LocalSignatureProvider);
}
private IReadOnlyDictionary<K, V> MapDefinitions<K, V>(IReadOnlyDictionary<K, V> items)
......
......@@ -9,24 +9,10 @@ namespace Roslyn.Utilities
internal static class ImmutableArrayExtensions
{
internal static ImmutableArray<T> ToImmutableArrayOrEmpty<T>(this IEnumerable<T> items)
{
if (items == null)
{
return ImmutableArray.Create<T>();
}
return ImmutableArray.CreateRange<T>(items);
}
=> items == null ? ImmutableArray<T>.Empty : ImmutableArray.CreateRange(items);
internal static ImmutableArray<T> ToImmutableArrayOrEmpty<T>(this ImmutableArray<T> items)
{
if (items.IsDefault)
{
return ImmutableArray.Create<T>();
}
return items;
}
=> items.IsDefault ? ImmutableArray<T>.Empty : items;
// same as Array.BinarySearch but the ability to pass arbitrary value to the comparer without allocation
internal static int BinarySearch<TElement, TValue>(this ImmutableArray<TElement> array, TValue value, Func<TElement, TValue, int> comparer)
......
......@@ -7,6 +7,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.PooledObjects;
namespace Roslyn.Utilities
{
......@@ -16,46 +17,45 @@ namespace Roslyn.Utilities
/// </summary>
internal sealed class SetWithInsertionOrder<T> : IEnumerable<T>, IReadOnlySet<T>
{
private HashSet<T> _set = new HashSet<T>();
private uint _nextElementValue = 0;
private T[] _elements = null;
private HashSet<T> _set = null;
private ArrayBuilder<T> _elements = null;
public bool Add(T value)
{
if (!_set.Add(value)) return false;
var thisValue = _nextElementValue++;
if (_elements == null)
if (_set == null)
{
_elements = new T[10];
_set = new HashSet<T>();
_elements = new ArrayBuilder<T>();
}
else if (_elements.Length <= thisValue)
if (!_set.Add(value))
{
Array.Resize(ref _elements, _elements.Length * 2);
return false;
}
_elements[thisValue] = value;
_elements.Add(value);
return true;
}
public bool Remove(T value)
{
if (!_set.Remove(value))
{
return false;
}
_elements.RemoveAt(_elements.IndexOf(value));
return true;
}
public int Count => (int)_nextElementValue;
public int Count => _elements?.Count ?? 0;
public bool Contains(T value) => _set.Contains(value);
public bool Contains(T value) => _set?.Contains(value) ?? false;
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _nextElementValue; i++) yield return _elements[i];
}
=> _elements?.GetEnumerator() ?? SpecializedCollections.EmptyEnumerator<T>();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// An enumerable that yields the set's elements in insertion order.
/// </summary>
public SetWithInsertionOrder<T> InInsertionOrder => this;
public ImmutableArray<T> AsImmutable()
{
return (_elements == null) ? ImmutableArray<T>.Empty : ImmutableArray.Create(_elements, 0, (int)_nextElementValue);
}
public ImmutableArray<T> AsImmutable() => _elements.ToImmutableArrayOrEmpty();
}
}
......@@ -1024,31 +1024,11 @@ private static ConstantValue DecodePrimitiveConstantValue(ref BlobReader sigRead
}
}
internal bool TryGetLocals(MethodDefinitionHandle handle, out ImmutableArray<LocalInfo<TypeSymbol>> localInfo)
internal ImmutableArray<LocalInfo<TypeSymbol>> GetLocalsOrThrow(StandaloneSignatureHandle handle)
{
try
{
Debug.Assert(Module.HasIL);
var methodBody = Module.GetMethodBodyOrThrow(handle);
if (!methodBody.LocalSignature.IsNil)
{
var signatureHandle = Module.MetadataReader.GetStandaloneSignature(methodBody.LocalSignature).Signature;
var signatureReader = Module.GetMemoryReaderOrThrow(signatureHandle);
localInfo = DecodeLocalSignatureOrThrow(ref signatureReader);
}
else
{
localInfo = ImmutableArray<LocalInfo<TypeSymbol>>.Empty;
}
}
catch (Exception e) when (e is UnsupportedSignatureContent || e is BadImageFormatException || e is IOException)
{
localInfo = ImmutableArray<LocalInfo<TypeSymbol>>.Empty;
return false;
}
return true;
var signatureHandle = Module.MetadataReader.GetStandaloneSignature(handle).Signature;
var signatureReader = Module.MetadataReader.GetBlobReader(signatureHandle);
return DecodeLocalSignatureOrThrow(ref signatureReader);
}
/// <summary>
......
......@@ -3028,7 +3028,7 @@ internal MethodBodyBlock GetMethodBodyOrThrow(MethodDefinitionHandle methodHandl
// we shouldn't ask for method IL if we don't have PE image
Debug.Assert(_peReaderOpt != null);
MethodDefinition method = this.MetadataReader.GetMethodDefinition(methodHandle);
MethodDefinition method = MetadataReader.GetMethodDefinition(methodHandle);
if ((method.ImplAttributes & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL ||
method.RelativeVirtualAddress == 0)
{
......
......@@ -168,14 +168,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
awaiterSlotCount = maxAwaiterSlotIndex + 1
End Sub
Protected Overrides Function TryGetLocalSlotMapFromMetadata(handle As MethodDefinitionHandle, debugInfo As EditAndContinueMethodDebugInformation) As ImmutableArray(Of EncLocalInfo)
Dim slotMetadata As ImmutableArray(Of LocalInfo(Of TypeSymbol)) = Nothing
If Not _metadataDecoder.TryGetLocals(handle, slotMetadata) Then
Return Nothing
End If
Protected Overrides Function GetLocalSlotMapFromMetadata(handle As StandaloneSignatureHandle, debugInfo As EditAndContinueMethodDebugInformation) As ImmutableArray(Of EncLocalInfo)
Debug.Assert(Not handle.IsNil)
Dim result = CreateLocalSlotMap(debugInfo, slotMetadata)
Debug.Assert(result.Length = slotMetadata.Length)
Dim localInfos = _metadataDecoder.GetLocalsOrThrow(handle)
Dim result = CreateLocalSlotMap(debugInfo, localInfos)
Debug.Assert(result.Length = localInfos.Length)
Return result
End Function
......
......@@ -1312,7 +1312,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
MakeDeclaredInterfacesInPart(syntaxRef.SyntaxTree, syntaxRef.GetVisualBasicSyntax(), interfaces, basesBeingResolved, diagnostics)
Next
Return interfaces.InInsertionOrder.AsImmutable
Return interfaces.AsImmutable
End Function
Private Function GetInheritsLocation(base As NamedTypeSymbol) As Location
......
......@@ -47,7 +47,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
languageVersion As LanguageVersion,
documentationMode As DocumentationMode,
kind As SourceCodeKind,
preprocessorSymbols As IEnumerable(Of KeyValuePair(Of String, Object)),
preprocessorSymbols As ImmutableArray(Of KeyValuePair(Of String, Object)),
features As ImmutableDictionary(Of String, String))
MyBase.New(kind, documentationMode)
......
......@@ -875,5 +875,453 @@ int M(int i)
}
}", ignoreTrivia: false);
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd1()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if (i == 1 && i == 2)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd2()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if (i == 1 && i == 2 && i == 3)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd3()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if (i == 1 && i == 2 && (i == 3))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && (i == 3): return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd4()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if (i == 1 && (i == 2) && i == 3)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when (i == 2) && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd5()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if (i == 1 && (i == 2) && (i == 3))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when (i == 2) && (i == 3): return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd6()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1) && i == 2 && i == 3)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd7()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1) && i == 2 && (i == 3))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && (i == 3): return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd8()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1) && (i == 2) && i == 3)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when (i == 2) && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd9()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1) && (i == 2) && (i == 3))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when (i == 2) && (i == 3): return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd10()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if (i == 1 && (i == 2 && i == 3))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd11()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1 && i == 2) && i == 3)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd12()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if (((i == 1) && i == 2) && i == 3)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd13()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1 && (i == 2)) && i == 3)
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when (i == 2) && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd14()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1 && (i == 2)) && (i == 3))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when (i == 2) && (i == 3): return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd15()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1) && ((i == 2) && i == 3))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when (i == 2) && i == 3: return;
case 10: return;
}
}
}");
}
[WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
public async Task TestCompoundLogicalAnd16()
{
await TestInRegularAndScriptAsync(
@"class C
{
void M(int i)
{
[||]if ((i == 1) && (i == 2 && (i == 3)))
return;
else if (i == 10)
return;
}
}",
@"class C
{
void M(int i)
{
switch (i)
{
case 1 when i == 2 && (i == 3): return;
case 10: return;
}
}
}");
}
}
}
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Debugging;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests;
using Microsoft.CodeAnalysis.Test.Utilities;
......@@ -416,7 +417,7 @@ public unsafe void ShouldTryAgain_Mixed()
}
else
{
Marshal.ThrowExceptionForHR(unchecked((int)MetadataUtilities.CORDBG_E_MISSING_METADATA));
Marshal.ThrowExceptionForHR(DkmExceptionUtilities.CORDBG_E_MISSING_METADATA);
throw ExceptionUtilities.Unreachable;
}
};
......@@ -443,7 +444,7 @@ public void ShouldTryAgain_CORDBG_E_MISSING_METADATA()
ShouldTryAgain_False(
(AssemblyIdentity assemblyIdentity, out uint uSize) =>
{
Marshal.ThrowExceptionForHR(unchecked((int)MetadataUtilities.CORDBG_E_MISSING_METADATA));
Marshal.ThrowExceptionForHR(DkmExceptionUtilities.CORDBG_E_MISSING_METADATA);
throw ExceptionUtilities.Unreachable;
});
}
......@@ -454,7 +455,7 @@ public void ShouldTryAgain_COR_E_BADIMAGEFORMAT()
ShouldTryAgain_False(
(AssemblyIdentity assemblyIdentity, out uint uSize) =>
{
Marshal.ThrowExceptionForHR(unchecked((int)MetadataUtilities.COR_E_BADIMAGEFORMAT));
Marshal.ThrowExceptionForHR(DkmExceptionUtilities.COR_E_BADIMAGEFORMAT);
throw ExceptionUtilities.Unreachable;
});
}
......
// 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 System;
namespace Microsoft.CodeAnalysis.Debugging
{
internal static partial class DkmExceptionUtilities
{
internal const int COR_E_BADIMAGEFORMAT = unchecked((int)0x8007000b);
internal const int CORDBG_E_MISSING_METADATA = unchecked((int)0x80131c35);
internal static bool IsBadOrMissingMetadataException(Exception e)
{
return e is ObjectDisposedException ||
e.HResult == COR_E_BADIMAGEFORMAT ||
e.HResult == CORDBG_E_MISSING_METADATA;
}
}
}
......@@ -7,6 +7,7 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.Debugging;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.VisualStudio.Debugger;
using Microsoft.VisualStudio.Debugger.Clr;
......@@ -66,7 +67,7 @@ private static IEnumerable<DkmClrModuleInstance> GetModulesInAppDomain(this DkmC
// DkmClrNcModuleInstance.GetMetaDataBytesPtr not implemented in Dev14.
throw new NotImplementedMetadataException(e);
}
catch (Exception e) when (MetadataUtilities.IsBadOrMissingMetadataException(e, module.FullName))
catch (Exception e) when (DkmExceptionUtilities.IsBadOrMissingMetadataException(e))
{
continue;
}
......@@ -94,7 +95,7 @@ internal static ImmutableArray<MetadataBlock> GetMetadataBlocks(GetMetadataBytes
Debug.Assert(size > 0);
block = GetMetadataBlock(ptr, size);
}
catch (Exception e) when (MetadataUtilities.IsBadOrMissingMetadataException(e, missingAssemblyIdentity.GetDisplayName()))
catch (Exception e) when (DkmExceptionUtilities.IsBadOrMissingMetadataException(e))
{
continue;
}
......@@ -128,7 +129,7 @@ internal static ImmutableArray<AssemblyReaders> MakeAssemblyReaders(this DkmClrI
Debug.Assert(size > 0);
reader = new MetadataReader((byte*)ptr, (int)size);
}
catch (Exception e) when (MetadataUtilities.IsBadOrMissingMetadataException(e, module.FullName))
catch (Exception e) when (DkmExceptionUtilities.IsBadOrMissingMetadataException(e))
{
continue;
}
......
......@@ -78,7 +78,7 @@ internal static partial class MetadataUtilities
metadataBuilder.Add(metadata);
}
}
catch (Exception e) when (IsBadMetadataException(e))
catch (BadImageFormatException)
{
// Ignore modules with "bad" metadata.
}
......@@ -281,7 +281,7 @@ private static PortableExecutableReference MakeAssemblyMetadata(ModuleMetadata m
}
}
}
catch (Exception e) when (IsBadMetadataException(e))
catch (BadImageFormatException)
{
// Ignore modules with "bad" metadata.
}
......
// 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 System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.Debugging;
using Microsoft.VisualStudio.Debugger;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.ComponentInterfaces;
using Microsoft.VisualStudio.Debugger.FunctionResolution;
using Microsoft.VisualStudio.Debugger.Symbols;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
......@@ -119,7 +120,7 @@ internal sealed override MetadataReader GetModuleMetadata(DkmClrModuleInstance m
{
ptr = module.GetMetaDataBytesPtr(out length);
}
catch (Exception e) when (MetadataUtilities.IsBadOrMissingMetadataException(e, module.FullName))
catch (Exception e) when (DkmExceptionUtilities.IsBadOrMissingMetadataException(e))
{
return null;
}
......
......@@ -34,8 +34,8 @@
<Compile Include="..\..\..\..\Compilers\CSharp\Portable\Syntax\SyntaxKindFacts.cs">
<Link>CSharp\Compiler\SyntaxKindFacts.cs</Link>
</Compile>
<Compile Include="..\ExpressionCompiler\MetadataUtilities_Exceptions.cs">
<Link>ExpressionCompiler\MetadataUtilities_Exceptions.cs</Link>
<Compile Include="..\ExpressionCompiler\DkmExceptionUtilities.cs">
<Link>ExpressionCompiler\DkmExceptionUtilities.cs</Link>
</Compile>
<VsdConfigXml Include="CSharp\FunctionResolver.vsdconfigxml" />
<VsdConfigXml Include="VisualBasic\FunctionResolver.vsdconfigxml" />
......
......@@ -21,10 +21,6 @@
<ExtensionInstallationFolder>Microsoft\ManagedLanguages\VBCSharp\ExpressionEvaluators</ExtensionInstallationFolder>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\..\VisualStudio\Core\Impl\ServicesVisualStudioImpl.csproj">
<Name>ServicesVisualStudioImpl</Name>
<Private>false</Private>
</ProjectReference>
<ProjectReference Include="..\..\VisualStudio\Setup\VisualStudioSetup.csproj">
<Name>VisualStudioSetup</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
......@@ -104,10 +100,14 @@
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Shell.Framework" Version="$(MicrosoftVisualStudioShellFrameworkVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="$(MicrosoftVisualStudioShell150Version)" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\VisualStudio\Setup\ProvideRoslynBindingRedirection.cs">
<Link>ProvideRoslynBindingRedirection.cs</Link>
</Compile>
</ItemGroup>
<Import Project="..\..\..\build\Targets\Imports.targets" />
</Project>
\ No newline at end of file
</Project>
......@@ -120,8 +120,10 @@ protected override IPattern<CasePatternSwitchLabelSyntax> CreatePatternFromExpre
// separate out the leftmost expression and reconstruct the rest of conditions into a new
// expression, so that they would be evaluated entirely after "expr" e.g. "expr && (cond1 && cond2)".
// Afterwards, we can directly use it in a case guard e.g. "case pat when cond1 && cond2:".
var condition = (leftmost.Parent.Parent as BinaryExpressionSyntax)
?.WithLeft(((BinaryExpressionSyntax)leftmost.Parent).Right);
var parentBinary = (BinaryExpressionSyntax)leftmost.WalkUpParentheses().Parent;
var grandparentBinary = parentBinary.WalkUpParentheses().Parent as BinaryExpressionSyntax;
var condition = grandparentBinary?.WithLeft(parentBinary.Right);
return new Pattern.Guarded(pattern, (condition ?? node.Right).WalkDownParentheses());
}
......
// 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 System;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.Text;
......@@ -13,7 +11,7 @@ internal sealed class CSharpScriptCompiler : ScriptCompiler
{
public static readonly ScriptCompiler Instance = new CSharpScriptCompiler();
private static readonly CSharpParseOptions s_defaultOptions = new CSharpParseOptions(kind: SourceCodeKind.Script);
private static readonly CSharpParseOptions s_defaultOptions = new CSharpParseOptions(kind: SourceCodeKind.Script, languageVersion: LanguageVersion.Latest);
private CSharpScriptCompiler()
{
......
......@@ -947,5 +947,48 @@ public void PreservingDeclarationsOnException()
Bang!",
runner.Console.Error.ToString());
}
[Fact]
[WorkItem(21327, "https://github.com/dotnet/roslyn/issues/21327")]
public void DefaultLiteral()
{
var runner = CreateRunner(input:
@"int i = default;
Print(i);
");
runner.RunInteractive();
AssertEx.AssertEqualToleratingWhitespaceDifferences(
$@"Microsoft (R) Visual C# Interactive Compiler version {s_compilerVersion}
Copyright (C) Microsoft Corporation. All rights reserved.
Type ""#help"" for more information.
> int i = default;
> Print(i);
0
> ", runner.Console.Out.ToString());
}
[Fact]
[WorkItem(21327, "https://github.com/dotnet/roslyn/issues/21327")]
public void InferredTupleNames()
{
var runner = CreateRunner(input:
@"var a = 1;
var t = (a, 2);
Print(t.a);
");
runner.RunInteractive();
AssertEx.AssertEqualToleratingWhitespaceDifferences(
$@"Microsoft (R) Visual C# Interactive Compiler version {s_compilerVersion}
Copyright (C) Microsoft Corporation. All rights reserved.
Type ""#help"" for more information.
> var a = 1;
> var t = (a, 2);
> Print(t.a);
1
> ", runner.Console.Out.ToString());
}
}
}
......@@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting
Public Shared ReadOnly Instance As ScriptCompiler = New VisualBasicScriptCompiler()
Private Shared ReadOnly s_defaultOptions As VisualBasicParseOptions = New VisualBasicParseOptions(kind:=SourceCodeKind.Script)
Private Shared ReadOnly s_defaultOptions As VisualBasicParseOptions = New VisualBasicParseOptions(kind:=SourceCodeKind.Script, languageVersion:=LanguageVersion.Latest)
Private Shared ReadOnly s_vbRuntimeReference As MetadataReference = MetadataReference.CreateFromAssemblyInternal(GetType(CompilerServices.NewLateBinding).GetTypeInfo().Assembly)
Private Sub New()
......
......@@ -29,8 +29,7 @@ private enum Size
private readonly Encoding _encoding = Encoding.UTF8;
internal readonly IOptionService _persistentEnabledOptionService = new OptionServiceMock(new Dictionary<IOption, object>
{
{ PersistentStorageOptions.Enabled, true },
{ PersistentStorageOptions.EsentPerformanceMonitor, false }
{ PersistentStorageOptions.Enabled, true }
});
private readonly string _persistentFolder;
......@@ -388,13 +387,13 @@ protected Solution CreateOrOpenSolution(bool nullPaths = false)
{
var projectFile = Path.Combine(Path.GetDirectoryName(solutionFile), "Project1.csproj");
File.WriteAllText(projectFile, "");
solution = solution.AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "Project1", "Project1", LanguageNames.CSharp,
solution = solution.AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "Project1", "Project1", LanguageNames.CSharp,
filePath: nullPaths ? null : projectFile));
var project = solution.Projects.Single();
var documentFile = Path.Combine(Path.GetDirectoryName(projectFile), "Document1.cs");
File.WriteAllText(documentFile, "");
solution = solution.AddDocument(DocumentInfo.Create(DocumentId.CreateNewId(project.Id), "Document1",
solution = solution.AddDocument(DocumentInfo.Create(DocumentId.CreateNewId(project.Id), "Document1",
filePath: nullPaths ? null : documentFile));
}
......
......@@ -9,7 +9,5 @@ internal static class PersistentStorageOptions
public const string OptionName = "FeatureManager/Persistence";
public static readonly Option<bool> Enabled = new Option<bool>(OptionName, "Enabled", defaultValue: true);
public static readonly Option<bool> EsentPerformanceMonitor = new Option<bool>(OptionName, "Esent PerfMon", defaultValue: false);
}
}
......@@ -40,6 +40,13 @@ public static void Report(Exception exception)
/// <param name="exception">Exception that triggered this non-fatal error</param>
public static void Report(string description, Exception exception)
{
// if given exception is non recoverable exception,
// crash instead of NFW
if (IsNonRecoverableException(exception))
{
CodeAnalysis.FailFast.OnFatalException(exception);
}
SessionOpt?.PostFault(
eventName: FunctionId.NonFatalWatson.GetEventName(),
description: description,
......@@ -53,5 +60,10 @@ public static void Report(string description, Exception exception)
return 0;
});
}
private static bool IsNonRecoverableException(Exception exception)
{
return exception is OutOfMemoryException;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册