Browse Source

Fix #2806: Do not use implicitly typed out variables, if argument and parameter types do not match exactly.

pull/2828/head
Siegfried Pammer 3 years ago
parent
commit
bde782e4f5
  1. 29
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/OutVariables.cs
  2. 22
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 6
      ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolutionErrors.cs
  4. 13
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  5. 7
      ICSharpCode.Decompiler/Semantics/OutVarResolveResult.cs
  6. 9
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

29
ICSharpCode.Decompiler.Tests/TestCases/Pretty/OutVariables.cs

@ -43,5 +43,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -43,5 +43,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
return null;
}
private bool TryGet<T>(out T result)
{
result = default(T);
return true;
}
public void M3()
{
TryGet<Dictionary<int, (int, string)>>(out Dictionary<int, (int A, string B)> data);
Test();
int Test()
{
return data[0].A;
}
}
public void GetObject(out object obj)
{
obj = null;
}
public void M4()
{
GetObject(out dynamic obj);
obj.Method();
}
}
}

22
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -77,8 +77,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -77,8 +77,8 @@ namespace ICSharpCode.Decompiler.CSharp
ResolveResult GetResolveResult(int index, TranslatedExpression expression)
{
var param = expectedParameters[index];
if (useImplicitlyTypedOut && param.IsOut)
return OutVarResolveResult.Instance;
if (useImplicitlyTypedOut && param.IsOut && expression.Type is ByReferenceType brt)
return new OutVarResolveResult(brt.ElementType);
return expression.ResolveResult;
}
}
@ -1017,6 +1017,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1017,6 +1017,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
switch (errors)
{
case OverloadResolutionErrors.OutVarTypeMismatch:
Debug.Assert(argumentList.UseImplicitlyTypedOut);
argumentList.UseImplicitlyTypedOut = false;
continue;
case OverloadResolutionErrors.TypeInferenceFailed:
if ((allowedTransforms & CallTransformation.RequireTypeArguments) != 0)
{
@ -1318,6 +1322,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1318,6 +1322,20 @@ namespace ICSharpCode.Decompiler.CSharp
foundMember = or.GetBestCandidateWithSubstitutedTypeArguments();
if (!IsAppropriateCallTarget(expectedTargetDetails, method, foundMember))
return OverloadResolutionErrors.AmbiguousMatch;
var map = or.GetArgumentToParameterMap();
for (int i = 0; i < arguments.Length; i++)
{
ResolveResult arg = arguments[i];
int parameterIndex = map[i];
if (arg is OutVarResolveResult rr && parameterIndex >= 0)
{
var param = foundMember.Parameters[parameterIndex];
var paramType = param.Type.UnwrapByRef();
if (!paramType.Equals(rr.OriginalVariableType))
return OverloadResolutionErrors.OutVarTypeMismatch;
}
}
return OverloadResolutionErrors.None;
}

6
ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolutionErrors.cs

@ -82,6 +82,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -82,6 +82,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// <remarks>
/// This error does not prevent a candidate from being applicable.
/// </remarks>
MethodConstraintsNotSatisfied = 0x0800
MethodConstraintsNotSatisfied = 0x0800,
/// <summary>
/// Using 'out var' instead of 'out T' would result in loss of type information.
/// </summary>
OutVarTypeMismatch = 0x1000,
}
}

13
ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

@ -493,7 +493,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -493,7 +493,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (targetMethod.TypeParameters.Count > 0)
{
var lastParams = targetMethod.Parameters.Where(p => IsClosureParameter(p, this.resolveContext)).SelectMany(p => UnwrapByRef(p.Type).TypeArguments)
var lastParams = targetMethod.Parameters.Where(p => IsClosureParameter(p, this.resolveContext)).SelectMany(p => p.Type.UnwrapByRef().TypeArguments)
.Select(pt => (int?)targetMethod.TypeParameters.IndexOf(pt)).DefaultIfEmpty().Max();
if (lastParams != null && lastParams.GetValueOrDefault() + 1 > skipCount)
skipCount = lastParams.GetValueOrDefault() + 1;
@ -564,15 +564,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -564,15 +564,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
&& TransformDisplayClassUsage.IsPotentialClosure(context.CurrentTypeDefinition, type);
}
static IType UnwrapByRef(IType type)
{
if (type is ByReferenceType byRef)
{
type = byRef.ElementType;
}
return type;
}
internal static ILInstruction GetStatement(ILInstruction inst)
{
while (inst.Parent != null)
@ -733,7 +724,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -733,7 +724,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction GetClosureInitializer(ILVariable variable)
{
var type = UnwrapByRef(variable.Type).GetDefinition();
var type = variable.Type.UnwrapByRef().GetDefinition();
if (type == null)
return null;
if (variable.Kind == VariableKind.Parameter)

7
ICSharpCode.Decompiler/Semantics/OutVarResolveResult.cs

@ -26,8 +26,11 @@ namespace ICSharpCode.Decompiler.Semantics @@ -26,8 +26,11 @@ namespace ICSharpCode.Decompiler.Semantics
/// </summary>
class OutVarResolveResult : ResolveResult
{
public static readonly OutVarResolveResult Instance = new OutVarResolveResult();
/// <summary>
/// Type of the variable originally used in IL. It will be used, if "out var" cannot be used.
/// </summary>
public readonly IType OriginalVariableType;
public OutVarResolveResult() : base(SpecialType.NoType) { }
public OutVarResolveResult(IType originalVariableType) : base(SpecialType.NoType) { OriginalVariableType = originalVariableType; }
}
}

9
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -374,6 +374,15 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -374,6 +374,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
return ty;
}
public static IType UnwrapByRef(this IType type)
{
if (type is ByReferenceType byRef)
{
type = byRef.ElementType;
}
return type;
}
public static bool HasReadonlyModifier(this IMethod accessor)
{
return accessor.ThisIsRefReadOnly && accessor.DeclaringTypeDefinition?.IsReadOnly == false;

Loading…
Cancel
Save