public bool DependsOn(TypeParameterType pType) { Debug.Assert(pType != null); // * If a type parameter T is used as a constraint for type parameter S // then S depends on T. // * If a type parameter S depends on a type parameter T and T depends on // U then S depends on U. TypeArray pConstraints = GetBounds(); for (int iConstraint = 0; iConstraint < pConstraints.size; ++iConstraint) { CType pConstraint = pConstraints.Item(iConstraint); if (pConstraint == pType) { return true; } if (pConstraint.IsTypeParameterType() && pConstraint.AsTypeParameterType().DependsOn(pType)) { return true; } } return false; }
public TypeArray typeVars; // All the type variables for a generic method, as declarations. // If there is a type variable in the method which is used in no parameter, // then inference must fail. Since this is expensive to check, we cache // the result of the first call. public bool InferenceMustFail() { if (_checkedInfMustFail) { return(_inferenceMustFail); } Debug.Assert(!_inferenceMustFail); _checkedInfMustFail = true; for (int ivar = 0; ivar < typeVars.Size; ivar++) { TypeParameterType var = typeVars.ItemAsTypeParameterType(ivar); // See if type var is used in a parameter. for (int ipar = 0; ; ipar++) { if (ipar >= Params.Size) { // This type variable is not in any parameter. _inferenceMustFail = true; return(true); } if (TypeManager.TypeContainsType(Params.Item(ipar), var)) { break; } } } // All type variables are used in a parameter. return(false); }
////////////////////////////////////////////////////////////////////////////// private static bool HasVariantConversion(AggregateType pSource, AggregateType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (pSource == pDest) { return(true); } AggregateSymbol pAggSym = pSource.OwningAggregate; if (pAggSym != pDest.OwningAggregate) { return(false); } TypeArray pTypeParams = pAggSym.GetTypeVarsAll(); TypeArray pSourceArgs = pSource.TypeArgsAll; TypeArray pDestArgs = pDest.TypeArgsAll; Debug.Assert(pTypeParams.Count == pSourceArgs.Count); Debug.Assert(pTypeParams.Count == pDestArgs.Count); for (int iParam = 0; iParam < pTypeParams.Count; ++iParam) { CType pSourceArg = pSourceArgs[iParam]; CType pDestArg = pDestArgs[iParam]; // If they're identical then this one is automatically good, so skip it. if (pSourceArg == pDestArg) { continue; } TypeParameterType pParam = (TypeParameterType)pTypeParams[iParam]; if (pParam.Invariant) { return(false); } if (pParam.Covariant) { if (!HasImplicitReferenceConversion(pSourceArg, pDestArg)) { return(false); } } if (pParam.Contravariant) { if (!HasImplicitReferenceConversion(pDestArg, pSourceArg)) { return(false); } } } return(true); }
public TypeArray GetStdMethTyVarArray(int cTyVars) { TypeParameterType[] prgvar = new TypeParameterType[cTyVars]; for (int ivar = 0; ivar < cTyVars; ivar++) { prgvar[ivar] = GetStdMethTypeVar(ivar); } return(_BSymmgr.AllocParams(cTyVars, (CType[])prgvar)); }
public static bool HasGenericDelegateExplicitReferenceConversion(CType pSource, AggregateType pTarget) { if (!(pSource is AggregateType aggSrc) || !aggSrc.IsDelegateType || !pTarget.IsDelegateType || aggSrc.OwningAggregate != pTarget.OwningAggregate || SymbolLoader.HasIdentityOrImplicitReferenceConversion(aggSrc, pTarget)) { return(false); } TypeArray pTypeParams = aggSrc.OwningAggregate.GetTypeVarsAll(); TypeArray pSourceArgs = aggSrc.TypeArgsAll; TypeArray pTargetArgs = pTarget.TypeArgsAll; Debug.Assert(pTypeParams.Count == pSourceArgs.Count); Debug.Assert(pTypeParams.Count == pTargetArgs.Count); for (int iParam = 0; iParam < pTypeParams.Count; ++iParam) { CType pSourceArg = pSourceArgs[iParam]; CType pTargetArg = pTargetArgs[iParam]; // If they're identical then this one is automatically good, so skip it. // If we have an error type, then we're in some fault tolerance. Let it through. if (pSourceArg == pTargetArg) { continue; } TypeParameterType pParam = (TypeParameterType)pTypeParams[iParam]; if (pParam.Invariant) { return(false); } if (pParam.Covariant) { if (!FExpRefConv(pSourceArg, pTargetArg)) { return(false); } } else if (pParam.Contravariant) { if (!pSourceArg.IsReferenceType || !pTargetArg.IsReferenceType) { return(false); } } } return(true); }
////////////////////////////////////////////////////////////////////////////// bool HasVariantConversion(AggregateType pSource, AggregateType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (pSource == pDest) { return(true); } AggregateSymbol pAggSym = pSource.getAggregate(); if (pAggSym != pDest.getAggregate()) { return(false); } TypeArray pTypeParams = pAggSym.GetTypeVarsAll(); TypeArray pSourceArgs = pSource.GetTypeArgsAll(); TypeArray pDestArgs = pDest.GetTypeArgsAll(); Debug.Assert(pTypeParams.size == pSourceArgs.size); Debug.Assert(pTypeParams.size == pDestArgs.size); for (int iParam = 0; iParam < pTypeParams.size; ++iParam) { CType pSourceArg = pSourceArgs.Item(iParam); CType pDestArg = pDestArgs.Item(iParam); // If they're identical then this one is automatically good, so skip it. if (pSourceArg == pDestArg) { continue; } TypeParameterType pParam = pTypeParams.Item(iParam).AsTypeParameterType(); if (pParam.Invariant) { return(false); } if (pParam.Covariant) { if (!HasImplicitReferenceConversion(pSourceArg, pDestArg)) { return(false); } } if (pParam.Contravariant) { if (!HasImplicitReferenceConversion(pDestArg, pSourceArg)) { return(false); } } } return(true); }
// TypeParameter public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol) { TypeParameterType type = new TypeParameterType(); type.SetTypeParameterSymbol(pSymbol); type.SetName(pSymbol.name); Debug.Assert(pSymbol.GetTypeParameterType() == null); pSymbol.SetTypeParameterType(type); type.SetTypeKind(TypeKind.TK_TypeParameterType); return(type); }
private static IEnumerable <AggregateType> AllPossibleInterfaces(TypeParameterType type) { foreach (AggregateType t in type.GetEffectiveBaseClass().TypeAndBaseClassInterfaces()) { yield return(t); } foreach (AggregateType t in type.GetInterfaceBounds().AllConstraintInterfaces()) { yield return(t); } }
private static Type CalculateAssociatedSystemType(CType src) { Type result = null; switch (src.GetTypeKind()) { case TypeKind.TK_ArrayType: ArrayType a = (ArrayType)src; Type elementType = a.GetElementType().AssociatedSystemType; result = a.IsSZArray ? elementType.MakeArrayType() : elementType.MakeArrayType(a.rank); break; case TypeKind.TK_NullableType: NullableType n = (NullableType)src; Type underlyingType = n.GetUnderlyingType().AssociatedSystemType; result = typeof(Nullable <>).MakeGenericType(underlyingType); break; case TypeKind.TK_PointerType: PointerType p = (PointerType)src; Type referentType = p.GetReferentType().AssociatedSystemType; result = referentType.MakePointerType(); break; case TypeKind.TK_ParameterModifierType: ParameterModifierType r = (ParameterModifierType)src; Type parameterType = r.GetParameterType().AssociatedSystemType; result = parameterType.MakeByRefType(); break; case TypeKind.TK_AggregateType: result = CalculateAssociatedSystemTypeForAggregate((AggregateType)src); break; case TypeKind.TK_TypeParameterType: TypeParameterType t = (TypeParameterType)src; if (t.IsMethodTypeParameter()) { MethodInfo meth = ((MethodSymbol)t.GetOwningSymbol()).AssociatedMemberInfo as MethodInfo; result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()]; } else { Type parentType = ((AggregateSymbol)t.GetOwningSymbol()).AssociatedSystemType; result = parentType.GetGenericArguments()[t.GetIndexInOwnParameters()]; } break; } Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType); return(result); }
// TypeParameter public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol) { TypeParameterType type = new TypeParameterType(); type.SetTypeParameterSymbol(pSymbol); type.SetUnresolved(pSymbol.parent != null && pSymbol.parent.IsAggregateSymbol() && pSymbol.parent.AsAggregateSymbol().IsUnresolved()); type.SetName(pSymbol.name); Debug.Assert(pSymbol.GetTypeParameterType() == null); pSymbol.SetTypeParameterType(type); type.SetTypeKind(TypeKind.TK_TypeParameterType); return(type); }
/*************************************************************************************************** * * There exists an explicit conversion ... * From a generic delegate type S to generic delegate type T, provided all of the follow are true: * o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is, * S is D<S1,... Sk> and T is D<T1,... Tk>. * o S is not compatible with or identical to T. * o If type parameter Xi is declared to be invariant then Si must be identical to Ti. * o If type parameter Xi is declared to be covariant ("out") then Si must be convertible * to Ti via an identify conversion, implicit reference conversion, or explicit reference conversion. * o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, * or Si and Ti must both be reference types. ***************************************************************************************************/ public static bool HasGenericDelegateExplicitReferenceConversion(SymbolLoader loader, CType pSource, CType pTarget) { if (!pSource.isDelegateType() || !pTarget.isDelegateType() || pSource.getAggregate() != pTarget.getAggregate() || loader.HasIdentityOrImplicitReferenceConversion(pSource, pTarget)) { return(false); } TypeArray pTypeParams = pSource.getAggregate().GetTypeVarsAll(); TypeArray pSourceArgs = pSource.AsAggregateType().GetTypeArgsAll(); TypeArray pTargetArgs = pTarget.AsAggregateType().GetTypeArgsAll(); Debug.Assert(pTypeParams.size == pSourceArgs.size); Debug.Assert(pTypeParams.size == pTargetArgs.size); for (int iParam = 0; iParam < pTypeParams.size; ++iParam) { CType pSourceArg = pSourceArgs.Item(iParam); CType pTargetArg = pTargetArgs.Item(iParam); // If they're identical then this one is automatically good, so skip it. // If we have an error type, then we're in some fault tolerance. Let it through. if (pSourceArg == pTargetArg || pTargetArg.IsErrorType() || pSourceArg.IsErrorType()) { continue; } TypeParameterType pParam = pTypeParams.Item(iParam).AsTypeParameterType(); if (pParam.Invariant) { return(false); } if (pParam.Covariant) { if (!FExpRefConv(loader, pSourceArg, pTargetArg)) { return(false); } } else if (pParam.Contravariant) { if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType()) { return(false); } } } return(true); }
public static bool ParametersContainTyVar(TypeArray @params, TypeParameterType typeFind) { Debug.Assert(@params != null); Debug.Assert(typeFind != null); for (int p = 0; p < @params.Count; p++) { CType sym = @params[p]; if (TypeContainsType(sym, typeFind)) { return(true); } } return(false); }
public TypeParameterType GetTypeParameter(TypeParameterSymbol pSymbol) { // These guys should be singletons for each. TypeParameterType pTypeParameter = _typeTable.LookupTypeParameter(pSymbol); if (pTypeParameter == null) { pTypeParameter = _typeFactory.CreateTypeParameter(pSymbol); _typeTable.InsertTypeParameter(pSymbol, pTypeParameter); } return(pTypeParameter); }
private bool HasImplicitReferenceTypeParameterConversion( TypeParameterType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (!pSource.IsRefType()) { // Not a reference conversion. return(false); } // The following implicit conversions exist for a given type parameter T: // // * From T to its effective base class C. AggregateType pEBC = pSource.GetEffectiveBaseClass(); if (pDest == pEBC) { return(true); } // * From T to any base class of C. if (IsBaseClass(pEBC, pDest)) { return(true); } // * From T to any interface implemented by C. if (IsBaseInterface(pEBC, pDest)) { return(true); } // * From T to any interface type I in T's effective interface set, and // from T to any base interface of I. TypeArray pInterfaces = pSource.GetInterfaceBounds(); for (int i = 0; i < pInterfaces.Count; ++i) { if (pInterfaces[i] == pDest) { return(true); } } // * From T to a type parameter U, provided T depends on U. if (pDest.IsTypeParameterType() && pSource.DependsOn(pDest.AsTypeParameterType())) { return(true); } return(false); }
private bool HasImplicitBoxingTypeParameterConversion( TypeParameterType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (pSource.IsRefType()) { // Not a boxing conversion; both source and destination are references. return(false); } // The following implicit conversions exist for a given type parameter T: // // * From T to its effective base class C. AggregateType pEBC = pSource.GetEffectiveBaseClass(); if (pDest == pEBC) { return(true); } // * From T to any base class of C. if (IsBaseClass(pEBC, pDest)) { return(true); } // * From T to any interface implemented by C. if (IsBaseInterface(pEBC, pDest)) { return(true); } // * From T to any interface type I in T's effective interface set, and // from T to any base interface of I. TypeArray pInterfaces = pSource.GetInterfaceBounds(); for (int i = 0; i < pInterfaces.Count; ++i) { if (pInterfaces[i] == pDest) { return(true); } } // * The conversion from T to a type parameter U, provided T depends on U, is not // classified as a boxing conversion because it is not guaranteed to box. // (If both T and U are value types then it is an identity conversion.) return(false); }
private bool HasImplicitTypeParameterBaseConversion( TypeParameterType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (HasImplicitReferenceTypeParameterConversion(pSource, pDest)) { return(true); } if (HasImplicitBoxingTypeParameterConversion(pSource, pDest)) { return(true); } return(pDest is TypeParameterType typeParamDest && pSource.DependsOn(typeParamDest)); }
//////////////////////////////////////////////////////////////////////////////// // Check whether typeArgs satisfies the constraints of typeVars. The // typeArgsCls and typeArgsMeth are used for substitution on the bounds. The // tree and symErr are used for error reporting. private static bool CheckConstraintsCore(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { Debug.Assert(typeVars.Count == typeArgs.Count); Debug.Assert(typeVars.Count > 0); Debug.Assert(flags == CheckConstraintsFlags.None || flags == CheckConstraintsFlags.NoErrors); bool fError = false; for (int i = 0; i < typeVars.Count; i++) { // Empty bounds should be set to object. TypeParameterType var = (TypeParameterType)typeVars[i]; CType arg = typeArgs[i]; bool fOK = CheckSingleConstraint(checker, errHandling, symErr, var, arg, typeArgsCls, typeArgsMeth, flags); fError |= !fOK; } return(!fError); }
//////////////////////////////////////////////////////////////////////////////// // Check whether typeArgs satisfies the constraints of typeVars. The // typeArgsCls and typeArgsMeth are used for substitution on the bounds. The // tree and symErr are used for error reporting. private static bool CheckConstraintsCore(Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { Debug.Assert(typeVars.Count == typeArgs.Count); Debug.Assert(typeVars.Count > 0); Debug.Assert(flags == CheckConstraintsFlags.None || flags == CheckConstraintsFlags.NoErrors); for (int i = 0; i < typeVars.Count; i++) { // Empty bounds should be set to object. TypeParameterType var = (TypeParameterType)typeVars[i]; CType arg = typeArgs[i]; if (!CheckSingleConstraint(symErr, var, arg, typeArgsCls, typeArgsMeth, flags)) { return(false); } } return(true); }
// TypeParameter public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol) { TypeParameterType type = new TypeParameterType(); type.SetTypeParameterSymbol(pSymbol); type.SetUnresolved(pSymbol.parent != null && pSymbol.parent.IsAggregateSymbol() && pSymbol.parent.AsAggregateSymbol().IsUnresolved()); type.SetName(pSymbol.name); #if CSEE type.typeRes = type; if (!type.IsUnresolved()) { type.tsRes = ktsImportMax; } #endif // CSEE Debug.Assert(pSymbol.GetTypeParameterType() == null); pSymbol.SetTypeParameterType(type); type.SetTypeKind(TypeKind.TK_TypeParameterType); return type; }
// TypeParameter public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol) { TypeParameterType type = new TypeParameterType(); type.SetTypeParameterSymbol(pSymbol); type.SetUnresolved(pSymbol.parent != null && pSymbol.parent.IsAggregateSymbol() && pSymbol.parent.AsAggregateSymbol().IsUnresolved()); type.SetName(pSymbol.name); #if CSEE type.typeRes = type; if (!type.IsUnresolved()) { type.tsRes = ktsImportMax; } #endif // CSEE Debug.Assert(pSymbol.GetTypeParameterType() == null); pSymbol.SetTypeParameterType(type); type.SetTypeKind(TypeKind.TK_TypeParameterType); return(type); }
//////////////////////////////////////////////////////////////////////////////// // Get the standard type variable (eg, !0, !1, or !!0, !!1). // // iv is the index. // pbsm is the containing symbol manager // fMeth designates whether this is a method type var or class type var // // The standard class type variables are useful during emit, but not for type // comparison when binding. The standard method type variables are useful during // binding for signature comparison. public TypeParameterType GetTypeVarSym(int iv, TypeManager pTypeManager, bool fMeth) { Debug.Assert(iv >= 0); TypeParameterType tpt = null; if (iv >= this.prgptvs.Count) { TypeParameterSymbol pTypeParameter = new TypeParameterSymbol(); pTypeParameter.SetIsMethodTypeParameter(fMeth); pTypeParameter.SetIndexInOwnParameters(iv); pTypeParameter.SetIndexInTotalParameters(iv); pTypeParameter.SetAccess(ACCESS.ACC_PRIVATE); tpt = pTypeManager.GetTypeParameter(pTypeParameter); this.prgptvs.Add(tpt); } else { tpt = this.prgptvs[iv]; } Debug.Assert(tpt != null); return(tpt); }
private static Type CalculateAssociatedSystemType(CType src) { Type result = null; switch (src.GetTypeKind()) { case TypeKind.TK_ArrayType: ArrayType a = src.AsArrayType(); Type elementType = a.GetElementType().AssociatedSystemType; if (a.rank == 1) { result = elementType.MakeArrayType(); } else { result = elementType.MakeArrayType(a.rank); } break; case TypeKind.TK_NullableType: NullableType n = src.AsNullableType(); Type underlyingType = n.GetUnderlyingType().AssociatedSystemType; result = typeof(Nullable <>).MakeGenericType(underlyingType); break; case TypeKind.TK_PointerType: PointerType p = src.AsPointerType(); Type referentType = p.GetReferentType().AssociatedSystemType; result = referentType.MakePointerType(); break; case TypeKind.TK_ParameterModifierType: ParameterModifierType r = src.AsParameterModifierType(); Type parameterType = r.GetParameterType().AssociatedSystemType; result = parameterType.MakeByRefType(); break; case TypeKind.TK_AggregateType: result = CalculateAssociatedSystemTypeForAggregate(src.AsAggregateType()); break; case TypeKind.TK_TypeParameterType: TypeParameterType t = src.AsTypeParameterType(); Type parentType = null; if (t.IsMethodTypeParameter()) { MethodInfo meth = t.GetOwningSymbol().AsMethodSymbol().AssociatedMemberInfo as MethodInfo; result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()]; } else { parentType = t.GetOwningSymbol().AsAggregateSymbol().AssociatedSystemType; result = parentType.GetTypeInfo().GenericTypeParameters[t.GetIndexInOwnParameters()]; } break; case TypeKind.TK_ArgumentListType: case TypeKind.TK_BoundLambdaType: case TypeKind.TK_ErrorType: case TypeKind.TK_MethodGroupType: case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_NullType: case TypeKind.TK_OpenTypePlaceholderType: case TypeKind.TK_UnboundLambdaType: case TypeKind.TK_VoidType: default: break; } Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType); return(result); }
public void InsertTypeParameter( TypeParameterSymbol pTypeParameterSymbol, TypeParameterType pTypeParameter) { _pTypeParameterTable.Add(pTypeParameterSymbol, pTypeParameter); }
public TypeArray GetStdMethTyVarArray(int cTyVars) { TypeParameterType[] prgvar = new TypeParameterType[cTyVars]; for (int ivar = 0; ivar < cTyVars; ivar++) { prgvar[ivar] = GetStdMethTypeVar(ivar); } return _BSymmgr.AllocParams(cTyVars, (CType[])prgvar); }
//////////////////////////////////////////////////////////////////////////////// // // Output types // private bool DoesOutputTypeContain(EXPR pSource, CType pDest, TypeParameterType pParam) { // SPEC: If E is a method group or an anonymous function and T is a delegate // SPEC: CType or expression tree CType then the return CType of T is an output CType // SPEC: of E with CType T. pDest = pDest.GetDelegateTypeOfPossibleExpression(); if (!pDest.isDelegateType()) { return false; } if (!pSource.isUNBOUNDLAMBDA() && !pSource.isMEMGRP()) { return false; } CType pDelegateReturn = pDest.AsAggregateType().GetDelegateReturnType(GetSymbolLoader()); if (pDelegateReturn == null) { return false; } return TypeManager.TypeContainsType(pDelegateReturn, pParam); }
//////////////////////////////////////////////////////////////////////////////// private void AddExactBound(TypeParameterType pParam, CType pBound) { Debug.Assert(IsUnfixed(pParam)); int iParam = pParam.GetIndexInTotalParameters(); if (!_pExactBounds[iParam].Contains(pBound)) { _pExactBounds[iParam].Add(pBound); } }
private static bool CheckSingleConstraint(Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { Debug.Assert(!(arg is PointerType)); Debug.Assert(!arg.IsStaticClass); bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors); if (var.HasRefConstraint && !arg.IsReferenceType) { if (fReportErrors) { throw ErrorHandling.Error(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return(false); } TypeArray bnds = TypeManager.SubstTypeArray(var.Bounds, typeArgsCls, typeArgsMeth); int itypeMin = 0; if (var.HasValConstraint) { // If we have a type variable that is constrained to a value type, then we // want to check if its a nullable type, so that we can report the // constraint error below. In order to do this however, we need to check // that either the type arg is not a value type, or it is a nullable type. // // To check whether or not its a nullable type, we need to get the resolved // bound from the type argument and check against that. if (!arg.IsNonNullableValueType) { if (fReportErrors) { throw ErrorHandling.Error(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return(false); } // Since FValCon() is set it is redundant to check System.ValueType as well. if (bnds.Count != 0 && bnds[0].IsPredefType(PredefinedType.PT_VALUE)) { itypeMin = 1; } } for (int j = itypeMin; j < bnds.Count; j++) { CType typeBnd = bnds[j]; if (!SatisfiesBound(arg, typeBnd)) { if (fReportErrors) { // The bound isn't satisfied because of a constraint type. Explain to the user why not. // There are 4 main cases, based on the type of the supplied type argument: // - reference type, or type parameter known to be a reference type // - nullable type, from which there is a boxing conversion to the constraint type(see below for details) // - type variable // - value type // These cases are broken out because: a) The sets of conversions which can be used // for constraint satisfaction is different based on the type argument supplied, // and b) Nullable is one funky type, and user's can use all the help they can get // when using it. ErrorCode error; if (arg.IsReferenceType) { // A reference type can only satisfy bounds to types // to which they have an implicit reference conversion error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (arg is NullableType nubArg && SymbolLoader.HasBaseConversion(nubArg.UnderlyingType, typeBnd)) // This is inlining FBoxingConv { // nullable types do not satisfy bounds to every type that they are boxable to // They only satisfy bounds of object and ValueType if (typeBnd.IsPredefType(PredefinedType.PT_ENUM) || nubArg.UnderlyingType == typeBnd) { // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum // even though the conversion from Nullable to these types is a boxing conversion // This is a rare case, because these bounds can never be directly stated ... // These bounds can only occur when one type paramter is constrained to a second type parameter // and the second type parameter is instantiated with Enum or the underlying type of the first type // parameter error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else { // Nullable types don't satisfy the bounds of any interface type // even when there is a boxing conversion from the Nullable type to // the interface type. This will be a relatively common scenario // so we cal it out separately from the previous case. Debug.Assert(typeBnd.IsInterfaceType); error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface; } } else { // Value types can only satisfy bounds through boxing conversions. // Note that the exceptional case of Nullable types and boxing is handled above. error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } throw ErrorHandling.Error(error, new ErrArg(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArg(arg, ErrArgFlags.Unique)); } return(false); } }
private bool HasImplicitTypeParameterBaseConversion( TypeParameterType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (HasImplicitReferenceTypeParameterConversion(pSource, pDest)) { return true; } if (HasImplicitBoxingTypeParameterConversion(pSource, pDest)) { return true; } if (pDest.IsTypeParameterType() && pSource.DependsOn(pDest.AsTypeParameterType())) { return true; } return false; }
private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors); if (arg.IsOpenTypePlaceholderType()) { return(true); } if (arg.IsErrorType()) { // Error should have been reported previously. return(false); } if (checker.CheckBogus(arg)) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg); } return(false); } if (arg.IsPointerType() || arg.isSpecialByRefType()) { if (fReportErrors) { errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg); } return(false); } if (arg.isStaticClass()) { if (fReportErrors) { checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass); } return(false); } bool fError = false; if (var.HasRefConstraint() && !arg.IsRefType()) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } TypeArray bnds = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth); int itypeMin = 0; if (var.HasValConstraint()) { // If we have a type variable that is constrained to a value type, then we // want to check if its a nullable type, so that we can report the // constraint error below. In order to do this however, we need to check // that either the type arg is not a value type, or it is a nullable type. // // To check whether or not its a nullable type, we need to get the resolved // bound from the type argument and check against that. bool bIsValueType = arg.IsValType(); bool bIsNullable = arg.IsNullableType(); if (bIsValueType && arg.IsTypeParameterType()) { TypeArray pArgBnds = arg.AsTypeParameterType().GetBounds(); if (pArgBnds.Count > 0) { bIsNullable = pArgBnds[0].IsNullableType(); } } if (!bIsValueType || bIsNullable) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } // Since FValCon() is set it is redundant to check System.ValueType as well. if (bnds.Count != 0 && bnds[0].isPredefType(PredefinedType.PT_VALUE)) { itypeMin = 1; } } for (int j = itypeMin; j < bnds.Count; j++) { CType typeBnd = bnds[j]; if (!SatisfiesBound(checker, arg, typeBnd)) { if (fReportErrors) { // The bound isn't satisfied because of a constraint type. Explain to the user why not. // There are 4 main cases, based on the type of the supplied type argument: // - reference type, or type parameter known to be a reference type // - nullable type, from which there is a boxing conversion to the constraint type(see below for details) // - type variable // - value type // These cases are broken out because: a) The sets of conversions which can be used // for constraint satisfaction is different based on the type argument supplied, // and b) Nullable is one funky type, and user's can use all the help they can get // when using it. ErrorCode error; if (arg.IsRefType()) { // A reference type can only satisfy bounds to types // to which they have an implicit reference conversion error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (arg.IsNullableType() && checker.GetSymbolLoader().HasBaseConversion(arg.AsNullableType().GetUnderlyingType(), typeBnd)) // This is inlining FBoxingConv { // nullable types do not satisfy bounds to every type that they are boxable to // They only satisfy bounds of object and ValueType if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || arg.AsNullableType().GetUnderlyingType() == typeBnd) { // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum // even though the conversion from Nullable to these types is a boxing conversion // This is a rare case, because these bounds can never be directly stated ... // These bounds can only occur when one type paramter is constrained to a second type parameter // and the second type parameter is instantiated with Enum or the underlying type of the first type // parameter error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else { // Nullable types don't satisfy the bounds of any interface type // even when there is a boxing conversion from the Nullable type to // the interface type. This will be a relatively common scenario // so we cal it out separately from the previous case. Debug.Assert(typeBnd.isInterfaceType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface; } } else if (arg.IsTypeParameterType()) { // Type variables can satisfy bounds through boxing and type variable conversions Debug.Assert(!arg.IsRefType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { // Value types can only satisfy bounds through boxing conversions. // Note that the exceptional case of Nullable types and boxing is handled above. error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique)); } fError = true; } } // Check the newable constraint. if (!var.HasNewConstraint() || arg.IsValType()) { return(!fError); } if (arg.isClassType()) { AggregateSymbol agg = arg.AsAggregateType().getAggregate(); // Due to late binding nature of IDE created symbols, the AggregateSymbol might not // have all the information necessary yet, if it is not fully bound. // by calling LookupAggMember, it will ensure that we will update all the // information necessary at least for the given method. checker.GetSymbolLoader().LookupAggMember(checker.GetNameManager().GetPredefName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL); if (agg.HasPubNoArgCtor() && !agg.IsAbstract()) { return(!fError); } } else if (arg.IsTypeParameterType() && arg.AsTypeParameterType().HasNewConstraint()) { return(!fError); } if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return(false); }
public static bool ParametersContainTyVar(TypeArray @params, TypeParameterType typeFind) { Debug.Assert(@params != null); Debug.Assert(typeFind != null); for (int p = 0; p < @params.size; p++) { CType sym = @params[p]; if (TypeContainsType(sym, typeFind)) { return true; } } return false; }
private bool bindImplicitConversionFromTypeVar(TypeParameterType tyVarSrc) { // 13.1.4 // // For a type-parameter T that is known to be a reference type (25.7), the following implicit // reference conversions exist: // // * From T to its effective base class C, from T to any base class of C, and from T to any // interface implemented by C. // * From T to an interface-type I in T's effective interface set and from T to any base // interface of I. // * From T to a type parameter U provided that T depends on U (25.7). [Note: Since T is known // to be a reference type, within the scope of T, the run-time type of U will always be a // reference type, even if U is not known to be a reference type at compile-time.] // * From the null type (11.2.7) to T. // // 13.1.5 // // For a type-parameter T that is not known to be a reference type (25.7), the following conversions // involving T are considered to be boxing conversions at compile-time. At run-time, if T is a value // type, the conversion is executed as a boxing conversion. At run-time, if T is a reference type, // the conversion is executed as an implicit reference conversion or identity conversion. // // * From T to its effective base class C, from T to any base class of C, and from T to any // interface implemented by C. [Note: C will be one of the types System.Object, System.ValueType, // or System.Enum (otherwise T would be known to be a reference type and 13.1.4 would apply // instead of this clause).] // * From T to an interface-type I in T's effective interface set and from T to any base // interface of I. // // 13.1.6 Implicit type parameter conversions // // This clause details implicit conversions involving type parameters that are not classified as // implicit reference conversions or implicit boxing conversions. // // For a type-parameter T that is not known to be a reference type, there is an implicit conversion // from T to a type parameter U provided T depends on U. At run-time, if T is a value type and U is // a reference type, the conversion is executed as a boxing conversion. At run-time, if both T and U // are value types, then T and U are necessarily the same type and no conversion is performed. At // run-time, if T is a reference type, then U is necessarily also a reference type and the conversion // is executed as an implicit reference conversion or identity conversion (25.7). CType typeTmp = tyVarSrc.GetEffectiveBaseClass(); TypeArray bnds = tyVarSrc.GetBounds(); int itype = -1; for (; ;) { if (binder.canConvert(typeTmp, typeDest, flags | CONVERTTYPE.NOUDC)) { if (!needsExprDest) { return(true); } if (typeDest.IsTypeParameterType()) { // For a type var destination we need to cast to object then to the other type var. EXPR exprT; EXPRCLASS exprObj = GetExprFactory().MakeClass(binder.GetReqPDT(PredefinedType.PT_OBJECT)); binder.bindSimpleCast(exprSrc, exprObj, out exprT, EXPRFLAG.EXF_FORCE_BOX); binder.bindSimpleCast(exprT, exprTypeDest, out exprDest, EXPRFLAG.EXF_FORCE_UNBOX); } else { binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, EXPRFLAG.EXF_FORCE_BOX); } return(true); } do { if (++itype >= bnds.Size) { return(false); } typeTmp = bnds.Item(itype); }while (!typeTmp.isInterfaceType() && !typeTmp.IsTypeParameterType()); } }
public void SetTypeParameterType(TypeParameterType pType) { _pTypeParameterType = pType; }
//////////////////////////////////////////////////////////////////////////////// private bool IsUnfixed(TypeParameterType pParam) { Debug.Assert(pParam != null); Debug.Assert(pParam.IsMethodTypeParameter()); int iParam = pParam.GetIndexInTotalParameters(); Debug.Assert(_pMethodTypeParameters.ItemAsTypeParameterType(iParam) == pParam); return IsUnfixed(iParam); }
private bool HasImplicitReferenceTypeParameterConversion( TypeParameterType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (!pSource.IsRefType()) { // Not a reference conversion. return false; } // The following implicit conversions exist for a given type parameter T: // // * From T to its effective base class C. AggregateType pEBC = pSource.GetEffectiveBaseClass(); if (pDest == pEBC) { return true; } // * From T to any base class of C. if (IsBaseClass(pEBC, pDest)) { return true; } // * From T to any interface implemented by C. if (IsBaseInterface(pEBC, pDest)) { return true; } // * From T to any interface type I in T's effective interface set, and // from T to any base interface of I. TypeArray pInterfaces = pSource.GetInterfaceBounds(); for (int i = 0; i < pInterfaces.Size; ++i) { if (pInterfaces.Item(i) == pDest) { return true; } } // * From T to a type parameter U, provided T depends on U. if (pDest.IsTypeParameterType() && pSource.DependsOn(pDest.AsTypeParameterType())) { return true; } return false; }
//////////////////////////////////////////////////////////////////////////////// // // Input types // private bool DoesInputTypeContain(EXPR pSource, CType pDest, TypeParameterType pParam) { // SPEC: If E is a method group or an anonymous function and T is a delegate // SPEC: CType or expression tree CType then all the parameter types of T are // SPEC: input types of E with CType T. pDest = pDest.GetDelegateTypeOfPossibleExpression(); if (!pDest.isDelegateType()) { return false; // No input types. } if (!pSource.isUNBOUNDLAMBDA() && !pSource.isMEMGRP()) { return false; // No input types. } TypeArray pDelegateParameters = pDest.AsAggregateType().GetDelegateParameters(GetSymbolLoader()); if (pDelegateParameters == null) { return false; } return TypeManager.ParametersContainTyVar(pDelegateParameters, pParam); }
private bool bindImplicitConversionFromTypeVar(TypeParameterType tyVarSrc) { // 13.1.4 // // For a type-parameter T that is known to be a reference type (25.7), the following implicit // reference conversions exist: // // * From T to its effective base class C, from T to any base class of C, and from T to any // interface implemented by C. // * From T to an interface-type I in T's effective interface set and from T to any base // interface of I. // * From T to a type parameter U provided that T depends on U (25.7). [Note: Since T is known // to be a reference type, within the scope of T, the run-time type of U will always be a // reference type, even if U is not known to be a reference type at compile-time.] // * From the null type (11.2.7) to T. // // 13.1.5 // // For a type-parameter T that is not known to be a reference type (25.7), the following conversions // involving T are considered to be boxing conversions at compile-time. At run-time, if T is a value // type, the conversion is executed as a boxing conversion. At run-time, if T is a reference type, // the conversion is executed as an implicit reference conversion or identity conversion. // // * From T to its effective base class C, from T to any base class of C, and from T to any // interface implemented by C. [Note: C will be one of the types System.Object, System.ValueType, // or System.Enum (otherwise T would be known to be a reference type and 13.1.4 would apply // instead of this clause).] // * From T to an interface-type I in T's effective interface set and from T to any base // interface of I. // // 13.1.6 Implicit type parameter conversions // // This clause details implicit conversions involving type parameters that are not classified as // implicit reference conversions or implicit boxing conversions. // // For a type-parameter T that is not known to be a reference type, there is an implicit conversion // from T to a type parameter U provided T depends on U. At run-time, if T is a value type and U is // a reference type, the conversion is executed as a boxing conversion. At run-time, if both T and U // are value types, then T and U are necessarily the same type and no conversion is performed. At // run-time, if T is a reference type, then U is necessarily also a reference type and the conversion // is executed as an implicit reference conversion or identity conversion (25.7). CType typeTmp = tyVarSrc.GetEffectiveBaseClass(); TypeArray bnds = tyVarSrc.GetBounds(); int itype = -1; for (; ;) { if (_binder.canConvert(typeTmp, _typeDest, _flags | CONVERTTYPE.NOUDC)) { if (!_needsExprDest) { return true; } if (_typeDest.IsTypeParameterType()) { // For a type var destination we need to cast to object then to the other type var. EXPR exprT; EXPRCLASS exprObj = GetExprFactory().MakeClass(_binder.GetReqPDT(PredefinedType.PT_OBJECT)); _binder.bindSimpleCast(_exprSrc, exprObj, out exprT, EXPRFLAG.EXF_FORCE_BOX); _binder.bindSimpleCast(exprT, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_UNBOX); } else { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_BOX); } return true; } do { if (++itype >= bnds.Size) { return false; } typeTmp = bnds.Item(itype); } while (!typeTmp.isInterfaceType() && !typeTmp.IsTypeParameterType()); } }
private bool HasImplicitBoxingTypeParameterConversion( TypeParameterType pSource, CType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); if (pSource.IsRefType()) { // Not a boxing conversion; both source and destination are references. return false; } // The following implicit conversions exist for a given type parameter T: // // * From T to its effective base class C. AggregateType pEBC = pSource.GetEffectiveBaseClass(); if (pDest == pEBC) { return true; } // * From T to any base class of C. if (IsBaseClass(pEBC, pDest)) { return true; } // * From T to any interface implemented by C. if (IsBaseInterface(pEBC, pDest)) { return true; } // * From T to any interface type I in T's effective interface set, and // from T to any base interface of I. TypeArray pInterfaces = pSource.GetInterfaceBounds(); for (int i = 0; i < pInterfaces.Size; ++i) { if (pInterfaces.Item(i) == pDest) { return true; } } // * The conversion from T to a type parameter U, provided T depends on U, is not // classified as a boxing conversion because it is not guaranteed to box. // (If both T and U are value types then it is an identity conversion.) return false; }
private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors); if (arg.IsOpenTypePlaceholderType()) { return true; } if (arg.IsErrorType()) { // Error should have been reported previously. return false; } if (checker.CheckBogus(arg)) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg); } return false; } if (arg.IsPointerType() || arg.isSpecialByRefType()) { if (fReportErrors) { errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg); } return false; } if (arg.isStaticClass()) { if (fReportErrors) { checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass); } return false; } bool fError = false; if (var.HasRefConstraint() && !arg.IsRefType()) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } TypeArray bnds = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth); int itypeMin = 0; if (var.HasValConstraint()) { // If we have a type variable that is constrained to a value type, then we // want to check if its a nullable type, so that we can report the // constraint error below. In order to do this however, we need to check // that either the type arg is not a value type, or it is a nullable type. // // To check whether or not its a nullable type, we need to get the resolved // bound from the type argument and check against that. bool bIsValueType = arg.IsValType(); bool bIsNullable = arg.IsNullableType(); if (bIsValueType && arg.IsTypeParameterType()) { TypeArray pArgBnds = arg.AsTypeParameterType().GetBounds(); if (pArgBnds.size > 0) { bIsNullable = pArgBnds.Item(0).IsNullableType(); } } if (!bIsValueType || bIsNullable) { if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } fError = true; } // Since FValCon() is set it is redundant to check System.ValueType as well. if (bnds.size != 0 && bnds.Item(0).isPredefType(PredefinedType.PT_VALUE)) { itypeMin = 1; } } for (int j = itypeMin; j < bnds.size; j++) { CType typeBnd = bnds.Item(j); if (!SatisfiesBound(checker, arg, typeBnd)) { if (fReportErrors) { // The bound isn't satisfied because of a constaint type. Explain to the user why not. // There are 4 main cases, based on the type of the supplied type argument: // - reference type, or type parameter known to be a reference type // - nullable type, from which there is a boxing conversion to the constraint type(see below for details) // - type varaiable // - value type // These cases are broken out because: a) The sets of conversions which can be used // for constraint satisfaction is different based on the type argument supplied, // and b) Nullable is one funky type, and user's can use all the help they can get // when using it. ErrorCode error; if (arg.IsRefType()) { // A reference type can only satisfy bounds to types // to which they have an implicit reference conversion error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (arg.IsNullableType() && checker.GetSymbolLoader().HasBaseConversion(arg.AsNullableType().GetUnderlyingType(), typeBnd)) // This is inlining FBoxingConv { // nullable types do not satisfy bounds to every type that they are boxable to // They only satisfy bounds of object and ValueType if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || arg.AsNullableType().GetUnderlyingType() == typeBnd) { // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum // even though the conversion from Nullable to these types is a boxing conversion // This is a rare case, because these bounds can never be directly stated ... // These bounds can only occur when one type paramter is constrained to a second type parameter // and the second type parameter is instantiated with Enum or the underlying type of the first type // parameter error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else { // Nullable types don't satisfy the bounds of any interface type // even when there is a boxing conversion from the Nullable type to // the interface type. This will be a relatively common scenario // so we cal it out separately from the previous case. Debug.Assert(typeBnd.isInterfaceType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface; } } else if (arg.IsTypeParameterType()) { // Type variables can satisfy bounds through boxing and type variable conversions Debug.Assert(!arg.IsRefType()); error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { // Value types can only satisfy bounds through boxing conversions. // Note that the exceptional case of Nullable types and boxing is handled above. error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique)); } fError = true; } } // Check the newable constraint. if (!var.HasNewConstraint() || arg.IsValType()) { return !fError; } if (arg.isClassType()) { AggregateSymbol agg = arg.AsAggregateType().getAggregate(); // Due to late binding nature of IDE created symbols, the AggregateSymbol might not // have all the information necessary yet, if it is not fully bound. // by calling LookupAggMember, it will ensure that we will update all the // information necessary at least for the given method. checker.GetSymbolLoader().LookupAggMember(checker.GetNameManager().GetPredefName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL); if (agg.HasPubNoArgCtor() && !agg.IsAbstract()) { return !fError; } } else if (arg.IsTypeParameterType() && arg.AsTypeParameterType().HasNewConstraint()) { return !fError; } if (fReportErrors) { errHandling.ErrorRef(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return false; }