提交 fdb1cfd4 编写于 作者: A AlekseyTs

Adjust constraints check for reduced extension methods to avoid failures for...

Adjust constraints check for reduced extension methods to avoid failures for type parameters that couldn’t be inferred from the first argument.

Fixes #2288.
上级 860fa08f
......@@ -2575,18 +2575,12 @@ private bool InferTypeArgumentsFromFirstArgument(ref HashSet<DiagnosticInfo> use
}
/// <summary>
/// Return the inferred type arguments using the original type
/// parameters for any type arguments that were not inferred.
/// Return the inferred type arguments using null
/// for any type arguments that were not inferred.
/// </summary>
private ImmutableArray<TypeSymbol> GetInferredTypeArguments()
{
var typeArgs = ArrayBuilder<TypeSymbol>.GetInstance();
for (int i = 0; i < _methodTypeParameters.Length; i++)
{
var typeArg = _fixedResults[i] ?? _methodTypeParameters[i];
typeArgs.Add(typeArg);
}
return typeArgs.ToImmutableAndFree();
return _fixedResults.AsImmutable();
}
private static bool IsReallyAType(TypeSymbol type)
......
......@@ -73,12 +73,35 @@ public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol m
return null;
}
int firstNullInTypeArgs = -1;
// For the purpose of constraint checks we use error type symbol in place of type arguments that we couldn't infer from the first argument.
// This prevents constraint checking from failing for corresponding type parameters.
var typeArgsForConstraintsCheck = typeArgs;
for (int i = 0; i < typeArgsForConstraintsCheck.Length; i++)
{
if ((object)typeArgsForConstraintsCheck[i] == null)
{
firstNullInTypeArgs = i;
var builder = ArrayBuilder<TypeSymbol>.GetInstance();
builder.AddRange(typeArgs, firstNullInTypeArgs);
for (; i < typeArgsForConstraintsCheck.Length; i++)
{
builder.Add(typeArgsForConstraintsCheck[i] ?? ErrorTypeSymbol.UnknownResultType);
}
typeArgsForConstraintsCheck = builder.ToImmutableAndFree();
break;
}
}
// Check constraints.
var diagnosticsBuilder = ArrayBuilder<TypeParameterDiagnosticInfo>.GetInstance();
var typeParams = method.TypeParameters;
var substitution = new TypeMap(typeParams, typeArgs);
var substitution = new TypeMap(typeParams, typeArgsForConstraintsCheck);
ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null;
var success = method.CheckConstraints(conversions, substitution, method.TypeParameters, typeArgs, compilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder);
var success = method.CheckConstraints(conversions, substitution, typeParams, typeArgsForConstraintsCheck, compilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder);
diagnosticsBuilder.Free();
if (useSiteDiagnosticsBuilder != null && useSiteDiagnosticsBuilder.Count > 0)
......@@ -99,7 +122,22 @@ public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol m
return null;
}
return method.Construct(typeArgs);
// For the purpose of construction we use original type parameters in place of type arguments that we couldn't infer from the first argument.
var typeArgsForConstruct = typeArgs;
if (firstNullInTypeArgs != -1)
{
var builder = ArrayBuilder<TypeSymbol>.GetInstance();
builder.AddRange(typeArgs, firstNullInTypeArgs);
for (int i = firstNullInTypeArgs; i < typeArgsForConstruct.Length; i++)
{
builder.Add(typeArgsForConstruct[i] ?? typeParams[i]);
}
typeArgsForConstruct = builder.ToImmutableAndFree();
}
return method.Construct(typeArgsForConstruct);
}
internal static bool IsSynthesizedLambda(this MethodSymbol method)
......
......@@ -3615,5 +3615,54 @@ public static void Foo(this int x)
// using X = N.S;
Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using X = N.S;").WithLocation(4, 5));
}
[WorkItem(1094849, "DevDiv"), WorkItem(2288, "https://github.com/dotnet/roslyn/issues/2288")]
[Fact]
public void LookupSymbolsWithPartialInference()
{
var source =
@"
using System.Collections.Generic;
namespace ConsoleApplication22
{
static class Program
{
static void Main(string[] args)
{
}
internal static void GetEnumerableDisposable1<T, TEnumerator>(this IEnumerable<T> enumerable)
where TEnumerator : struct , IEnumerator<T>
{
}
internal static void GetEnumerableDisposable2<T, TEnumerator>(this IEnumerable<T> enumerable)
where TEnumerator : struct
{
}
private static void Overlaps<T, TEnumerator>(IEnumerable<T> other) where TEnumerator : struct, IEnumerator<T>
{
other.GetEnumerableDisposable1<T, TEnumerator>();
}
}
}";
var compilation = CreateCompilationWithMscorlib(source, new[] { SystemCoreRef });
compilation.VerifyDiagnostics();
var syntaxTree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(syntaxTree);
var member = (MemberAccessExpressionSyntax)syntaxTree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single().Expression;
Assert.Equal("other.GetEnumerableDisposable1<T, TEnumerator>", member.ToString());
var type = model.GetTypeInfo(member.Expression).Type;
Assert.Equal("System.Collections.Generic.IEnumerable<T>", type.ToTestDisplayString());
var symbols = model.LookupSymbols(member.Expression.EndPosition, type, includeReducedExtensionMethods: true).Select(s => s.Name).ToArray();
Assert.Contains("GetEnumerableDisposable2", symbols);
Assert.Contains("GetEnumerableDisposable1", symbols);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册