提交 817ce379 编写于 作者: N Neal Gafter

Move cyclic variable inference detection to a syntactic check.

Fixes #12883
上级 7af530db
......@@ -290,14 +290,6 @@ internal virtual TypeSymbol GetIteratorElementType(YieldStatementSyntax node, Di
return Next.GetIteratorElementType(node, diagnostics);
}
public virtual ConsList<LocalSymbol> ImplicitlyTypedLocalsBeingBound
{
get
{
return _next.ImplicitlyTypedLocalsBeingBound;
}
}
/// <summary>
/// The imports for all containing namespace declarations (innermost-to-outermost, including global),
/// or null if there are none.
......
......@@ -1192,18 +1192,6 @@ private BoundExpression SynthesizeMethodGroupReceiver(CSharpSyntaxNode syntax, A
}
}
private bool IsBindingImplicitlyTypedLocal(LocalSymbol symbol)
{
foreach (LocalSymbol s in this.ImplicitlyTypedLocalsBeingBound)
{
if (s == symbol)
{
return true;
}
}
return false;
}
private bool IsBadLocalOrParameterCapture(Symbol symbol, RefKind refKind)
{
if (refKind != RefKind.None)
......@@ -1235,20 +1223,30 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
case SymbolKind.Local:
{
var localSymbol = (LocalSymbol)symbol;
var constantValueOpt = localSymbol.IsConst && this.EnclosingNameofArgument == null
? localSymbol.GetConstantValue(node, this.LocalInProgress, diagnostics) : null;
TypeSymbol type;
Location localSymbolLocation = localSymbol.Locations[0];
bool usedBeforeDecl =
node.SyntaxTree == localSymbolLocation.SourceTree &&
node.SpanStart < localSymbolLocation.SourceSpan.Start;
bool isBindingVar = IsBindingImplicitlyTypedLocal(localSymbol);
if (usedBeforeDecl || isBindingVar)
TypeSymbol type;
if ((localSymbol as SourceLocalSymbol)?.IsVar == true && localSymbol.ForbiddenZone?.Contains(node) == true)
{
// A var (type-inferred) local variable has been used in its own initialization (the "forbidden zone").
// There are many cases where this occurs, including:
//
// 1. var x = M(out x);
// 2. M(out var x, out x);
// 3. var (x, y) = (y, x);
//
// localSymbol.ForbiddenDiagnostic provides a suitable diagnostic for whichever case applies.
//
diagnostics.Add(localSymbol.ForbiddenDiagnostic, node.Location, node);
type = new ExtendedErrorTypeSymbol(
this.Compilation, name: "var", arity: 0, errorInfo: null, variableUsedBeforeDeclaration: true);
}
else if (node.SyntaxTree == localSymbolLocation.SourceTree &&
node.SpanStart < localSymbolLocation.SourceSpan.Start)
{
// Here we check for errors
// Here we report a local variable being used before its declaration
//
// There are two possible diagnostics for this:
//
// CS0841: ERR_VariableUsedBeforeDeclaration
// Cannot use local variable 'x' before it is declared
......@@ -1278,54 +1276,22 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
// bind to "this.x" in the "Print". (In C++ the local does not come
// into scope until its declaration.)
//
// The second case is when an implicitly typed local is used
// in its initializer, like "var x = N(out x);". Since overload
// resolution cannot proceed until the type of x is known, this is
// an error.
//
// CONSIDER:
// In the case of something like "var x = M(out x);" we give the error
// that x cannot be used before it is *declared*. But that seems like
// the wrong error; we didn't say "x = M(out x); int x;" -- the usage
// happened after the declaration. Should we give a better error?
//
// In the native compiler we give the "hides field" error even
// in this case:
//
// class C {
// int x;
// void M() {
// var x = N(out x);
// } }
//
// but that seems like the wrong error to give in this scenario. The "out x" is not
// "hiding the field" the same way the "Print(x);" is in the previous example. In
// Roslyn we do not report that error in this scenario; we only report that
// the offending usage is possibly hiding a field if it really is lexically
// before the declaration.
FieldSymbol possibleField = null;
if (usedBeforeDecl)
{
var lookupResult = LookupResult.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupMembersInType(
lookupResult,
ContainingType,
localSymbol.Name,
arity: 0,
basesBeingResolved: null,
options: LookupOptions.Default,
originalBinder: this,
diagnose: false,
useSiteDiagnostics: ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
possibleField = lookupResult.SingleSymbolOrDefault as FieldSymbol;
lookupResult.Free();
}
var lookupResult = LookupResult.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.LookupMembersInType(
lookupResult,
ContainingType,
localSymbol.Name,
arity: 0,
basesBeingResolved: null,
options: LookupOptions.Default,
originalBinder: this,
diagnose: false,
useSiteDiagnostics: ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
possibleField = lookupResult.SingleSymbolOrDefault as FieldSymbol;
lookupResult.Free();
if ((object)possibleField != null)
{
Error(diagnostics, ErrorCode.ERR_VariableUsedBeforeDeclarationAndHidesField, node, node, possibleField);
......@@ -1335,67 +1301,20 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
Error(diagnostics, ErrorCode.ERR_VariableUsedBeforeDeclaration, node, node);
}
// Moreover: we wish to avoid any deadlocks, unbounded recursion or
// race conditions that might result from a situation like:
//
// var x = M(y);
// var y = x;
//
// We therefore say that if an illegal forward reference is made
// to a local variable then we do not attempt to determine its
// type for the purposes of error recovery; we only look
// backwards. In the case above, the analysis of "= M(y)" will not
// attempt to determine the type of y, but the analysis of "= x"
// will attempt to determine the type of x.
//
// CONSIDER:
// We could interrogate the local symbol and only skip checking its
// type if it is "var".
type = new ExtendedErrorTypeSymbol(this.Compilation, name: "var", arity: 0, errorInfo: null, variableUsedBeforeDeclaration: true);
type = new ExtendedErrorTypeSymbol(
this.Compilation, name: "var", arity: 0, errorInfo: null, variableUsedBeforeDeclaration: true);
}
else
{
SourceLocalSymbol sourceLocal;
DeclarationExpressionSyntax declExpression;
ArgumentSyntax argument;
type = null;
if (node.SyntaxTree == localSymbolLocation.SourceTree &&
(object)(sourceLocal = localSymbol as SourceLocalSymbol) != null &&
(declExpression = sourceLocal.IdentifierToken.Parent?.Parent?.Parent as DeclarationExpressionSyntax) != null &&
(argument = declExpression.Parent as ArgumentSyntax) != null)
{
if (declExpression.Type().IsVar)
{
// We are referring to an out variable which might need type inference.
// If it is in fact needs inference, it is illegal to reference it in the same argument list that immediately
// contains its declaration.
// Technically, we could support some restricted scenarios (when it is used as another argument in the same list),
// but their utility is very questionable. Otherwise, we are looking into getting into a cycle trying to infer its type.
if (node.SpanStart < ((ArgumentListSyntax)argument.Parent).CloseParenToken.SpanStart &&
sourceLocal.IsVar) // This check involves trying to bind 'var' as a real type, so keeping it last for performance.
{
Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList, node, node);
// Treat this case as variable used before declaration, we might be able to infer type of the variable anyway and SemanticModel
// will be able to return non-error type information for this node.
type = new ExtendedErrorTypeSymbol(this.Compilation, name: "var", arity: 0, errorInfo: null, variableUsedBeforeDeclaration: true);
}
}
}
if ((object)type == null)
{
type = localSymbol.Type;
}
type = localSymbol.Type;
if (IsBadLocalOrParameterCapture(localSymbol, localSymbol.RefKind))
{
Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUseLocal, node, localSymbol);
}
}
var constantValueOpt = localSymbol.IsConst && this.EnclosingNameofArgument == null && !type.IsErrorType()
? localSymbol.GetConstantValue(node, this.LocalInProgress, diagnostics) : null;
return new BoundLocal(node, localSymbol, constantValueOpt, type, hasErrors: isError);
}
......
......@@ -817,8 +817,7 @@ private TypeSymbol BindVariableType(CSharpSyntaxNode declarationNode, Diagnostic
{
aliasOpt = null;
var binder = new ImplicitlyTypedLocalBinder(this, localSymbol);
initializerOpt = binder.BindInferredVariableInitializer(diagnostics, value, valueKind, declarator);
initializerOpt = BindInferredVariableInitializer(diagnostics, value, valueKind, declarator);
// If we got a good result then swap the inferred type for the "var"
if ((object)initializerOpt?.Type != null)
......
......@@ -19,14 +19,6 @@ internal BuckStopsHereBinder(CSharpCompilation compilation)
{
}
public override ConsList<LocalSymbol> ImplicitlyTypedLocalsBeingBound
{
get
{
return ConsList<LocalSymbol>.Empty;
}
}
internal override ImportChain ImportChain
{
get
......
// 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.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
/// <summary>
/// This binder is for binding the initializer of an implicitly typed
/// local variable. While binding an implicitly typed local variable
/// it is illegal to refer to the variable.
/// </summary>
internal sealed class ImplicitlyTypedLocalBinder : Binder
{
//
// This is legal:
//
// int x = M(out x);
//
// because x is known to be int, so overload resolution on M can work,
// and x is assigned before it is read. This is not legal:
//
// var x = M(out x);
//
// We cannot know the type of x until overload resolution determines the
// meaning of M, but that requires knowing the type of x.
//
// In certain scenarios we might find ourselves in loops, like
//
// var x = y;
// var y = M(x);
//
// We break the cycle by ensuring that a var initializer which illegally refers
// forwards to an in-scope local does not attempt to work out the type of the
// forward local. However, just to make sure, we also keep track of every
// local whose type we are attempting to infer. (This might be necessary for
// "script class" scenarios where local vars are actually fields.)
private readonly ConsList<LocalSymbol> _symbols;
public ImplicitlyTypedLocalBinder(Binder next, LocalSymbol symbol)
: base(next)
{
_symbols = new ConsList<LocalSymbol>(symbol, next.ImplicitlyTypedLocalsBeingBound);
}
public override ConsList<LocalSymbol> ImplicitlyTypedLocalsBeingBound
{
get
{
return _symbols;
}
}
internal override LocalSymbol LocalInProgress
{
get
{
return _symbols.Head;
}
}
}
}
......@@ -109,7 +109,6 @@
<Compile Include="Binder\ForLoopBinder.cs" />
<Compile Include="Binder\HostObjectModeBinder.cs" />
<Compile Include="Binder\ImplicitlyTypedFieldBinder.cs" />
<Compile Include="Binder\ImplicitlyTypedLocalBinder.cs" />
<Compile Include="Binder\ImportChain.cs" />
<Compile Include="Binder\Imports.cs" />
<Compile Include="Binder\InContainerBinder.cs" />
......
......@@ -340,6 +340,19 @@ internal virtual bool IsReturnable
}
}
/// <summary>
/// When a local variable's type is inferred, it may not be used in the
/// expression that computes its value (and type). This property returns
/// the expression where a reference to an inferred variable is forbidden.
/// </summary>
internal virtual SyntaxNode ForbiddenZone => null;
/// <summary>
/// The diagnostic code to be reported when an inferred variable is used
/// in its forbidden zone.
/// </summary>
internal virtual ErrorCode ForbiddenDiagnostic => ErrorCode.ERR_VariableUsedBeforeDeclaration;
#region ILocalSymbol Members
ITypeSymbol ILocalSymbol.Type
......
......@@ -116,9 +116,13 @@ internal Binder Binder
DeclarationExpressionSyntax declarationExpression;
if (identifierToken.IsIdentifierOfOutVariableDeclaration(out declarationExpression))
{
if (declarationExpression.Type().IsVar)
if (typeSyntax.IsVar)
{
return new PossiblyImplicitlyTypedOutVarLocalSymbol(containingSymbol, binder, typeSyntax, identifierToken, declarationKind);
var invocation = declarationExpression
.Parent // ArgumentSyntax
.Parent // ArgumentListSyntax
.Parent; // invocation of some kind
return new PossiblyImplicitlyTypedOutVarLocalSymbol(containingSymbol, binder, typeSyntax, identifierToken, declarationKind, invocation);
}
}
......@@ -478,16 +482,13 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
Debug.Assert(parentBinder != null);
#endif
var newBinder = new ImplicitlyTypedLocalBinder(initializerBinder ?? this.binder, this);
var newBinder = initializerBinder ?? this.binder;
var initializerOpt = newBinder.BindInferredVariableInitializer(diagnostics, RefKind, _initializer, _initializer);
if (initializerOpt != null)
{
return initializerOpt.Type;
}
return null;
return initializerOpt?.Type;
}
internal override SyntaxNode ForbiddenZone => _initializer;
/// <summary>
/// Determine the constant value of this local and the corresponding diagnostics.
/// Set both to constantTuple in a single operation for thread safety.
......@@ -575,6 +576,8 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
// in the factory method call for this symbol.
return ((ForEachLoopBinder)this.binder).InferCollectionElementType(diagnostics, _collection);
}
internal override SyntaxNode ForbiddenZone => _collection;
}
/// <summary>
......@@ -582,12 +585,15 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
/// </summary>
private class PossiblyImplicitlyTypedOutVarLocalSymbol : SourceLocalSymbol
{
private readonly CSharpSyntaxNode _containingInvocation;
public PossiblyImplicitlyTypedOutVarLocalSymbol(
Symbol containingSymbol,
Binder binder,
TypeSyntax typeSyntax,
SyntaxToken identifierToken,
LocalDeclarationKind declarationKind)
LocalDeclarationKind declarationKind,
CSharpSyntaxNode containingInvocation)
: base(containingSymbol, binder, true, typeSyntax, identifierToken, declarationKind)
{
#if DEBUG
......@@ -597,40 +603,35 @@ private class PossiblyImplicitlyTypedOutVarLocalSymbol : SourceLocalSymbol
binder.ScopeDesignator == declarationExpression.Parent.Parent :
binder.ScopeDesignator.Contains(declarationExpression.Parent.Parent.Parent));
#endif
_containingInvocation = containingInvocation;
}
internal override SyntaxNode ForbiddenZone => _containingInvocation;
internal override ErrorCode ForbiddenDiagnostic => ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList;
protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
{
// Try binding immediately enclosing invocation expression, this should force the inference.
CSharpSyntaxNode invocation = (CSharpSyntaxNode)IdentifierToken.
Parent. // SingleVariableDesignationSyntax
Parent. // TypedVariableComponentSyntax
Parent. // DeclarationExpressionSyntax
Parent. // ArgumentSyntax
Parent. // ArgumentListSyntax
Parent; // invocation/constructor initializer
TypeSymbol result;
switch (invocation.Kind())
switch (_containingInvocation.Kind())
{
case SyntaxKind.InvocationExpression:
case SyntaxKind.ObjectCreationExpression:
this.binder.BindExpression((ExpressionSyntax)invocation, diagnostics);
this.binder.BindExpression((ExpressionSyntax)_containingInvocation, diagnostics);
result = this._type;
Debug.Assert((object)result != null);
return result;
case SyntaxKind.ThisConstructorInitializer:
case SyntaxKind.BaseConstructorInitializer:
this.binder.BindConstructorInitializer(((ConstructorInitializerSyntax)invocation).ArgumentList, (MethodSymbol)this.binder.ContainingMember(), diagnostics);
this.binder.BindConstructorInitializer(((ConstructorInitializerSyntax)_containingInvocation).ArgumentList, (MethodSymbol)this.binder.ContainingMember(), diagnostics);
result = this._type;
Debug.Assert((object)result != null);
return result;
default:
throw ExceptionUtilities.UnexpectedValue(invocation.Kind());
throw ExceptionUtilities.UnexpectedValue(_containingInvocation.Kind());
}
}
}
......@@ -669,15 +670,13 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
case SyntaxKind.DeconstructionDeclarationStatement:
var localDecl = (DeconstructionDeclarationStatementSyntax)statement;
var localBinder = this.binder.GetBinder(localDecl);
var newLocalBinder = new ImplicitlyTypedLocalBinder(localBinder, this);
newLocalBinder.BindDeconstructionDeclaration(localDecl, localDecl.Assignment.VariableComponent, localDecl.Assignment.Value, diagnostics);
localBinder.BindDeconstructionDeclaration(localDecl, localDecl.Assignment.VariableComponent, localDecl.Assignment.Value, diagnostics);
break;
case SyntaxKind.ForStatement:
var forStatement = (ForStatementSyntax)statement;
var forBinder = this.binder.GetBinder(forStatement);
var newForBinder = new ImplicitlyTypedLocalBinder(forBinder, this);
newForBinder.BindDeconstructionDeclaration(forStatement, forStatement.Deconstruction.VariableComponent, forStatement.Deconstruction.Value, diagnostics);
forBinder.BindDeconstructionDeclaration(forStatement, forStatement.Deconstruction.VariableComponent, forStatement.Deconstruction.Value, diagnostics);
break;
case SyntaxKind.ForEachComponentStatement:
......@@ -693,6 +692,33 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
Debug.Assert((object)result != null);
return result;
}
internal override SyntaxNode ForbiddenZone
{
get
{
SyntaxNode statement;
bool isDeconstruction = SyntaxFacts.IsDeconstructionIdentifier(IdentifierToken, out statement);
Debug.Assert(isDeconstruction);
switch (statement.Kind())
{
case SyntaxKind.DeconstructionDeclarationStatement:
var localDecl = (DeconstructionDeclarationStatementSyntax)statement;
return localDecl.Assignment.Value;
case SyntaxKind.ForStatement:
var forStatement = (ForStatementSyntax)statement;
return forStatement.Deconstruction;
case SyntaxKind.ForEachComponentStatement:
var forEachStatement = (ForEachComponentStatementSyntax)statement;
return forEachStatement.Expression;
default:
throw ExceptionUtilities.UnexpectedValue(statement.Kind());
}
}
}
}
}
}
......@@ -1956,9 +1956,6 @@ void M()
// (11,15): error CS0822: Implicitly-typed variables cannot be constant
// const var E = E.A;
Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, "var E = E.A").WithLocation(11, 15),
// (11,23): error CS0110: The evaluation of the constant value for 'E' involves a circular definition
// const var E = E.A;
Diagnostic(ErrorCode.ERR_CircConstValue, "E").WithArguments("E").WithLocation(11, 23),
// (11,23): error CS0841: Cannot use local variable 'E' before it is declared
// const var E = E.A;
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "E").WithArguments("E").WithLocation(11, 23)
......
......@@ -1639,6 +1639,9 @@ static void Main()
var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (6,28): error CS0841: Cannot use local variable 'x1' before it is declared
// var (x1, x2) = (1, x1);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x1").WithArguments("x1").WithLocation(6, 28),
// (6,28): error CS0165: Use of unassigned local variable 'x1'
// var (x1, x2) = (1, x1);
Diagnostic(ErrorCode.ERR_UseDefViolation, "x1").WithArguments("x1").WithLocation(6, 28)
......@@ -1659,6 +1662,9 @@ static void Main()
";
var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (6,25): error CS0841: Cannot use local variable 'x2' before it is declared
// var (x1, x2) = (x2, 2);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x2").WithArguments("x2").WithLocation(6, 25),
// (6,25): error CS0165: Use of unassigned local variable 'x2'
// var (x1, x2) = (x2, 2);
Diagnostic(ErrorCode.ERR_UseDefViolation, "x2").WithArguments("x2").WithLocation(6, 25)
......@@ -1910,6 +1916,9 @@ static void Main()
var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (6,33): error CS0841: Cannot use local variable 'x1' before it is declared
// for (var (x1, x2) = (1, x1); ; ) { }
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x1").WithArguments("x1").WithLocation(6, 33),
// (6,33): error CS0165: Use of unassigned local variable 'x1'
// for (var (x1, x2) = (1, x1); ; ) { }
Diagnostic(ErrorCode.ERR_UseDefViolation, "x1").WithArguments("x1").WithLocation(6, 33)
......@@ -1930,6 +1939,9 @@ static void Main()
";
var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (6,30): error CS0841: Cannot use local variable 'x2' before it is declared
// for (var (x1, x2) = (x2, 2); ; ) { }
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x2").WithArguments("x2").WithLocation(6, 30),
// (6,30): error CS0165: Use of unassigned local variable 'x2'
// for (var (x1, x2) = (x2, 2); ; ) { }
Diagnostic(ErrorCode.ERR_UseDefViolation, "x2").WithArguments("x2").WithLocation(6, 30)
......@@ -2186,5 +2198,29 @@ static void Main()
var verifier = CompileAndVerify(source, additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator);
verifier.VerifyDiagnostics();
}
[Fact]
public void DeclarationWithCircularity3()
{
string source = @"
class C
{
static void Main()
{
var (x1, x2) = (M(out x2), M(out x1));
}
static T M<T>(out T x) { x = default(T); return x; }
}
";
var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (6,31): error CS0841: Cannot use local variable 'x2' before it is declared
// var (x1, x2) = (M(out x2), M(out x1));
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x2").WithArguments("x2").WithLocation(6, 31),
// (6,42): error CS0841: Cannot use local variable 'x1' before it is declared
// var (x1, x2) = (M(out x2), M(out x1));
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x1").WithArguments("x1").WithLocation(6, 42)
);
}
}
}
......@@ -7,7 +7,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class SyntaxBinderTests : CompilingTestBase
public partial class ImplicitlyTypedLocalTests : CompilingTestBase
{
[Fact]
public void ConstVarField1()
......
......@@ -11,7 +11,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class SyntaxBinderTests : CompilingTestBase
public partial class NullableConversionTests : CompilingTestBase
{
[Fact, WorkItem(544450, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544450")]
public void TestBug12780()
......
......@@ -8,7 +8,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class SyntaxBinderTests : CompilingTestBase
public partial class SemanticAnlyzerTests : CompilingTestBase
{
[Fact]
public void TestMethodGroupConversionError()
......
......@@ -7,7 +7,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public partial class SyntaxBinderTests : CompilingTestBase
public partial class UserDefinedConversionTests : CompilingTestBase
{
#region "Source"
private readonly string _userDefinedConversionTestTemplate = @"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册