Browse Source

Fixed bugs regarding lambda type inference.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3017 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 18 years ago
parent
commit
94b6797bc1
  1. 8
      src/Libraries/NRefactory/Test/Parser/Expressions/LambdaExpressionTests.cs
  2. 14
      src/Main/Base/Test/GenericResolverTests.cs
  3. 30
      src/Main/Base/Test/OverloadFinding.cs
  4. 26
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/TypeInference.cs
  5. 5
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs
  6. 14
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/LambdaReturnType.cs
  7. 15
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs

8
src/Libraries/NRefactory/Test/Parser/Expressions/LambdaExpressionTests.cs

@ -65,5 +65,13 @@ namespace ICSharpCode.NRefactory.Tests.Ast @@ -65,5 +65,13 @@ namespace ICSharpCode.NRefactory.Tests.Ast
Assert.AreEqual("int", e.Parameters[0].TypeReference.Type);
Assert.IsTrue(e.StatementBody.Children[0] is ReturnStatement);
}
[Test]
public void LambdaExpressionContainingConditionalExpression()
{
LambdaExpression e = Parse("rr => rr != null ? rr.ResolvedType : null");
Assert.AreEqual("rr", e.Parameters[0].ParameterName);
Assert.IsTrue(e.ExpressionBody is ConditionalExpression);
}
}
}

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

@ -474,6 +474,20 @@ static class TestClass { @@ -474,6 +474,20 @@ static class TestClass {
Assert.AreEqual("System.Collections.Generic.IEnumerable{System.Int32}", mrr.ResolvedType.DotNetName);
}
[Test]
public void SelectWithImplicitlyTypedLambdaPassingGenericList()
{
MemberResolveResult mrr = ResolveInSelectProgram("Select(new List<string>(), s => s.Length)");
Assert.AreEqual("System.Collections.Generic.IEnumerable{System.Int32}", mrr.ResolvedType.DotNetName);
}
[Test]
public void SelectWithImplicitlyTypedLambdaPassingGenericDictionary()
{
MemberResolveResult mrr = ResolveInSelectProgram("Select(new Dictionary<double, string>(), s => s.Key)");
Assert.AreEqual("System.Collections.Generic.IEnumerable{System.Double}", mrr.ResolvedType.DotNetName);
}
[Test]
public void MultipleOverloadsWithDifferentParameterCounts()
{

30
src/Main/Base/Test/OverloadFinding.cs

@ -119,5 +119,35 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -119,5 +119,35 @@ namespace ICSharpCode.SharpDevelop.Tests
var mrr = nrrt.Resolve<MemberResolveResult>(program, "M(x=>x.ToUpper())", 3, 3, ExpressionContext.Default);
Assert.AreEqual("System.String", mrr.ResolvedType.DotNetName);
}
[Test]
public void MultipleOverloadsWithImplicitLambda2()
{
string program = @"class MainClass {
void Main() {
M(x=>x.Length);
}
delegate R Func<T, R>(T arg);
int M(Func<int, int> f){ /* whatever ... */ }
string M(Func<string, int> f){ /* whatever ... */ }
}";
var mrr = nrrt.Resolve<MemberResolveResult>(program, "M(x=>x.Length)", 3, 3, ExpressionContext.Default);
Assert.AreEqual("System.String", mrr.ResolvedType.DotNetName);
}
[Test]
public void MultipleOverloadsWithImplicitLambda3()
{
string program = @"class MainClass {
void Main() {
M(x=>x+x);
}
delegate R Func<T, R>(T arg);
string M(Func<string, int> f){ /* whatever ... */ }
int M(Func<int, int> f){ /* whatever ... */ }
}";
var mrr = nrrt.Resolve<MemberResolveResult>(program, "M(x=>x+x)", 3, 3, ExpressionContext.Default);
Assert.AreEqual("System.Int32", mrr.ResolvedType.DotNetName);
}
}
}

26
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/TypeInference.cs

