From 6af53ab981ead6e35f44cf39b1ae19e3089ea344 Mon Sep 17 00:00:00 2001 From: Samuel Arzt Date: Fri, 20 Oct 2017 21:00:21 +0200 Subject: [PATCH] [ILVerify] Instantiate generic constraints on initialization (#4758) * Implemented InstantiatedGenericParameter in order to be able to correctly cast constraints with generic parameter instantiations. * Added test case for casting constrained generic with generic parameter inside constraint. * Changed InstantiatedGenericParameter to be able to handle complex generic constraints. * Added GetInstantiatedGenericParameter to TypeSystemContext. * Changed generic type / method instantation to be created by InstantiatedGenericParameter. --- src/ILVerify/src/ILImporter.Verify.cs | 20 ++-- src/ILVerify/src/ILVerify.csproj | 1 + .../src/InstantiatedGenericParameter.cs | 96 +++++++++++++++++++ src/ILVerify/tests/ILTests/CastingTests.il | 24 +++++ 4 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 src/ILVerify/src/InstantiatedGenericParameter.cs diff --git a/src/ILVerify/src/ILImporter.Verify.cs b/src/ILVerify/src/ILImporter.Verify.cs index 41ce6434a..3ebc18f9b 100644 --- a/src/ILVerify/src/ILImporter.Verify.cs +++ b/src/ILVerify/src/ILImporter.Verify.cs @@ -40,7 +40,6 @@ namespace Internal.IL readonly MethodDesc _method; readonly MethodSignature _methodSignature; readonly TypeSystemContext _typeSystemContext; - readonly InstantiationContext _instantiationContext; readonly TypeDesc _thisType; @@ -154,16 +153,21 @@ namespace Internal.IL var instantiatedMethod = method; if (instantiatedType.HasInstantiation) { - instantiatedType = _typeSystemContext.GetInstantiatedType((MetadataType)instantiatedType, instantiatedType.Instantiation); + Instantiation genericTypeInstantiation = InstantiatedGenericParameter.CreateGenericTypeInstantiaton(instantiatedType.Instantiation); + instantiatedType = _typeSystemContext.GetInstantiatedType((MetadataType)instantiatedType, genericTypeInstantiation); instantiatedMethod = _typeSystemContext.GetMethodForInstantiatedType(instantiatedMethod.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedType); } if (instantiatedMethod.HasInstantiation) - instantiatedMethod = _typeSystemContext.GetInstantiatedMethod(instantiatedMethod, instantiatedMethod.Instantiation); + { + Instantiation genericMethodInstantiation = InstantiatedGenericParameter.CreateGenericMethodInstantiation( + instantiatedType.Instantiation, instantiatedMethod.Instantiation); + instantiatedMethod = _typeSystemContext.GetInstantiatedMethod(instantiatedMethod, genericMethodInstantiation); + } _method = instantiatedMethod; + _methodSignature = _method.Signature; _methodIL = method == instantiatedMethod ? methodIL : new InstantiatedMethodIL(instantiatedMethod, methodIL); - _instantiationContext = new InstantiationContext(instantiatedType.Instantiation, instantiatedMethod.Instantiation); // Determine this type if (!_method.Signature.IsStatic) @@ -1293,9 +1297,9 @@ again: } // Check any constraints on the callee's class and type parameters - if (!method.OwningType.CheckConstraints(_instantiationContext)) + if (!method.OwningType.CheckConstraints()) VerificationError(VerifierError.UnsatisfiedMethodParentInst, method.OwningType); - else if (!method.CheckConstraints(_instantiationContext)) + else if (!method.CheckConstraints()) VerificationError(VerifierError.UnsatisfiedMethodInst, method); Check(_method.OwningType.CanAccess(method, instance), VerifierError.MethodAccess); @@ -1404,9 +1408,9 @@ again: } // Check any constraints on the callee's class and type parameters - if (!method.OwningType.CheckConstraints(_instantiationContext)) + if (!method.OwningType.CheckConstraints()) VerificationError(VerifierError.UnsatisfiedMethodParentInst, method.OwningType); - else if (!method.CheckConstraints(_instantiationContext)) + else if (!method.CheckConstraints()) VerificationError(VerifierError.UnsatisfiedMethodInst, method); Check(_method.OwningType.CanAccess(method, instance), VerifierError.MethodAccess); diff --git a/src/ILVerify/src/ILVerify.csproj b/src/ILVerify/src/ILVerify.csproj index 615183886..73c0208a6 100644 --- a/src/ILVerify/src/ILVerify.csproj +++ b/src/ILVerify/src/ILVerify.csproj @@ -17,6 +17,7 @@ + diff --git a/src/ILVerify/src/InstantiatedGenericParameter.cs b/src/ILVerify/src/InstantiatedGenericParameter.cs new file mode 100644 index 000000000..a767de4fe --- /dev/null +++ b/src/ILVerify/src/InstantiatedGenericParameter.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Internal.TypeSystem +{ + internal sealed partial class InstantiatedGenericParameter : GenericParameterDesc + { + private readonly GenericParameterDesc _genericParam; + private Instantiation _typeInstantiation; + private Instantiation _methodInstantiation; + + public GenericParameterDesc GenericParameter + { + get + { + return _genericParam; + } + } + + internal static Instantiation CreateGenericTypeInstantiaton(Instantiation instantiation) + { + if (instantiation.Length == 0) + return instantiation; + + var genericInstantiation = CreateGenericInstantiation(instantiation); + + foreach (var parameter in genericInstantiation) + ((InstantiatedGenericParameter)parameter)._typeInstantiation = genericInstantiation; + + return genericInstantiation; + } + + internal static Instantiation CreateGenericMethodInstantiation(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + if (methodInstantiation.Length == 0) + return methodInstantiation; + + var genericInstantiation = CreateGenericInstantiation(methodInstantiation); + + foreach (var parameter in genericInstantiation) + { + var par = (InstantiatedGenericParameter)parameter; + par._typeInstantiation = typeInstantiation; + par._methodInstantiation = genericInstantiation; + } + + return genericInstantiation; + } + + private static Instantiation CreateGenericInstantiation(Instantiation fromInstantiation) + { + var parameters = new TypeDesc[fromInstantiation.Length]; + for (int i = 0; i < fromInstantiation.Length; ++i) + parameters[i] = new InstantiatedGenericParameter((GenericParameterDesc)fromInstantiation[i]); + + return new Instantiation(parameters); + } + + private InstantiatedGenericParameter(GenericParameterDesc genericParam) + { + Debug.Assert(!(genericParam is InstantiatedGenericParameter)); + _genericParam = genericParam; + } + + public override GenericParameterKind Kind => _genericParam.Kind; + + public override int Index => _genericParam.Index; + + public override TypeSystemContext Context => _genericParam.Context; + + public override GenericVariance Variance => _genericParam.Variance; + + public override GenericConstraints Constraints => _genericParam.Constraints; + + public override IEnumerable TypeConstraints + { + get + { + foreach (var constraint in _genericParam.TypeConstraints) + { + yield return constraint.InstantiateSignature(_typeInstantiation, _methodInstantiation); + } + } + } + + public override string ToString() + { + return _genericParam.ToString(); + } + } +} diff --git a/src/ILVerify/tests/ILTests/CastingTests.il b/src/ILVerify/tests/ILTests/CastingTests.il index 8387ea85f..4be6b764e 100644 --- a/src/ILVerify/tests/ILTests/CastingTests.il +++ b/src/ILVerify/tests/ILTests/CastingTests.il @@ -104,6 +104,30 @@ stloc.0 ret } + + .method static public hidebysig void Assign.ConstrainedGenericToComparable_Valid<(class [System.Runtime]System.IComparable`1) T>(!!T t) + { + .locals init ( + class [System.Runtime]System.IComparable`1 c + ) + + ldarg.0 + box !!T + stloc.0 + ret + } + + .method static public hidebysig void Assign.ComplexConstrainedGenericToComparable_Valid<(!!S) T, (class [System.Runtime]System.IComparable`1) S>(!!T t) + { + .locals init ( + class [System.Runtime]System.IComparable`1 c + ) + + ldarg.0 + box !!T + stloc.0 + ret + } } .class public sequential ansi sealed beforefieldinit GenericOtherFieldsType`1