提交 38e9fdfb 编写于 作者: N Neal Gafter

Enable out variables in indexers, and implement lazy inference of pattern variables.

Also eliminates some cases of cascaded definite assignment errors.
Fixes #13219
Fixes #13009
Fixes #12996
Fixes #10446
上级 0ccb2f89
......@@ -1242,22 +1242,7 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
Location localSymbolLocation = localSymbol.Locations[0];
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 &&
if (node.SyntaxTree == localSymbolLocation.SourceTree &&
node.SpanStart < localSymbolLocation.SourceSpan.Start)
{
// Here we report a local variable being used before its declaration
......@@ -1320,6 +1305,21 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag
type = new ExtendedErrorTypeSymbol(
this.Compilation, name: "var", arity: 0, errorInfo: null, variableUsedBeforeDeclaration: true);
}
else 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
{
type = localSymbol.Type;
......@@ -6060,6 +6060,11 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no
{
Debug.Assert(index != null);
if (index.Kind == BoundKind.OutVarLocalPendingInference)
{
return ((OutVarLocalPendingInference)index).FailInference(this, diagnostics);
}
var result =
TryImplicitConversionToArrayIndex(index, SpecialType.System_Int32, node, diagnostics) ??
TryImplicitConversionToArrayIndex(index, SpecialType.System_UInt32, node, diagnostics) ??
......
......@@ -250,7 +250,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
if (declType == (object)null)
{
Debug.Assert(hasErrors);
declType = this.CreateErrorType();
declType = this.CreateErrorType("var");
}
var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType);
......@@ -279,10 +279,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
LocalDeclarationKind.PatternVariable);
}
if (isVar)
{
localSymbol.SetTypeSymbol(operandType);
}
localSymbol.SetType(declType);
// Check for variable declaration errors.
hasErrors |= localSymbol.Binder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
......@@ -296,7 +293,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
hasErrors = true;
}
DeclareLocalVariable(localSymbol, identifier, declType);
localSymbol.SetType(declType);
return new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors);
}
}
......
......@@ -917,12 +917,7 @@ private TypeSymbol BindVariableType(CSharpSyntaxNode declarationNode, Diagnostic
hasErrors = true;
}
Debug.Assert((object)localSymbol != null);
DeclareLocalVariable(
localSymbol,
declarator.Identifier,
declTypeOpt);
localSymbol.SetType(declTypeOpt);
if (localSymbol.RefKind != RefKind.None && initializerOpt != null)
{
......@@ -2295,24 +2290,6 @@ private TypeSymbol GetAccessThroughType(BoundExpression receiver)
return BindUnexpectedArrayInitializer((InitializerExpressionSyntax)node, diagnostics, ErrorCode.ERR_ArrayInitToNonArrayType);
}
internal static void DeclareLocalVariable(
SourceLocalSymbol symbol,
SyntaxToken identifierToken,
TypeSymbol type)
{
// In the original compiler this
// method has many side effects; it sets the type
// of the local symbol, it gives errors if the local
// is a duplicate, it creates new symbols for lambda
// expressions, puts stuff in caches, and so on.
Debug.Assert((object)symbol != null);
Debug.Assert(symbol.IdentifierToken == identifierToken);
symbol.SetTypeSymbol(type);
// UNDONE: Can we come up with a way to set the type of a local which does
// UNDONE: not duplicate work and does not mutate the symbol?
}
protected virtual SourceLocalSymbol LookupLocal(SyntaxToken nameToken)
{
return Next.LookupLocal(nameToken);
......@@ -2988,6 +2965,11 @@ internal virtual BoundStatement BindSwitchExpressionAndSections(SwitchStatementS
return this.Next.BindSwitchExpressionAndSections(node, originalBinder, diagnostics);
}
internal virtual void BindPatternSwitchLabelForInference(CasePatternSwitchLabelSyntax node, DiagnosticBag diagnostics)
{
this.Next.BindPatternSwitchLabelForInference(node, diagnostics);
}
private BoundStatement BindWhile(WhileStatementSyntax node, DiagnosticBag diagnostics)
{
Debug.Assert(node != null);
......
......@@ -162,6 +162,12 @@ internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatement
throw ExceptionUtilities.Unreachable;
}
internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabelSyntax node, DiagnosticBag diagnostics)
{
// There's supposed to be a SwitchBinder (or other overrider of this method) in the chain.
throw ExceptionUtilities.Unreachable;
}
internal override BoundForStatement BindForParts(DiagnosticBag diagnostics, Binder originalBinder)
{
// There's supposed to be a ForLoopBinder (or other overrider of this method) in the chain.
......
......@@ -115,7 +115,9 @@ public override void VisitSwitchStatement(SwitchStatementSyntax node)
public override void VisitDeclarationPattern(DeclarationPatternSyntax node)
{
_localsBuilder.Add(SourceLocalSymbol.MakeLocal(_scopeBinder.ContainingMemberOrLambda, _scopeBinder, false, node.Type, node.Identifier, LocalDeclarationKind.PatternVariable));
_localsBuilder.Add(SourceLocalSymbol.MakePatternLocalSymbol(
_scopeBinder.ContainingMemberOrLambda, _scopeBinder, node));
base.VisitDeclarationPattern(node);
}
public override void VisitParenthesizedLambdaExpression(ParenthesizedLambdaExpressionSyntax node) { }
......@@ -180,11 +182,26 @@ public override void VisitDeclarationExpression(DeclarationExpressionSyntax node
{
case SyntaxKind.InvocationExpression:
case SyntaxKind.ObjectCreationExpression:
case SyntaxKind.ElementAccessExpression:
{
var local = SourceLocalSymbol.MakeVariableDeclaredInExpression(
_scopeBinder.ContainingMemberOrLambda, _scopeBinder, _enclosingBinderOpt, node.Type(),
node.Identifier(), LocalDeclarationKind.RegularVariable, (ExpressionSyntax)context);
_localsBuilder.Add(local);
break;
}
case SyntaxKind.ThisConstructorInitializer:
case SyntaxKind.BaseConstructorInitializer:
var local = SourceLocalSymbol.MakeOutVariable(_scopeBinder.ContainingMemberOrLambda, _scopeBinder, _enclosingBinderOpt, node.Type(), node.Identifier(), context);
_localsBuilder.Add(local);
break;
{
Debug.Assert(_enclosingBinderOpt == null || _enclosingBinderOpt == _scopeBinder);
var local = SourceLocalSymbol.MakeOutVariableInCtorInitializer(
_scopeBinder.ContainingMemberOrLambda, _scopeBinder, node.Type(), node.Identifier(),
(ConstructorInitializerSyntax)context);
_localsBuilder.Add(local);
break;
}
default:
// It looks like we are deling with a syntax tree that has a shape that could never be
......
......@@ -148,7 +148,7 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
}
boundIterationVariableType = new BoundTypeExpression(typeSyntax, alias, iterationVariableType);
this.IterationVariable.SetTypeSymbol(iterationVariableType);
this.IterationVariable.SetType(iterationVariableType);
break;
}
case SyntaxKind.ForEachComponentStatement:
......
......@@ -70,6 +70,20 @@ internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatement
locals, functions, switchSections, defaultLabel, this.BreakLabel, this);
}
internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabelSyntax node, DiagnosticBag diagnostics)
{
// This simulates enough of the normal binding path of a switch statement to cause
// the label's pattern variables to have their types inferred, if necessary.
BoundPatternSwitchLabel defaultLabel = null;
BindPatternSwitchSectionLabel(
sectionBinder: GetBinder(node.Parent),
boundSwitchExpression: SwitchGoverningExpression,
node: node,
label: LabelsByNode[node],
defaultLabel: ref defaultLabel,
diagnostics: diagnostics);
}
private ImmutableArray<BoundPatternSwitchSection> BindPatternSwitchSections(BoundExpression boundSwitchExpression, SyntaxList<SwitchSectionSyntax> sections, Binder originalBinder, out BoundPatternSwitchLabel defaultLabel, DiagnosticBag diagnostics)
{
defaultLabel = null;
......
......@@ -379,6 +379,12 @@ internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatement
GetDeclaredLocalFunctionsForScope(node), boundSwitchSections, this.BreakLabel, null);
}
internal override void BindPatternSwitchLabelForInference(CasePatternSwitchLabelSyntax node, DiagnosticBag diagnostics)
{
// A pattern should be handled by a pattern switch binder.
throw ExceptionUtilities.Unreachable;
}
// Bind the switch expression
private BoundExpression BindSwitchExpression(DiagnosticBag diagnostics)
{
......
......@@ -1579,7 +1579,7 @@
<Node Name="OutVarLocalPendingInference" Base="BoundExpression">
<!-- Type is not significant for this node type; always null -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="always"/>
<Field Name="LocalSymbol" Type="LocalSymbol"/>
<Field Name="LocalSymbol" Type="SourceLocalSymbol"/>
</Node>
<!-- The node is transformed into BoundDeconstructValuePlaceholder after inference -->
......@@ -1592,6 +1592,6 @@
<Node Name="DeconstructionLocalPendingInference" Base="BoundExpression">
<!-- Type is not significant for this node type; always null -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="always"/>
<Field Name="LocalSymbol" Type="LocalSymbol"/>
<Field Name="LocalSymbol" Type="SourceLocalSymbol"/>
</Node>
</Tree>
......@@ -10,10 +10,11 @@ internal partial class DeconstructionLocalPendingInference
{
public BoundLocal SetInferredType(TypeSymbol type, bool success)
{
Debug.Assert(type != null);
var syntaxNode = (SingleVariableDesignationSyntax)this.Syntax;
Binder.DeclareLocalVariable((SourceLocalSymbol)this.LocalSymbol, syntaxNode.Identifier, type);
return new BoundLocal(syntaxNode, this.LocalSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || !success);
Debug.Assert((object)type != null);
Debug.Assert(this.Syntax is SingleVariableDesignationSyntax);
this.LocalSymbol.SetType(type);
return new BoundLocal(this.Syntax, this.LocalSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || !success);
}
public BoundLocal FailInference(Binder binder)
......
......@@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -9,13 +10,11 @@ internal partial class OutVarLocalPendingInference
{
public BoundLocal SetInferredType(TypeSymbol type, bool success)
{
var syntaxNode = (DeclarationExpressionSyntax)this.Syntax;
Binder.DeclareLocalVariable(
(SourceLocalSymbol)this.LocalSymbol,
syntaxNode.Identifier(),
type);
Debug.Assert((object)type != null);
Debug.Assert(this.Syntax is DeclarationExpressionSyntax);
return new BoundLocal(syntaxNode, this.LocalSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || !success);
this.LocalSymbol.SetType(type);
return new BoundLocal(this.Syntax, this.LocalSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || !success);
}
public BoundLocal FailInference(Binder binder, DiagnosticBag diagnosticsOpt)
......
......@@ -174,7 +174,7 @@
<Compile Include="Binder\SingleLookupResult.cs" />
<Compile Include="Binder\SwitchBinder.cs" />
<Compile Include="Binder\SimpleLocalScopeBinder.cs" />
<Compile Include="Binder\SwitchBinder_BindPatternSwitch.cs" />
<Compile Include="Binder\PatternSwitchBinder.cs" />
<Compile Include="Binder\TypeofBinder.cs" />
<Compile Include="Binder\UsingStatementBinder.cs" />
<Compile Include="Binder\WhileBinder.cs" />
......@@ -921,4 +921,4 @@
</ItemGroup>
<Import Project="..\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems" Label="Shared" />
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</Project>
</Project>
\ No newline at end of file
......@@ -870,7 +870,7 @@ protected virtual void ReportUnassigned(Symbol symbol, SyntaxNode node)
// We've already reported the use of a local before its declaration. No need to emit
// another diagnostic for the same issue.
}
else if (!_alreadyReported[slot])
else if (!_alreadyReported[slot] && VariableType(symbol)?.IsErrorType() != true)
{
// CONSIDER: could suppress this diagnostic in cases where the local was declared in a using
// or fixed statement because there's a special error code for not initializing those.
......
......@@ -9797,8 +9797,7 @@ private ArgumentSyntax ParseArgumentExpression(bool isIndexer)
// However, we actually do support ref indexing of indexed properties in COM interop
// scenarios, and when indexing an object of static type "dynamic". So we enforce
// that the ref/out of the argument must match the parameter when binding the argument list.
if (!isIndexer && refOrOutKeyword?.Kind == SyntaxKind.OutKeyword &&
IsPossibleOutVarDeclaration())
if (refOrOutKeyword?.Kind == SyntaxKind.OutKeyword && IsPossibleOutVarDeclaration())
{
TypeSyntax typeSyntax = ParseType(parentIsParameter: false);
SyntaxToken identifier = CheckFeatureAvailability(this.ParseIdentifierToken(), MessageID.IDS_FeatureOutVar);
......
......@@ -67,11 +67,18 @@ internal class SourceLocalSymbol : LocalSymbol
_locations = ImmutableArray.Create<Location>(identifierToken.GetLocation());
}
/// <summary>
/// A binder for the local's scope that is used to check for name conflicts.
/// </summary>
internal Binder Binder
{
get { return binder; }
}
/// <summary>
/// Make a local variable symbol for a foreach iteration variable that can be inferred
/// (if necessary) by binding the collection element type of a foreach loop.
/// </summary>
public static SourceLocalSymbol MakeForeachLocal(
MethodSymbol containingMethod,
ForEachLoopBinder binder,
......@@ -82,6 +89,10 @@ internal Binder Binder
return new ForEachLocalSymbol(containingMethod, binder, typeSyntax, identifierToken, collection, LocalDeclarationKind.ForEachIterationVariable);
}
/// <summary>
/// Make a local variable symbol for an element of a deconstruction,
/// which can be inferred (if necessary) by binding the enclosing statement.
/// </summary>
public static SourceLocalSymbol MakeDeconstructionLocal(
Symbol containingSymbol,
Binder binder,
......@@ -92,6 +103,7 @@ internal Binder Binder
{
Debug.Assert(closestTypeSyntax != null);
Debug.Assert(closestTypeSyntax.Kind() != SyntaxKind.RefType);
if (closestTypeSyntax.IsVar)
{
return new DeconstructionLocalSymbol(
......@@ -103,6 +115,48 @@ internal Binder Binder
}
}
/// <summary>
/// Make a pattern local variable symbol which can be inferred (if necessary) by binding the enclosing pattern-matching operation.
/// </summary>
internal static LocalSymbol MakePatternLocalSymbol(
Symbol containingSymbol,
Binder binder,
DeclarationPatternSyntax node)
{
Debug.Assert(node.Type.Kind() != SyntaxKind.RefType);
if (!node.Type.IsVar)
{
return new SourceLocalSymbol(containingSymbol, binder, false, node.Type, node.Identifier, LocalDeclarationKind.PatternVariable);
}
//
// A pattern variable's type can be inferred from context.
//
// The syntax allows a pattern either (1) on the right-hand-side of an "is-pattern" expression, or
// (2) in the pattern of a switch case. These have their type inferred using different mechanisms,
// so we need to find that context. These are the only cases the parser will produce, so we can be
// confident that we will find one of them by scanning up node's .Parent chain. We allow
// a NullReferenceException at n.Parent to occur when we are fed bad trees.
//
for (SyntaxNode n = node; ; n = n.Parent)
{
var kind = n.Kind();
if (kind == SyntaxKind.IsPatternExpression)
{
var expr = (IsPatternExpressionSyntax)n;
return new VariableDeclaredInExpression(containingSymbol, binder, binder, node.Type, node.Identifier, LocalDeclarationKind.PatternVariable, expr);
}
else if (kind == SyntaxKind.CasePatternSwitchLabel)
{
var label = (CasePatternSwitchLabelSyntax)n;
return new SwitchPatternLocalSymbol(containingSymbol, binder, node.Type, node.Identifier, label);
}
}
}
/// <summary>
/// Make a local variable symbol which can be inferred (if necessary) by binding its initializing expression.
/// </summary>
public static SourceLocalSymbol MakeLocal(
Symbol containingSymbol,
Binder binder,
......@@ -121,31 +175,52 @@ internal Binder Binder
return new LocalWithInitializer(containingSymbol, binder, typeSyntax, identifierToken, initializer, declarationKind);
}
/// <summary>
/// Make a local variable for an out variable declaration whose type is inferred as a side-effect of binding the enclosing expression.
/// </summary>
/// <param name="containingSymbol"></param>
/// <param name="scopeBinder">
/// Binder that owns the scope for the local, the one that returns it in its <see cref="Binder.Locals"/> array.
/// </param>
/// <param name="enclosingBinderOpt">
/// Enclosing binder for the location where the local is declared, if different from the <paramref name="scopeBinder"/>.
/// It should be used to bind something at that location.
/// </param>
/// <param name="typeSyntax"></param>
/// <param name="scopeBinder">The binder for the scope of the local</param>
/// <param name="invocationBinderOpt">The binder for the invocation, if different from scopeBinder</param>
/// <param name="typeSyntax">The type syntax</param>
/// <param name="identifierToken"></param>
/// <param name="context"></param>
public static SourceLocalSymbol MakeOutVariable(
/// <param name="declarationKind"></param>
/// <param name="context">The expression to be bound, which will result in the variable receiving a type</param>
/// <returns></returns>
public static SourceLocalSymbol MakeVariableDeclaredInExpression(
Symbol containingSymbol,
Binder scopeBinder,
Binder enclosingBinderOpt,
Binder invocationBinderOpt,
TypeSyntax typeSyntax,
SyntaxToken identifierToken,
CSharpSyntaxNode context)
LocalDeclarationKind declarationKind,
ExpressionSyntax context)
{
if (typeSyntax.IsVar)
{
return new PossiblyImplicitlyTypedOutVarLocalSymbol(containingSymbol, scopeBinder, enclosingBinderOpt, typeSyntax, identifierToken, context);
}
Debug.Assert(typeSyntax.Kind() != SyntaxKind.RefType);
return typeSyntax.IsVar
? new VariableDeclaredInExpression(containingSymbol, scopeBinder, invocationBinderOpt ?? scopeBinder, typeSyntax, identifierToken, declarationKind, context)
: new SourceLocalSymbol(containingSymbol, scopeBinder, false, typeSyntax, identifierToken, declarationKind);
}
return new SourceLocalSymbol(containingSymbol, scopeBinder, false, typeSyntax, identifierToken, LocalDeclarationKind.RegularVariable);
/// <summary>
/// Make a local variable for an out variable declaration that can be inferred by binding a constructor initializer.
/// </summary>
/// <param name="containingSymbol"></param>
/// <param name="scopeBinder">The binder for the scope of the local</param>
/// <param name="typeSyntax"></param>
/// <param name="identifierToken"></param>
/// <param name="context">The expression to be bound, which will result in the variable receiving a type</param>
/// <returns></returns>
public static SourceLocalSymbol MakeOutVariableInCtorInitializer(
Symbol containingSymbol,
Binder scopeBinder,
TypeSyntax typeSyntax,
SyntaxToken identifierToken,
ConstructorInitializerSyntax context)
{
Debug.Assert(typeSyntax.Kind() != SyntaxKind.RefType);
return typeSyntax.IsVar
? new OutVariableInCtorInitializer(containingSymbol, scopeBinder, typeSyntax, identifierToken, context)
: new SourceLocalSymbol(containingSymbol, scopeBinder, false, typeSyntax, identifierToken, LocalDeclarationKind.RegularVariable);
}
internal override bool IsImportedFromMetadata
......@@ -229,7 +304,7 @@ public override TypeSymbol Type
if ((object)_type == null)
{
TypeSymbol localType = GetTypeSymbol();
SetTypeSymbol(localType);
SetType(localType);
}
return _type;
......@@ -264,18 +339,8 @@ private TypeSymbol GetTypeSymbol()
Binder typeBinder = this.binder;
bool isVar;
TypeSymbol declType;
if (_typeSyntax == null)
{
// in "let x = 1;", there is no syntax for the type. It is just inferred.
declType = null;
isVar = true;
}
else
{
RefKind refKind;
declType = typeBinder.BindType(_typeSyntax.SkipRef(out refKind), diagnostics, out isVar);
}
RefKind refKind;
TypeSymbol declType = typeBinder.BindType(_typeSyntax.SkipRef(out refKind), diagnostics, out isVar);
if (isVar)
{
......@@ -296,6 +361,14 @@ private TypeSymbol GetTypeSymbol()
Debug.Assert((object)declType != null);
//
// Note that we drop the diagnostics on the floor! That is because this code is invoked mainly in
// IDE scenarios where we are attempting to use the types of a variable before we have processed
// the code which causes the variable's type to be inferred. In batch compilation, on the
// other hand, local variables have their type inferred, if necessary, in the course of binding
// the statements of a method from top to bottom, and an inferred type is given to a variable
// before the variable's type is used by the compiler.
//
diagnostics.Free();
return declType;
}
......@@ -308,9 +381,8 @@ protected virtual TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
return _type;
}
internal void SetTypeSymbol(TypeSymbol newType)
internal void SetType(TypeSymbol newType)
{
#if PATTERNS_FIXED
TypeSymbol originalType = _type;
// In the event that we race to set the type of a local, we should
......@@ -324,9 +396,6 @@ internal void SetTypeSymbol(TypeSymbol newType)
{
Interlocked.CompareExchange(ref _type, newType, null);
}
#else
Interlocked.CompareExchange(ref _type, newType, _type);
#endif
}
/// <summary>
......@@ -424,6 +493,9 @@ public sealed override int GetHashCode()
return Hash.Combine(_identifierToken.GetHashCode(), _containingSymbol.GetHashCode());
}
/// <summary>
/// Symbol for a local whose type can be inferred by binding its initializer.
/// </summary>
private sealed class LocalWithInitializer : SourceLocalSymbol
{
private readonly EqualsValueClauseSyntax _initializer;
......@@ -568,6 +640,10 @@ internal override bool IsReturnable
}
}
/// <summary>
/// Symbol for a foreach iteration variable that can be inferred by binding the
/// collection element type of the foreach.
/// </summary>
private sealed class ForEachLocalSymbol : SourceLocalSymbol
{
private readonly ExpressionSyntax _collection;
......@@ -597,61 +673,109 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
}
/// <summary>
/// Symbol for an out variable local that might require type inference during overload resolution, i.e.
/// its type is syntactically 'var'.
/// Symbol for a variable that can be inferred by binding an expression.
/// </summary>
private class PossiblyImplicitlyTypedOutVarLocalSymbol : SourceLocalSymbol
private class VariableDeclaredInExpression : SourceLocalSymbol
{
private readonly CSharpSyntaxNode _containingInvocation;
private readonly Binder _enclosingBinderOpt;
private readonly ExpressionSyntax _expression;
private readonly Binder _expressionBinder;
public PossiblyImplicitlyTypedOutVarLocalSymbol(
public VariableDeclaredInExpression(
Symbol containingSymbol,
Binder scopeBinder,
Binder enclosingBinderOpt,
Binder expressionBinder,
TypeSyntax typeSyntax,
SyntaxToken identifierToken,
CSharpSyntaxNode containingInvocation)
: base(containingSymbol, scopeBinder, false, typeSyntax, identifierToken, LocalDeclarationKind.RegularVariable)
LocalDeclarationKind declarationKind,
ExpressionSyntax expression)
: base(containingSymbol, scopeBinder, false, typeSyntax, identifierToken, declarationKind)
{
_containingInvocation = containingInvocation;
_enclosingBinderOpt = enclosingBinderOpt;
Debug.Assert(expression != null && expressionBinder != null);
_expression = expression;
_expressionBinder = expressionBinder;
}
internal override SyntaxNode ForbiddenZone => _containingInvocation;
internal override SyntaxNode ForbiddenZone => _expression;
//
// The forbidden zone for this type can only come into play for out variables, since they have a forbidden
// zone that extends beyond the declaration point. For pattern variables, which are the other
// kind of variable that can be typed based on an expression, we only need to bind the
// immediately enclosing expression, which due to the shape of the syntax has the variable
// declaration following any expression from which its value is inferred.
//
internal override ErrorCode ForbiddenDiagnostic => ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList;
protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
{
// Try binding immediately enclosing invocation expression, this should force the inference.
TypeSymbol result;
switch (_containingInvocation.Kind())
{
case SyntaxKind.InvocationExpression:
case SyntaxKind.ObjectCreationExpression:
(_enclosingBinderOpt ?? this.binder).BindExpression((ExpressionSyntax)_containingInvocation, diagnostics);
result = this._type;
Debug.Assert((object)result != null);
return result;
case SyntaxKind.ThisConstructorInitializer:
case SyntaxKind.BaseConstructorInitializer:
Debug.Assert(_enclosingBinderOpt == null || _enclosingBinderOpt == this.binder);
(_enclosingBinderOpt ?? this.binder).BindConstructorInitializer(((ConstructorInitializerSyntax)_containingInvocation).ArgumentList, (MethodSymbol)this.binder.ContainingMember(), diagnostics);
result = this._type;
Debug.Assert((object)result != null);
return result;
// Bind the invocation to force inference.
_expressionBinder.BindExpression(_expression, diagnostics);
Debug.Assert((object)this._type != null);
return this._type;
}
}
default:
throw ExceptionUtilities.UnexpectedValue(_containingInvocation.Kind());
}
/// <summary>
/// Symbol for a variable that can be inferred by binding a pattern switch section label.
/// </summary>
private class SwitchPatternLocalSymbol : SourceLocalSymbol
{
private readonly CasePatternSwitchLabelSyntax _labelSyntax;
public SwitchPatternLocalSymbol(
Symbol containingSymbol, Binder binder, TypeSyntax type, SyntaxToken identifier, CasePatternSwitchLabelSyntax labelSyntax)
: base(containingSymbol, binder, false, type, identifier, LocalDeclarationKind.PatternVariable)
{
this._labelSyntax = labelSyntax;
}
protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
{
// bind the switch label to cause inference of its pattern variables
var sectionSyntax = (SwitchSectionSyntax)_labelSyntax.Parent;
var switchStatement = (SwitchStatementSyntax)sectionSyntax.Parent;
binder.GetBinder(switchStatement).BindPatternSwitchLabelForInference(_labelSyntax, diagnostics);
Debug.Assert((object)this._type != null);
return this._type;
}
}
/// <summary>
/// Symbol for an out variable that can be inferred by binding a ctor-initializer.
/// </summary>
private class OutVariableInCtorInitializer : SourceLocalSymbol
{
private readonly ConstructorInitializerSyntax _invocation;
public OutVariableInCtorInitializer(
Symbol containingSymbol,
Binder scopeBinder,
TypeSyntax typeSyntax,
SyntaxToken identifierToken,
ConstructorInitializerSyntax invocation)
: base(containingSymbol, scopeBinder, false, typeSyntax, identifierToken, LocalDeclarationKind.RegularVariable)
{
Debug.Assert(invocation != null);
_invocation = invocation;
}
internal override SyntaxNode ForbiddenZone => _invocation;
internal override ErrorCode ForbiddenDiagnostic => ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList;
protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics)
{
// Bind the ctor-initializer to force inference.
this.binder.BindConstructorInitializer(_invocation.ArgumentList, (MethodSymbol)this.binder.ContainingMember(), diagnostics);
Debug.Assert((object)this._type != null);
return this._type;
}
}
/// <summary>
/// Symbol for a deconstruction local that might require type inference.
/// For instance, local `x` in `var(x, y) = ...` or `(var x, int y) = ...`.
/// For instance, local `x` in `var (x, y) = ...` or `(var x, int y) = ...`.
/// </summary>
private class DeconstructionLocalSymbol : SourceLocalSymbol
{
......@@ -715,8 +839,9 @@ internal override SyntaxNode ForbiddenZone
return forStatement.Deconstruction;
case SyntaxKind.ForEachComponentStatement:
var forEachStatement = (ForEachComponentStatementSyntax)_deconstruction;
return forEachStatement.Expression;
// There is no forbidden zone for a foreach statement, because the deconstruction
// variables are not in scope in the expression.
return null;
default:
throw ExceptionUtilities.UnexpectedValue(_deconstruction.Kind());
......
......@@ -2058,12 +2058,9 @@ void M()
Assert.Equal("? E", symbolInfo.Symbol.ToTestDisplayString());
compilation.VerifyDiagnostics(
// (11,17): error CS0841: Cannot use local variable 'E' before it is declared
// var E = E.A;
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "E").WithArguments("E").WithLocation(11, 17),
// (11,17): error CS0165: Use of unassigned local variable 'E'
// var E = E.A;
Diagnostic(ErrorCode.ERR_UseDefViolation, "E").WithArguments("E").WithLocation(11, 17)
// (11,17): error CS0841: Cannot use local variable 'E' before it is declared
// var E = E.A;
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "E").WithArguments("E").WithLocation(11, 17)
);
}
}
......
......@@ -69,16 +69,14 @@ static void Main(string[] args)
CreateCompilationWithMscorlib(text).VerifyDiagnostics(
// (6,23): error CS0841: Cannot use local variable 'x' before it is declared
// var x = y.Foo(x);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x").WithArguments("x"),
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x").WithArguments("x").WithLocation(6, 23),
// (6,17): error CS0841: Cannot use local variable 'y' before it is declared
// var x = y.Foo(x);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y").WithArguments("y"),
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y").WithArguments("y").WithLocation(6, 17),
// (7,23): error CS0841: Cannot use local variable 'y' before it is declared
// var y = x.Foo(y);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y").WithArguments("y"),
// (6,23): error CS0165: Use of unassigned local variable 'x'
// var x = y.Foo(x);
Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x"));
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "y").WithArguments("y").WithLocation(7, 23)
);
}
[WorkItem(545612, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545612")]
......
......@@ -13276,10 +13276,7 @@ static void Test2(object x, object y)
compilation.VerifyDiagnostics(
// (6,37): error CS0149: Method name expected
// Test2(new System.Action(out var x1),
Diagnostic(ErrorCode.ERR_MethodNameExpected, "var x1").WithLocation(6, 37),
// (6,37): error CS0165: Use of unassigned local variable 'x1'
// Test2(new System.Action(out var x1),
Diagnostic(ErrorCode.ERR_UseDefViolation, "var x1").WithArguments("x1").WithLocation(6, 37)
Diagnostic(ErrorCode.ERR_MethodNameExpected, "var x1").WithLocation(6, 37)
);
var tree = compilation.SyntaxTrees.Single();
......@@ -13879,22 +13876,16 @@ static void Test2(object x, object y)
parseOptions: TestOptions.Regular);
compilation.VerifyDiagnostics(
// (7,25): error CS1003: Syntax error, ',' expected
// Test2(x[out var x1], x1);
Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",", "").WithLocation(7, 25),
// (7,21): error CS0103: The name 'var' does not exist in the current context
// (7,21): error CS1615: Argument 1 may not be passed with the 'out' keyword
// Test2(x[out var x1], x1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(7, 21),
// (7,25): error CS0103: The name 'x1' does not exist in the current context
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "var x1").WithArguments("1", "out").WithLocation(7, 21),
// (7,25): error CS8197: Cannot infer the type of implicitly-typed out variable.
// Test2(x[out var x1], x1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(7, 25),
// (7,30): error CS0103: The name 'x1' does not exist in the current context
// Test2(x[out var x1], x1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(7, 30)
Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedOutVariable, "x1").WithLocation(7, 25)
);
var tree = compilation.SyntaxTrees.Single();
Assert.False(GetOutVarDeclarations(tree, "x1").Any());
Assert.Equal(1, GetOutVarDeclarations(tree, "x1").Count());
}
[Fact]
......@@ -13917,24 +13908,17 @@ static void Test2(object x, object y)
var compilation = CreateCompilationWithMscorlib(text,
options: TestOptions.ReleaseExe,
parseOptions: TestOptions.Regular);
compilation.VerifyDiagnostics(
// (7,21): error CS1525: Invalid expression term 'int'
// (7,21): error CS1615: Argument 1 may not be passed with the 'out' keyword
// Test2(x[out int x1], x1);
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(7, 21),
// (7,25): error CS1003: Syntax error, ',' expected
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "int x1").WithArguments("1", "out").WithLocation(7, 21),
// (7,21): error CS0165: Use of unassigned local variable 'x1'
// Test2(x[out int x1], x1);
Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",", "").WithLocation(7, 25),
// (7,25): error CS0103: The name 'x1' does not exist in the current context
// Test2(x[out int x1], x1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(7, 25),
// (7,30): error CS0103: The name 'x1' does not exist in the current context
// Test2(x[out int x1], x1);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(7, 30)
Diagnostic(ErrorCode.ERR_UseDefViolation, "int x1").WithArguments("x1").WithLocation(7, 21)
);
var tree = compilation.SyntaxTrees.Single();
Assert.False(GetOutVarDeclarations(tree, "x1").Any());
Assert.Equal(1, GetOutVarDeclarations(tree, "x1").Count());
}
[Fact]
......@@ -14101,7 +14085,7 @@ static int Test1(out int x)
Assert.Equal("System.Int32", model.GetTypeInfo(yRef).Type.ToTestDisplayString());
}
[Fact]
[WorkItem(12266, "https://github.com/dotnet/roslyn/issues/12266")]
public void LocalVariableTypeInferenceAndOutVar_05()
......@@ -14136,5 +14120,199 @@ static int Test1(out int x)
Assert.Equal("System.Int32", model.GetTypeInfo(yRef).Type.ToTestDisplayString());
}
[Fact, WorkItem(13219, "https://github.com/dotnet/roslyn/issues/13219")]
public void IndexingDynamic()
{
var text = @"
public class Cls
{
public static void Main()
{
dynamic d = null;
var x = d[out int z];
}
}";
// the C# dynamic binder does not support ref or out indexers, so we don't run this
var compilation = CompileAndVerify(text, additionalRefs: new[] { SystemCoreRef, CSharpRef }).VerifyIL("Cls.Main()",
@"{
// Code size 87 (0x57)
.maxstack 7
.locals init (object V_0, //d
int V_1) //z
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>> Cls.<>o__0.<>p__0""
IL_0007: brtrue.s IL_003e
IL_0009: ldc.i4.0
IL_000a: ldtoken ""Cls""
IL_000f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0014: ldc.i4.2
IL_0015: newarr ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo""
IL_001a: dup
IL_001b: ldc.i4.0
IL_001c: ldc.i4.0
IL_001d: ldnull
IL_001e: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_0023: stelem.ref
IL_0024: dup
IL_0025: ldc.i4.1
IL_0026: ldc.i4.s 17
IL_0028: ldnull
IL_0029: call ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
IL_002e: stelem.ref
IL_002f: call ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.GetIndex(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)""
IL_0034: call ""System.Runtime.CompilerServices.CallSite<<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>> System.Runtime.CompilerServices.CallSite<<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
IL_0039: stsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>> Cls.<>o__0.<>p__0""
IL_003e: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>> Cls.<>o__0.<>p__0""
IL_0043: ldfld ""<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic> System.Runtime.CompilerServices.CallSite<<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>>.Target""
IL_0048: ldsfld ""System.Runtime.CompilerServices.CallSite<<>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>> Cls.<>o__0.<>p__0""
IL_004d: ldloc.0
IL_004e: ldloca.s V_1
IL_0050: callvirt ""dynamic <>F{00000004}<System.Runtime.CompilerServices.CallSite, dynamic, int, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, dynamic, ref int)""
IL_0055: pop
IL_0056: ret
}");
}
[ClrOnlyFact, WorkItem(13219, "https://github.com/dotnet/roslyn/issues/13219")]
public void OutVariableDeclarationInIndex()
{
var source1 =
@".class interface public abstract import IA
{
.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6D 00 00 ) // ...Item..
.custom instance void [mscorlib]System.Runtime.InteropServices.CoClassAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 01 41 00 00 )
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 31 36 35 46 37 35 32 44 2D 45 39 43 34 2D 34 46 37 45 2D 42 30 44 30 2D 43 44 46 44 37 41 33 36 45 32 31 31 00 00 )
.method public abstract virtual instance int32 get_Item([out] int32& i) { }
.method public abstract virtual instance void set_Item([out] int32& i, int32 v) { }
.property instance int32 Item([out] int32&)
{
.get instance int32 IA::get_Item([out] int32&)
.set instance void IA::set_Item([out] int32&, int32)
}
.method public abstract virtual instance int32 get_P([out] int32& i) { }
.method public abstract virtual instance void set_P([out] int32& i, int32 v) { }
.property instance int32 P([out] int32&)
{
.get instance int32 IA::get_P([out] int32&)
.set instance void IA::set_P([out] int32&, int32)
}
}
.class public A implements IA
{
.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6D 00 00 ) // ...Item..
.method public hidebysig specialname rtspecialname instance void .ctor()
{
ret
}
// i = 1; return 2;
.method public virtual instance int32 get_P([out] int32& i)
{
ldarg.1
ldc.i4.1
stind.i4
ldc.i4.2
ret
}
// i = 3; return;
.method public virtual instance void set_P([out] int32& i, int32 v)
{
ldarg.1
ldc.i4.3
stind.i4
ret
}
.property instance int32 P([out] int32&)
{
.get instance int32 A::get_P([out] int32&)
.set instance void A::set_P([out] int32&, int32)
}
// i = 4; return 5;
.method public virtual instance int32 get_Item([out] int32& i)
{
ldarg.1
ldc.i4.4
stind.i4
ldc.i4.5
ret
}
// i = 6; return;
.method public virtual instance void set_Item([out] int32& i, int32 v)
{
ldarg.1
ldc.i4.6
stind.i4
ret
}
.property instance int32 Item([out] int32&)
{
.get instance int32 A::get_Item([out] int32&)
.set instance void A::set_Item([out] int32&, int32)
}
}";
var reference1 = CompileIL(source1);
var source2 =
@"using System;
class B
{
public static void Main()
{
A a = new A();
IA ia = a;
Console.WriteLine(ia.P[out int i1] + "" "" + i1);
ia.P[out int i2] = 4;
Console.WriteLine(i2);
Console.WriteLine(ia[out int i3] + "" "" + i3);
ia[out int i4] = 4;
Console.WriteLine(i4);
}
}";
var compilation2 = CompileAndVerify(source2, additionalRefs: new[] { reference1 }, expectedOutput:
@"2 1
3
5 4
6");
compilation2.VerifyIL("B.Main()",
@"{
// Code size 103 (0x67)
.maxstack 4
.locals init (int V_0, //i1
int V_1, //i2
int V_2, //i3
int V_3) //i4
IL_0000: newobj ""A..ctor()""
IL_0005: dup
IL_0006: ldloca.s V_0
IL_0008: callvirt ""int IA.P[out int].get""
IL_000d: box ""int""
IL_0012: ldstr "" ""
IL_0017: ldloc.0
IL_0018: box ""int""
IL_001d: call ""string string.Concat(object, object, object)""
IL_0022: call ""void System.Console.WriteLine(string)""
IL_0027: dup
IL_0028: ldloca.s V_1
IL_002a: ldc.i4.4
IL_002b: callvirt ""void IA.P[out int].set""
IL_0030: ldloc.1
IL_0031: call ""void System.Console.WriteLine(int)""
IL_0036: dup
IL_0037: ldloca.s V_2
IL_0039: callvirt ""int IA.this[out int].get""
IL_003e: box ""int""
IL_0043: ldstr "" ""
IL_0048: ldloc.2
IL_0049: box ""int""
IL_004e: call ""string string.Concat(object, object, object)""
IL_0053: call ""void System.Console.WriteLine(string)""
IL_0058: ldloca.s V_3
IL_005a: ldc.i4.4
IL_005b: callvirt ""void IA.this[out int].set""
IL_0060: ldloc.3
IL_0061: call ""void System.Console.WriteLine(int)""
IL_0066: ret
}");
}
}
}
......@@ -11842,5 +11842,50 @@ public static void Main(string[] args)
);
var comp = CompileAndVerify(compilation, expectedOutput: "whatever");
}
[Fact, WorkItem(12996, "https://github.com/dotnet/roslyn/issues/12996")]
public void TypeOfAVarPatternVariable()
{
var source =
@"
class Program
{
public static void Main(string[] args)
{
}
public static void Test(int val)
{
if (val is var o1)
{
System.Console.WriteLine(o1);
}
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
compilation.VerifyDiagnostics(
);
var tree = compilation.SyntaxTrees[0];
var model1 = compilation.GetSemanticModel(tree);
var declaration = tree.GetRoot().DescendantNodes().OfType<IsPatternExpressionSyntax>().Single();
var o1 = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "o1").Single();
var typeInfo1 = model1.GetTypeInfo(declaration);
Assert.Equal(SymbolKind.NamedType, typeInfo1.Type.Kind);
Assert.Equal("System.Boolean", typeInfo1.Type.ToTestDisplayString());
typeInfo1 = model1.GetTypeInfo(o1);
Assert.Equal(SymbolKind.NamedType, typeInfo1.Type.Kind);
Assert.Equal("System.Int32", typeInfo1.Type.ToTestDisplayString());
var model2 = compilation.GetSemanticModel(tree);
var typeInfo2 = model2.GetTypeInfo(o1);
Assert.Equal(SymbolKind.NamedType, typeInfo2.Type.Kind);
Assert.Equal("System.Int32", typeInfo2.Type.ToTestDisplayString());
}
}
}
// 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.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
......@@ -1220,5 +1222,32 @@ public enum EnumA
Default";
var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
}
[Fact, WorkItem(10446, "https://github.com/dotnet/roslyn/issues/10446")]
public void InferenceInSwitch()
{
var source =
@"
public class X
{
public static void Main()
{
object o = 1;
switch (o)
{
case var i:
var s = i.ToString();
Console.WriteLine(s);
break;
}
}
}
";
var compilation = CreateCompilationWithMscorlib45(source);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var sRef = tree.GetCompilationUnitRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(n => n.ToString() == "s").Single();
Assert.Equal("System.String", model.GetTypeInfo(sRef).Type.ToTestDisplayString());
}
}
}
......@@ -3,6 +3,7 @@
using System.Collections.Generic;
using Xunit;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
......@@ -919,7 +920,7 @@ public static void Main()
Diagnostic(ErrorCode.WRN_UnreferencedVar, "Moo3").WithArguments("Moo3").WithLocation(17, 14));
}
[Fact]
[Fact, WorkItem(13062, "https://github.com/dotnet/roslyn/issues/13062")]
public void NoRefInIndex()
{
var text = @"
......
......@@ -742,10 +742,8 @@ public void ERR_VariableUsedBeforeDeclaration_01()
c.VerifyDiagnostics(
// (1,22): error CS0841: Cannot use local variable 'x' before it is declared
// var x = 1; { var x = x;}
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x").WithArguments("x").WithLocation(1, 22),
// (1,22): error CS0165: Use of unassigned local variable 'x'
// var x = 1; { var x = x;}
Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(1, 22));
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x").WithArguments("x").WithLocation(1, 22)
);
}
[WorkItem(550, "https://github.com/dotnet/roslyn/issues/550")]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册