private bool bindImplicitConversionBetweenSimpleTypes(AggregateType aggTypeSrc) { AggregateSymbol aggSrc = aggTypeSrc.getAggregate(); Debug.Assert(aggSrc.getThisType().isSimpleType()); Debug.Assert(_typeDest.isSimpleType()); Debug.Assert(aggSrc.IsPredefined() && _typeDest.isPredefined()); PredefinedType ptSrc = aggSrc.GetPredefType(); PredefinedType ptDest = _typeDest.getPredefType(); ConvKind convertKind; bool fConstShrinkCast = false; Debug.Assert((int)ptSrc < NUM_SIMPLE_TYPES && (int)ptDest < NUM_SIMPLE_TYPES); // 13.1.7 Implicit constant expression conversions // // An implicit constant expression conversion permits the following conversions: // * A constant-expression (14.16) of type int can be converted to type sbyte, byte, short, // ushort, uint, or ulong, provided the value of the constant-expression is within the range // of the destination type. // * A constant-expression of type long can be converted to type ulong, provided the value of // the constant-expression is not negative. // Note: Don't use GetConst here since the conversion only applies to bona-fide compile time constants. if (_exprSrc is ExprConstant constant && _exprSrc.IsOK && ((ptSrc == PredefinedType.PT_INT && ptDest != PredefinedType.PT_BOOL && ptDest != PredefinedType.PT_CHAR) || (ptSrc == PredefinedType.PT_LONG && ptDest == PredefinedType.PT_ULONG)) && isConstantInRange(constant, _typeDest)) { // Special case (CLR 6.1.6): if integral constant is in range, the conversion is a legal implicit conversion. convertKind = ConvKind.Implicit; fConstShrinkCast = _needsExprDest && (GetConvKind(ptSrc, ptDest) != ConvKind.Implicit); }
private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, AggregateDeclaration context, AggregateType typeSrc, out CType typeDst) { Debug.Assert(typeSrc != null); Debug.Assert(typeSrc.IsInterfaceType || typeSrc.IsDelegateType); typeDst = null; AggregateSymbol aggSym = typeSrc.OwningAggregate; AggregateType aggOpenType = aggSym.getThisType(); if (!semanticChecker.CheckTypeAccess(aggOpenType, context)) { // 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.TypeArgsThis; TypeArray typeParams = aggOpenType.TypeArgsThis; CType[] newTypeArgsTemp = new CType[typeArgs.Count]; for (int i = 0; i < newTypeArgsTemp.Length; i++) { CType typeArg = typeArgs[i]; if (semanticChecker.CheckTypeAccess(typeArg, context)) { // we have an accessible argument, this position is not a problem. newTypeArgsTemp[i] = typeArg; continue; } if (!typeArg.IsReferenceType || !((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); } newTypeArgsTemp[i] = GetBestAccessibleType(semanticChecker, context, typeArg); // 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. } TypeArray newTypeArgs = semanticChecker.getBSymmgr().AllocParams(typeArgs.Count, newTypeArgsTemp); CType intermediateType = 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, errHandling: null, intermediateType, CheckConstraintsFlags.NoErrors)) { return(false); } typeDst = intermediateType; Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, context)); return(true); }
private bool bindImplicitConversionFromAgg(AggregateType aggTypeSrc) { // GENERICS: The case for constructed types is very similar to types with // no parameters. The parameters are irrelevant for most of the conversions // below. They could be relevant if we had user-defined conversions on // generic types. AggregateSymbol aggSrc = aggTypeSrc.getAggregate(); if (aggSrc.IsEnum()) { return(bindImplicitConversionFromEnum(aggTypeSrc)); } if (_typeDest.isEnumType()) { if (bindImplicitConversionToEnum(aggTypeSrc)) { return(true); } // Even though enum is sealed, a class can derive from enum in LAF scenarios -- // continue testing for derived to base conversions below. } else if (aggSrc.getThisType().isSimpleType() && _typeDest.isSimpleType()) { if (bindImplicitConversionBetweenSimpleTypes(aggTypeSrc)) { return(true); } // No simple conversion -- continue testing for derived to base conversions below. } return(bindImplicitConversionToBase(aggTypeSrc)); }
public AggregateType GetAggregate(AggregateSymbol agg, TypeArray typeArgsAll) { Debug.Assert(typeArgsAll != null && typeArgsAll.Count == agg.GetTypeVarsAll().Count); if (typeArgsAll.Count == 0) { return(agg.getThisType()); } AggregateSymbol aggOuter = agg.GetOuterAgg(); if (aggOuter == null) { return(GetAggregate(agg, null, typeArgsAll)); } int cvarOuter = aggOuter.GetTypeVarsAll().Count; Debug.Assert(cvarOuter <= typeArgsAll.Count); TypeArray typeArgsOuter = _BSymmgr.AllocParams(cvarOuter, typeArgsAll, 0); TypeArray typeArgsInner = _BSymmgr.AllocParams(agg.GetTypeVars().Count, typeArgsAll, cvarOuter); AggregateType atsOuter = GetAggregate(aggOuter, typeArgsOuter); return(GetAggregate(agg, atsOuter, typeArgsInner)); }
private AggCastResult bindExplicitConversionBetweenAggregates(AggregateType aggTypeDest) { // 13.2.3 // // The explicit reference conversions are: // // * From object to any reference-type. // * From any class-type S to any class-type T, provided S is a base class of T. // * From any class-type S to any interface-type T, provided S is not sealed and // provided S does not implement T. // * From any interface-type S to any class-type T, provided T is not sealed or provided // T implements S. // * From any interface-type S to any interface-type T, provided S is not derived from T. Debug.Assert(_typeSrc != null); Debug.Assert(aggTypeDest != null); if (!(_typeSrc is AggregateType atSrc)) { return(AggCastResult.Failure); } AggregateSymbol aggSrc = atSrc.getAggregate(); AggregateSymbol aggDest = aggTypeDest.getAggregate(); if (GetSymbolLoader().HasBaseConversion(aggTypeDest, atSrc)) { if (_needsExprDest) { if (aggDest.IsValueType() && aggSrc.getThisType().fundType() == FUNDTYPE.FT_REF) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_UNBOX); } else { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK | (_exprSrc?.Flags & EXPRFLAG.EXF_CANTBENULL ?? 0)); } } return(AggCastResult.Success); } if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) || (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) || (aggSrc.IsInterface() && aggDest.IsInterface()) || CConversions.HasGenericDelegateExplicitReferenceConversion(GetSymbolLoader(), _typeSrc, aggTypeDest)) { if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK | (_exprSrc?.Flags & EXPRFLAG.EXF_CANTBENULL ?? 0)); } return(AggCastResult.Success); } return(AggCastResult.Failure); }
public AggregateType GetOptPredefType(PredefinedType pt, bool fEnsureState) { AggregateSymbol agg = GetTypeManager().GetOptPredefAgg(pt); if (agg == null) { return(null); } AggregateType ats = agg.getThisType(); return(ats); }
public AggregateType GetReqPredefType(PredefinedType pt, bool fEnsureState) { AggregateSymbol agg = GetTypeManager().GetReqPredefAgg(pt); if (agg == null) { Debug.Assert(false, "Required predef type missing"); return(null); } AggregateType ats = agg.getThisType(); return(ats); }
public AggregateType GetOptPredefTypeErr(PredefinedType pt, bool fEnsureState) { AggregateSymbol agg = GetTypeManager().GetOptPredefAgg(pt); if (agg == null) { getPredefTypes().ReportMissingPredefTypeError(ErrorContext, pt); return(null); } AggregateType ats = agg.getThisType(); return(ats); }
// 13.2.2 Explicit enumeration conversions // // The explicit enumeration conversions are: // // * From sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, or // decimal to any enum-type. // // * From any enum-type to sbyte, byte, short, ushort, int, uint, long, ulong, char, // float, double, or decimal. // // * From any enum-type to any other enum-type. // // * An explicit enumeration conversion between two types is processed by treating any // participating enum-type as the underlying type of that enum-type, and then performing // an implicit or explicit numeric conversion between the resulting types. private AggCastResult bindExplicitConversionFromEnumToAggregate(AggregateType aggTypeDest) { Debug.Assert(_typeSrc != null); Debug.Assert(aggTypeDest != null); if (!_typeSrc.isEnumType()) { return(AggCastResult.Failure); } AggregateSymbol aggDest = aggTypeDest.getAggregate(); if (aggDest.isPredefAgg(PredefinedType.PT_DECIMAL)) { return(bindExplicitConversionFromEnumToDecimal(aggTypeDest)); } if (!aggDest.getThisType().isNumericType() && !aggDest.IsEnum() && !(aggDest.IsPredefined() && aggDest.GetPredefType() == PredefinedType.PT_CHAR)) { return(AggCastResult.Failure); } if (_exprSrc.GetConst() != null) { ConstCastResult result = _binder.bindConstantCast(_exprSrc, _exprTypeDest, _needsExprDest, out _exprDest, true); if (result == ConstCastResult.Success) { return(AggCastResult.Success); } else if (result == ConstCastResult.CheckFailure) { return(AggCastResult.Abort); } } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest); } return(AggCastResult.Success); }
///////////////////////////////////////////////////////////////////////////////// private CType GetConstructedType(Type type, AggregateSymbol agg) { // We've found the one we want, so return it. if (type.GetTypeInfo().IsGenericType) { // If we're a generic type, then we need to add the type arguments. List<CType> types = new List<CType>(); foreach (Type argument in type.GetGenericArguments()) { types.Add(GetCTypeFromType(argument)); } TypeArray typeArray = _bsymmgr.AllocParams(types.ToArray()); AggregateType aggType = _typeManager.GetAggregate(agg, typeArray); return aggType; } CType ctype = agg.getThisType(); return ctype; }
///////////////////////////////////////////////////////////////////////////////// internal void AddPredefinedMethodToSymbolTable(AggregateSymbol type, Name methodName) { Type t = type.getThisType().AssociatedSystemType; // If we got here, it means we couldn't find it in our initial lookup. Means we haven't loaded it from reflection yet. // Lets go and do that now. // Check if we have constructors or not. if (methodName == _nameManager.GetPredefinedName(PredefinedName.PN_CTOR)) { var ctors = Enumerable.Where(t.GetConstructors(), m => m.Name == methodName.Text); foreach (ConstructorInfo c in ctors) { AddMethodToSymbolTable( c, type, MethodKindEnum.Constructor); } } else { var methods = Enumerable.Where(t.GetRuntimeMethods(), m => m.Name == methodName.Text && m.DeclaringType == t); foreach (MethodInfo m in methods) { AddMethodToSymbolTable( m, type, m.Name == SpecialNames.Invoke ? MethodKindEnum.Invoke : MethodKindEnum.Actual); } } }
///////////////////////////////////////////////////////////////////////////////// internal void AddPredefinedPropertyToSymbolTable(AggregateSymbol type, Name property) { AggregateType aggtype = type.getThisType(); Type t = aggtype.AssociatedSystemType; var props = Enumerable.Where(t.GetRuntimeProperties(), x => x.Name == property.Text); foreach (PropertyInfo pi in props) { AddPropertyToSymbolTable(pi, type); } }
private bool bindImplicitConversionBetweenSimpleTypes(AggregateType aggTypeSrc) { AggregateSymbol aggSrc = aggTypeSrc.getAggregate(); Debug.Assert(aggSrc.getThisType().isSimpleType()); Debug.Assert(typeDest.isSimpleType()); Debug.Assert(aggSrc.IsPredefined() && typeDest.isPredefined()); PredefinedType ptSrc = aggSrc.GetPredefType(); PredefinedType ptDest = typeDest.getPredefType(); ConvKind convertKind; bool fConstShrinkCast = false; Debug.Assert((int)ptSrc < NUM_SIMPLE_TYPES && (int)ptDest < NUM_SIMPLE_TYPES); // 13.1.7 Implicit constant expression conversions // // An implicit constant expression conversion permits the following conversions: // * A constant-expression (14.16) of type int can be converted to type sbyte, byte, short, // ushort, uint, or ulong, provided the value of the constant-expression is within the range // of the destination type. // * A constant-expression of type long can be converted to type ulong, provided the value of // the constant-expression is not negative. // Note: Don't use GetConst here since the conversion only applies to bona-fide compile time constants. if (exprSrc != null && exprSrc.isCONSTANT_OK() && ((ptSrc == PredefinedType.PT_INT && ptDest != PredefinedType.PT_BOOL && ptDest != PredefinedType.PT_CHAR) || (ptSrc == PredefinedType.PT_LONG && ptDest == PredefinedType.PT_ULONG)) && isConstantInRange(exprSrc.asCONSTANT(), typeDest)) { // Special case (CLR 6.1.6): if integral constant is in range, the conversion is a legal implicit conversion. convertKind = ConvKind.Implicit; fConstShrinkCast = needsExprDest && (GetConvKind(ptSrc, ptDest) != ConvKind.Implicit); } else if (ptSrc == ptDest) { // Special case: precision limiting casts to float or double Debug.Assert(ptSrc == PredefinedType.PT_FLOAT || ptSrc == PredefinedType.PT_DOUBLE); Debug.Assert(0 != (flags & CONVERTTYPE.ISEXPLICIT)); convertKind = ConvKind.Implicit; } else { convertKind = GetConvKind(ptSrc, ptDest); Debug.Assert(convertKind != ConvKind.Identity); // identity conversion should have been handled at first. } if (convertKind != ConvKind.Implicit) { return(false); } // An implicit conversion exists. Do the conversion. if (exprSrc.GetConst() != null) { // Fold the constant cast if possible. ConstCastResult result = binder.bindConstantCast(exprSrc, exprTypeDest, needsExprDest, out exprDest, false); if (result == ConstCastResult.Success) { return(true); // else, don't fold and use a regular cast, below. } // REVIEW: I don't think this can ever be hit. If exprSrc is a constant then // it's either a floating point number (which always succeeds), it's a numeric implicit // conversion (which always succeeds), or it's a constant numeric conversion (which // has already been checked by isConstantInRange, so should always succeed) } if (isUserDefinedConversion(ptSrc, ptDest)) { if (!needsExprDest) { return(true); } // According the language, this is a standard conversion, but it is implemented // through a user-defined conversion. Because it's a standard conversion, we don't // test the NOUDC flag here. return(binder.bindUserDefinedConversion(exprSrc, aggTypeSrc, typeDest, needsExprDest, out exprDest, true)); } if (needsExprDest) { binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest); } 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.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); }
public AggregateType GetAggregate(AggregateSymbol agg, TypeArray typeArgsAll) { Debug.Assert(typeArgsAll != null && typeArgsAll.Size == agg.GetTypeVarsAll().Size); if (typeArgsAll.size == 0) return agg.getThisType(); AggregateSymbol aggOuter = agg.GetOuterAgg(); if (aggOuter == null) return GetAggregate(agg, null, typeArgsAll); int cvarOuter = aggOuter.GetTypeVarsAll().Size; Debug.Assert(cvarOuter <= typeArgsAll.Size); TypeArray typeArgsOuter = _BSymmgr.AllocParams(cvarOuter, typeArgsAll, 0); TypeArray typeArgsInner = _BSymmgr.AllocParams(agg.GetTypeVars().Size, typeArgsAll, cvarOuter); AggregateType atsOuter = GetAggregate(aggOuter, typeArgsOuter); return GetAggregate(agg, atsOuter, typeArgsInner); }