From 8d2116dea77ce5387dd0f2a5b4007dd0bc30bf87 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 25 Nov 2016 21:43:10 +0100 Subject: [PATCH] Fix casts to type parameters. --- .../CSharp/ExpressionBuilder.cs | 15 +++++++++++++-- .../IL/Transforms/DelegateConstruction.cs | 2 +- .../Tests/TestCases/Correctness/Generics.cs | 13 +++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index ae2be27ad..74198effd 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1307,9 +1307,20 @@ namespace ICSharpCode.Decompiler.CSharp // ensure we treat the input as a reference type arg = arg.ConvertTo(compilation.FindType(KnownTypeCode.Object), this); } - return new CastExpression(ConvertType(inst.Type), arg.Expression) + + IType targetType = inst.Type; + if (targetType.Kind == TypeKind.TypeParameter) { + var rr = resolver.ResolveCast(targetType, arg.ResolveResult); + if (rr.IsError) { + // C# 6.2.7 Explicit conversions involving type parameters: + // if we can't directly convert to a type parameter, + // try via its effective base class. + arg = arg.ConvertTo(((ITypeParameter)targetType).EffectiveBaseClass, this); + } + } + return new CastExpression(ConvertType(targetType), arg.Expression) .WithILInstruction(inst) - .WithRR(new ConversionResolveResult(inst.Type, arg.ResolveResult, Conversion.UnboxingConversion)); + .WithRR(new ConversionResolveResult(targetType, arg.ResolveResult, Conversion.UnboxingConversion)); } protected internal override TranslatedExpression VisitUnbox(Unbox inst, TranslationContext context) diff --git a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs index a90d5c2b4..b31b6afd7 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs @@ -248,7 +248,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } else { ILInstruction value; ILVariable v; - if (inst.Value.MatchLdLoc(out v)) { + if (inst.Value.MatchLdLoc(out v) && v.Kind != VariableKind.PinnedLocal) { orphanedVariableInits.Add(inst); value = inst.Value; } else { diff --git a/ICSharpCode.Decompiler/Tests/TestCases/Correctness/Generics.cs b/ICSharpCode.Decompiler/Tests/TestCases/Correctness/Generics.cs index c8231e35b..cb251deca 100644 --- a/ICSharpCode.Decompiler/Tests/TestCases/Correctness/Generics.cs +++ b/ICSharpCode.Decompiler/Tests/TestCases/Correctness/Generics.cs @@ -47,6 +47,11 @@ namespace Generics { Console.WriteLine(typeof(T1) + " " + typeof(T2)); } + + public T CastToTypeParameter(DerivedClass d) where T: BaseClass + { + return (T)(BaseClass)d; + } } class GenericClass @@ -56,4 +61,12 @@ namespace Generics self = this; } } + + public class BaseClass + { + } + + public class DerivedClass : BaseClass + { + } }