Browse Source

Fixed inferring type argument for a method with an IEnumerable<T> parameter when an array is passed to the method. (backported from 3.0.0.2506)

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/2.1@2510 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
ad7a0b1646
  1. 3
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/TextUtilities.cs
  2. 37
      src/Main/Base/Test/GenericResolverTests.cs
  3. 2
      src/Main/Base/Test/Services_Navigation/NavigationServiceTestFixture.cs
  4. 21
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs

3
src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/TextUtilities.cs

@ -146,6 +146,9 @@ namespace ICSharpCode.TextEditor.Document
//// id. is typed on next line after comment one //// id. is typed on next line after comment one
//// Would be better if lexer would parse properly such expressions. However this will cause //// Would be better if lexer would parse properly such expressions. However this will cause
//// modifications in this area too - to get full comment line and remove it afterwards //// modifications in this area too - to get full comment line and remove it afterwards
if (offset < 0)
return string.Empty;
string resText=document.GetText(offset, textArea.Caret.Offset - offset ).Trim(); string resText=document.GetText(offset, textArea.Caret.Offset - offset ).Trim();
int pos=resText.LastIndexOf('\n'); int pos=resText.LastIndexOf('\n');
if (pos>=0) { if (pos>=0) {

37
src/Main/Base/Test/GenericResolverTests.cs

@ -22,6 +22,11 @@ namespace ICSharpCode.SharpDevelop.Tests
return nrrt.Resolve(program, expression, line); return nrrt.Resolve(program, expression, line);
} }
RR Resolve<RR>(string program, string expression, int line) where RR : ResolveResult
{
return nrrt.Resolve<RR>(program, expression, line);
}
ResolveResult ResolveVB(string program, string expression, int line) ResolveResult ResolveVB(string program, string expression, int line)
{ {
return nrrt.ResolveVB(program, expression, line); return nrrt.ResolveVB(program, expression, line);
@ -167,7 +172,7 @@ class DerivedClass : BaseClass<string> {
Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName); Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName);
} }
[Test] [Test]
public void CrossTypeParametersInheritance() public void CrossTypeParametersInheritance()
{ {
string program = @"using System; string program = @"using System;
@ -251,5 +256,35 @@ public class GenericClass<T> where T : IDisposable {
Assert.IsTrue(rr.ResolvedType is GenericReturnType); Assert.IsTrue(rr.ResolvedType is GenericReturnType);
} }
#endregion #endregion
#region Generic methods
[Test]
public void GenericMethodInstanciation()
{
string program = @"using System;
using System.Collections.Generic;
class TestClass {
void Main() {
}
static T First<T>(IEnumerable<T> input) {
foreach (T e in input) return e;
throw new EmptyCollectionException();
}
}
";
MemberResolveResult mrr = Resolve<MemberResolveResult>(program, "First(new string[0])", 5);
Assert.AreEqual("System.String", mrr.ResolvedType.FullyQualifiedName);
Assert.AreEqual("System.String", mrr.ResolvedMember.ReturnType.FullyQualifiedName);
IMethod genericMethod = mrr.ResolvedMember.DeclaringType.Methods[1];
Assert.AreEqual("T", genericMethod.ReturnType.FullyQualifiedName);
// ensure that the reference pointing to the specialized method is seen as a reference
// to the generic method.
// Fixing this requires changing the IMember interface: won't fix for 2.x
//Assert.IsTrue(Refactoring.RefactoringService.IsReferenceToMember(genericMethod, mrr));
}
#endregion
} }
} }

2
src/Main/Base/Test/Services_Navigation/NavigationServiceTestFixture.cs

@ -535,6 +535,7 @@ namespace NavigationServiceTests
Assert.AreEqual(r, NavigationService.CurrentPosition); Assert.AreEqual(r, NavigationService.CurrentPosition);
} }
/*
[Test] [Test]
[Ignore] // this test disabled on purpose - DA [Ignore] // this test disabled on purpose - DA
/// <summary> /// <summary>
@ -571,6 +572,7 @@ namespace NavigationServiceTests
Assert.IsTrue(NavigationService.CanNavigateBack); Assert.IsTrue(NavigationService.CanNavigateBack);
Assert.IsTrue(NavigationService.CanNavigateForwards); Assert.IsTrue(NavigationService.CanNavigateForwards);
} }
*/
[Test] [Test]
/// <summary> /// <summary>

21
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs

@ -397,20 +397,25 @@ namespace ICSharpCode.SharpDevelop.Dom
/// Returns false when expectedArgument and passedArgument are incompatible, otherwise true /// Returns false when expectedArgument and passedArgument are incompatible, otherwise true
/// is returned (true is used both for successful inferring and other kind of errors). /// is returned (true is used both for successful inferring and other kind of errors).
/// </summary> /// </summary>
/// <remarks>
/// The C# spec (§ 25.6.4) has a bug: it says that type inference works if the passedArgument is IEnumerable{T}
/// and the expectedArgument is an array; passedArgument and expectedArgument must be swapped here.
/// </remarks>
public static bool InferTypeArgument(IReturnType expectedArgument, IReturnType passedArgument, IReturnType[] outputArray) public static bool InferTypeArgument(IReturnType expectedArgument, IReturnType passedArgument, IReturnType[] outputArray)
{ {
if (expectedArgument == null) return true; if (expectedArgument == null) return true;
if (passedArgument == null) return true; // TODO: NullTypeReference if (passedArgument == null || passedArgument == NullReturnType.Instance) return true;
if (expectedArgument.IsArrayReturnType) {
IReturnType expectedArrayElementType = expectedArgument.CastToArrayReturnType().ArrayElementType; if (passedArgument.IsArrayReturnType) {
if (passedArgument.IsArrayReturnType && expectedArgument.CastToArrayReturnType().ArrayDimensions == passedArgument.CastToArrayReturnType().ArrayDimensions) { IReturnType passedArrayElementType = passedArgument.CastToArrayReturnType().ArrayElementType;
return InferTypeArgument(expectedArrayElementType, passedArgument.CastToArrayReturnType().ArrayElementType, outputArray); if (expectedArgument.IsArrayReturnType && expectedArgument.CastToArrayReturnType().ArrayDimensions == passedArgument.CastToArrayReturnType().ArrayDimensions) {
} else if (passedArgument.IsConstructedReturnType) { return InferTypeArgument(expectedArgument.CastToArrayReturnType().ArrayElementType, passedArrayElementType, outputArray);
switch (passedArgument.FullyQualifiedName) { } else if (expectedArgument.IsConstructedReturnType) {
switch (expectedArgument.FullyQualifiedName) {
case "System.Collections.Generic.IList": case "System.Collections.Generic.IList":
case "System.Collections.Generic.ICollection": case "System.Collections.Generic.ICollection":
case "System.Collections.Generic.IEnumerable": case "System.Collections.Generic.IEnumerable":
return InferTypeArgument(expectedArrayElementType, passedArgument.CastToConstructedReturnType().TypeArguments[0], outputArray); return InferTypeArgument(expectedArgument.CastToConstructedReturnType().TypeArguments[0], passedArrayElementType, outputArray);
} }
} }
// If P is an array type, and A is not an array type of the same rank, // If P is an array type, and A is not an array type of the same rank,

Loading…
Cancel
Save