提交 567d12f6 编写于 作者: G gafter

Improved error recovery for lambdas in a call with extra arguments.

Fixes #557, #5498
上级 b6e3176e
......@@ -97,6 +97,12 @@ private enum Dependency
private Dependency[,] _dependencies; // Initialized lazily
private bool _dependenciesDirty;
/// <summary>
/// For error recovery, we allow a mismatch between the number of arguments and parameters
/// during type inference. This sometimes enables inferring the type for a lambda parameter.
/// </summary>
private int Length => System.Math.Min(_arguments.Length, _formalParameterTypes.Length);
public static MethodTypeInferenceResult Infer(
Binder binder,
ImmutableArray<TypeParameterSymbol> methodTypeParameters,
......@@ -524,14 +530,13 @@ private void InferTypeArgsFirstPhase(Binder binder, ref HashSet<DiagnosticInfo>
{
Debug.Assert(!_formalParameterTypes.IsDefault);
Debug.Assert(!_arguments.IsDefault);
Debug.Assert(_arguments.Length == _formalParameterTypes.Length);
// We expect that we have been handed a list of arguments and a list of the
// formal parameter types they correspond to; all the details about named and
// optional parameters have already been dealt with.
// SPEC: For each of the method arguments Ei:
for (int arg = 0; arg < _arguments.Length; arg++)
for (int arg = 0, length = this.Length; arg < length; arg++)
{
var argument = _arguments[arg];
......@@ -795,7 +800,7 @@ private void MakeOutputTypeInferences(Binder binder, ref HashSet<DiagnosticInfo>
// SPEC: where the output types contain unfixed type parameters but the input
// SPEC: types do not, an output type inference is made from Ei to Ti.
for (int arg = 0; arg < _arguments.Length; arg++)
for (int arg = 0, length = this.Length; arg < length; arg++)
{
var formalType = _formalParameterTypes[arg];
var argument = _arguments[arg];
......@@ -1067,7 +1072,7 @@ private bool DependsDirectlyOn(int iParam, int jParam)
Debug.Assert(IsUnfixed(iParam));
Debug.Assert(IsUnfixed(jParam));
for (int iArg = 0; iArg < _arguments.Length; iArg++)
for (int iArg = 0, length = this.Length; iArg < length; iArg++)
{
var formalParameterType = _formalParameterTypes[iArg];
var argument = _arguments[iArg];
......
......@@ -2407,7 +2407,7 @@ internal EffectiveParameters(ImmutableArray<TypeSymbol> types, ImmutableArray<Re
{
int parm = argToParamMap.IsDefault ? arg : argToParamMap[arg];
// If this is the __arglist parameter, just skip it.
if (parm == parameters.Length)
if (parm >= parameters.Length)
{
continue;
}
......@@ -2519,12 +2519,17 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
var argumentAnalysis = AnalyzeArguments(member, arguments, isMethodGroupConversion, expanded: false);
if (!argumentAnalysis.IsValid)
{
// When we are producing more complete results, and a required parameter is missing, we push on
// to type inference so that lambda arguments can be bound to their delegate-typed parameters,
// thus improving the API and intellisense experience.
if (!completeResults || argumentAnalysis.Kind != ArgumentAnalysisResultKind.RequiredParameterMissing)
switch (argumentAnalysis.Kind)
{
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
case ArgumentAnalysisResultKind.RequiredParameterMissing:
case ArgumentAnalysisResultKind.NoCorrespondingParameter:
if (!completeResults) goto default;
// When we are producing more complete results, and we have the wrong number of arguments, we push on
// through type inference so that lambda arguments can be bound to their delegate-typed parameters,
// thus improving the API and intellisense experience.
break;
default:
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
}
}
......@@ -2824,10 +2829,6 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
// treating the method as inapplicable.
paramCount = arguments.Arguments.Count;
}
else
{
Debug.Assert(paramCount == arguments.Arguments.Count);
}
// For each argument in A, the parameter passing mode of the argument (i.e., value, ref, or out) is
// identical to the parameter passing mode of the corresponding parameter, and
......
......@@ -1963,5 +1963,62 @@ public TSource FirstOrDefault(Func<TSource, bool> predicate, params TSource[] de
Assert.Equal("String", typeInfo.Type.Name);
Assert.NotEmpty(typeInfo.Type.GetMembers("Replace"));
}
[Fact]
[WorkItem(557, "https://github.com/dotnet/roslyn/issues/557")]
public void TestLambdaWithError11()
{
var source =
@"using System.Linq;
public static class Program
{
public static void Main()
{
var x = new {
X = """".Select(c => c.
Y = 0,
};
}
}
";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
var tree = compilation.SyntaxTrees[0];
var sm = compilation.GetSemanticModel(tree);
var lambda = tree.GetCompilationUnitRoot().DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
var eReference = lambda.Body.DescendantNodes().OfType<IdentifierNameSyntax>().First();
Assert.Equal("c", eReference.ToString());
var typeInfo = sm.GetTypeInfo(eReference);
Assert.Equal(TypeKind.Struct, typeInfo.Type.TypeKind);
Assert.Equal("Char", typeInfo.Type.Name);
Assert.NotEmpty(typeInfo.Type.GetMembers("IsHighSurrogate")); // check it is the char we know and love
}
[Fact]
[WorkItem(5498, "https://github.com/dotnet/roslyn/issues/5498")]
public void TestLambdaWithError12()
{
var source =
@"using System.Linq;
class Program
{
static void Main(string[] args)
{
var z = args.Select(a => a.
var foo =
}
}";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source);
var tree = compilation.SyntaxTrees[0];
var sm = compilation.GetSemanticModel(tree);
var lambda = tree.GetCompilationUnitRoot().DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
var eReference = lambda.Body.DescendantNodes().OfType<IdentifierNameSyntax>().First();
Assert.Equal("a", eReference.ToString());
var typeInfo = sm.GetTypeInfo(eReference);
Assert.Equal(TypeKind.Class, typeInfo.Type.TypeKind);
Assert.Equal("String", typeInfo.Type.Name);
Assert.NotEmpty(typeInfo.Type.GetMembers("Replace"));
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册