private ImmutableArray <TypeWithAnnotations> GetDeclaredConstraintTypes(ConsList <PETypeParameterSymbol> inProgress) { Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); if (_lazyDeclaredConstraintTypes.IsDefault) { ImmutableArray <TypeWithAnnotations> declaredConstraintTypes; var moduleSymbol = ((PEModuleSymbol)this.ContainingModule); PEModule peModule = moduleSymbol.Module; GenericParameterConstraintHandleCollection constraints = GetConstraintHandleCollection(peModule); bool hasUnmanagedModreqPattern = false; if (constraints.Count > 0) { var symbolsBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); MetadataDecoder tokenDecoder = GetDecoder(moduleSymbol); TypeWithAnnotations bestObjectConstraint = default; var metadataReader = peModule.MetadataReader; foreach (var constraintHandle in constraints) { TypeWithAnnotations type = GetConstraintTypeOrDefault(moduleSymbol, metadataReader, tokenDecoder, constraintHandle, ref hasUnmanagedModreqPattern); if (!type.HasType) { // Dropped 'System.ValueType' constraint type when the 'valuetype' constraint was also specified. continue; } // Drop 'System.Object' constraint type. if (ConstraintsHelper.IsObjectConstraint(type, ref bestObjectConstraint)) { continue; } symbolsBuilder.Add(type); } if (bestObjectConstraint.HasType) { // See if we need to put Object! or Object~ back in order to preserve nullability information for the type parameter. if (ConstraintsHelper.IsObjectConstraintSignificant(CalculateIsNotNullableFromNonTypeConstraints(), bestObjectConstraint)) { Debug.Assert(!HasNotNullConstraint && !HasValueTypeConstraint); if (symbolsBuilder.Count == 0) { if (bestObjectConstraint.NullableAnnotation.IsOblivious() && !HasReferenceTypeConstraint) { bestObjectConstraint = default; } } else { inProgress = inProgress.Prepend(this); foreach (TypeWithAnnotations constraintType in symbolsBuilder) { if (!ConstraintsHelper.IsObjectConstraintSignificant(IsNotNullableFromConstraintType(constraintType, inProgress, out _), bestObjectConstraint)) { bestObjectConstraint = default; break; } } } if (bestObjectConstraint.HasType) { symbolsBuilder.Insert(0, bestObjectConstraint); } } } declaredConstraintTypes = symbolsBuilder.ToImmutableAndFree(); } else { declaredConstraintTypes = ImmutableArray <TypeWithAnnotations> .Empty; } // - presence of unmanaged pattern has to be matched with `valuetype` // - IsUnmanagedAttribute is allowed iff there is an unmanaged pattern if (hasUnmanagedModreqPattern && (_flags & GenericParameterAttributes.NotNullableValueTypeConstraint) == 0 || hasUnmanagedModreqPattern != peModule.HasIsUnmanagedAttribute(_handle)) { // we do not recognize these combinations as "unmanaged" hasUnmanagedModreqPattern = false; _lazyCachedConstraintsUseSiteInfo.InterlockedCompareExchange(primaryDependency: null, new UseSiteInfo <AssemblySymbol>(new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, this))); } _lazyHasIsUnmanagedConstraint = hasUnmanagedModreqPattern.ToThreeState(); ImmutableInterlocked.InterlockedInitialize(ref _lazyDeclaredConstraintTypes, declaredConstraintTypes); } return(_lazyDeclaredConstraintTypes); }
private ImmutableArray <TypeWithAnnotations> GetDeclaredConstraintTypes() { if (_lazyDeclaredConstraintTypes.IsDefault) { ImmutableArray <TypeWithAnnotations> declaredConstraintTypes; PEMethodSymbol containingMethod = null; PENamedTypeSymbol containingType; if (_containingSymbol.Kind == SymbolKind.Method) { containingMethod = (PEMethodSymbol)_containingSymbol; containingType = (PENamedTypeSymbol)containingMethod.ContainingSymbol; } else { containingType = (PENamedTypeSymbol)_containingSymbol; } var moduleSymbol = containingType.ContainingPEModule; PEModule peModule = moduleSymbol.Module; GenericParameterConstraintHandleCollection constraints = GetConstraintHandleCollection(peModule); bool hasUnmanagedModreqPattern = false; if (constraints.Count > 0) { var symbolsBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); MetadataDecoder tokenDecoder; if ((object)containingMethod != null) { tokenDecoder = new MetadataDecoder(moduleSymbol, containingMethod); } else { tokenDecoder = new MetadataDecoder(moduleSymbol, containingType); } var metadataReader = peModule.MetadataReader; foreach (var constraintHandle in constraints) { var constraint = metadataReader.GetGenericParameterConstraint(constraintHandle); var typeSymbol = tokenDecoder.DecodeGenericParameterConstraint(constraint.Type, out bool hasUnmanagedModreq); if (typeSymbol.SpecialType == SpecialType.System_ValueType) { // recognize "(class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType" pattern as "unmanaged" if (hasUnmanagedModreq) { hasUnmanagedModreqPattern = true; } // Drop 'System.ValueType' constraint type if the 'valuetype' constraint was also specified. if (((_flags & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)) { continue; } } var type = TypeWithAnnotations.Create(typeSymbol); type = NullableTypeDecoder.TransformType(type, constraintHandle, moduleSymbol); // Drop 'System.Object?' constraint type. if (type.SpecialType == SpecialType.System_Object && type.NullableAnnotation.IsAnnotated()) { continue; } type = TupleTypeDecoder.DecodeTupleTypesIfApplicable(type, constraintHandle, moduleSymbol); symbolsBuilder.Add(type); } declaredConstraintTypes = symbolsBuilder.ToImmutableAndFree(); } else { declaredConstraintTypes = ImmutableArray <TypeWithAnnotations> .Empty; } // - presence of unmanaged pattern has to be matched with `valuetype` // - IsUnmanagedAttribute is allowed iif there is an unmanaged pattern if (hasUnmanagedModreqPattern && (_flags & GenericParameterAttributes.NotNullableValueTypeConstraint) == 0 || hasUnmanagedModreqPattern != peModule.HasIsUnmanagedAttribute(_handle)) { // we do not recognize these combinations as "unmanaged" hasUnmanagedModreqPattern = false; Interlocked.CompareExchange(ref _lazyConstraintsUseSiteErrorInfo, new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, this), CSDiagnosticInfo.EmptyErrorInfo); } _lazyHasIsUnmanagedConstraint = hasUnmanagedModreqPattern.ToThreeState(); ImmutableInterlocked.InterlockedInitialize(ref _lazyDeclaredConstraintTypes, declaredConstraintTypes); } return(_lazyDeclaredConstraintTypes); }