public virtual bool CheckTypeAccess(CType type, Symbol symWhere) { Debug.Assert(type != null); // Array, Ptr, Nub, etc don't matter. type = type.GetNakedType(true); if (!type.IsAggregateType()) { Debug.Assert(type.IsVoidType() || type.IsErrorType() || type.IsTypeParameterType()); return(true); } for (AggregateType ats = type.AsAggregateType(); ats != null; ats = ats.outerType) { if (ACCESSERROR.ACCESSERROR_NOERROR != CheckAccessCore(ats.GetOwningAggregate(), ats.outerType, symWhere, null)) { return(false); } } TypeArray typeArgs = type.AsAggregateType().GetTypeArgsAll(); for (int i = 0; i < typeArgs.size; i++) { if (!CheckTypeAccess(typeArgs.Item(i), symWhere)) { return(false); } } return(true); }
private static Type CalculateAssociatedSystemTypeForAggregate(AggregateType aggtype) { AggregateSymbol agg = aggtype.GetOwningAggregate(); TypeArray typeArgs = aggtype.GetTypeArgsAll(); List <Type> list = new List <Type>(); // Get each type arg. for (int i = 0; i < typeArgs.Count; i++) { // Unnamed type parameter types are just placeholders. if (typeArgs[i] is TypeParameterType typeParamArg && typeParamArg.GetTypeParameterSymbol().name == null) { return(null); } list.Add(typeArgs[i].AssociatedSystemType); } Type[] systemTypeArgs = list.ToArray(); Type uninstantiatedType = agg.AssociatedSystemType; if (uninstantiatedType.IsGenericType) { try { return(uninstantiatedType.MakeGenericType(systemTypeArgs)); } catch (ArgumentException) { // If the constraints don't work, just return the type without substituting it. return(uninstantiatedType); } } return(uninstantiatedType); }
//////////////////////////////////////////////////////////////////////////////// private void UpperBoundTypeArgumentInference( AggregateType pSource, AggregateType pDest) { // SPEC: The choice of inference for the i-th CType argument is made // SPEC: based on the declaration of the i-th CType parameter of C, as // SPEC: follows: // SPEC: if Ui is known to be of reference CType and the i-th CType parameter // SPEC: was declared as covariant then an upper-bound inference is made. // SPEC: if Ui is known to be of reference CType and the i-th CType parameter // SPEC: was declared as contravariant then a lower-bound inference is made. // SPEC: otherwise, an exact inference is made. Debug.Assert(pSource != null); Debug.Assert(pDest != null); Debug.Assert(pSource.GetOwningAggregate() == pDest.GetOwningAggregate()); TypeArray pTypeParams = pSource.GetOwningAggregate().GetTypeVarsAll(); TypeArray pSourceArgs = pSource.GetTypeArgsAll(); TypeArray pDestArgs = pDest.GetTypeArgsAll(); Debug.Assert(pTypeParams != null); Debug.Assert(pSourceArgs != null); Debug.Assert(pDestArgs != null); Debug.Assert(pTypeParams.size == pSourceArgs.size); Debug.Assert(pTypeParams.size == pDestArgs.size); for (int arg = 0; arg < pSourceArgs.size; ++arg) { TypeParameterType pTypeParam = pTypeParams.ItemAsTypeParameterType(arg); CType pSourceArg = pSourceArgs.Item(arg); CType pDestArg = pDestArgs.Item(arg); if (pSourceArg.IsRefType() && pTypeParam.Covariant) { UpperBoundInference(pSourceArg, pDestArg); } else if (pSourceArg.IsRefType() && pTypeParam.Contravariant) { LowerBoundInference(pSourceArgs.Item(arg), pDestArgs.Item(arg)); } else { ExactInference(pSourceArgs.Item(arg), pDestArgs.Item(arg)); } } }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundInterfaceInference(AggregateType pSource, CType pDest) { if (!pSource.isInterfaceType()) { return false; } // SPEC: Otherwise, if U is an interface CType C<U1...Uk> and V is a class CType // SPEC: or struct CType and there is a unique set V1...Vk such that V directly // SPEC: or indirectly implements C<V1...Vk> then an exact ... // SPEC: ... and U is an interface CType ... if (!pDest.isStructType() && !pDest.isClassType() && !pDest.isInterfaceType()) { return false; } var interfaces = pDest.AllPossibleInterfaces(); AggregateType pInterface = null; foreach (AggregateType pCurrent in interfaces) { if (pCurrent.GetOwningAggregate() == pSource.GetOwningAggregate()) { if (pInterface == null) { pInterface = pCurrent; } else if (pInterface != pCurrent) { // Not unique. Bail out. return false; } } } if (pInterface == null) { return false; } UpperBoundTypeArgumentInference(pInterface, pDest.AsAggregateType()); return true; }
//////////////////////////////////////////////////////////////////////////////// private bool UpperBoundClassInference(AggregateType pSource, CType pDest) { if (!pSource.isClassType() || !pDest.isClassType()) { return false; } // SPEC: Otherwise, if U is a class CType C<U1...Uk> and V is a class CType which // SPEC: inherits directly or indirectly from C<V1...Vk> then an exact // SPEC: inference is made from each Ui to the corresponding Vi. AggregateType pDestBase = pDest.AsAggregateType().GetBaseClass(); while (pDestBase != null) { if (pDestBase.GetOwningAggregate() == pSource.GetOwningAggregate()) { ExactTypeArgumentInference(pSource, pDestBase); return true; } pDestBase = pDestBase.GetBaseClass(); } return false; }
//////////////////////////////////////////////////////////////////////////////// private bool LowerBoundInterfaceInference(CType pSource, AggregateType pDest) { if (!pDest.isInterfaceType()) { return false; } // SPEC: Otherwise, if V is an interface CType C<V1...Vk> and U is a class CType // SPEC: or struct CType and there is a unique set U1...Uk such that U directly // SPEC: or indirectly implements C<U1...Uk> then an // SPEC: exact, upper-bound, or lower-bound inference ... // SPEC: ... and U is an interface CType ... // SPEC: ... and U is a CType parameter ... //TypeArray pInterfaces = null; if (!pSource.isStructType() && !pSource.isClassType() && !pSource.isInterfaceType() && !pSource.IsTypeParameterType()) { return false; } var interfaces = pSource.AllPossibleInterfaces(); AggregateType pInterface = null; foreach (AggregateType pCurrent in interfaces) { if (pCurrent.GetOwningAggregate() == pDest.GetOwningAggregate()) { if (pInterface == null) { pInterface = pCurrent; } else if (pInterface != pCurrent) { // Not unique. Bail out. return false; } } } if (pInterface == null) { return false; } LowerBoundTypeArgumentInference(pInterface, pDest); return true; }
//////////////////////////////////////////////////////////////////////////////// private bool LowerBoundClassInference(CType pSource, AggregateType pDest) { if (!pDest.isClassType()) { return false; } // SPEC: Otherwise, if V is a class CType C<V1...Vk> and U is a class CType which // SPEC: inherits directly or indirectly from C<U1...Uk> // SPEC: then an exact inference is made from each Ui to the corresponding Vi. // SPEC: Otherwise, if V is a class CType C<V1...Vk> and U is a CType parameter // SPEC: with effective base class C<U1...Uk> // SPEC: then an exact inference is made from each Ui to the corresponding Vi. // SPEC: Otherwise, if V is a class CType C<V1...Vk> and U is a CType parameter // SPEC: with an effective base class which inherits directly or indirectly from // SPEC: C<U1...Uk> then an exact inference is made // SPEC: from each Ui to the corresponding Vi. AggregateType pSourceBase = null; if (pSource.isClassType()) { pSourceBase = pSource.AsAggregateType().GetBaseClass(); } else if (pSource.IsTypeParameterType()) { pSourceBase = pSource.AsTypeParameterType().GetEffectiveBaseClass(); } while (pSourceBase != null) { if (pSourceBase.GetOwningAggregate() == pDest.GetOwningAggregate()) { ExactTypeArgumentInference(pSourceBase, pDest); return true; } pSourceBase = pSourceBase.GetBaseClass(); } return false; }
//////////////////////////////////////////////////////////////////////////////// private void ExactTypeArgumentInference( AggregateType pSource, AggregateType pDest) { Debug.Assert(pSource != null); Debug.Assert(pDest != null); Debug.Assert(pSource.GetOwningAggregate() == pDest.GetOwningAggregate()); TypeArray pSourceArgs = pSource.GetTypeArgsAll(); TypeArray pDestArgs = pDest.GetTypeArgsAll(); Debug.Assert(pSourceArgs != null); Debug.Assert(pDestArgs != null); Debug.Assert(pSourceArgs.size == pDestArgs.size); for (int arg = 0; arg < pSourceArgs.size; ++arg) { ExactInference(pSourceArgs.Item(arg), pDestArgs.Item(arg)); } }
private static Type CalculateAssociatedSystemTypeForAggregate(AggregateType aggtype) { AggregateSymbol agg = aggtype.GetOwningAggregate(); TypeArray typeArgs = aggtype.GetTypeArgsAll(); List<Type> list = new List<Type>(); // Get each type arg. for (int i = 0; i < typeArgs.size; i++) { // Unnamed type parameter types are just placeholders. if (typeArgs.Item(i).IsTypeParameterType() && typeArgs.Item(i).AsTypeParameterType().GetTypeParameterSymbol().name == null) { return null; } list.Add(typeArgs.Item(i).AssociatedSystemType); } Type[] systemTypeArgs = list.ToArray(); Type uninstantiatedType = agg.AssociatedSystemType; if (uninstantiatedType.GetTypeInfo().IsGenericType) { try { return uninstantiatedType.MakeGenericType(systemTypeArgs); } catch (ArgumentException) { // If the constraints don't work, just return the type without substituting it. return uninstantiatedType; } } return uninstantiatedType; }
private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, AggregateType typeSrc, out CType typeDst) { Debug.Assert(typeSrc != null); Debug.Assert(typeSrc.isInterfaceType() || typeSrc.isDelegateType()); typeDst = null; AggregateSymbol aggSym = typeSrc.GetOwningAggregate(); AggregateType aggOpenType = aggSym.getThisType(); if (!semanticChecker.CheckTypeAccess(aggOpenType, bindingContext.ContextForMemberLookup)) { // if the aggregate symbol itself is not accessible, then forget it, there is no // variance that will help us arrive at an accessible type. return(false); } TypeArray typeArgs = typeSrc.GetTypeArgsThis(); TypeArray typeParams = aggOpenType.GetTypeArgsThis(); CType[] newTypeArgsTemp = new CType[typeArgs.Count]; for (int i = 0; i < typeArgs.Count; i++) { if (semanticChecker.CheckTypeAccess(typeArgs[i], bindingContext.ContextForMemberLookup)) { // we have an accessible argument, this position is not a problem. newTypeArgsTemp[i] = typeArgs[i]; continue; } if (!typeArgs[i].IsRefType() || !((TypeParameterType)typeParams[i]).Covariant) { // This guy is inaccessible, and we are not going to be able to vary him, so we need to fail. return(false); } CType intermediateTypeArg; if (GetBestAccessibleType(semanticChecker, bindingContext, typeArgs[i], out intermediateTypeArg)) { // now we either have a value type (which must be accessible due to the above // check, OR we have an inaccessible type (which must be a ref type). In either // case, the recursion worked out and we are OK to vary this argument. newTypeArgsTemp[i] = intermediateTypeArg; continue; } else { Debug.Assert(false, "GetBestAccessibleType unexpectedly failed on a type that was used as a type parameter"); return(false); } } TypeArray newTypeArgs = semanticChecker.getBSymmgr().AllocParams(typeArgs.Count, newTypeArgsTemp); CType intermediateType = this.GetAggregate(aggSym, typeSrc.outerType, newTypeArgs); // All type arguments were varied successfully, which means now we must be accessible. But we could // have violated constraints. Let's check that out. if (!TypeBind.CheckConstraints(semanticChecker, null /*ErrorHandling*/, intermediateType, CheckConstraintsFlags.NoErrors)) { return(false); } typeDst = intermediateType; Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup)); return(true); }
private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, AggregateType typeSrc, out CType typeDst) { Debug.Assert(typeSrc != null); Debug.Assert(typeSrc.isInterfaceType() || typeSrc.isDelegateType()); typeDst = null; AggregateSymbol aggSym = typeSrc.GetOwningAggregate(); AggregateType aggOpenType = aggSym.getThisType(); if (!semanticChecker.CheckTypeAccess(aggOpenType, bindingContext.ContextForMemberLookup())) { // if the aggregate symbol itself is not accessible, then forget it, there is no // variance that will help us arrive at an accessible type. return false; } TypeArray typeArgs = typeSrc.GetTypeArgsThis(); TypeArray typeParams = aggOpenType.GetTypeArgsThis(); CType[] newTypeArgsTemp = new CType[typeArgs.size]; for (int i = 0; i < typeArgs.size; i++) { if (semanticChecker.CheckTypeAccess(typeArgs.Item(i), bindingContext.ContextForMemberLookup())) { // we have an accessible argument, this position is not a problem. newTypeArgsTemp[i] = typeArgs.Item(i); continue; } if (!typeArgs.Item(i).IsRefType() || !typeParams.Item(i).AsTypeParameterType().Covariant) { // This guy is inaccessible, and we are not going to be able to vary him, so we need to fail. return false; } CType intermediateTypeArg; if (GetBestAccessibleType(semanticChecker, bindingContext, typeArgs.Item(i), out intermediateTypeArg)) { // now we either have a value type (which must be accessible due to the above // check, OR we have an inaccessible type (which must be a ref type). In either // case, the recursion worked out and we are OK to vary this argument. newTypeArgsTemp[i] = intermediateTypeArg; continue; } else { Debug.Assert(false, "GetBestAccessibleType unexpectedly failed on a type that was used as a type parameter"); return false; } } TypeArray newTypeArgs = semanticChecker.getBSymmgr().AllocParams(typeArgs.size, newTypeArgsTemp); CType intermediateType = this.GetAggregate(aggSym, typeSrc.outerType, newTypeArgs); // All type arguments were varied successfully, which means now we must be accessible. But we could // have violated constraints. Let's check that out. if (!TypeBind.CheckConstraints(semanticChecker, null/*ErrorHandling*/, intermediateType, CheckConstraintsFlags.NoErrors)) { return false; } typeDst = intermediateType; Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup())); return true; }