protected override Expr VisitFIELD(ExprField expr) { Debug.Assert(expr != null); Expr pObject; if (expr.OptionalObject == null) { pObject = ExprFactory.CreateNull(); } else { pObject = Visit(expr.OptionalObject); } ExprFieldInfo pFieldInfo = ExprFactory.CreateFieldInfo(expr.FieldWithType.Field(), expr.FieldWithType.GetType()); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_FIELD, pObject, pFieldInfo)); }
protected override Expr VisitPROP(ExprProperty expr) { Debug.Assert(expr != null); Expr pObject; if (expr.PropWithTypeSlot.Prop().isStatic || expr.MemberGroup.OptionalObject == null) { pObject = ExprFactory.CreateNull(); } else { pObject = Visit(expr.MemberGroup.OptionalObject); } Expr propInfo = ExprFactory.CreatePropertyInfo(expr.PropWithTypeSlot.Prop(), expr.PropWithTypeSlot.GetType()); if (expr.OptionalArguments != null) { // It is an indexer property. Turn it into a virtual method call. Expr args = GenerateArgsList(expr.OptionalArguments); Expr Params = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, pObject, propInfo, Params)); } return(GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, pObject, propInfo)); }
///////////////////////////////////////////////////////////////////////////////// private static EXPR GenerateOptionalArgument( SymbolLoader symbolLoader, ExprFactory exprFactory, MethodOrPropertySymbol methprop, CType type, int index) { CType pParamType = type; CType pRawParamType = type.IsNullableType() ? type.AsNullableType().GetUnderlyingType() : type; EXPR optionalArgument = null; if (methprop.HasDefaultParameterValue(index)) { CType pConstValType = methprop.GetDefaultParameterValueConstValType(index); CONSTVAL cv = methprop.GetDefaultParameterValue(index); if (pConstValType.isPredefType(PredefinedType.PT_DATETIME) && (pRawParamType.isPredefType(PredefinedType.PT_DATETIME) || pRawParamType.isPredefType(PredefinedType.PT_OBJECT) || pRawParamType.isPredefType(PredefinedType.PT_VALUE))) { // This is the specific case where we want to create a DateTime // but the constval that stores it is a long. AggregateType dateTimeType = symbolLoader.GetReqPredefType(PredefinedType.PT_DATETIME); optionalArgument = exprFactory.CreateConstant(dateTimeType, new CONSTVAL(DateTime.FromBinary(cv.longVal))); } else if (pConstValType.isSimpleOrEnumOrString()) { // In this case, the constval is a simple type (all the numerics, including // decimal), or an enum or a string. This covers all the substantial values, // and everything else that can be encoded is just null or default(something). // For enum parameters, we create a constant of the enum type. For everything // else, we create the appropriate constant. if (pRawParamType.isEnumType() && pConstValType == pRawParamType.underlyingType()) { optionalArgument = exprFactory.CreateConstant(pRawParamType, cv); } else { optionalArgument = exprFactory.CreateConstant(pConstValType, cv); } } else if ((pParamType.IsRefType() || pParamType.IsNullableType()) && cv.IsNullRef()) { // We have an "= null" default value with a reference type or a nullable type. optionalArgument = exprFactory.CreateNull(); } else { // We have a default value that is encoded as a nullref, and that nullref is // interpreted as default(something). For instance, the pParamType could be // a type parameter type or a non-simple value type. optionalArgument = exprFactory.CreateZeroInit(pParamType); } } else { // There was no default parameter specified, so generally use default(T), // except for some cases when the parameter type in metatdata is object. if (pParamType.isPredefType(PredefinedType.PT_OBJECT)) { if (methprop.MarshalAsObject(index)) { // For [opt] parameters of type object, if we have marshal(iunknown), // marshal(idispatch), or marshal(interface), then we emit a null. optionalArgument = exprFactory.CreateNull(); } else { // Otherwise, we generate Type.Missing AggregateSymbol agg = symbolLoader.GetOptPredefAgg(PredefinedType.PT_MISSING); Name name = symbolLoader.GetNameManager().GetPredefinedName(PredefinedName.PN_CAP_VALUE); FieldSymbol field = symbolLoader.LookupAggMember(name, agg, symbmask_t.MASK_FieldSymbol).AsFieldSymbol(); FieldWithType fwt = new FieldWithType(field, agg.getThisType()); EXPRFIELD exprField = exprFactory.CreateField(0, agg.getThisType(), null, 0, fwt, null); if (agg.getThisType() != type) { optionalArgument = exprFactory.CreateCast(0, type, exprField); } else { optionalArgument = exprField; } } } else { // Every type aside from object that doesn't have a default value gets // its default value. optionalArgument = exprFactory.CreateZeroInit(pParamType); } } Debug.Assert(optionalArgument != null); optionalArgument.IsOptionalArgument = true; return optionalArgument; }
protected override Expr VisitCALL(ExprCall expr) { Debug.Assert(expr != null); switch (expr.NullableCallLiftKind) { default: break; case NullableCallLiftKind.NullableIntermediateConversion: case NullableCallLiftKind.NullableConversion: case NullableCallLiftKind.NullableConversionConstructor: return(GenerateConversion(expr.OptionalArguments, expr.Type, expr.isChecked())); case NullableCallLiftKind.NotLiftedIntermediateConversion: case NullableCallLiftKind.UserDefinedConversion: return(GenerateUserDefinedConversion(expr.OptionalArguments, expr.Type, expr.MethWithInst)); } if (expr.MethWithInst.Meth().IsConstructor()) { return(GenerateConstructor(expr)); } ExprMemberGroup memberGroup = expr.MemberGroup; if (memberGroup.IsDelegate) { return(GenerateDelegateInvoke(expr)); } Expr pObject; if (expr.MethWithInst.Meth().isStatic || expr.MemberGroup.OptionalObject == null) { pObject = ExprFactory.CreateNull(); } else { pObject = expr.MemberGroup.OptionalObject; // If we have, say, an int? which is the object of a call to ToString // then we do NOT want to generate ((object)i).ToString() because that // will convert a null-valued int? to a null object. Rather what we want // to do is box it to a ValueType and call ValueType.ToString. // // To implement this we say that if the object of the call is an implicit boxing cast // then just generate the object, not the cast. If the cast is explicit in the // source code then it will be an EXPLICITCAST and we will visit it normally. // // It might be better to rewrite the expression tree API so that it // can handle in the general case all implicit boxing conversions. Right now it // requires that all arguments to a call that need to be boxed be explicitly boxed. if (pObject != null && pObject is ExprCast cast && cast.IsBoxingCast) { pObject = cast.Argument; } pObject = Visit(pObject); } Expr methodInfo = ExprFactory.CreateMethodInfo(expr.MethWithInst); Expr args = GenerateArgsList(expr.OptionalArguments); Expr Params = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); PREDEFMETH pdm = PREDEFMETH.PM_EXPRESSION_CALL; Debug.Assert(!expr.MethWithInst.Meth().isVirtual || expr.MemberGroup.OptionalObject != null); return(GenerateCall(pdm, pObject, methodInfo, Params)); }