提交 07984da9 编写于 作者: N Neal Gafter

Merge pull request #11718 from gafter/master-errlambda02

Attempt type inference when there are no applicable methods
......@@ -605,43 +605,6 @@ private static ThreeState ReportDiagnosticsIfObsoleteInternal(DiagnosticBag diag
return ThreeState.True;
}
internal void ResolveOverloads<TMember>(
ImmutableArray<TMember> members,
ImmutableArray<TypeSymbol> typeArguments,
ImmutableArray<ArgumentSyntax> arguments,
OverloadResolutionResult<TMember> result,
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
bool allowRefOmittedArguments)
where TMember : Symbol
{
var methodsBuilder = ArrayBuilder<TMember>.GetInstance(members.Length);
methodsBuilder.AddRange(members);
var typeArgumentsBuilder = ArrayBuilder<TypeSymbol>.GetInstance(typeArguments.Length);
typeArgumentsBuilder.AddRange(typeArguments);
var analyzedArguments = AnalyzedArguments.GetInstance();
var unusedDiagnostics = DiagnosticBag.GetInstance();
foreach (var argumentSyntax in arguments)
{
BindArgumentAndName(analyzedArguments, unusedDiagnostics, false, argumentSyntax, allowArglist: false);
}
OverloadResolution.MethodOrPropertyOverloadResolution(
methodsBuilder,
typeArgumentsBuilder,
analyzedArguments,
result,
isMethodGroupConversion: false,
allowRefOmittedArguments: allowRefOmittedArguments,
useSiteDiagnostics: ref useSiteDiagnostics);
methodsBuilder.Free();
typeArgumentsBuilder.Free();
analyzedArguments.Free();
unusedDiagnostics.Free();
}
internal bool IsSymbolAccessibleConditional(
Symbol symbol,
AssemblySymbol within,
......
......@@ -252,17 +252,16 @@ private static bool OverloadResolutionResultIsValid<TMember>(ArrayBuilder<Member
// Also note that less derived members are not actually removed - they are simply flagged.
ReportUseSiteDiagnostics(results, ref useSiteDiagnostics);
// SPEC: If the resulting set of candidate methods is empty, then further processing along the following steps are abandoned,
// SPEC: and instead an attempt is made to process the invocation as an extension method invocation. If this fails, then no
// SPEC: applicable methods exist, and a binding-time error occurs.
// SPEC: If the resulting set of candidate methods is empty, then further processing along the following steps are abandoned,
// SPEC: and instead an attempt is made to process the invocation as an extension method invocation. If this fails, then no
// SPEC: applicable methods exist, and a binding-time error occurs.
if (RemainingCandidatesCount(results) == 0)
{
// UNDONE: Extension methods!
return;
}
// SPEC: The best method of the set of candidate methods is identified. If a single best method cannot be identified,
// SPEC: the method invocation is ambiguous, and a binding-time error occurs.
// SPEC: The best method of the set of candidate methods is identified. If a single best method cannot be identified,
// SPEC: the method invocation is ambiguous, and a binding-time error occurs.
RemoveWorseMembers(results, arguments, ref useSiteDiagnostics);
......@@ -494,7 +493,7 @@ private MemberAnalysisResult IsConstructorApplicableInExpandedForm(MethodSymbol
// Second, we need to determine if the method is applicable in its normal form or its expanded form.
var normalResult = (allowUnexpandedForm || !IsValidParams(leastOverriddenMember))
? IsMemberApplicableInNormalForm(member, leastOverriddenMember, typeArguments, arguments, isMethodGroupConversion, allowRefOmittedArguments, inferWithDynamic, ref useSiteDiagnostics)
? IsMemberApplicableInNormalForm(member, leastOverriddenMember, typeArguments, arguments, isMethodGroupConversion, allowRefOmittedArguments, inferWithDynamic, ref useSiteDiagnostics, completeResults: completeResults)
: default(MemberResolutionResult<TMember>);
var result = normalResult;
......@@ -2511,7 +2510,8 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
bool isMethodGroupConversion,
bool allowRefOmittedArguments,
bool inferWithDynamic,
ref HashSet<DiagnosticInfo> useSiteDiagnostics)
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
bool completeResults = false)
where TMember : Symbol
{
// AnalyzeArguments matches arguments to parameter names and positions.
......@@ -2519,7 +2519,13 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
var argumentAnalysis = AnalyzeArguments(member, arguments, isMethodGroupConversion, expanded: false);
if (!argumentAnalysis.IsValid)
{
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
// 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)
{
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
}
}
// Check after argument analysis, but before more complicated type inference and argument type validation.
......@@ -2552,12 +2558,21 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
// The member passed to the following call is returned in the result (possibly a constructed version of it).
// The applicability is checked based on effective parameters passed in.
return IsApplicable(
var applicableResult = IsApplicable(
member, leastOverriddenMember,
typeArguments, arguments, originalEffectiveParameters, constructedEffectiveParameters,
argumentAnalysis.ArgsToParamsOpt, hasAnyRefOmittedArgument,
ref useSiteDiagnostics,
inferWithDynamic);
// If we were producing complete results and had missing arguments, we pushed on in order to call IsApplicable for
// type inference and lambda binding. In that case we still need to return the argument mismatch failure here.
if (completeResults && !argumentAnalysis.IsValid)
{
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis));
}
return applicableResult;
}
private MemberResolutionResult<TMember> IsMemberApplicableInExpandedForm<TMember>(
......@@ -2802,7 +2817,17 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
// We add a "virtual parameter" for the __arglist.
int paramCount = parameters.ParameterTypes.Length + (isVararg ? 1 : 0);
Debug.Assert(paramCount == arguments.Arguments.Count);
if (arguments.Arguments.Count < paramCount)
{
// For improved error recovery, we perform type inference even when the argument
// list is of the wrong length. The caller is expected to detect and handle that,
// 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
......
......@@ -1768,8 +1768,7 @@ public class MyArgumentType
// (6,57): error CS1002: ; expected
// var handler = new MyDelegateType((s, e) => { e. });
Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(6, 57)
)
;
);
var tree = compilation.SyntaxTrees[0];
var sm = compilation.GetSemanticModel(tree);
var lambda = tree.GetCompilationUnitRoot().DescendantNodes().OfType<LambdaExpressionSyntax>().Single();
......@@ -1780,6 +1779,189 @@ public class MyArgumentType
Assert.Equal(TypeKind.Class, typeInfo.Type.TypeKind);
Assert.NotEmpty(typeInfo.Type.GetMembers("SomePublicMember"));
}
[Fact]
[WorkItem(11053, "https://github.com/dotnet/roslyn/issues/11053")]
[WorkItem(11358, "https://github.com/dotnet/roslyn/issues/11358")]
public void TestLambdaWithError07()
{
var source =
@"using System;
using System.Collections.Generic;
public static class Program
{
public static void Main()
{
var parameter = new List<string>();
var result = parameter.FirstOrDefault(x => x. );
}
}
public static class Enumerable
{
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
{
return default(TSource);
}
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource defaultValue)
{
return default(TSource);
}
}";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics(
// (9,55): error CS1001: Identifier expected
// var result = parameter.FirstOrDefault(x => x. );
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(9, 55)
);
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("x", 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"));
}
[Fact]
[WorkItem(11053, "https://github.com/dotnet/roslyn/issues/11053")]
[WorkItem(11358, "https://github.com/dotnet/roslyn/issues/11358")]
public void TestLambdaWithError08()
{
var source =
@"using System;
using System.Collections.Generic;
public static class Program
{
public static void Main()
{
var parameter = new List<string>();
var result = parameter.FirstOrDefault(x => x. );
}
}
public static class Enumerable
{
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, params TSource[] defaultValue)
{
return default(TSource);
}
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, params TSource[] defaultValue)
{
return default(TSource);
}
}";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics(
// (9,55): error CS1001: Identifier expected
// var result = parameter.FirstOrDefault(x => x. );
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(9, 55)
);
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("x", 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"));
}
[Fact]
[WorkItem(11053, "https://github.com/dotnet/roslyn/issues/11053")]
[WorkItem(11358, "https://github.com/dotnet/roslyn/issues/11358")]
public void TestLambdaWithError09()
{
var source =
@"using System;
public static class Program
{
public static void Main()
{
var parameter = new MyList<string>();
var result = parameter.FirstOrDefault(x => x. );
}
}
public class MyList<TSource>
{
public TSource FirstOrDefault(TSource defaultValue)
{
return default(TSource);
}
public TSource FirstOrDefault(Func<TSource, bool> predicate, TSource defaultValue)
{
return default(TSource);
}
}
";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics(
// (8,55): error CS1001: Identifier expected
// var result = parameter.FirstOrDefault(x => x. );
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(8, 55)
);
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("x", 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"));
}
[Fact]
[WorkItem(11053, "https://github.com/dotnet/roslyn/issues/11053")]
[WorkItem(11358, "https://github.com/dotnet/roslyn/issues/11358")]
public void TestLambdaWithError10()
{
var source =
@"using System;
public static class Program
{
public static void Main()
{
var parameter = new MyList<string>();
var result = parameter.FirstOrDefault(x => x. );
}
}
public class MyList<TSource>
{
public TSource FirstOrDefault(params TSource[] defaultValue)
{
return default(TSource);
}
public TSource FirstOrDefault(Func<TSource, bool> predicate, params TSource[] defaultValue)
{
return default(TSource);
}
}
";
var compilation = CreateCompilationWithMscorlibAndSystemCore(source).VerifyDiagnostics(
// (8,55): error CS1001: Identifier expected
// var result = parameter.FirstOrDefault(x => x. );
Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(8, 55)
);
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("x", 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.
先完成此消息的编辑!
想要评论请 注册