@ -262,13 +262,10 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp @@ -262,13 +262,10 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp
IReturnType inferredReturnType;
if (amrt.HasParameterList && amrt.MethodParameters.Count == m.Parameters.Count) {
var inferredParameterTypes = m.Parameters.Select(p => SubstituteFixedTypes(p.ReturnType)).ToArray();
Log(" infer rt from lambda with parameters ", inferredParameterTypes);
inferredReturnType = amrt.ResolveReturnType(inferredParameterTypes);
} else {
Log(" infer rt from anonymous method");
inferredReturnType = amrt.ResolveReturnType();
}
Log(" inferred " + inferredReturnType);
MakeLowerBoundInference(inferredReturnType, m.ReturnType);
return;
@ -360,7 +357,7 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp @@ -360,7 +357,7 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp
}
/// <summary>
/// Make exact inference from U for V.
/// Make lower bound inference from U for V.
/// </summary>
void MakeLowerBoundInference(IReturnType U, IReturnType V)
{
@ -400,18 +397,17 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp @@ -400,18 +397,17 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp
// types U1…Uk such that a standard implicit conversion exists from U to C<U1…Uk>
// then an exact inference is made from each Ui for the corresponding Vi.
if (CV != null) {
// TODO: implement this rule
// For now, I'm just copying the exact inference code here
ConstructedReturnType CU = U.CastToConstructedReturnType();
if (CU != null && CV != null
&& object.Equals(CU.UnboundType, CV.UnboundType)
&& CU.TypeArgumentCount == CV.TypeArgumentCount)
{
for (int i = 0; i < CU.TypeArgumentCount; i++) {
MakeExactInference(CU.TypeArguments[i], CV.TypeArguments[i]);
foreach (IReturnType U2 in MemberLookupHelper.GetTypeInheritanceTree(U)) {
ConstructedReturnType CU2 = U2.CastToConstructedReturnType();
if (CU2 != null &&
object.Equals(CU2.UnboundType, CV.UnboundType) &&
CU2.TypeArgumentCount == CV.TypeArgumentCount)
{
for (int i = 0; i < CU2.TypeArgumentCount; i++) {
MakeExactInference(CU2.TypeArguments[i], CV.TypeArguments[i]);
}
return;
}
return;
}
}
}

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

@ -442,10 +442,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -442,10 +442,7 @@ namespace ICSharpCode.SharpDevelop.Dom
}
}
IReturnType rt = amrt.ResolveReturnType(method.Parameters.Select(p => p.ReturnType).ToArray());
if (rt == null)
return false;
return true;
return ConversionExistsInternal(rt, method.ReturnType, allowGenericTargetsOnThisMethod);
}
}

14
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/LambdaReturnType.cs

@ -81,6 +81,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver @@ -81,6 +81,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
return ResolveReturnType();
try {
MemberLookupHelper.Log("LambdaReturnType: SetImplicitLambdaParameterTypes ", parameterTypes);
resolver.SetImplicitLambdaParameterTypes(lambdaExpression, parameterTypes);
return ResolveReturnType();
} finally {
@ -90,11 +91,16 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver @@ -90,11 +91,16 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
public override IReturnType ResolveReturnType()
{
MemberLookupHelper.Log("LambdaReturnType: ResolveReturnType");
IReturnType result;
if (returnExpressions.Count == 0)
return resolver.ProjectContent.SystemTypes.Void;
return returnExpressions.Select(rt => resolver.ResolveInternal(rt, ExpressionContext.Default))
.Select(rr => rr != null ? rr.ResolvedType : null)
.Aggregate((rt1, rt2) => MemberLookupHelper.GetCommonType(resolver.ProjectContent, rt1, rt2));
result = resolver.ProjectContent.SystemTypes.Void;
else
result = returnExpressions.Select(rt => resolver.ResolveInternal(rt, ExpressionContext.Default))
.Select(rr => rr != null ? rr.ResolvedType : null)
.Aggregate((rt1, rt2) => MemberLookupHelper.GetCommonType(resolver.ProjectContent, rt1, rt2));
MemberLookupHelper.Log("LambdaReturnType: inferred " + result);
return result;
}
}
}

15
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs

@ -443,8 +443,19 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver @@ -443,8 +443,19 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
// ForEachStatement when the method in truncated in the middle.
// VB does not have the "inserted line looks like variable declaration"-problem
// anyways.
if (caretLine > startLine && caretLine < endLine)
endLine = caretLine;
// Fix removed because it causes problems with type inference for "variable" in these examples:
// - var variable = multilineInitializer;
// - foreach (var variable in multilineCollectionExpression)
// - var query = from variable in multilineExpression
// Also a bug (caused because we use caretLine=expression.StartLocation.Line, would be fixed
// with the cutoff at expression.EndLocation.Line):
// - any multiline expression that contains lambdas in lines after the first
// does not resolve if the expression's return type depends on the types
// of implicitly typed lambda parameters.
// if (caretLine > startLine && caretLine < endLine)
// endLine = caretLine;
}
int offset = 0;

Loading…
Cancel
Save