private static bool VerifyGenericParamConstraint(InstantiationContext genericParamContext, GenericParameterDesc genericParam, InstantiationContext instantiationParamContext, TypeDesc instantiationParam) { GenericConstraints constraints = genericParam.Constraints; // Check class constraint if ((constraints & GenericConstraints.ReferenceTypeConstraint) != 0) { if (!instantiationParam.IsGCPointer && !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.ReferenceTypeConstraint)) { return(false); } } // Check default constructor constraint if ((constraints & GenericConstraints.DefaultConstructorConstraint) != 0) { if (!instantiationParam.HasExplicitOrImplicitDefaultConstructor() && !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.DefaultConstructorConstraint)) { return(false); } } // Check struct constraint if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { if ((!instantiationParam.IsValueType || instantiationParam.IsNullable) && !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.NotNullableValueTypeConstraint)) { return(false); } } var instantiatedConstraints = new ArrayBuilder <TypeDesc>(); GetInstantiatedConstraintsRecursive(instantiationParamContext, instantiationParam, ref instantiatedConstraints); foreach (var constraintType in genericParam.TypeConstraints) { var instantiatedType = constraintType.InstantiateSignature(genericParamContext.TypeInstantiation, genericParamContext.MethodInstantiation); if (CanCastConstraint(ref instantiatedConstraints, instantiatedType)) { continue; } if (!instantiationParam.CanCastTo(instantiatedType)) { return(false); } } return(true); }
public override AstNode?VisitTypeParamConstraintList(TypeParamConstraintListContext context) { foreach (var constraintContext in context.typeParamConstraint()) { if (Visit(constraintContext) is GenericConstraint constraint) { _currentMessage !.GenericConstraints.Add(constraint); } } return(null); }
private static bool VerifyGenericParamConstraint(Instantiation typeInstantiation, Instantiation methodInstantiation, GenericParameterDesc genericParam, TypeDesc instantiationParam) { GenericConstraints constraints = genericParam.Constraints; // Check class constraint if ((constraints & GenericConstraints.ReferenceTypeConstraint) != 0) { if (!instantiationParam.IsGCPointer) { return(false); } } // Check default constructor constraint if ((constraints & GenericConstraints.DefaultConstructorConstraint) != 0) { if (!instantiationParam.HasExplicitOrImplicitDefaultConstructor()) { return(false); } } // Check struct constraint if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { if (!instantiationParam.IsValueType) { return(false); } if (instantiationParam.IsNullable) { return(false); } } foreach (var constraintType in genericParam.TypeConstraints) { var instantiatedType = constraintType.InstantiateSignature(typeInstantiation, methodInstantiation); if (!instantiationParam.CanCastTo(instantiatedType)) { return(false); } } return(true); }
private static TypeDesc GetTypeThatMeetsConstraints(GenericParameterDesc genericParam) { TypeSystemContext context = genericParam.Context; // Universal canon is the best option if it's supported if (context.SupportsUniversalCanon) { return(context.UniversalCanonType); } // Try normal canon next if (!context.SupportsCanon) { return(null); } // Not nullable type is the only thing where reference canon doesn't make sense. GenericConstraints constraints = genericParam.Constraints; if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { return(null); } foreach (var c in genericParam.TypeConstraints) { // Could be e.g. "where T : U" // We could try to dig into the U and solve it, but that just opens us up to // recursion and it's just not worth it. if (c.IsSignatureVariable) { return(null); } if (!c.IsGCPointer) { return(null); } } return(genericParam.Context.CanonType); }
private static TypeDesc GetTypeThatMeetsConstraints(GenericParameterDesc genericParam, bool allowCanon) { TypeSystemContext context = genericParam.Context; // Universal canon is the best option if it's supported if (allowCanon && context.SupportsUniversalCanon) { return(context.UniversalCanonType); } // Not nullable type is the only thing where we can't substitute reference types GenericConstraints constraints = genericParam.Constraints; if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { return(null); } // If canon is allowed, we can use that if (allowCanon && context.SupportsCanon) { foreach (var c in genericParam.TypeConstraints) { // Could be e.g. "where T : U" // We could try to dig into the U and solve it, but that just opens us up to // recursion and it's just not worth it. if (c.IsSignatureVariable) { return(null); } if (!c.IsGCPointer) { return(null); } } return(genericParam.Context.CanonType); } // If canon is not allowed, we're limited in our choices. TypeDesc constrainedType = null; foreach (var c in genericParam.TypeConstraints) { // Can't do multiple constraints if (constrainedType != null) { return(null); } // Could be e.g. "where T : IFoo<U>" or "where T : U" if (c.ContainsSignatureVariables()) { return(null); } constrainedType = c; } return(constrainedType ?? genericParam.Context.GetWellKnownType(WellKnownType.Object)); }
// Used to determine whether a type parameter used to instantiate another type parameter with a specific special // constraint satisfies that constraint. private static bool CheckGenericSpecialConstraint(TypeDesc type, GenericConstraints specialConstraint) { if (!type.IsGenericParameter) { return(false); } var genericType = (GenericParameterDesc)type; GenericConstraints constraints = genericType.Constraints; // Check if type has specialConstraint on its own if ((constraints & specialConstraint) != 0) { return(true); } // Value type always has default constructor if (specialConstraint == GenericConstraints.DefaultConstructorConstraint && (constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { return(true); } // The special constraints did not match, check if there is a primary type constraint, // that would always satisfy the special constraint foreach (var constraint in genericType.TypeConstraints) { if (constraint.IsGenericParameter || constraint.IsInterface) { continue; } switch (specialConstraint) { case GenericConstraints.NotNullableValueTypeConstraint: if (constraint.IsValueType && !constraint.IsNullable) { return(true); } break; case GenericConstraints.ReferenceTypeConstraint: if (!constraint.IsValueType) { return(true); } break; case GenericConstraints.DefaultConstructorConstraint: // As constraint is only ancestor, can only be sure whether type has public default constructor if it is a value type if (constraint.IsValueType) { return(true); } break; default: Debug.Assert(false); break; } } // type did not satisfy special constraint in any way return(false); }
private static TypeDesc GetTypeThatMeetsConstraints(GenericParameterDesc genericParam, bool allowCanon) { TypeSystemContext context = genericParam.Context; // Universal canon is the best option if it's supported if (allowCanon && context.SupportsUniversalCanon) { return(context.UniversalCanonType); } // Not nullable type is the only thing where we can't substitute reference types GenericConstraints constraints = genericParam.Constraints; if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { return(null); } // If canon is allowed, we can use that if (allowCanon && context.SupportsCanon) { foreach (var c in genericParam.TypeConstraints) { // Could be e.g. "where T : U" // We could try to dig into the U and solve it, but that just opens us up to // recursion and it's just not worth it. if (c.IsSignatureVariable) { return(null); } if (!c.IsGCPointer) { return(null); } } return(genericParam.Context.CanonType); } // If canon is not allowed, we're limited in our choices. TypeDesc constrainedType = null; foreach (var c in genericParam.TypeConstraints) { // Can't do multiple constraints if (constrainedType != null) { return(null); } // Could be e.g. "where T : IFoo<U>" or "where T : U" if (c.ContainsSignatureVariables()) { return(null); } // If there's unimplemented static abstract methods, this is not a suitable instantiation. // We shortcut to look for any static virtuals. It matches what Roslyn does for error CS8920. // Once TypeSystemConstraintsHelpers is updated to check constraints around static virtuals, // we could dispatch there instead. if (c.IsInterface) { if (HasStaticVirtualMethods(c)) { return(null); } foreach (DefType intface in c.RuntimeInterfaces) { if (HasStaticVirtualMethods(intface)) { return(null); } }