Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
944ec4f7
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
944ec4f7
编写于
5月 08, 2018
作者:
C
Charles Stoner
提交者:
GitHub
5月 08, 2018
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Set nullability of foreach iteration variable (#26660)
上级
c112e519
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
318 addition
and
34 deletion
+318
-34
src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs
...Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs
+3
-3
src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
+29
-25
src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
...pilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
+1
-1
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+13
-1
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs
.../Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs
+1
-1
src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
...ilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
+1
-2
src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs
src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs
+1
-1
src/Compilers/CSharp/Test/Semantic/Semantics/StaticNullChecking.cs
...lers/CSharp/Test/Semantic/Semantics/StaticNullChecking.cs
+269
-0
未找到文件。
src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs
浏览文件 @
944ec4f7
...
...
@@ -16,7 +16,7 @@ internal sealed class ForEachEnumeratorInfo
// Types identified by the algorithm in the spec (8.8.4).
public
readonly
TypeSymbol
CollectionType
;
// public readonly TypeSymbol EnumeratorType; // redundant - return type of GetEnumeratorMethod
public
readonly
TypeSymbol
ElementType
;
public
readonly
TypeSymbol
WithAnnotations
ElementType
;
// Members required by the "pattern" based approach. Also populated for other approaches.
public
readonly
MethodSymbol
GetEnumeratorMethod
;
...
...
@@ -37,7 +37,7 @@ internal sealed class ForEachEnumeratorInfo
private
ForEachEnumeratorInfo
(
TypeSymbol
collectionType
,
TypeSymbol
elementType
,
TypeSymbol
WithAnnotations
elementType
,
MethodSymbol
getEnumeratorMethod
,
MethodSymbol
currentPropertyGetter
,
MethodSymbol
moveNextMethod
,
...
...
@@ -69,7 +69,7 @@ internal sealed class ForEachEnumeratorInfo
internal
struct
Builder
{
public
TypeSymbol
CollectionType
;
public
TypeSymbol
ElementType
;
public
TypeSymbol
WithAnnotations
ElementType
;
public
MethodSymbol
GetEnumeratorMethod
;
public
MethodSymbol
CurrentPropertyGetter
;
...
...
src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
浏览文件 @
944ec4f7
...
...
@@ -164,13 +164,13 @@ internal override BoundStatement BindForEachDeconstruction(DiagnosticBag diagnos
BoundExpression
collectionExpr
=
originalBinder
.
GetBinder
(
_syntax
.
Expression
).
BindValue
(
_syntax
.
Expression
,
diagnostics
,
BindValueKind
.
RValue
);
ForEachEnumeratorInfo
.
Builder
builder
=
new
ForEachEnumeratorInfo
.
Builder
();
TypeSymbol
inferredType
;
TypeSymbol
WithAnnotations
inferredType
;
bool
hasErrors
=
!
GetEnumeratorInfoAndInferCollectionElementType
(
ref
builder
,
ref
collectionExpr
,
diagnostics
,
out
inferredType
);
ExpressionSyntax
variables
=
((
ForEachVariableStatementSyntax
)
_syntax
).
Variable
;
// Tracking narrowest safe-to-escape scope by default, the proper val escape will be set when doing full binding of the foreach statement
var
valuePlaceholder
=
new
BoundDeconstructValuePlaceholder
(
_syntax
.
Expression
,
this
.
LocalScopeDepth
,
inferredType
??
CreateErrorType
(
"var"
));
var
valuePlaceholder
=
new
BoundDeconstructValuePlaceholder
(
_syntax
.
Expression
,
this
.
LocalScopeDepth
,
inferredType
?.
TypeSymbol
??
CreateErrorType
(
"var"
));
DeclarationExpressionSyntax
declaration
=
null
;
ExpressionSyntax
expression
=
null
;
...
...
@@ -192,7 +192,7 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
BoundExpression
collectionExpr
=
originalBinder
.
GetBinder
(
_syntax
.
Expression
).
BindValue
(
_syntax
.
Expression
,
diagnostics
,
BindValueKind
.
RValue
);
ForEachEnumeratorInfo
.
Builder
builder
=
new
ForEachEnumeratorInfo
.
Builder
();
TypeSymbol
inferredType
;
TypeSymbol
WithAnnotations
inferredType
;
bool
hasErrors
=
!
GetEnumeratorInfoAndInferCollectionElementType
(
ref
builder
,
ref
collectionExpr
,
diagnostics
,
out
inferredType
);
// These should only occur when special types are missing or malformed.
...
...
@@ -226,18 +226,18 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
if
(
isVar
)
{
iterationVariableType
=
inferredType
??
CreateErrorType
(
"var"
);
declType
=
inferredType
??
TypeSymbolWithAnnotations
.
Create
(
CreateErrorType
(
"var"
),
isNullableIfReferenceType
:
null
);
}
else
{
Debug
.
Assert
((
object
)
declType
!=
null
);
iterationVariableType
=
declType
.
TypeSymbol
;
}
iterationVariableType
=
declType
.
TypeSymbol
;
boundIterationVariableType
=
new
BoundTypeExpression
(
typeSyntax
,
alias
,
iterationVariableType
);
SourceLocalSymbol
local
=
this
.
IterationVariable
;
local
.
SetTypeSymbol
(
TypeSymbolWithAnnotations
.
Create
(
iterationVariableType
)
);
local
.
SetTypeSymbol
(
declType
);
local
.
SetValEscape
(
collectionEscape
);
if
(
local
.
RefKind
!=
RefKind
.
None
)
...
...
@@ -280,7 +280,7 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
case
SyntaxKind
.
ForEachVariableStatement
:
{
var
node
=
(
ForEachVariableStatementSyntax
)
_syntax
;
iterationVariableType
=
inferredType
??
CreateErrorType
(
"var"
);
iterationVariableType
=
inferredType
?.
TypeSymbol
??
CreateErrorType
(
"var"
);
var
variables
=
node
.
Variable
;
if
(
variables
.
IsDeconstructionLeft
())
...
...
@@ -370,18 +370,18 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
// but it turns out that these are equivalent (when both are available).
HashSet
<
DiagnosticInfo
>
useSiteDiagnostics
=
null
;
Conversion
elementConversion
=
this
.
Conversions
.
ClassifyConversionFromType
(
inferredType
,
iterationVariableType
,
ref
useSiteDiagnostics
,
forCast
:
true
);
Conversion
elementConversion
=
this
.
Conversions
.
ClassifyConversionFromType
(
inferredType
.
TypeSymbol
,
iterationVariableType
,
ref
useSiteDiagnostics
,
forCast
:
true
);
if
(!
elementConversion
.
IsValid
)
{
ImmutableArray
<
MethodSymbol
>
originalUserDefinedConversions
=
elementConversion
.
OriginalUserDefinedConversions
;
if
(
originalUserDefinedConversions
.
Length
>
1
)
{
diagnostics
.
Add
(
ErrorCode
.
ERR_AmbigUDConv
,
foreachKeyword
.
GetLocation
(),
originalUserDefinedConversions
[
0
],
originalUserDefinedConversions
[
1
],
inferredType
,
iterationVariableType
);
diagnostics
.
Add
(
ErrorCode
.
ERR_AmbigUDConv
,
foreachKeyword
.
GetLocation
(),
originalUserDefinedConversions
[
0
],
originalUserDefinedConversions
[
1
],
inferredType
.
TypeSymbol
,
iterationVariableType
);
}
else
{
SymbolDistinguisher
distinguisher
=
new
SymbolDistinguisher
(
this
.
Compilation
,
inferredType
,
iterationVariableType
);
SymbolDistinguisher
distinguisher
=
new
SymbolDistinguisher
(
this
.
Compilation
,
inferredType
.
TypeSymbol
,
iterationVariableType
);
diagnostics
.
Add
(
ErrorCode
.
ERR_NoExplicitConv
,
foreachKeyword
.
GetLocation
(),
distinguisher
.
First
,
distinguisher
.
Second
);
}
hasErrors
=
true
;
...
...
@@ -395,7 +395,7 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
// If the type X of expression is dynamic then there is an implicit conversion from >>expression<< (not the type of the expression)
// to the System.Collections.IEnumerable interface (§6.1.8).
builder
.
CollectionConversion
=
this
.
Conversions
.
ClassifyConversionFromExpression
(
collectionExpr
,
builder
.
CollectionType
,
ref
useSiteDiagnostics
);
builder
.
CurrentConversion
=
this
.
Conversions
.
ClassifyConversionFromType
(
builder
.
CurrentPropertyGetter
.
ReturnType
.
TypeSymbol
,
builder
.
ElementType
,
ref
useSiteDiagnostics
);
builder
.
CurrentConversion
=
this
.
Conversions
.
ClassifyConversionFromType
(
builder
.
CurrentPropertyGetter
.
ReturnType
.
TypeSymbol
,
builder
.
ElementType
.
TypeSymbol
,
ref
useSiteDiagnostics
);
var
getEnumeratorType
=
builder
.
GetEnumeratorMethod
.
ReturnType
.
TypeSymbol
;
// we never convert struct enumerators to object - it is done only for null-checks.
...
...
@@ -419,7 +419,7 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
Debug
.
Assert
(
builder
.
CollectionConversion
.
IsValid
);
Debug
.
Assert
(
builder
.
CurrentConversion
.
IsValid
||
(
builder
.
ElementType
.
IsPointerType
()
&&
collectionExpr
.
Type
.
IsArray
())
||
(
builder
.
ElementType
.
IsNullableType
()
&&
builder
.
ElementType
.
GetMemberTypeArgumentsNoUseSiteDiagnostics
().
Single
().
IsErrorType
()
&&
collectionExpr
.
Type
.
IsArray
()));
(
builder
.
ElementType
.
IsNullableType
()
&&
builder
.
ElementType
.
TypeSymbol
.
GetMemberTypeArgumentsNoUseSiteDiagnostics
().
Single
().
IsErrorType
()
&&
collectionExpr
.
Type
.
IsArray
()));
Debug
.
Assert
(
builder
.
EnumeratorConversion
.
IsValid
||
this
.
Compilation
.
GetSpecialType
(
SpecialType
.
System_Object
).
TypeKind
==
TypeKind
.
Error
||
!
useSiteDiagnostics
.
IsNullOrEmpty
(),
...
...
@@ -460,18 +460,18 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
hasErrors
);
}
internal
TypeSymbol
InferCollectionElementType
(
DiagnosticBag
diagnostics
,
ExpressionSyntax
collectionSyntax
)
internal
TypeSymbol
WithAnnotations
InferCollectionElementType
(
DiagnosticBag
diagnostics
,
ExpressionSyntax
collectionSyntax
)
{
// Use the right binder to avoid seeing iteration variable
BoundExpression
collectionExpr
=
this
.
GetBinder
(
collectionSyntax
).
BindValue
(
collectionSyntax
,
diagnostics
,
BindValueKind
.
RValue
);
ForEachEnumeratorInfo
.
Builder
builder
=
new
ForEachEnumeratorInfo
.
Builder
();
TypeSymbol
inferredType
;
TypeSymbol
WithAnnotations
inferredType
;
GetEnumeratorInfoAndInferCollectionElementType
(
ref
builder
,
ref
collectionExpr
,
diagnostics
,
out
inferredType
);
return
inferredType
;
}
private
bool
GetEnumeratorInfoAndInferCollectionElementType
(
ref
ForEachEnumeratorInfo
.
Builder
builder
,
ref
BoundExpression
collectionExpr
,
DiagnosticBag
diagnostics
,
out
TypeSymbol
inferredType
)
private
bool
GetEnumeratorInfoAndInferCollectionElementType
(
ref
ForEachEnumeratorInfo
.
Builder
builder
,
ref
BoundExpression
collectionExpr
,
DiagnosticBag
diagnostics
,
out
TypeSymbol
WithAnnotations
inferredType
)
{
UnwrapCollectionExpressionIfNullable
(
ref
collectionExpr
,
diagnostics
);
...
...
@@ -484,7 +484,7 @@ private bool GetEnumeratorInfoAndInferCollectionElementType(ref ForEachEnumerato
else
if
(
collectionExpr
.
HasDynamicType
())
{
// If the enumerator is dynamic, it yields dynamic values
inferredType
=
DynamicTypeSymbol
.
Instance
;
inferredType
=
TypeSymbolWithAnnotations
.
Create
(
DynamicTypeSymbol
.
Instance
,
isNullableIfReferenceType
:
null
)
;
}
else
if
(
collectionExpr
.
Type
.
SpecialType
==
SpecialType
.
System_String
&&
builder
.
CollectionType
.
SpecialType
==
SpecialType
.
System_Collections_IEnumerable
)
{
...
...
@@ -492,7 +492,7 @@ private bool GetEnumeratorInfoAndInferCollectionElementType(ref ForEachEnumerato
// over the string's Chars indexer. Therefore, we should infer "char", regardless of what the spec
// indicates the element type is. This actually matters in practice because the System.String in
// the portable library doesn't have a pattern GetEnumerator method or implement IEnumerable<char>.
inferredType
=
GetSpecialType
(
SpecialType
.
System_Char
,
diagnostics
,
collectionExpr
.
Syntax
);
inferredType
=
TypeSymbolWithAnnotations
.
Create
(
GetSpecialType
(
SpecialType
.
System_Char
,
diagnostics
,
collectionExpr
.
Syntax
),
isNullableIfReferenceType
:
null
);
}
else
{
...
...
@@ -610,7 +610,7 @@ private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundE
if
(
SatisfiesForEachPattern
(
ref
builder
,
diagnostics
))
{
builder
.
ElementType
=
GetTypeOrReturnTypeWithAdjustedNullableAnnotations
((
PropertySymbol
)
builder
.
CurrentPropertyGetter
.
AssociatedSymbol
)
.
TypeSymbol
;
builder
.
ElementType
=
GetTypeOrReturnTypeWithAdjustedNullableAnnotations
((
PropertySymbol
)
builder
.
CurrentPropertyGetter
.
AssociatedSymbol
);
// NOTE: if IDisposable is not available at all, no diagnostics will be reported - we will just assume that
// the enumerator is not disposable. If it has IDisposable in its interface list, there will be a diagnostic there.
...
...
@@ -660,7 +660,7 @@ private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundE
{
// If the type is generic, we have to search for the methods
Debug
.
Assert
(
collectionType
.
OriginalDefinition
.
SpecialType
==
SpecialType
.
System_Collections_Generic_IEnumerable_T
);
builder
.
ElementType
=
collectionType
.
TypeArgumentsNoUseSiteDiagnostics
.
Single
()
.
TypeSymbol
;
builder
.
ElementType
=
collectionType
.
TypeArgumentsNoUseSiteDiagnostics
.
Single
();
MethodSymbol
getEnumeratorMethod
=
(
MethodSymbol
)
GetSpecialTypeMember
(
SpecialMember
.
System_Collections_Generic_IEnumerable_T__GetEnumerator
,
diagnostics
,
errorLocationSyntax
);
if
((
object
)
getEnumeratorMethod
!=
null
)
...
...
@@ -682,11 +682,13 @@ private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundE
{
// Non-generic - use special members to avoid re-computing
Debug
.
Assert
(
collectionType
.
SpecialType
==
SpecialType
.
System_Collections_IEnumerable
);
builder
.
ElementType
=
GetSpecialType
(
SpecialType
.
System_Object
,
diagnostics
,
errorLocationSyntax
);
builder
.
GetEnumeratorMethod
=
(
MethodSymbol
)
GetSpecialTypeMember
(
SpecialMember
.
System_Collections_IEnumerable__GetEnumerator
,
diagnostics
,
errorLocationSyntax
);
builder
.
CurrentPropertyGetter
=
(
MethodSymbol
)
GetSpecialTypeMember
(
SpecialMember
.
System_Collections_IEnumerator__get_Current
,
diagnostics
,
errorLocationSyntax
);
builder
.
MoveNextMethod
=
(
MethodSymbol
)
GetSpecialTypeMember
(
SpecialMember
.
System_Collections_IEnumerator__MoveNext
,
diagnostics
,
errorLocationSyntax
);
builder
.
ElementType
=
TypeSymbolWithAnnotations
.
Create
(
GetSpecialType
(
SpecialType
.
System_Object
,
diagnostics
,
errorLocationSyntax
),
isNullableIfReferenceType
:
builder
.
CurrentPropertyGetter
?.
ReturnType
.
IsNullable
);
Debug
.
Assert
((
object
)
builder
.
GetEnumeratorMethod
==
null
||
builder
.
GetEnumeratorMethod
.
ReturnType
.
SpecialType
==
SpecialType
.
System_Collections_IEnumerator
);
...
...
@@ -722,15 +724,17 @@ private ForEachEnumeratorInfo.Builder GetDefaultEnumeratorInfo(ForEachEnumerator
if
(
collectionExprType
.
IsDynamic
())
{
builder
.
ElementType
=
((
_syntax
as
ForEachStatementSyntax
)?.
Type
.
IsVar
==
true
)
?
(
TypeSymbol
)
DynamicTypeSymbol
.
Instance
:
GetSpecialType
(
SpecialType
.
System_Object
,
diagnostics
,
_syntax
);
builder
.
ElementType
=
TypeSymbolWithAnnotations
.
Create
(
((
_syntax
as
ForEachStatementSyntax
)?.
Type
.
IsVar
==
true
)
?
(
TypeSymbol
)
DynamicTypeSymbol
.
Instance
:
GetSpecialType
(
SpecialType
.
System_Object
,
diagnostics
,
_syntax
),
isNullableIfReferenceType
:
null
);
}
else
{
builder
.
ElementType
=
collectionExprType
.
SpecialType
==
SpecialType
.
System_String
?
GetSpecialType
(
SpecialType
.
System_Char
,
diagnostics
,
_syntax
)
:
((
ArrayTypeSymbol
)
collectionExprType
).
ElementType
.
TypeSymbol
;
TypeSymbolWithAnnotations
.
Create
(
GetSpecialType
(
SpecialType
.
System_Char
,
diagnostics
,
_syntax
),
isNullableIfReferenceType
:
null
)
:
((
ArrayTypeSymbol
)
collectionExprType
).
ElementType
;
}
// CONSIDER:
...
...
src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
浏览文件 @
944ec4f7
...
...
@@ -840,7 +840,7 @@ public override ForEachStatementInfo GetForEachStatementInfo(CommonForEachStatem
enumeratorInfoOpt
.
MoveNextMethod
,
(
PropertySymbol
)
enumeratorInfoOpt
.
CurrentPropertyGetter
.
AssociatedSymbol
,
enumeratorInfoOpt
.
NeedsDisposeMethod
?
(
MethodSymbol
)
Compilation
.
GetSpecialTypeMember
(
SpecialMember
.
System_IDisposable__Dispose
)
:
null
,
enumeratorInfoOpt
.
ElementType
,
enumeratorInfoOpt
.
ElementType
.
TypeSymbol
,
boundForEach
.
ElementConversion
,
enumeratorInfoOpt
.
CurrentConversion
);
}
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
浏览文件 @
944ec4f7
...
...
@@ -2749,7 +2749,19 @@ public override void VisitForEachIterationVariables(BoundForEachStatement node)
// declare and assign all iteration variables
foreach
(
var
iterationVariable
in
node
.
IterationVariables
)
{
// PROTOTYPE(NullableReferenceTypes): Mark as assigned.
int
slot
=
GetOrCreateSlot
(
iterationVariable
);
TypeSymbolWithAnnotations
sourceType
=
node
.
EnumeratorInfoOpt
?.
ElementType
;
bool
?
isNullableIfReferenceType
=
null
;
if
((
object
)
sourceType
!=
null
)
{
TypeSymbolWithAnnotations
destinationType
=
iterationVariable
.
Type
;
HashSet
<
DiagnosticInfo
>
useSiteDiagnostics
=
null
;
Conversion
conversion
=
_conversions
.
ClassifyImplicitConversionFromType
(
sourceType
.
TypeSymbol
,
destinationType
.
TypeSymbol
,
ref
useSiteDiagnostics
);
// PROTOTYPE(NullableReferenceTypes): Report nullability mismatch if any.
TypeSymbolWithAnnotations
result
=
InferResultNullability
(
operand
:
null
,
conversion
,
destinationType
.
TypeSymbol
,
sourceType
);
isNullableIfReferenceType
=
result
.
IsNullable
;
}
this
.
State
[
slot
]
=
!
isNullableIfReferenceType
;
}
}
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs
浏览文件 @
944ec4f7
...
...
@@ -106,7 +106,7 @@ private BoundStatement RewriteEnumeratorForEachStatement(BoundForEachStatement n
BoundStatement
rewrittenBody
=
(
BoundStatement
)
Visit
(
node
.
Body
);
TypeSymbol
enumeratorType
=
enumeratorInfo
.
GetEnumeratorMethod
.
ReturnType
.
TypeSymbol
;
TypeSymbol
elementType
=
enumeratorInfo
.
ElementType
;
TypeSymbol
elementType
=
enumeratorInfo
.
ElementType
.
TypeSymbol
;
// E e
LocalSymbol
enumeratorVar
=
_factory
.
SynthesizedLocal
(
enumeratorType
,
syntax
:
forEachSyntax
,
kind
:
SynthesizedLocalKind
.
ForEachEnumerator
);
...
...
src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
浏览文件 @
944ec4f7
...
...
@@ -623,8 +623,7 @@ private sealed class ForEachLocalSymbol : SourceLocalSymbol
protected
override
TypeSymbolWithAnnotations
InferTypeOfVarVariable
(
DiagnosticBag
diagnostics
)
{
var
type
=
ForEachLoopBinder
.
InferCollectionElementType
(
diagnostics
,
_collection
);
return
type
==
null
?
null
:
TypeSymbolWithAnnotations
.
Create
(
type
);
return
ForEachLoopBinder
.
InferCollectionElementType
(
diagnostics
,
_collection
);
}
/// <summary>
...
...
src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs
浏览文件 @
944ec4f7
...
...
@@ -3049,7 +3049,7 @@ private static BoundForEachStatement GetBoundForEachStatement(string text, param
Assert
.
Null
(
statementInfo
.
DisposeMethod
);
}
Assert
.
Equal
(
enumeratorInfo
.
ElementType
,
statementInfo
.
ElementType
);
Assert
.
Equal
(
enumeratorInfo
.
ElementType
.
TypeSymbol
,
statementInfo
.
ElementType
);
Assert
.
Equal
(
boundNode
.
ElementConversion
,
statementInfo
.
ElementConversion
);
Assert
.
Equal
(
enumeratorInfo
.
CurrentConversion
,
statementInfo
.
CurrentConversion
);
}
...
...
src/Compilers/CSharp/Test/Semantic/Semantics/StaticNullChecking.cs
浏览文件 @
944ec4f7
...
...
@@ -19516,6 +19516,275 @@ public void ExplicitCast_StaticType()
Diagnostic(ErrorCode.ERR_ConvertToStaticClass, "(C?)y").WithArguments("C").WithLocation(4, 36));
}
[Fact]
public void ForEach_01()
{
var source =
@"class Enumerable
{
public Enumerator GetEnumerator() => new Enumerator();
}
class Enumerator
{
public object Current => throw null;
public bool MoveNext() => false;
}
class C
{
static void F(Enumerable e)
{
foreach (var x in e)
x.ToString();
foreach (string y in e)
y.ToString();
foreach (string? z in e)
z.ToString();
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
}
[Fact]
public void ForEach_02()
{
var source =
@"class Enumerable
{
public Enumerator GetEnumerator() => new Enumerator();
}
class Enumerator
{
public object? Current => throw null;
public bool MoveNext() => false;
}
class C
{
static void F(Enumerable e)
{
foreach (var x in e)
x.ToString();
foreach (object y in e)
y.ToString();
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (15,13): warning CS8602: Possible dereference of a null reference.
// x.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(15, 13),
// (17,13): warning CS8602: Possible dereference of a null reference.
// y.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(17, 13));
}
[Fact]
public void ForEach_03()
{
var source =
@"using System.Collections;
namespace System
{
public class Object
{
public string ToString() => throw null;
}
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
public class String { }
}
namespace System.Collections
{
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerator
{
object? Current { get; }
bool MoveNext();
}
}
class Enumerable : IEnumerable
{
IEnumerator IEnumerable.GetEnumerator() => throw null;
}
class C
{
static void F(Enumerable e)
{
foreach (var x in e)
x.ToString();
foreach (object y in e)
y.ToString();
}
static void G(IEnumerable e)
{
foreach (var z in e)
z.ToString();
foreach (object w in e)
w.ToString();
}
}";
var comp = CreateEmptyCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (34,13): warning CS8602: Possible dereference of a null reference.
// x.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(34, 13),
// (36,13): warning CS8602: Possible dereference of a null reference.
// y.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(36, 13),
// (41,13): warning CS8602: Possible dereference of a null reference.
// z.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(41, 13),
// (43,13): warning CS8602: Possible dereference of a null reference.
// w.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "w").WithLocation(43, 13));
}
// z.ToString() should warn if IEnumerator.Current is annotated as `object?`.
[Fact]
public void ForEach_04()
{
var source =
@"using System.Collections;
using System.Collections.Generic;
class C
{
static void F(IEnumerable<object?> cx, object?[] cy)
{
foreach (var x in cx)
x.ToString();
foreach (object? y in cy)
y.ToString();
foreach (object? z in (IEnumerable)cx)
z.ToString();
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (8,13): warning CS8602: Possible dereference of a null reference.
// x.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(8, 13),
// (10,13): warning CS8602: Possible dereference of a null reference.
// y.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(10, 13));
}
[Fact]
public void ForEach_05()
{
var source =
@"class C
{
static void F1(dynamic c)
{
foreach (var x in c)
x.ToString();
foreach (object? y in c)
y.ToString();
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
}
[Fact]
public void ForEach_06()
{
var source =
@"using System.Collections;
using System.Collections.Generic;
class C<T> : IEnumerable<T> where T : class
{
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null;
IEnumerator IEnumerable.GetEnumerator() => throw null;
}
class P
{
static void F<T>(C<T?> c) where T : class
{
foreach (var x in c)
x.ToString();
foreach (T? y in c)
y.ToString();
foreach (T z in c)
z.ToString();
foreach (object w in c)
w.ToString();
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (13,13): warning CS8602: Possible dereference of a null reference.
// x.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(13, 13),
// (15,13): warning CS8602: Possible dereference of a null reference.
// y.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(15, 13),
// (17,13): warning CS8602: Possible dereference of a null reference.
// z.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(17, 13),
// (19,13): warning CS8602: Possible dereference of a null reference.
// w.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "w").WithLocation(19, 13));
}
[Fact]
public void ForEach_07()
{
var source =
@"struct S<T> where T : class
{
public E<T> GetEnumerator() => new E<T>();
}
struct E<T> where T : class
{
public T Current => throw null;
public bool MoveNext() => false;
}
class P
{
static void F1<T>() where T : class
{
foreach (var x1 in new S<T>())
x1.ToString();
foreach (T y1 in new S<T>())
y1.ToString();
foreach (T? z1 in new S<T>())
z1.ToString();
foreach (object? w1 in new S<T>())
w1.ToString();
}
static void F2<T>() where T : class
{
foreach (var x2 in new S<T?>())
x2.ToString();
foreach (T y2 in new S<T?>())
y2.ToString();
foreach (T? z2 in new S<T?>())
z2.ToString();
foreach (object? w2 in new S<T?>())
w2.ToString();
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (26,13): warning CS8602: Possible dereference of a null reference.
// x2.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(26, 13),
// (28,13): warning CS8602: Possible dereference of a null reference.
// y2.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y2").WithLocation(28, 13),
// (30,13): warning CS8602: Possible dereference of a null reference.
// z2.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z2").WithLocation(30, 13),
// (32,13): warning CS8602: Possible dereference of a null reference.
// w2.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "w2").WithLocation(32, 13));
}
[Fact]
public void UnconstrainedTypeParameter_MayBeNonNullable()
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录