|
4 | 4 | using System; |
5 | 5 | using System.Collections.Concurrent; |
6 | 6 | using System.Collections.Generic; |
| 7 | +using System.Diagnostics; |
7 | 8 | using System.Linq; |
8 | 9 | using System.Reflection; |
9 | 10 | using System.Text; |
@@ -133,6 +134,18 @@ Task<bool> ValidateTypeWorkerHelper(TypeDesc typeToCheckForSkipValidation) |
133 | 134 | AddTypeValidationError(type, $"Interface type {interfaceType} failed validation"); |
134 | 135 | return false; |
135 | 136 | } |
| 137 | + |
| 138 | + if (!interfaceType.IsInterface) |
| 139 | + { |
| 140 | + AddTypeValidationError(type, $"Runtime interface {interfaceType} is not an interface"); |
| 141 | + return false; |
| 142 | + } |
| 143 | + |
| 144 | + if (interfaceType.HasInstantiation) |
| 145 | + { |
| 146 | + // Interfaces behave covariantly |
| 147 | + ValidateVarianceInType(type.Instantiation, interfaceType, Internal.TypeSystem.GenericVariance.Covariant); |
| 148 | + } |
136 | 149 | } |
137 | 150 |
|
138 | 151 | // Validate that each interface type explicitly implemented on this type is accessible to this type -- UNIMPLEMENTED |
@@ -293,14 +306,76 @@ Task<bool> ValidateTypeWorkerHelper(TypeDesc typeToCheckForSkipValidation) |
293 | 306 | AddTypeValidationError(type, $"'{method}' is an runtime-impl generic method"); |
294 | 307 | return false; |
295 | 308 | } |
296 | | - // Validate that generic variance is properly respected in method signatures -- UNIMPLEMENTED |
297 | | - // Validate that there are no cyclical method constraints -- UNIMPLEMENTED |
| 309 | + |
| 310 | + |
| 311 | + // Validate that generic variance is properly respected in method signatures |
| 312 | + if (type.IsInterface && method.IsVirtual && !method.Signature.IsStatic && type.HasInstantiation) |
| 313 | + { |
| 314 | + if (!ValidateVarianceInSignature(type.Instantiation, method.Signature, Internal.TypeSystem.GenericVariance.Covariant, Internal.TypeSystem.GenericVariance.Contravariant)) |
| 315 | + { |
| 316 | + AddTypeValidationError(type, $"'{method}' has invalid variance in signature"); |
| 317 | + return false; |
| 318 | + } |
| 319 | + } |
| 320 | + |
| 321 | + foreach (var genericParameterType in method.Instantiation) |
| 322 | + { |
| 323 | + foreach (var constraint in ((GenericParameterDesc)genericParameterType).TypeConstraints) |
| 324 | + { |
| 325 | + if (!ValidateVarianceInType(type.Instantiation, constraint, Internal.TypeSystem.GenericVariance.Contravariant)) |
| 326 | + { |
| 327 | + AddTypeValidationError(type, $"'{method}' has invalid variance in generic parameter constraint {constraint} on type {genericParameterType}"); |
| 328 | + return false; |
| 329 | + } |
| 330 | + } |
| 331 | + } |
| 332 | + |
| 333 | + if (!BoundedCheckForInstantiation(method.Instantiation)) |
| 334 | + { |
| 335 | + AddTypeValidationError(type, $"'{method}' has cyclical generic parameter constraints"); |
| 336 | + return false; |
| 337 | + } |
298 | 338 | // Validate that constraints are all acccessible to the method using them -- UNIMPLEMENTED |
299 | 339 | } |
300 | 340 |
|
301 | 341 | // Generic class special rules |
302 | 342 | // Validate that a generic class cannot be a ComImport class, or a ComEventInterface class -- UNIMPLEMENTED |
303 | | - // Validate that there are no cyclical class or method constraints, and that constraints are all acccessible to the type using them -- UNIMPLEMENTED |
| 343 | + |
| 344 | + foreach (var genericParameterType in type.Instantiation) |
| 345 | + { |
| 346 | + foreach (var constraint in ((GenericParameterDesc)genericParameterType).TypeConstraints) |
| 347 | + { |
| 348 | + if (!ValidateVarianceInType(type.Instantiation, constraint, Internal.TypeSystem.GenericVariance.Contravariant)) |
| 349 | + { |
| 350 | + AddTypeValidationError(type, $"'{genericParameterType}' has invalid variance in generic parameter constraint {constraint}"); |
| 351 | + return false; |
| 352 | + } |
| 353 | + } |
| 354 | + } |
| 355 | + |
| 356 | + // Validate that generic variance is properly respected in interface signatures |
| 357 | + if (type.HasInstantiation && type.IsInterface) |
| 358 | + { |
| 359 | + foreach (var interfaceType in type.ExplicitlyImplementedInterfaces) |
| 360 | + { |
| 361 | + if (interfaceType.HasInstantiation) |
| 362 | + { |
| 363 | + // Interfaces behave covariantly |
| 364 | + if (!ValidateVarianceInType(type.Instantiation, interfaceType, Internal.TypeSystem.GenericVariance.Covariant)) |
| 365 | + { |
| 366 | + AddTypeValidationError(type, $"'{type}' has invalid variance in in interface impl of {interfaceType}"); |
| 367 | + return false; |
| 368 | + } |
| 369 | + } |
| 370 | + } |
| 371 | + } |
| 372 | + |
| 373 | + // Validate that there are no cyclical class or method constraints, and that constraints are all acccessible to the type using them |
| 374 | + if (!BoundedCheckForInstantiation(type.Instantiation)) |
| 375 | + { |
| 376 | + AddTypeValidationError(type, $"'{type}' has cyclical generic parameter constraints"); |
| 377 | + return false; |
| 378 | + } |
304 | 379 |
|
305 | 380 | // Override rules |
306 | 381 | // Validate that each override results does not violate accessibility rules -- UNIMPLEMENTED |
@@ -579,6 +654,114 @@ async Task<bool> ValidateTypeHelperFunctionPointerType(FunctionPointerType funct |
579 | 654 | } |
580 | 655 | return true; |
581 | 656 | } |
| 657 | + |
| 658 | + static bool BoundedCheckForInstantiation(Instantiation instantiation) |
| 659 | + { |
| 660 | + foreach (var type in instantiation) |
| 661 | + { |
| 662 | + Debug.Assert(type.IsGenericParameter); |
| 663 | + GenericParameterDesc genericParameter = (GenericParameterDesc)type; |
| 664 | + |
| 665 | + if (!BoundedCheckForType(genericParameter, instantiation.Length)) |
| 666 | + return false; |
| 667 | + } |
| 668 | + return true; |
| 669 | + } |
| 670 | + |
| 671 | + static bool BoundedCheckForType(GenericParameterDesc genericParameter, int maxDepth) |
| 672 | + { |
| 673 | + if (maxDepth <= 0) |
| 674 | + return false; |
| 675 | + foreach (var type in genericParameter.TypeConstraints) |
| 676 | + { |
| 677 | + if (type is GenericParameterDesc possiblyCircularGenericParameter) |
| 678 | + { |
| 679 | + if (possiblyCircularGenericParameter.Kind == genericParameter.Kind) |
| 680 | + { |
| 681 | + if (!BoundedCheckForType(possiblyCircularGenericParameter, maxDepth - 1)) |
| 682 | + return false; |
| 683 | + } |
| 684 | + } |
| 685 | + } |
| 686 | + return true; |
| 687 | + } |
| 688 | + |
| 689 | + static bool ValidateVarianceInSignature(Instantiation associatedTypeInstantiation, MethodSignature signature, Internal.TypeSystem.GenericVariance returnTypePosition, Internal.TypeSystem.GenericVariance argTypePosition) |
| 690 | + { |
| 691 | + for (int i = 0; i < signature.Length; i++) |
| 692 | + { |
| 693 | + if (!ValidateVarianceInType(associatedTypeInstantiation, signature[i], argTypePosition)) |
| 694 | + return false; |
| 695 | + } |
| 696 | + |
| 697 | + if (!ValidateVarianceInType(associatedTypeInstantiation, signature.ReturnType, returnTypePosition)) |
| 698 | + return false; |
| 699 | + |
| 700 | + return true; |
| 701 | + } |
| 702 | + |
| 703 | + static bool ValidateVarianceInType(Instantiation associatedTypeInstantiation, TypeDesc type, Internal.TypeSystem.GenericVariance position) |
| 704 | + { |
| 705 | + if (type is SignatureTypeVariable signatureTypeVar) |
| 706 | + { |
| 707 | + GenericParameterDesc gp = (GenericParameterDesc)associatedTypeInstantiation[signatureTypeVar.Index]; |
| 708 | + if (gp.Variance != Internal.TypeSystem.GenericVariance.None) |
| 709 | + { |
| 710 | + if (position != gp.Variance) |
| 711 | + { |
| 712 | + // Covariant and contravariant parameters can *only* appear in resp. covariant and contravariant positions |
| 713 | + return false; |
| 714 | + } |
| 715 | + } |
| 716 | + } |
| 717 | + else if (type is InstantiatedType instantiatedType) |
| 718 | + { |
| 719 | + var typeDef = instantiatedType.GetTypeDefinition(); |
| 720 | + if (typeDef.IsValueType || position == Internal.TypeSystem.GenericVariance.None) |
| 721 | + { |
| 722 | + // Value types and non-variant positions require all parameters to be non-variant |
| 723 | + foreach (TypeDesc instType in instantiatedType.Instantiation) |
| 724 | + { |
| 725 | + if (!ValidateVarianceInType(associatedTypeInstantiation, instType, Internal.TypeSystem.GenericVariance.None)) |
| 726 | + return false; |
| 727 | + } |
| 728 | + } |
| 729 | + else |
| 730 | + { |
| 731 | + int index = 0; |
| 732 | + for (index = 0; index < typeDef.Instantiation.Length; index++) |
| 733 | + { |
| 734 | + Internal.TypeSystem.GenericVariance positionForParameter = ((GenericParameterDesc)typeDef.Instantiation[index]).Variance; |
| 735 | + // If the surrounding context is contravariant then we need to flip the variance of this parameter |
| 736 | + if (position == Internal.TypeSystem.GenericVariance.Contravariant) |
| 737 | + { |
| 738 | + if (positionForParameter == Internal.TypeSystem.GenericVariance.Covariant) |
| 739 | + positionForParameter = Internal.TypeSystem.GenericVariance.Contravariant; |
| 740 | + else if (positionForParameter == Internal.TypeSystem.GenericVariance.Contravariant) |
| 741 | + positionForParameter = Internal.TypeSystem.GenericVariance.Covariant; |
| 742 | + else |
| 743 | + positionForParameter = Internal.TypeSystem.GenericVariance.None; |
| 744 | + } |
| 745 | + |
| 746 | + if (!ValidateVarianceInType(associatedTypeInstantiation, instantiatedType.Instantiation[index], positionForParameter)) |
| 747 | + return false; |
| 748 | + } |
| 749 | + } |
| 750 | + } |
| 751 | + else if (type is ParameterizedType parameterizedType) |
| 752 | + { |
| 753 | + // Arrays behave as covariant, byref and pointer types are non-variant |
| 754 | + if (!ValidateVarianceInType(associatedTypeInstantiation, parameterizedType.ParameterType, (parameterizedType.IsByRef || parameterizedType.IsPointer) ? Internal.TypeSystem.GenericVariance.None : position)) |
| 755 | + return false; |
| 756 | + } |
| 757 | + else if (type is FunctionPointerType functionPointerType) |
| 758 | + { |
| 759 | + if (!ValidateVarianceInSignature(associatedTypeInstantiation, functionPointerType.Signature, Internal.TypeSystem.GenericVariance.None, Internal.TypeSystem.GenericVariance.None)) |
| 760 | + return false; |
| 761 | + } |
| 762 | + |
| 763 | + return true; |
| 764 | + } |
582 | 765 | } |
583 | 766 | } |
584 | 767 | } |
0 commit comments