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); }
// It would be nice to make this a virtual method on typeSym. public AggregateType GetAggTypeSym(CType typeSym) { Debug.Assert(typeSym != null); Debug.Assert(typeSym is AggregateType || typeSym is TypeParameterType || typeSym is ArrayType || typeSym is NullableType); switch (typeSym.GetTypeKind()) { case TypeKind.TK_AggregateType: return((AggregateType)typeSym); case TypeKind.TK_ArrayType: return(GetPredefindType(PredefinedType.PT_ARRAY)); case TypeKind.TK_TypeParameterType: return(((TypeParameterType)typeSym).GetEffectiveBaseClass()); case TypeKind.TK_NullableType: return(((NullableType)typeSym).GetAts()); } Debug.Assert(false, "Bad typeSym!"); return(null); }
// It would be nice to make this a virtual method on typeSym. public AggregateType GetAggTypeSym(CType typeSym) { Debug.Assert(typeSym != null); Debug.Assert(typeSym.IsAggregateType() || typeSym.IsTypeParameterType() || typeSym.IsArrayType() || typeSym.IsNullableType()); switch (typeSym.GetTypeKind()) { case TypeKind.TK_AggregateType: return(typeSym.AsAggregateType()); case TypeKind.TK_ArrayType: return(GetReqPredefType(PredefinedType.PT_ARRAY)); case TypeKind.TK_TypeParameterType: return(typeSym.AsTypeParameterType().GetEffectiveBaseClass()); case TypeKind.TK_NullableType: return(typeSym.AsNullableType().GetAts(ErrorContext)); } Debug.Assert(false, "Bad typeSym!"); return(null); }
//////////////////////////////////////////////////////////////////////////////// // Determine whether the arg type satisfies the typeBnd constraint. Note that // typeBnd could be just about any type (since we added naked type parameter // constraints). private static bool SatisfiesBound(CSemanticChecker checker, CType arg, CType typeBnd) { if (typeBnd == arg) { return(true); } switch (typeBnd.GetTypeKind()) { default: Debug.Assert(false, "Unexpected type."); return(false); case TypeKind.TK_VoidType: case TypeKind.TK_PointerType: case TypeKind.TK_ErrorType: return(false); case TypeKind.TK_ArrayType: case TypeKind.TK_TypeParameterType: break; case TypeKind.TK_NullableType: typeBnd = typeBnd.AsNullableType().GetAts(checker.GetErrorContext()); if (null == typeBnd) { return(true); } break; case TypeKind.TK_AggregateType: break; } Debug.Assert(typeBnd.IsAggregateType() || typeBnd.IsTypeParameterType() || typeBnd.IsArrayType()); switch (arg.GetTypeKind()) { default: return(false); case TypeKind.TK_ErrorType: case TypeKind.TK_PointerType: return(false); case TypeKind.TK_NullableType: arg = arg.AsNullableType().GetAts(checker.GetErrorContext()); if (null == arg) { return(true); } // Fall through. goto case TypeKind.TK_TypeParameterType; case TypeKind.TK_TypeParameterType: case TypeKind.TK_ArrayType: case TypeKind.TK_AggregateType: return(checker.GetSymbolLoader().HasBaseConversion(arg, typeBnd)); } }
//////////////////////////////////////////////////////////////////////////////// // Strips off ArrayType, ParameterModifierType, PointerType, PinnedType and optionally NullableType // and returns the result. public CType GetNakedType(bool fStripNub) { for (CType type = this; ;) { switch (type.GetTypeKind()) { default: return(type); case TypeKind.TK_NullableType: if (!fStripNub) { return(type); } type = type.GetBaseOrParameterOrElementType(); break; case TypeKind.TK_ArrayType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_PointerType: type = type.GetBaseOrParameterOrElementType(); break; } } }
public static bool TypeContainsType(CType type, CType typeFind) { LRecurse: // Label used for "tail" recursion. if (type == typeFind || type.Equals(typeFind)) { return(true); } switch (type.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in TypeContainsType"); return(false); case TypeKind.TK_NullType: case TypeKind.TK_VoidType: // There should only be a single instance of these. Debug.Assert(typeFind.GetTypeKind() != type.GetTypeKind()); return(false); case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_PointerType: type = type.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: { // BLOCK AggregateType ats = (AggregateType)type; for (int i = 0; i < ats.GetTypeArgsAll().Count; i++) { if (TypeContainsType(ats.GetTypeArgsAll()[i], typeFind)) { return(true); } } } return(false); case TypeKind.TK_ErrorType: case TypeKind.TK_TypeParameterType: return(false); } }
public static bool TypeContainsTyVars(CType type, TypeArray typeVars) { LRecurse: // Label used for "tail" recursion. switch (type.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in TypeContainsTyVars"); return(false); case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_MethodGroupType: case TypeKind.TK_ErrorType: return(false); case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_PointerType: type = type.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: { // BLOCK AggregateType ats = (AggregateType)type; for (int i = 0; i < ats.GetTypeArgsAll().Count; i++) { if (TypeContainsTyVars(ats.GetTypeArgsAll()[i], typeVars)) { return(true); } } } return(false); case TypeKind.TK_TypeParameterType: if (typeVars != null && typeVars.Count > 0) { int ivar = ((TypeParameterType)type).GetIndexInTotalParameters(); return(ivar < typeVars.Count && type == typeVars[ivar]); } return(true); } }
public static bool TypeContainsTyVars(CType type, TypeArray typeVars) { LRecurse: // Label used for "tail" recursion. switch (type.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in TypeContainsTyVars"); return false; case TypeKind.TK_UnboundLambdaType: case TypeKind.TK_BoundLambdaType: case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: case TypeKind.TK_MethodGroupType: return false; case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_PointerType: type = type.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: { // BLOCK AggregateType ats = type.AsAggregateType(); for (int i = 0; i < ats.GetTypeArgsAll().Size; i++) { if (TypeContainsTyVars(ats.GetTypeArgsAll().Item(i), typeVars)) { return true; } } } return false; case TypeKind.TK_ErrorType: if (type.AsErrorType().HasParent()) { ErrorType err = type.AsErrorType(); Debug.Assert(err.nameText != null && err.typeArgs != null); for (int i = 0; i < err.typeArgs.Size; i++) { if (TypeContainsTyVars(err.typeArgs.Item(i), typeVars)) { return true; } } if (err.HasTypeParent()) { type = err.GetTypeParent(); goto LRecurse; } } return false; case TypeKind.TK_TypeParameterType: if (typeVars != null && typeVars.Size > 0) { int ivar = type.AsTypeParameterType().GetIndexInTotalParameters(); return ivar < typeVars.Size && type == typeVars.Item(ivar); } return true; } }
/* * BindImplicitConversion * * This is a complex routine with complex parameters. Generally, this should * be called through one of the helper methods that insulates you * from the complexity of the interface. This routine handles all the logic * associated with implicit conversions. * * exprSrc - the expression being converted. Can be null if only type conversion * info is being supplied. * typeSrc - type of the source * typeDest - type of the destination * exprDest - returns an expression of the src converted to the dest. If null, we * only care about whether the conversion can be attempted, not the * expression tree. * flags - flags possibly customizing the conversions allowed. E.g., can suppress * user-defined conversions. * * returns true if the conversion can be made, false if not. */ public bool Bind() { // 13.1 Implicit conversions // // The following conversions are classified as implicit conversions: // // * Identity conversions // * Implicit numeric conversions // * Implicit enumeration conversions // * Implicit reference conversions // * Boxing conversions // * Implicit type parameter conversions // * Implicit constant expression conversions // * User-defined implicit conversions // * Implicit conversions from an anonymous method expression to a compatible delegate type // * Implicit conversion from a method group to a compatible delegate type // * Conversions from the null type (11.2.7) to any nullable type // * Implicit nullable conversions // * Lifted user-defined implicit conversions // // Implicit conversions can occur in a variety of situations, including function member invocations // (14.4.3), cast expressions (14.6.6), and assignments (14.14). // Can't convert to or from the error type. if (_typeSrc == null || _typeDest == null || _typeDest.IsNeverSameType()) { return(false); } Debug.Assert(_typeSrc != null && _typeDest != null); // types must be supplied. Debug.Assert(_exprSrc == null || _typeSrc == _exprSrc.Type); // type of source should be correct if source supplied Debug.Assert(!_needsExprDest || _exprSrc != null); // need source expr to create dest expr switch (_typeDest.GetTypeKind()) { case TypeKind.TK_ErrorType: Debug.Assert(((ErrorType)_typeDest).HasParent); if (_typeSrc != _typeDest) { return(false); } if (_needsExprDest) { _exprDest = _exprSrc; } return(true); case TypeKind.TK_NullType: // Can only convert to the null type if src is null. if (!(_typeSrc is NullType)) { return(false); } if (_needsExprDest) { _exprDest = _exprSrc; } return(true); case TypeKind.TK_MethodGroupType: Debug.Fail("Something is wrong with Type.IsNeverSameType()"); return(false); case TypeKind.TK_ArgumentListType: return(_typeSrc == _typeDest); case TypeKind.TK_VoidType: return(false); default: break; } if (_typeSrc is ErrorType) { Debug.Assert(!(_typeDest is ErrorType)); return(false); } // 13.1.1 Identity conversion // // An identity conversion converts from any type to the same type. This conversion exists only // such that an entity that already has a required type can be said to be convertible to that type. if (_typeSrc == _typeDest && ((_flags & CONVERTTYPE.ISEXPLICIT) == 0 || (!_typeSrc.isPredefType(PredefinedType.PT_FLOAT) && !_typeSrc.isPredefType(PredefinedType.PT_DOUBLE)))) { if (_needsExprDest) { _exprDest = _exprSrc; } return(true); } if (_typeDest is NullableType nubDest) { return(BindNubConversion(nubDest)); } if (_typeSrc is NullableType nubSrc) { return(bindImplicitConversionFromNullable(nubSrc)); } if ((_flags & CONVERTTYPE.ISEXPLICIT) != 0) { _flags |= CONVERTTYPE.NOUDC; } // Get the fundamental types of destination. FUNDTYPE ftDest = _typeDest.fundType(); Debug.Assert(ftDest != FUNDTYPE.FT_NONE || _typeDest is ParameterModifierType); switch (_typeSrc.GetTypeKind()) { default: Debug.Fail($"Bad type symbol kind: {_typeSrc.GetTypeKind()}"); break; case TypeKind.TK_VoidType: case TypeKind.TK_ErrorType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_ArgumentListType: return(false); case TypeKind.TK_NullType: if (bindImplicitConversionFromNull()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_ArrayType: if (bindImplicitConversionFromArray()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_PointerType: if (bindImplicitConversionFromPointer()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_AggregateType: if (bindImplicitConversionFromAgg(_typeSrc as AggregateType)) { return(true); } // If not, try user defined implicit conversions. break; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // Every incoming dynamic operand should be implicitly convertible // to any type that it is an instance of. object srcRuntimeObject = _exprSrc?.RuntimeObject; if (srcRuntimeObject != null && _typeDest.AssociatedSystemType.IsInstanceOfType(srcRuntimeObject) && _binder.GetSemanticChecker().CheckTypeAccess(_typeDest, _binder.Context.ContextForMemberLookup)) { if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, _exprSrc.Flags & EXPRFLAG.EXF_CANTBENULL); } return(true); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // END RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // 13.1.8 User-defined implicit conversions // // A user-defined implicit conversion consists of an optional standard implicit conversion, // followed by execution of a user-defined implicit conversion operator, followed by another // optional standard implicit conversion. The exact rules for evaluating user-defined // conversions are described in 13.4.3. if (0 == (_flags & CONVERTTYPE.NOUDC)) { return(_binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, true)); } // No conversion was found. return(false); }
/* * BindImplicitConversion * * This is a complex routine with complex parameters. Generally, this should * be called through one of the helper methods that insulates you * from the complexity of the interface. This routine handles all the logic * associated with implicit conversions. * * exprSrc - the expression being converted. Can be null if only type conversion * info is being supplied. * typeSrc - type of the source * typeDest - type of the destination * exprDest - returns an expression of the src converted to the dest. If null, we * only care about whether the conversion can be attempted, not the * expression tree. * flags - flags possibly customizing the conversions allowed. E.g., can suppress * user-defined conversions. * * returns true if the conversion can be made, false if not. */ public bool Bind() { // 13.1 Implicit conversions // // The following conversions are classified as implicit conversions: // // * Identity conversions // * Implicit numeric conversions // * Implicit enumeration conversions // * Implicit reference conversions // * Boxing conversions // * Implicit type parameter conversions // * Implicit constant expression conversions // * User-defined implicit conversions // * Implicit conversions from an anonymous method expression to a compatible delegate type // * Implicit conversion from a method group to a compatible delegate type // * Conversions from the null type (11.2.7) to any nullable type // * Implicit nullable conversions // * Lifted user-defined implicit conversions // // Implicit conversions can occur in a variety of situations, including function member invocations // (14.4.3), cast expressions (14.6.6), and assignments (14.14). // Can't convert to or from the error type. if (typeSrc == null || typeDest == null || typeDest.IsNeverSameType()) { return(false); } Debug.Assert(typeSrc != null && typeDest != null); // types must be supplied. Debug.Assert(exprSrc == null || typeSrc == exprSrc.type); // type of source should be correct if source supplied Debug.Assert(!needsExprDest || exprSrc != null); // need source expr to create dest expr switch (typeDest.GetTypeKind()) { case TypeKind.TK_ErrorType: Debug.Assert(typeDest.AsErrorType().HasTypeParent() || typeDest.AsErrorType().HasNSParent()); if (typeSrc != typeDest) { return(false); } if (needsExprDest) { exprDest = exprSrc; } return(true); case TypeKind.TK_NullType: // Can only convert to the null type if src is null. if (!typeSrc.IsNullType()) { return(false); } if (needsExprDest) { exprDest = exprSrc; } return(true); case TypeKind.TK_MethodGroupType: VSFAIL("Something is wrong with Type.IsNeverSameType()"); return(false); case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_ArgumentListType: return(typeSrc == typeDest); case TypeKind.TK_VoidType: return(false); default: break; } if (typeSrc.IsErrorType()) { Debug.Assert(!typeDest.IsErrorType()); return(false); } // 13.1.1 Identity conversion // // An identity conversion converts from any type to the same type. This conversion exists only // such that an entity that already has a required type can be said to be convertible to that type. if (typeSrc == typeDest && ((flags & CONVERTTYPE.ISEXPLICIT) == 0 || (!typeSrc.isPredefType(PredefinedType.PT_FLOAT) && !typeSrc.isPredefType(PredefinedType.PT_DOUBLE)))) { if (needsExprDest) { exprDest = exprSrc; } return(true); } if (typeDest.IsNullableType()) { return(BindNubConversion(typeDest.AsNullableType())); } if (typeSrc.IsNullableType()) { return(bindImplicitConversionFromNullable(typeSrc.AsNullableType())); } if ((flags & CONVERTTYPE.ISEXPLICIT) != 0) { flags |= CONVERTTYPE.NOUDC; } // Get the fundamental types of destination. FUNDTYPE ftDest = typeDest.fundType(); Debug.Assert(ftDest != FUNDTYPE.FT_NONE || typeDest.IsParameterModifierType()); switch (typeSrc.GetTypeKind()) { default: VSFAIL("Bad type symbol kind"); break; case TypeKind.TK_MethodGroupType: if (exprSrc.isMEMGRP()) { EXPRCALL outExpr; bool retVal = binder.BindGrpConversion(exprSrc.asMEMGRP(), typeDest, needsExprDest, out outExpr, false); exprDest = outExpr; return(retVal); } return(false); case TypeKind.TK_VoidType: case TypeKind.TK_ErrorType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_ArgumentListType: return(false); case TypeKind.TK_NullType: if (bindImplicitConversionFromNull()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_ArrayType: if (bindImplicitConversionFromArray()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_PointerType: if (bindImplicitConversionFromPointer()) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_TypeParameterType: if (bindImplicitConversionFromTypeVar(typeSrc.AsTypeParameterType())) { return(true); } // If not, try user defined implicit conversions. break; case TypeKind.TK_AggregateType: // TypeReference and ArgIterator can't be boxed (or converted to anything else) if (typeSrc.isSpecialByRefType()) { return(false); } if (bindImplicitConversionFromAgg(typeSrc.AsAggregateType())) { return(true); } // If not, try user defined implicit conversions. break; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // Every incoming dynamic operand should be implicitly convertible // to any type that it is an instance of. if (exprSrc != null && exprSrc.RuntimeObject != null && typeDest.AssociatedSystemType.IsInstanceOfType(exprSrc.RuntimeObject) && binder.GetSemanticChecker().CheckTypeAccess(typeDest, binder.Context.ContextForMemberLookup())) { if (needsExprDest) { binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, exprSrc.flags & EXPRFLAG.EXF_CANTBENULL); } return(true); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // END RUNTIME BINDER ONLY CHANGE // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // 13.1.8 User-defined implicit conversions // // A user-defined implicit conversion consists of an optional standard implicit conversion, // followed by execution of a user-defined implicit conversion operator, followed by another // optional standard implicit conversion. The exact rules for evaluating user-defined // conversions are described in 13.4.3. if (0 == (flags & CONVERTTYPE.NOUDC)) { return(binder.bindUserDefinedConversion(exprSrc, typeSrc, typeDest, needsExprDest, out exprDest, true)); } // No conversion was found. return(false); }
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); }
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(); if (t.IsMethodTypeParameter()) { MethodInfo meth = t.GetOwningSymbol().AsMethodSymbol().AssociatedMemberInfo as MethodInfo; result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()]; } else { Type 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 BetterType CompareTypes(TypeArray ta1, TypeArray ta2) { if (ta1 == ta2) { return(BetterType.Same); } if (ta1.Size != ta2.Size) { // The one with more parameters is more specific. return(ta1.Size > ta2.Size ? BetterType.Left : BetterType.Right); } BetterType nTot = BetterType.Neither; for (int i = 0; i < ta1.Size; i++) { CType type1 = ta1.Item(i); CType type2 = ta2.Item(i); BetterType nParam = BetterType.Neither; LAgain: if (type1.GetTypeKind() != type2.GetTypeKind()) { if (type1.IsTypeParameterType()) { nParam = BetterType.Right; } else if (type2.IsTypeParameterType()) { nParam = BetterType.Left; } } else { switch (type1.GetTypeKind()) { default: Debug.Assert(false, "Bad kind in CompareTypes"); break; case TypeKind.TK_TypeParameterType: case TypeKind.TK_ErrorType: break; case TypeKind.TK_PointerType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: type1 = type1.GetBaseOrParameterOrElementType(); type2 = type2.GetBaseOrParameterOrElementType(); goto LAgain; case TypeKind.TK_AggregateType: nParam = CompareTypes(type1.AsAggregateType().GetTypeArgsAll(), type2.AsAggregateType().GetTypeArgsAll()); break; } } if (nParam == BetterType.Right || nParam == BetterType.Left) { if (nTot == BetterType.Same || nTot == BetterType.Neither) { nTot = nParam; } else if (nParam != nTot) { return(BetterType.Neither); } } } return(nTot); }
private bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx) { LRecurse: // Label used for "tail" recursion. if (typeDst == typeSrc || typeDst.Equals(typeSrc)) { return(true); } switch (typeSrc.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in SubstEqualTypesCore"); return(false); case TypeKind.TK_NullType: case TypeKind.TK_VoidType: // There should only be a single instance of these. Debug.Assert(typeDst.GetTypeKind() != typeSrc.GetTypeKind()); return(false); case TypeKind.TK_ArrayType: ArrayType arrSrc = (ArrayType)typeSrc; if (!(typeDst is ArrayType arrDst) || arrDst.rank != arrSrc.rank || arrDst.IsSZArray != arrSrc.IsSZArray) { return(false); } goto LCheckBases; case TypeKind.TK_ParameterModifierType: if (!(typeDst is ParameterModifierType modDest) || ((pctx.grfst & SubstTypeFlags.NoRefOutDifference) == 0 && modDest.isOut != ((ParameterModifierType)typeSrc).isOut)) { return(false); } goto LCheckBases; case TypeKind.TK_PointerType: case TypeKind.TK_NullableType: if (typeDst.GetTypeKind() != typeSrc.GetTypeKind()) { return(false); } LCheckBases: typeSrc = typeSrc.GetBaseOrParameterOrElementType(); typeDst = typeDst.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: if (!(typeDst is AggregateType atsDst)) { return(false); } { // BLOCK AggregateType atsSrc = (AggregateType)typeSrc; if (atsSrc.getAggregate() != atsDst.getAggregate()) { return(false); } Debug.Assert(atsSrc.GetTypeArgsAll().Count == atsDst.GetTypeArgsAll().Count); // All the args must unify. for (int i = 0; i < atsSrc.GetTypeArgsAll().Count; i++) { if (!SubstEqualTypesCore(atsDst.GetTypeArgsAll()[i], atsSrc.GetTypeArgsAll()[i], pctx)) { return(false); } } } return(true); case TypeKind.TK_ErrorType: ErrorType errSrc = (ErrorType)typeSrc; if (!(typeDst is ErrorType errDst) || !errSrc.HasParent || !errDst.HasParent) { return(false); } { Debug.Assert(errSrc.nameText != null && errSrc.typeArgs != null); Debug.Assert(errDst.nameText != null && errDst.typeArgs != null); if (errSrc.nameText != errDst.nameText || errSrc.typeArgs.Count != errDst.typeArgs.Count || errSrc.HasParent != errDst.HasParent) { return(false); } // All the args must unify. for (int i = 0; i < errSrc.typeArgs.Count; i++) { if (!SubstEqualTypesCore(errDst.typeArgs[i], errSrc.typeArgs[i], pctx)) { return(false); } } } return(true); case TypeKind.TK_TypeParameterType: { // BLOCK TypeParameterSymbol tvs = ((TypeParameterType)typeSrc).GetTypeParameterSymbol(); int index = tvs.GetIndexInTotalParameters(); if (tvs.IsMethodTypeParameter()) { if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null) { // typeDst == typeSrc was handled above. Debug.Assert(typeDst != typeSrc); return(false); } Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters()); Debug.Assert(pctx.prgtypeMeth == null || tvs.GetIndexInTotalParameters() < pctx.ctypeMeth); if (index < pctx.ctypeMeth && pctx.prgtypeMeth != null) { return(typeDst == pctx.prgtypeMeth[index]); } if ((pctx.grfst & SubstTypeFlags.NormMeth) != 0) { return(typeDst == GetStdMethTypeVar(index)); } } else { if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null) { // typeDst == typeSrc was handled above. Debug.Assert(typeDst != typeSrc); return(false); } Debug.Assert(pctx.prgtypeCls == null || tvs.GetIndexInTotalParameters() < pctx.ctypeCls); if (index < pctx.ctypeCls) { return(typeDst == pctx.prgtypeCls[index]); } if ((pctx.grfst & SubstTypeFlags.NormClass) != 0) { return(typeDst == GetStdClsTypeVar(index)); } } } return(false); } }
private CType SubstTypeCore(CType type, SubstContext pctx) { CType typeSrc; CType typeDst; switch (type.GetTypeKind()) { default: Debug.Assert(false); return(type); case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_MethodGroupType: case TypeKind.TK_ArgumentListType: return(type); case TypeKind.TK_ParameterModifierType: ParameterModifierType mod = (ParameterModifierType)type; typeDst = SubstTypeCore(typeSrc = mod.GetParameterType(), pctx); return((typeDst == typeSrc) ? type : GetParameterModifier(typeDst, mod.isOut)); case TypeKind.TK_ArrayType: var arr = (ArrayType)type; typeDst = SubstTypeCore(typeSrc = arr.GetElementType(), pctx); return((typeDst == typeSrc) ? type : GetArray(typeDst, arr.rank, arr.IsSZArray)); case TypeKind.TK_PointerType: typeDst = SubstTypeCore(typeSrc = ((PointerType)type).GetReferentType(), pctx); return((typeDst == typeSrc) ? type : GetPointer(typeDst)); case TypeKind.TK_NullableType: typeDst = SubstTypeCore(typeSrc = ((NullableType)type).GetUnderlyingType(), pctx); return((typeDst == typeSrc) ? type : GetNullable(typeDst)); case TypeKind.TK_AggregateType: AggregateType ats = (AggregateType)type; if (ats.GetTypeArgsAll().Count > 0) { TypeArray typeArgs = SubstTypeArray(ats.GetTypeArgsAll(), pctx); if (ats.GetTypeArgsAll() != typeArgs) { return(GetAggregate(ats.getAggregate(), typeArgs)); } } return(type); case TypeKind.TK_ErrorType: ErrorType err = (ErrorType)type; if (err.HasParent) { Debug.Assert(err.nameText != null && err.typeArgs != null); TypeArray typeArgs = SubstTypeArray(err.typeArgs, pctx); if (typeArgs != err.typeArgs) { return(GetErrorType(err.nameText, typeArgs)); } } return(type); case TypeKind.TK_TypeParameterType: { TypeParameterSymbol tvs = ((TypeParameterType)type).GetTypeParameterSymbol(); int index = tvs.GetIndexInTotalParameters(); if (tvs.IsMethodTypeParameter()) { if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null) { return(type); } Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters()); if (index < pctx.ctypeMeth) { Debug.Assert(pctx.prgtypeMeth != null); return(pctx.prgtypeMeth[index]); } else { return((pctx.grfst & SubstTypeFlags.NormMeth) != 0 ? GetStdMethTypeVar(index) : type); } } if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null) { return(type); } return(index < pctx.ctypeCls ? pctx.prgtypeCls[index] : ((pctx.grfst & SubstTypeFlags.NormClass) != 0 ? GetStdClsTypeVar(index) : type)); } } }
// It would be nice to make this a virtual method on typeSym. public AggregateType GetAggTypeSym(CType typeSym) { Debug.Assert(typeSym != null); Debug.Assert(typeSym.IsAggregateType() || typeSym.IsTypeParameterType() || typeSym.IsArrayType() || typeSym.IsNullableType()); switch (typeSym.GetTypeKind()) { case TypeKind.TK_AggregateType: return typeSym.AsAggregateType(); case TypeKind.TK_ArrayType: return GetReqPredefType(PredefinedType.PT_ARRAY); case TypeKind.TK_TypeParameterType: return typeSym.AsTypeParameterType().GetEffectiveBaseClass(); case TypeKind.TK_NullableType: return typeSym.AsNullableType().GetAts(ErrorContext); } Debug.Assert(false, "Bad typeSym!"); return null; }
private AggregateType GetUserDefinedBinopArgumentType(CType type) { for (; ;) { switch (type.GetTypeKind()) { case TypeKind.TK_NullableType: type = type.StripNubs(); break; case TypeKind.TK_TypeParameterType: type = type.AsTypeParameterType().GetEffectiveBaseClass(); break; case TypeKind.TK_AggregateType: if ((type.isClassType() || type.isStructType()) && !type.AsAggregateType().getAggregate().IsSkipUDOps()) { return type.AsAggregateType(); } return null; default: return null; } } }
public static bool TypeContainsType(CType type, CType typeFind) { LRecurse: // Label used for "tail" recursion. if (type == typeFind || type.Equals(typeFind)) return true; switch (type.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in TypeContainsType"); return false; case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: // There should only be a single instance of these. Debug.Assert(typeFind.GetTypeKind() != type.GetTypeKind()); return false; case TypeKind.TK_ArrayType: case TypeKind.TK_NullableType: case TypeKind.TK_ParameterModifierType: case TypeKind.TK_PointerType: type = type.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: { // BLOCK AggregateType ats = type.AsAggregateType(); for (int i = 0; i < ats.GetTypeArgsAll().Size; i++) { if (TypeContainsType(ats.GetTypeArgsAll().Item(i), typeFind)) return true; } } return false; case TypeKind.TK_ErrorType: if (type.AsErrorType().HasParent()) { ErrorType err = type.AsErrorType(); Debug.Assert(err.nameText != null && err.typeArgs != null); for (int i = 0; i < err.typeArgs.Size; i++) { if (TypeContainsType(err.typeArgs.Item(i), typeFind)) return true; } if (err.HasTypeParent()) { type = err.GetTypeParent(); goto LRecurse; } } return false; case TypeKind.TK_TypeParameterType: return false; } }
public bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx) { LRecurse: // Label used for "tail" recursion. if (typeDst == typeSrc || typeDst.Equals(typeSrc)) { return true; } switch (typeSrc.GetTypeKind()) { default: Debug.Assert(false, "Bad Symbol kind in SubstEqualTypesCore"); return false; case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: // There should only be a single instance of these. Debug.Assert(typeDst.GetTypeKind() != typeSrc.GetTypeKind()); return false; case TypeKind.TK_ArrayType: if (typeDst.GetTypeKind() != TypeKind.TK_ArrayType || typeDst.AsArrayType().rank != typeSrc.AsArrayType().rank) return false; goto LCheckBases; case TypeKind.TK_ParameterModifierType: if (typeDst.GetTypeKind() != TypeKind.TK_ParameterModifierType || ((pctx.grfst & SubstTypeFlags.NoRefOutDifference) == 0 && typeDst.AsParameterModifierType().isOut != typeSrc.AsParameterModifierType().isOut)) return false; goto LCheckBases; case TypeKind.TK_PointerType: case TypeKind.TK_NullableType: if (typeDst.GetTypeKind() != typeSrc.GetTypeKind()) return false; LCheckBases: typeSrc = typeSrc.GetBaseOrParameterOrElementType(); typeDst = typeDst.GetBaseOrParameterOrElementType(); goto LRecurse; case TypeKind.TK_AggregateType: if (typeDst.GetTypeKind() != TypeKind.TK_AggregateType) return false; { // BLOCK AggregateType atsSrc = typeSrc.AsAggregateType(); AggregateType atsDst = typeDst.AsAggregateType(); if (atsSrc.getAggregate() != atsDst.getAggregate()) return false; Debug.Assert(atsSrc.GetTypeArgsAll().Size == atsDst.GetTypeArgsAll().Size); // All the args must unify. for (int i = 0; i < atsSrc.GetTypeArgsAll().Size; i++) { if (!SubstEqualTypesCore(atsDst.GetTypeArgsAll().Item(i), atsSrc.GetTypeArgsAll().Item(i), pctx)) return false; } } return true; case TypeKind.TK_ErrorType: if (!typeDst.IsErrorType() || !typeSrc.AsErrorType().HasParent() || !typeDst.AsErrorType().HasParent()) return false; { ErrorType errSrc = typeSrc.AsErrorType(); ErrorType errDst = typeDst.AsErrorType(); Debug.Assert(errSrc.nameText != null && errSrc.typeArgs != null); Debug.Assert(errDst.nameText != null && errDst.typeArgs != null); if (errSrc.nameText != errDst.nameText || errSrc.typeArgs.Size != errDst.typeArgs.Size) return false; if (errSrc.HasTypeParent() != errDst.HasTypeParent()) { return false; } if (errSrc.HasTypeParent()) { if (errSrc.GetTypeParent() != errDst.GetTypeParent()) { return false; } if (!SubstEqualTypesCore(errDst.GetTypeParent(), errSrc.GetTypeParent(), pctx)) { return false; } } else { if (errSrc.GetNSParent() != errDst.GetNSParent()) { return false; } } // All the args must unify. for (int i = 0; i < errSrc.typeArgs.Size; i++) { if (!SubstEqualTypesCore(errDst.typeArgs.Item(i), errSrc.typeArgs.Item(i), pctx)) return false; } } return true; case TypeKind.TK_TypeParameterType: { // BLOCK TypeParameterSymbol tvs = typeSrc.AsTypeParameterType().GetTypeParameterSymbol(); int index = tvs.GetIndexInTotalParameters(); if (tvs.IsMethodTypeParameter()) { if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null) { // typeDst == typeSrc was handled above. Debug.Assert(typeDst != typeSrc); return false; } Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters()); Debug.Assert(pctx.prgtypeMeth == null || tvs.GetIndexInTotalParameters() < pctx.ctypeMeth); if (index < pctx.ctypeMeth && pctx.prgtypeMeth != null) { return typeDst == pctx.prgtypeMeth[index]; } if ((pctx.grfst & SubstTypeFlags.NormMeth) != 0) { return typeDst == GetStdMethTypeVar(index); } } else { if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null) { // typeDst == typeSrc was handled above. Debug.Assert(typeDst != typeSrc); return false; } Debug.Assert(pctx.prgtypeCls == null || tvs.GetIndexInTotalParameters() < pctx.ctypeCls); if (index < pctx.ctypeCls) return typeDst == pctx.prgtypeCls[index]; if ((pctx.grfst & SubstTypeFlags.NormClass) != 0) return typeDst == GetStdClsTypeVar(index); } } return false; } }
private CType SubstTypeCore(CType type, SubstContext pctx) { CType typeSrc; CType typeDst; switch (type.GetTypeKind()) { default: Debug.Assert(false); return type; case TypeKind.TK_NullType: case TypeKind.TK_VoidType: case TypeKind.TK_OpenTypePlaceholderType: case TypeKind.TK_MethodGroupType: case TypeKind.TK_BoundLambdaType: case TypeKind.TK_UnboundLambdaType: case TypeKind.TK_NaturalIntegerType: case TypeKind.TK_ArgumentListType: return type; case TypeKind.TK_ParameterModifierType: typeDst = SubstTypeCore(typeSrc = type.AsParameterModifierType().GetParameterType(), pctx); return (typeDst == typeSrc) ? type : GetParameterModifier(typeDst, type.AsParameterModifierType().isOut); case TypeKind.TK_ArrayType: typeDst = SubstTypeCore(typeSrc = type.AsArrayType().GetElementType(), pctx); return (typeDst == typeSrc) ? type : GetArray(typeDst, type.AsArrayType().rank); case TypeKind.TK_PointerType: typeDst = SubstTypeCore(typeSrc = type.AsPointerType().GetReferentType(), pctx); return (typeDst == typeSrc) ? type : GetPointer(typeDst); case TypeKind.TK_NullableType: typeDst = SubstTypeCore(typeSrc = type.AsNullableType().GetUnderlyingType(), pctx); return (typeDst == typeSrc) ? type : GetNullable(typeDst); case TypeKind.TK_AggregateType: if (type.AsAggregateType().GetTypeArgsAll().size > 0) { AggregateType ats = type.AsAggregateType(); TypeArray typeArgs = SubstTypeArray(ats.GetTypeArgsAll(), pctx); if (ats.GetTypeArgsAll() != typeArgs) return GetAggregate(ats.getAggregate(), typeArgs); } return type; case TypeKind.TK_ErrorType: if (type.AsErrorType().HasParent()) { ErrorType err = type.AsErrorType(); Debug.Assert(err.nameText != null && err.typeArgs != null); CType pParentType = null; if (err.HasTypeParent()) { pParentType = SubstTypeCore(err.GetTypeParent(), pctx); } TypeArray typeArgs = SubstTypeArray(err.typeArgs, pctx); if (typeArgs != err.typeArgs || (err.HasTypeParent() && pParentType != err.GetTypeParent())) { return GetErrorType(pParentType, err.GetNSParent(), err.nameText, typeArgs); } } return type; case TypeKind.TK_TypeParameterType: { TypeParameterSymbol tvs = type.AsTypeParameterType().GetTypeParameterSymbol(); int index = tvs.GetIndexInTotalParameters(); if (tvs.IsMethodTypeParameter()) { if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null) return type; Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters()); if (index < pctx.ctypeMeth) { Debug.Assert(pctx.prgtypeMeth != null); return pctx.prgtypeMeth[index]; } else { return ((pctx.grfst & SubstTypeFlags.NormMeth) != 0 ? GetStdMethTypeVar(index) : type); } } if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null) return type; return index < pctx.ctypeCls ? pctx.prgtypeCls[index] : ((pctx.grfst & SubstTypeFlags.NormClass) != 0 ? GetStdClsTypeVar(index) : type); } } }
//////////////////////////////////////////////////////////////////////////////// // Determine whether the arg type satisfies the typeBnd constraint. Note that // typeBnd could be just about any type (since we added naked type parameter // constraints). private static bool SatisfiesBound(CSemanticChecker checker, CType arg, CType typeBnd) { if (typeBnd == arg) return true; switch (typeBnd.GetTypeKind()) { default: Debug.Assert(false, "Unexpected type."); return false; case TypeKind.TK_VoidType: case TypeKind.TK_PointerType: case TypeKind.TK_ErrorType: return false; case TypeKind.TK_ArrayType: case TypeKind.TK_TypeParameterType: break; case TypeKind.TK_NullableType: typeBnd = typeBnd.AsNullableType().GetAts(checker.GetErrorContext()); if (null == typeBnd) return true; break; case TypeKind.TK_AggregateType: break; } Debug.Assert(typeBnd.IsAggregateType() || typeBnd.IsTypeParameterType() || typeBnd.IsArrayType()); switch (arg.GetTypeKind()) { default: return false; case TypeKind.TK_ErrorType: case TypeKind.TK_PointerType: return false; case TypeKind.TK_NullableType: arg = arg.AsNullableType().GetAts(checker.GetErrorContext()); if (null == arg) return true; // Fall through. goto case TypeKind.TK_TypeParameterType; case TypeKind.TK_TypeParameterType: case TypeKind.TK_ArrayType: case TypeKind.TK_AggregateType: return checker.GetSymbolLoader().HasBaseConversion(arg, typeBnd); } }
/* * BindExplicitConversion * * This is a complex routine with complex parameter. Generally, this should * be called through one of the helper methods that insulates you * from the complexity of the interface. This routine handles all the logic * associated with explicit conversions. * * Note that this function calls BindImplicitConversion first, so the main * logic is only concerned with conversions that can be made explicitly, but * not implicitly. */ public bool Bind() { // To test for a standard conversion, call canConvert(exprSrc, typeDest, STANDARDANDCONVERTTYPE.NOUDC) and // canConvert(typeDest, typeSrc, STANDARDANDCONVERTTYPE.NOUDC). Debug.Assert((_flags & CONVERTTYPE.STANDARD) == 0); // 13.2 Explicit conversions // // The following conversions are classified as explicit conversions: // // * All implicit conversions // * Explicit numeric conversions // * Explicit enumeration conversions // * Explicit reference conversions // * Explicit interface conversions // * Unboxing conversions // * Explicit type parameter conversions // * User-defined explicit conversions // * Explicit nullable conversions // * Lifted user-defined explicit conversions // // Explicit conversions can occur in cast expressions (14.6.6). // // The explicit conversions that are not implicit conversions are conversions that cannot be // proven always to succeed, conversions that are known possibly to lose information, and // conversions across domains of types sufficiently different to merit explicit notation. // The set of explicit conversions includes all implicit conversions. // Don't try user-defined conversions now because we'll try them again later. if (_binder.BindImplicitConversion(_exprSrc, _typeSrc, _exprTypeDest, _pDestinationTypeForLambdaErrorReporting, _needsExprDest, out _exprDest, _flags | CONVERTTYPE.ISEXPLICIT)) { return(true); } if (_typeSrc == null || _typeDest == null || _typeSrc is ErrorType || _typeDest is ErrorType || _typeDest.IsNeverSameType()) { return(false); } if (_typeDest is NullableType) { // This is handled completely by BindImplicitConversion. return(false); } if (_typeSrc is NullableType) { return(bindExplicitConversionFromNub()); } if (bindExplicitConversionFromArrayToIList()) { return(true); } // if we were casting an integral constant to another constant type, // then, if the constant were in range, then the above call would have succeeded. // But it failed, and so we know that the constant is not in range switch (_typeDest.GetTypeKind()) { default: VSFAIL("Bad type kind"); return(false); case TypeKind.TK_VoidType: return(false); // Can't convert to a method group or anon method. case TypeKind.TK_NullType: return(false); // Can never convert TO the null type. case TypeKind.TK_TypeParameterType: if (bindExplicitConversionToTypeVar()) { return(true); } break; case TypeKind.TK_ArrayType: if (bindExplicitConversionToArray((ArrayType)_typeDest)) { return(true); } break; case TypeKind.TK_PointerType: if (bindExplicitConversionToPointer()) { return(true); } break; case TypeKind.TK_AggregateType: { AggCastResult result = bindExplicitConversionToAggregate(_typeDest as AggregateType); if (result == AggCastResult.Success) { return(true); } if (result == AggCastResult.Abort) { return(false); } break; } } // No built-in conversion was found. Maybe a user-defined conversion? if (0 == (_flags & CONVERTTYPE.NOUDC)) { return(_binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, false)); } return(false); }
public void ErrAppendType(CType pType, SubstContext pctx, bool fArgs) { if (pctx != null) { if (!pctx.FNop()) { pType = GetTypeManager().SubstType(pType, pctx); } // We shouldn't use the SubstContext again so set it to NULL. pctx = null; } switch (pType.GetTypeKind()) { case TypeKind.TK_AggregateType: { AggregateType pAggType = pType.AsAggregateType(); // Check for a predefined class with a special "nice" name for // error reported. string text = PredefinedTypes.GetNiceName(pAggType.getAggregate()); if (text != null) { // Found a nice name. ErrAppendString(text); } else if (pAggType.getAggregate().IsAnonymousType()) { ErrAppendPrintf("AnonymousType#{0}", GetTypeID(pAggType)); break; } else { if (pAggType.outerType != null) { ErrAppendType(pAggType.outerType, pctx); ErrAppendChar('.'); } else { // In a namespace. ErrAppendParentSym(pAggType.getAggregate(), pctx); } ErrAppendName(pAggType.getAggregate().name); } ErrAppendTypeParameters(pAggType.GetTypeArgsThis(), pctx, true); break; } case TypeKind.TK_TypeParameterType: if (null == pType.GetName()) { // It's a standard type variable. if (pType.AsTypeParameterType().IsMethodTypeParameter()) { ErrAppendChar('!'); } ErrAppendChar('!'); ErrAppendPrintf("{0}", pType.AsTypeParameterType().GetIndexInTotalParameters()); } else { ErrAppendName(pType.GetName()); } break; case TypeKind.TK_ErrorType: if (pType.AsErrorType().HasParent()) { Debug.Assert(pType.AsErrorType().nameText != null && pType.AsErrorType().typeArgs != null); ErrAppendParentType(pType, pctx); ErrAppendName(pType.AsErrorType().nameText); ErrAppendTypeParameters(pType.AsErrorType().typeArgs, pctx, true); } else { // Load the string "<error>". Debug.Assert(null == pType.AsErrorType().typeArgs); ErrAppendId(MessageID.ERRORSYM); } break; case TypeKind.TK_NullType: // Load the string "<null>". ErrAppendId(MessageID.NULL); break; case TypeKind.TK_OpenTypePlaceholderType: // Leave blank. break; case TypeKind.TK_BoundLambdaType: ErrAppendId(MessageID.AnonMethod); break; case TypeKind.TK_UnboundLambdaType: ErrAppendId(MessageID.Lambda); break; case TypeKind.TK_MethodGroupType: ErrAppendId(MessageID.MethodGroup); break; case TypeKind.TK_ArgumentListType: ErrAppendString(TokenFacts.GetText(TokenKind.ArgList)); break; case TypeKind.TK_ArrayType: { CType elementType = pType.AsArrayType().GetBaseElementType(); int rank; if (null == elementType) { Debug.Assert(false, "No element type"); break; } ErrAppendType(elementType, pctx); for (elementType = pType; elementType != null && elementType.IsArrayType(); elementType = elementType.AsArrayType().GetElementType()) { rank = elementType.AsArrayType().rank; // Add [] with (rank-1) commas inside ErrAppendChar('['); #if ! CSEE // known rank. if (rank > 1) { ErrAppendChar('*'); } #endif for (int i = rank; i > 1; --i) { ErrAppendChar(','); #if ! CSEE ErrAppendChar('*'); #endif } ErrAppendChar(']'); } break; } case TypeKind.TK_VoidType: ErrAppendName(GetNameManager().Lookup(TokenFacts.GetText(TokenKind.Void))); break; case TypeKind.TK_ParameterModifierType: // add ref or out ErrAppendString(pType.AsParameterModifierType().isOut ? "out " : "ref "); // add base type name ErrAppendType(pType.AsParameterModifierType().GetParameterType(), pctx); break; case TypeKind.TK_PointerType: // Generate the base type. ErrAppendType(pType.AsPointerType().GetReferentType(), pctx); { // add the trailing * ErrAppendChar('*'); } break; case TypeKind.TK_NullableType: ErrAppendType(pType.AsNullableType().GetUnderlyingType(), pctx); ErrAppendChar('?'); break; case TypeKind.TK_NaturalIntegerType: default: // Shouldn't happen. Debug.Assert(false, "Bad type kind"); break; } }