Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
7cdd66af
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,发现更多精彩内容 >>
提交
7cdd66af
编写于
5月 17, 2017
作者:
C
CyrusNajmabadi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Move syntax checks about lambda-parameter type mismatches out of the parser.
上级
bab05cba
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
140 addition
and
96 deletion
+140
-96
src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
+27
-0
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+80
-60
src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs
...CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs
+0
-4
src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs
...ers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs
+33
-32
未找到文件。
src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
浏览文件 @
7cdd66af
...
...
@@ -61,6 +61,7 @@ internal partial class Binder
hasSignature
=
true
;
var
paren
=
(
ParenthesizedLambdaExpressionSyntax
)
syntax
;
parameterSyntaxList
=
paren
.
ParameterList
.
Parameters
;
CheckParanthesizedLambdaParameters
(
parameterSyntaxList
.
Value
,
diagnostics
);
isAsync
=
(
paren
.
AsyncKeyword
.
Kind
()
==
SyntaxKind
.
AsyncKeyword
);
break
;
case
SyntaxKind
.
AnonymousMethodExpression
:
...
...
@@ -180,6 +181,32 @@ internal partial class Binder
return
Tuple
.
Create
(
refKinds
,
types
,
names
,
isAsync
);
}
private
void
CheckParanthesizedLambdaParameters
(
SeparatedSyntaxList
<
ParameterSyntax
>
parameterSyntaxList
,
DiagnosticBag
diagnostics
)
{
if
(
parameterSyntaxList
.
Count
>
0
)
{
var
hasTypes
=
parameterSyntaxList
[
0
].
Type
!=
null
;
for
(
int
i
=
1
,
n
=
parameterSyntaxList
.
Count
;
i
<
n
;
i
++)
{
var
parameter
=
parameterSyntaxList
[
i
];
// Ignore parameters with missing names. We'll have already reported an error
// about them in the parser.
if
(!
parameter
.
Identifier
.
IsMissing
)
{
var
thisParameterHasType
=
parameter
.
Type
!=
null
;
if
(
hasTypes
!=
thisParameterHasType
)
{
diagnostics
.
Add
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
parameter
.
Type
?.
GetLocation
()
??
parameter
.
Identifier
.
GetLocation
());
}
}
}
}
}
private
UnboundLambda
BindAnonymousFunction
(
CSharpSyntaxNode
syntax
,
DiagnosticBag
diagnostics
)
{
Debug
.
Assert
(
syntax
!=
null
);
...
...
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
浏览文件 @
7cdd66af
...
...
@@ -10823,59 +10823,60 @@ private AnonymousMethodExpressionSyntax ParseAnonymousMethodExpression()
return
_syntaxFactory
.
AnonymousMethodExpression
(
asyncToken
,
@delegate
,
parameterList
,
body
);
}
private
ExpressionSyntax
ParseLambdaExpression
()
private
Lambda
ExpressionSyntax
ParseLambdaExpression
()
{
bool
parentScopeIsInAsync
=
IsInAsync
;
SyntaxToken
asyncToken
=
null
;
if
(
this
.
CurrentToken
.
ContextualKind
==
SyntaxKind
.
AsyncKeyword
&&
PeekToken
(
1
).
Kind
!=
SyntaxKind
.
EqualsGreaterThanToken
)
if
(
this
.
CurrentToken
.
ContextualKind
==
SyntaxKind
.
AsyncKeyword
&&
PeekToken
(
1
).
Kind
!=
SyntaxKind
.
EqualsGreaterThanToken
)
{
asyncToken
=
this
.
EatContextualToken
(
SyntaxKind
.
AsyncKeyword
);
asyncToken
=
CheckFeatureAvailability
(
asyncToken
,
MessageID
.
IDS_FeatureAsync
);
IsInAsync
=
true
;
}
ExpressionSyntax
result
;
var
result
=
ParseLambdaExpression
(
asyncToken
);
IsInAsync
=
parentScopeIsInAsync
;
return
result
;
}
private
LambdaExpressionSyntax
ParseLambdaExpression
(
SyntaxToken
asyncToken
)
{
if
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OpenParenToken
)
{
var
paramList
=
this
.
ParseLambdaParameterList
();
var
arrow
=
this
.
EatToken
(
SyntaxKind
.
EqualsGreaterThanToken
);
arrow
=
CheckFeatureAvailability
(
arrow
,
MessageID
.
IDS_FeatureLambda
);
CSharpSyntaxNode
body
;
if
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OpenBraceToken
)
{
body
=
this
.
ParseBlock
();
}
else
{
body
=
this
.
ParsePossibleRefExpression
();
}
var
body
=
ParseLambdaBody
();
re
sult
=
_syntaxFactory
.
ParenthesizedLambdaExpression
(
asyncToken
,
paramList
,
arrow
,
body
);
re
turn
_syntaxFactory
.
ParenthesizedLambdaExpression
(
asyncToken
,
paramList
,
arrow
,
body
);
}
else
{
var
name
=
this
.
ParseIdentifierToken
();
var
arrow
=
this
.
EatToken
(
SyntaxKind
.
EqualsGreaterThanToken
);
arrow
=
CheckFeatureAvailability
(
arrow
,
MessageID
.
IDS_FeatureLambda
);
CSharpSyntaxNode
body
;
if
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OpenBraceToken
)
{
body
=
this
.
ParseBlock
();
}
else
{
body
=
this
.
ParsePossibleRefExpression
();
}
result
=
_syntaxFactory
.
SimpleLambdaExpression
(
asyncToken
,
_syntaxFactory
.
Parameter
(
default
(
SyntaxList
<
AttributeListSyntax
>),
default
(
SyntaxList
<
SyntaxToken
>),
type
:
null
,
identifier
:
name
,
@default
:
null
),
arrow
,
body
);
var
parameter
=
_syntaxFactory
.
Parameter
(
default
(
SyntaxList
<
AttributeListSyntax
>),
default
(
SyntaxList
<
SyntaxToken
>),
type
:
null
,
identifier
:
name
,
@default
:
null
);
var
body
=
ParseLambdaBody
();
return
_syntaxFactory
.
SimpleLambdaExpression
(
asyncToken
,
parameter
,
arrow
,
body
);
}
}
IsInAsync
=
parentScopeIsInAsync
;
return
result
;
private
CSharpSyntaxNode
ParseLambdaBody
()
{
if
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OpenBraceToken
)
{
return
this
.
ParseBlock
();
}
else
{
return
this
.
ParsePossibleRefExpression
();
}
}
private
ParameterListSyntax
ParseLambdaParameterList
()
...
...
@@ -10887,15 +10888,13 @@ private ParameterListSyntax ParseLambdaParameterList()
var
nodes
=
_pool
.
AllocateSeparated
<
ParameterSyntax
>();
try
{
bool
hasTypes
=
false
;
if
(
this
.
CurrentToken
.
Kind
!=
SyntaxKind
.
CloseParenToken
)
{
tryAgain
:
if
(
this
.
IsPossibleLambdaParameter
()
||
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
CommaToken
)
if
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
CommaToken
||
this
.
IsPossibleLambdaParameter
()
)
{
// first parameter
var
parameter
=
this
.
ParseLambdaParameter
(
isFirst
:
true
,
hasTypes
:
ref
hasTypes
);
var
parameter
=
this
.
ParseLambdaParameter
();
nodes
.
Add
(
parameter
);
// additional parameters
...
...
@@ -10909,7 +10908,7 @@ private ParameterListSyntax ParseLambdaParameterList()
else
if
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
CommaToken
||
this
.
IsPossibleLambdaParameter
())
{
nodes
.
AddSeparator
(
this
.
EatToken
(
SyntaxKind
.
CommaToken
));
parameter
=
this
.
ParseLambdaParameter
(
false
,
ref
hasTypes
);
parameter
=
this
.
ParseLambdaParameter
();
nodes
.
Add
(
parameter
);
continue
;
}
...
...
@@ -10964,45 +10963,66 @@ private PostSkipAction SkipBadLambdaParameterListTokens(ref SyntaxToken openPare
expected
);
}
private
ParameterSyntax
ParseLambdaParameter
(
bool
isFirst
,
ref
bool
hasTypes
)
private
ParameterSyntax
ParseLambdaParameter
()
{
TypeSyntax
paramType
=
null
;
SyntaxToken
paramName
=
null
;
SyntaxToken
refOrOutOrParams
=
null
;
// Params are actually illegal in a lambda, but we'll allow it for error recovery purposes and
// give the "params unexpected" error at semantic analysis time.
bool
isRefOrOutOrParams
=
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
RefKeyword
||
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OutKeyword
||
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
ParamsKeyword
;
var
pk
=
this
.
PeekToken
(
1
).
Kind
;
if
(
isRefOrOutOrParams
||
(
pk
!=
SyntaxKind
.
CommaToken
&&
pk
!=
SyntaxKind
.
CloseParenToken
&&
(
hasTypes
||
isFirst
))
||
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OpenParenToken
&&
pk
==
SyntaxKind
.
CloseParenToken
&&
(
hasTypes
||
isFirst
))
||
IsPredefinedType
(
this
.
CurrentToken
.
Kind
))
{
if
(
isRefOrOutOrParams
)
{
refOrOutOrParams
=
this
.
EatToken
();
}
SyntaxToken
refOrOutOrParams
=
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
RefKeyword
||
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OutKeyword
||
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
ParamsKeyword
?
this
.
EatToken
()
:
null
;
paramType
=
this
.
ParseType
(
ParseTypeMode
.
Parameter
);
}
TypeSyntax
paramType
=
ShouldParseLambdaParameterType
(
refOrOutOrParams
)
?
ParseType
(
ParseTypeMode
.
Parameter
)
:
null
;
paramName
=
this
.
ParseIdentifierToken
();
SyntaxToken
paramName
=
this
.
ParseIdentifierToken
();
return
_syntaxFactory
.
Parameter
(
default
(
SyntaxList
<
AttributeListSyntax
>),
refOrOutOrParams
,
paramType
,
paramName
,
@default
:
null
);
}
private
bool
ShouldParseLambdaParameterType
(
SyntaxToken
refOrOutOrParams
)
{
// If we have "ref/out/params" always try to parse out a type.
if
(
refOrOutOrParams
!=
null
)
{
return
true
;
}
if
(
isFirst
)
// If we have "int/string/etc." always parse out a type.
if
(
IsPredefinedType
(
this
.
CurrentToken
.
Kind
))
{
hasTypes
=
paramType
!=
null
;
return
true
;
}
else
if
(
paramType
!=
null
&&
!
hasTypes
&&
!
paramName
.
IsMissing
)
// if we have a tuple type in a lambda.
if
(
this
.
CurrentToken
.
Kind
==
SyntaxKind
.
OpenParenToken
)
{
paramType
=
this
.
AddError
(
paramType
,
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
)
;
return
true
;
}
else
if
(
paramType
==
null
&&
hasTypes
&&
!
paramName
.
IsMissing
)
if
(
this
.
IsTrueIdentifier
(
this
.
CurrentToken
))
{
paramName
=
this
.
AddError
(
paramName
,
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
);
// Don't parse out a type if we see:
//
// (a,
// (a)
// (a =>
// (a {
//
// In all other cases, parse out a type.
var
peek1
=
this
.
PeekToken
(
1
);
if
(
peek1
.
Kind
!=
SyntaxKind
.
CommaToken
&&
peek1
.
Kind
!=
SyntaxKind
.
CloseParenToken
&&
peek1
.
Kind
!=
SyntaxKind
.
EqualsGreaterThanToken
&&
peek1
.
Kind
!=
SyntaxKind
.
OpenBraceToken
)
{
return
true
;
}
}
return
_syntaxFactory
.
Parameter
(
default
(
SyntaxList
<
AttributeListSyntax
>),
refOrOutOrParams
,
paramType
,
paramName
,
null
)
;
return
false
;
}
private
bool
IsCurrentTokenQueryContextualKeyword
...
...
src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs
浏览文件 @
7cdd66af
...
...
@@ -511,10 +511,6 @@ class C {
N
(
SyntaxKind
.
CommaToken
);
M
(
SyntaxKind
.
Parameter
);
{
M
(
SyntaxKind
.
IdentifierName
);
{
M
(
SyntaxKind
.
IdentifierToken
);
}
M
(
SyntaxKind
.
IdentifierToken
);
}
M
(
SyntaxKind
.
CloseParenToken
);
...
...
src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs
浏览文件 @
7cdd66af
...
...
@@ -1002,41 +1002,42 @@ class C
delegate T Func<T>();
delegate T Func<A0, T>(A0 a0);
delegate T Func<A0, A1, T>(A0 a0, A1 a1);
delegate T Func<A0, A1, A2, T>(A0 a0, A1 a1, A2 a2);
delegate T Func<A0, A1, A2, A3, T>(A0 a0, A1 a1, A2 a2, A3 a3);
static void X()
{
Func<int,int
> f1
= (int x, y) => 1; // err: mixed parameters
Func<int,int
> f2
= (x, int y) => 1; // err: mixed parameters
Func<int,int
> f3
= (int x, int y, z) => 1; // err: mixed parameters
Func<int,int
> f4
= (int x, y, int z) => 1; // err: mixed parameters
Func<int,int
> f5
= (x, int y, int z) => 1; // err: mixed parameters
Func<int,int
> f6
= (x, y, int z) => 1; // err: mixed parameters
}
}
"
;
ParseAndValidate
(
test
,
// (10,41): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f1 = (int x, y) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"y"
),
// (11,37): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f2 = (x, int y) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
),
// (12,48): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f3 = (int x, int y, z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"z"
),
// (13,41): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f4 = (int x, y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"y"
),
// (14,37): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f5 = (x, int y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
),
// (14,44): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f5 = (x, int y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
),
// (15,40): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f6 = (x, y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
));
Func<int,int
,int> f1
= (int x, y) => 1; // err: mixed parameters
Func<int,int
,int> f2
= (x, int y) => 1; // err: mixed parameters
Func<int,int
,int,int> f3
= (int x, int y, z) => 1; // err: mixed parameters
Func<int,int
,int,int> f4
= (int x, y, int z) => 1; // err: mixed parameters
Func<int,int
,int,int> f5
= (x, int y, int z) => 1; // err: mixed parameters
Func<int,int
,int,int> f6
= (x, y, int z) => 1; // err: mixed parameters
}
}
"
;
CreateCompilationWithMscorlib
(
test
).
VerifyDiagnostics
(
// (10,41): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f1 = (int x, y) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"y"
),
// (11,37): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f2 = (x, int y) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
),
// (12,48): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f3 = (int x, int y, z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"z"
),
// (13,41): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f4 = (int x, y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"y"
),
// (14,37): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f5 = (x, int y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
),
// (14,44): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f5 = (x, int y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
),
// (15,40): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit
// Func<int,int> f6 = (x, y, int z) => 1; // err: mixed parameters
Diagnostic
(
ErrorCode
.
ERR_InconsistentLambdaParameterUsage
,
"int"
));
}
[
WorkItem
(
535915
,
"http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/535915"
)]
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录