// Create an expr for new T?(exprSrc) where T is exprSrc.type. private static ExprCall BindNubNew(Expr exprSrc) { Debug.Assert(exprSrc != null); NullableType pNubSourceType = TypeManager.GetNullable(exprSrc.Type); AggregateType pSourceType = pNubSourceType.GetAts(); MethodSymbol meth = PredefinedMembers.GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR); MethWithInst methwithinst = new MethWithInst(meth, pSourceType, TypeArray.Empty); ExprMemberGroup memgroup = ExprFactory.CreateMemGroup(null, methwithinst); return(ExprFactory.CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, exprSrc, memgroup, methwithinst)); }
public AggregateType GetAts() { if (ats == null) { AggregateSymbol aggNullable = typeManager.GetNullable(); CType typePar = GetUnderlyingType(); CType[] typeParArray = { typePar }; TypeArray ta = symmgr.AllocParams(1, typeParArray); ats = typeManager.GetAggregate(aggNullable, ta); } return(ats); }
private static void FixLiftedUserDefinedBinaryOperators(ExprBinOp expr, ref Expr pp1, ref Expr pp2) { // If we have lifted T1 op T2 to T1? op T2?, and we have an expression T1 op T2? or T1? op T2 then // we need to ensure that the unlifted actual arguments are promoted to their nullable CType. Debug.Assert(expr != null); Debug.Assert(pp1 != null); Debug.Assert(pp1 != null); Debug.Assert(pp2 != null); Debug.Assert(pp2 != null); MethodSymbol method = expr.UserDefinedCallMethod.Meth(); Expr orig1 = expr.OptionalLeftChild; Expr orig2 = expr.OptionalRightChild; Debug.Assert(orig1 != null && orig2 != null); Expr new1 = pp1; Expr new2 = pp2; CType fptype1 = method.Params[0]; CType fptype2 = method.Params[1]; CType aatype1 = orig1.Type; CType aatype2 = orig2.Type; // Is the operator even a candidate for lifting? if (!(fptype1 is AggregateType fat1) || !fat1.OwningAggregate.IsValueType() || !(fptype2 is AggregateType fat2) || !fat2.OwningAggregate.IsValueType()) { return; } CType nubfptype1 = TypeManager.GetNullable(fptype1); CType nubfptype2 = TypeManager.GetNullable(fptype2); // If we have null op X, or T1 op T2?, or T1 op null, lift first arg to T1? if (aatype1 is NullType || aatype1 == fptype1 && (aatype2 == nubfptype2 || aatype2 is NullType)) { new1 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, new1, CreateTypeOf(nubfptype1)); } // If we have X op null, or T1? op T2, or null op T2, lift second arg to T2? if (aatype2 is NullType || aatype2 == fptype2 && (aatype1 == nubfptype1 || aatype1 is NullType)) { new2 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, new2, CreateTypeOf(nubfptype2)); } pp1 = new1; pp2 = new2; }
public AggregateType GetAts(ErrorHandling errorContext) { AggregateSymbol aggNullable = typeManager.GetNullable(); if (aggNullable == null) { throw Error.InternalCompilerError(); } if (ats == null) { CType typePar = GetUnderlyingType(); CType[] typeParArray = new CType[] { typePar }; TypeArray ta = symmgr.AllocParams(1, typeParArray); ats = typeManager.GetAggregate(aggNullable, ta); } return(ats); }
private static Expr GenerateUserDefinedConversion(Expr arg, CType CType, Expr target, MethWithInst method) { // The user-defined explicit conversion from enum? to decimal or decimal? requires // that we convert the enum? to its nullable underlying CType. if (isEnumToDecimalConversion(arg.Type, CType)) { // Special case: If we have enum? to decimal? then we need to emit // a conversion from enum? to its nullable underlying CType first. // This is unfortunate; we ought to reorganize how conversions are // represented in the Expr tree so that this is more transparent. // converting an enum to its underlying CType never fails, so no need to check it. CType underlyingType = arg.Type.StripNubs().UnderlyingEnumType; CType nullableType = TypeManager.GetNullable(underlyingType); Expr typeofNubEnum = CreateTypeOf(nullableType); target = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, target, typeofNubEnum); } // If the methodinfo does not return the target CType AND this is not a lifted conversion // from one value CType to another, then we need to wrap the whole thing in another conversion, // e.g. if we have a user-defined conversion from int to S? and we have (S)myint, then we need to generate // Convert(Convert(myint, typeof(S?), op_implicit), typeof(S)) CType pMethodReturnType = TypeManager.SubstType(method.Meth().RetType, method.GetType(), method.TypeArgs); bool fDontLiftReturnType = (pMethodReturnType == CType || (IsNullableValueType(arg.Type) && IsNullableValueType(CType))); Expr typeofInner = CreateTypeOf(fDontLiftReturnType ? CType : pMethodReturnType); Expr methodInfo = ExprFactory.CreateMethodInfo(method); PREDEFMETH pdmInner = arg.isChecked() ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED; Expr callUserDefinedConversion = GenerateCall(pdmInner, target, typeofInner, methodInfo); if (fDontLiftReturnType) { return(callUserDefinedConversion); } PREDEFMETH pdmOuter = arg.isChecked() ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED : PREDEFMETH.PM_EXPRESSION_CONVERT; Expr typeofOuter = CreateTypeOf(CType); return(GenerateCall(pdmOuter, callUserDefinedConversion, typeofOuter)); }
public AggregateType GetAts(ErrorHandling errorContext) { AggregateSymbol aggNullable = typeManager.GetNullable(); if (aggNullable == null) { throw Error.InternalCompilerError(); } if (ats == null) { if (aggNullable == null) { typeManager.ReportMissingPredefTypeError(errorContext, PredefinedType.PT_G_OPTIONAL); return(null); } CType typePar = GetUnderlyingType(); CType[] typeParArray = new CType[] { typePar }; TypeArray ta = symmgr.AllocParams(1, typeParArray); ats = typeManager.GetAggregate(aggNullable, ta); } return(ats); }
public AggregateType GetAts() => _ats ?? (_ats = _typeManager.GetAggregate( _typeManager.GetNullable(), _symmgr.AllocParams(UnderlyingType)));
public override AggregateType GetAts() => _ats ?? (_ats = TypeManager.GetAggregate(TypeManager.GetNullable(), TypeArray.Allocate(UnderlyingType)));
private Expr GenerateBuiltInBinaryOperator(ExprBinOp expr) { Debug.Assert(expr != null); PREDEFMETH pdm = expr.Kind switch { ExpressionKind.LeftShirt => PREDEFMETH.PM_EXPRESSION_LEFTSHIFT, ExpressionKind.RightShift => PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT, ExpressionKind.BitwiseExclusiveOr => PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR, ExpressionKind.BitwiseOr => PREDEFMETH.PM_EXPRESSION_OR, ExpressionKind.BitwiseAnd => PREDEFMETH.PM_EXPRESSION_AND, ExpressionKind.LogicalAnd => PREDEFMETH.PM_EXPRESSION_ANDALSO, ExpressionKind.LogicalOr => PREDEFMETH.PM_EXPRESSION_ORELSE, ExpressionKind.StringEq => PREDEFMETH.PM_EXPRESSION_EQUAL, ExpressionKind.Eq => PREDEFMETH.PM_EXPRESSION_EQUAL, ExpressionKind.StringNotEq => PREDEFMETH.PM_EXPRESSION_NOTEQUAL, ExpressionKind.NotEq => PREDEFMETH.PM_EXPRESSION_NOTEQUAL, ExpressionKind.GreaterThanOrEqual => PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL, ExpressionKind.LessThanOrEqual => PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL, ExpressionKind.LessThan => PREDEFMETH.PM_EXPRESSION_LESSTHAN, ExpressionKind.GreaterThan => PREDEFMETH.PM_EXPRESSION_GREATERTHAN, ExpressionKind.Modulo => PREDEFMETH.PM_EXPRESSION_MODULO, ExpressionKind.Divide => PREDEFMETH.PM_EXPRESSION_DIVIDE, ExpressionKind.Multiply => expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED : PREDEFMETH.PM_EXPRESSION_MULTIPLY, ExpressionKind.Subtract => expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED : PREDEFMETH.PM_EXPRESSION_SUBTRACT, ExpressionKind.Add => expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_ADDCHECKED : PREDEFMETH.PM_EXPRESSION_ADD, _ => throw Error.InternalCompilerError(), }; Expr origL = expr.OptionalLeftChild; Expr origR = expr.OptionalRightChild; Debug.Assert(origL != null); Debug.Assert(origR != null); CType typeL = origL.Type; CType typeR = origR.Type; Expr newL = Visit(origL); Expr newR = Visit(origR); bool didEnumConversion = false; CType convertL = null; CType convertR = null; if (typeL.IsEnumType) { // We have already inserted casts if not lifted, so we should never see an enum. Debug.Assert(expr.IsLifted); convertL = TypeManager.GetNullable(typeL.UnderlyingEnumType); typeL = convertL; didEnumConversion = true; } else if (typeL is NullableType nubL && nubL.UnderlyingType.IsEnumType) { Debug.Assert(expr.IsLifted); convertL = TypeManager.GetNullable(nubL.UnderlyingType.UnderlyingEnumType); typeL = convertL; didEnumConversion = true; } if (typeR.IsEnumType) { Debug.Assert(expr.IsLifted); convertR = TypeManager.GetNullable(typeR.UnderlyingEnumType); typeR = convertR; didEnumConversion = true; } else if (typeR is NullableType nubR && nubR.UnderlyingType.IsEnumType) { Debug.Assert(expr.IsLifted); convertR = TypeManager.GetNullable(nubR.UnderlyingType.UnderlyingEnumType); typeR = convertR; didEnumConversion = true; } if (typeL is NullableType nubL2 && nubL2.UnderlyingType == typeR) { convertR = typeL; } if (typeR is NullableType nubR2 && nubR2.UnderlyingType == typeL) { convertL = typeR; } if (convertL != null) { newL = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, newL, CreateTypeOf(convertL)); } if (convertR != null) { newR = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, newR, CreateTypeOf(convertR)); } Expr call = GenerateCall(pdm, newL, newR); if (didEnumConversion && expr.Type.StripNubs().IsEnumType) { call = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, call, CreateTypeOf(expr.Type)); } return(call); }