///////////////////////////////////////////////////////////////////////////////// // Expression types. private ExprBinOp VisitBoundLambda(ExprBoundLambda anonmeth) { Debug.Assert(anonmeth != null); MethodSymbol lambdaMethod = GetPreDefMethod(PREDEFMETH.PM_EXPRESSION_LAMBDA); AggregateType delegateType = anonmeth.DelegateType; TypeArray lambdaTypeParams = GetSymbolLoader().getBSymmgr().AllocParams(1, new CType[] { delegateType }); AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION); MethWithInst mwi = new MethWithInst(lambdaMethod, expressionType, lambdaTypeParams); Expr createParameters = CreateWraps(anonmeth); Debug.Assert(createParameters != null); Debug.Assert(anonmeth.Expression != null); Expr body = Visit(anonmeth.Expression); Debug.Assert(anonmeth.ArgumentScope.nextChild == null); Expr parameters = GenerateParamsArray(null, PredefinedType.PT_PARAMETEREXPRESSION); Expr args = GetExprFactory().CreateList(body, parameters); CType typeRet = GetSymbolLoader().GetTypeManager().SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs); ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); ExprCall call = GetExprFactory().CreateCall(0, typeRet, args, pMemGroup, mwi); call.PredefinedMethod = PREDEFMETH.PM_EXPRESSION_LAMBDA; return(GetExprFactory().CreateSequence(createParameters, call)); }
public ExprMethodInfo(CType type, MethodSymbol method, AggregateType methodType, TypeArray methodParameters) : base(ExpressionKind.MethodInfo, type) { Debug.Assert(method != null); Debug.Assert(methodType != null); Method = new MethWithInst(method, methodType, methodParameters); }
public ExprFuncPtr(CType type, EXPRFLAG flags, Expr optionalObject, MethWithInst method) : base(ExpressionKind.FunctionPointer, type) { Debug.Assert((flags & ~EXPRFLAG.EXF_BASECALL) == 0); Flags = flags; OptionalObject = optionalObject; MethWithInst = new MethWithInst(method); }
public ExprUserDefinedConversion(Expr argument, Expr call, MethWithInst method) : base(ExpressionKind.UserDefinedConversion) { Debug.Assert(argument != null); Debug.Assert(call != null); Argument = argument; UserDefinedCall = call; UserDefinedCallMethod = method; }
//////////////////////////////////////////////////////////////////////////////// // Check the constraints on the method instantiation. public static void CheckMethConstraints(MethWithInst mwi) { Debug.Assert(mwi.Meth() != null && mwi.GetType() != null && mwi.TypeArgs != null); Debug.Assert(mwi.Meth().typeVars.Count == mwi.TypeArgs.Count); Debug.Assert(mwi.GetType().OwningAggregate == mwi.Meth().getClass()); if (mwi.TypeArgs.Count > 0) { CheckConstraintsCore(mwi.Meth(), mwi.Meth().typeVars, mwi.TypeArgs, mwi.GetType().TypeArgsAll, mwi.TypeArgs, CheckConstraintsFlags.None); } }
public EXPRFUNCPTR CreateFunctionPointer(EXPRFLAG nFlags, CType pType, EXPR pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); EXPRFUNCPTR rval = new EXPRFUNCPTR(); rval.kind = ExpressionKind.EK_FUNCPTR; rval.type = pType; rval.flags = nFlags; rval.OptionalObject = pObject; rval.mwi = new MethWithInst(MWI); Debug.Assert(rval != null); return (rval); }
// 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 ExprCall(CType type, EXPRFLAG flags, Expr arguments, ExprMemberGroup member, MethWithInst method) : base(ExpressionKind.Call, type) { Debug.Assert( (flags & ~(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY)) == 0); Flags = flags; OptionalArguments = arguments; MemberGroup = member; NullableCallLiftKind = NullableCallLiftKind.NotLifted; MethWithInst = method; }
private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3, Expr arg4) { MethodSymbol method = GetPreDefMethod(pdm); if (method == null) { return(null); } AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION); Expr args = GetExprFactory().CreateList(arg1, arg2, arg3, arg4); MethWithInst mwi = new MethWithInst(method, expressionType); ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); ExprCall call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi); call.PredefinedMethod = pdm; return(call); }
private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1) { MethodSymbol method = GetPreDefMethod(pdm); // this should be enforced in an earlier pass and the transform pass should not // be handling this error if (method == null) { return(null); } AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION); MethWithInst mwi = new MethWithInst(method, expressionType); ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); ExprCall call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, arg1, pMemGroup, mwi); call.PredefinedMethod = pdm; return(call); }
public ExprCall BindNew(Expr pExprSrc) { Debug.Assert(pExprSrc != null); NullableType pNubSourceType = GetSymbolLoader().GetTypeManager().GetNullable(pExprSrc.Type); AggregateType pSourceType = pNubSourceType.GetAts(); MethodSymbol meth = GetSymbolLoader().getBSymmgr().methNubCtor; if (meth == null) { meth = GetSymbolLoader().getPredefinedMembers().GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR); Debug.Assert(meth != null); GetSymbolLoader().getBSymmgr().methNubCtor = meth; } MethWithInst methwithinst = new MethWithInst(meth, pSourceType, BSYMMGR.EmptyTypeArray()); ExprMemberGroup memgroup = GetExprFactory().CreateMemGroup(null, methwithinst); return(GetExprFactory().CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, pExprSrc, memgroup, methwithinst)); }
public EXPRCALL CreateCall(EXPRFLAG nFlags, CType pType, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY ) )); EXPRCALL rval = new EXPRCALL(); rval.kind = ExpressionKind.EK_CALL; rval.type = pType; rval.flags = nFlags; rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); rval.nubLiftKind = NullableCallLiftKind.NotLifted; rval.castOfNonLiftedResultToLiftedType = null; rval.mwi = MWI; Debug.Assert(rval != null); return (rval); }
public EXPRCALL BindNew(EXPR pExprSrc) { Debug.Assert(pExprSrc != null); NullableType pNubSourceType = GetSymbolLoader().GetTypeManager().GetNullable(pExprSrc.type); AggregateType pSourceType = pNubSourceType.GetAts(GetErrorContext()); if (pSourceType == null) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(pExprSrc, mwi); EXPRCALL rval = GetExprFactory().CreateCall(0, pNubSourceType, null, pMemGroup, null); rval.SetError(); return(rval); } // UNDONE: move this to transform pass MethodSymbol meth = GetSymbolLoader().getBSymmgr().methNubCtor; if (meth == null) { meth = GetSymbolLoader().getPredefinedMembers().GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR); GetSymbolLoader().getBSymmgr().methNubCtor = meth; } MethWithInst methwithinst = new MethWithInst(meth, pSourceType, BSYMMGR.EmptyTypeArray()); EXPRMEMGRP memgroup = GetExprFactory().CreateMemGroup(null, methwithinst); EXPRCALL pExprRes = GetExprFactory().CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, pExprSrc, memgroup, methwithinst); if (meth == null) { pExprRes.SetError(); } return(pExprRes); }
public ExprUserDefinedConversion CreateUserDefinedConversion(Expr arg, Expr call, MethWithInst mwi) { Debug.Assert(arg != null); Debug.Assert(call != null); ExprUserDefinedConversion rval = new ExprUserDefinedConversion(); rval.Kind = ExpressionKind.EK_USERDEFINEDCONVERSION; rval.Type = call.Type; rval.Flags = 0; rval.Argument = arg; rval.UserDefinedCall = call; rval.UserDefinedCallMethod = mwi; if (call.HasError) { rval.SetError(); } Debug.Assert(rval != null); return(rval); }
protected virtual EXPR GenerateDelegateConstructor(EXPRCALL expr) { // In: // // new DELEGATE(obj, &FUNC) // // Out: // // Cast( // Call( // null, // (MethodInfo)GetMethodFromHandle(&CreateDelegate), // new Expression[3]{ // Constant(typeof(DELEGATE)), // transformed-object, // Constant((MethodInfo)GetMethodFromHandle(&FUNC)}), // typeof(DELEGATE)) // Debug.Assert(expr != null); Debug.Assert(expr.mwi.Meth().IsConstructor()); Debug.Assert(expr.type.isDelegateType()); Debug.Assert(expr.GetOptionalArguments() != null); Debug.Assert(expr.GetOptionalArguments().isLIST()); EXPRLIST origArgs = expr.GetOptionalArguments().asLIST(); EXPR target = origArgs.GetOptionalElement(); Debug.Assert(origArgs.GetOptionalNextListNode().kind == ExpressionKind.EK_FUNCPTR); EXPRFUNCPTR funcptr = origArgs.GetOptionalNextListNode().asFUNCPTR(); MethodSymbol createDelegateMethod = GetPreDefMethod(PREDEFMETH.PM_METHODINFO_CREATEDELEGATE_TYPE_OBJECT); AggregateType delegateType = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_DELEGATE, true); MethWithInst mwi = new MethWithInst(createDelegateMethod, delegateType); EXPR instance = GenerateConstant(GetExprFactory().CreateMethodInfo(funcptr.mwi)); EXPR methinfo = GetExprFactory().CreateMethodInfo(mwi); EXPR param1 = GenerateConstant(CreateTypeOf(expr.type)); EXPR param2 = Visit(target); EXPR paramsList = GetExprFactory().CreateList(param1, param2); EXPR Params = GenerateParamsArray(paramsList, PredefinedType.PT_EXPRESSION); EXPR call = GenerateCall(PREDEFMETH.PM_EXPRESSION_CALL, instance, methinfo, Params); EXPR pTypeOf = CreateTypeOf(expr.type); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, call, pTypeOf); }
protected virtual EXPR GenerateUserDefinedConversion(EXPR arg, CType type, MethWithInst method) { EXPR target = Visit(arg); return GenerateUserDefinedConversion(arg, type, target, method); }
protected EXPRCALL GenerateCall(PREDEFMETH pdm, EXPR arg1) { MethodSymbol method = GetPreDefMethod(pdm); // this should be enforced in an earlier pass and the tranform pass should not // be handeling this error if (method == null) return null; AggregateType expressionType = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); MethWithInst mwi = new MethWithInst(method, expressionType); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, arg1, pMemGroup, mwi); call.PredefinedMethod = pdm; return call; }
//////////////////////////////////////////////////////////////////////////////// // This finds a method and binds it to the args provided. internal EXPRCALL BindPredefMethToArgs(PREDEFMETH predefMethod, EXPR obj, EXPR args, TypeArray clsTypeArgs, TypeArray methTypeArgs) { MethodSymbol methSym = GetSymbolLoader().getPredefinedMembers().GetMethod(predefMethod); if (methSym == null) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(obj, mwi); EXPRCALL rval = GetExprFactory().CreateCall(0, null, args, pMemGroup, null); rval.SetError(); return rval; } AggregateSymbol agg = methSym.getClass(); if (clsTypeArgs == null) { clsTypeArgs = BSYMMGR.EmptyTypeArray(); } AggregateType aggType = GetTypes().GetAggregate(agg, clsTypeArgs); MethPropWithInst mpwiBest = new MethPropWithInst(methSym, aggType, methTypeArgs); EXPRMEMGRP memgroup = GetExprFactory().CreateMemGroup(obj, mpwiBest); EXPRCALL exprRes = BindToMethod(new MethWithInst(mpwiBest), args, memgroup, (MemLookFlags)MemLookFlags.None); return exprRes; }
private Expr GenerateUserDefinedConversion(Expr arg, CType type, MethWithInst method) { Expr target = Visit(arg); return(GenerateUserDefinedConversion(arg, type, target, method)); }
public ExprUserDefinedConversion CreateUserDefinedConversion(Expr arg, Expr call, MethWithInst mwi) { Debug.Assert(arg != null); Debug.Assert(call != null); ExprUserDefinedConversion rval = new ExprUserDefinedConversion(); rval.Argument = arg; rval.UserDefinedCall = call; rval.UserDefinedCallMethod = mwi; if (call.HasError) { rval.SetError(); } return(rval); }
public static ExprUserDefinedConversion CreateUserDefinedConversion(Expr arg, Expr call, MethWithInst method) => new ExprUserDefinedConversion(arg, call, method);
public ExprFuncPtr CreateFunctionPointer(EXPRFLAG nFlags, CType pType, Expr pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); ExprFuncPtr rval = new ExprFuncPtr(pType); rval.Flags = nFlags; rval.OptionalObject = pObject; rval.MethWithInst = new MethWithInst(MWI); return(rval); }
internal void PostBindMethod(bool fBaseCall, ref MethWithInst pMWI, EXPR pObject) { MethWithInst mwiOrig = pMWI; // If it is virtual, find a remap of the method to something more specific. This // may alter where the method is found. if (pObject != null && (fBaseCall || pObject.type.isSimpleType() || pObject.type.isSpecialByRefType())) { RemapToOverride(GetSymbolLoader(), pMWI, pObject.type); } if (fBaseCall && pMWI.Meth().isAbstract) { ErrorContext.Error(ErrorCode.ERR_AbstractBaseCall, pMWI); } if (pMWI.Meth().RetType != null) { checkUnsafe(pMWI.Meth().RetType); bool fCheckParams = false; if (pMWI.Meth().isExternal) { fCheckParams = true; SetExternalRef(pMWI.Meth().RetType); } // We need to check unsafe on the parameters as well, since we cannot check in conversion. TypeArray pParams = pMWI.Meth().Params; for (int i = 0; i < pParams.size; i++) { // This is an optimization: don't call this in the vast majority of cases CType type = pParams.Item(i); if (type.isUnsafe()) { checkUnsafe(type); } if (fCheckParams && type.IsParameterModifierType()) { SetExternalRef(type); } } } }
//////////////////////////////////////////////////////////////////////////////// // Check the constraints on the method instantiation. public static void CheckMethConstraints(CSemanticChecker checker, ErrorHandling errCtx, MethWithInst mwi) { Debug.Assert(mwi.Meth() != null && mwi.GetType() != null && mwi.TypeArgs != null); Debug.Assert(mwi.Meth().typeVars.size == mwi.TypeArgs.size); Debug.Assert(mwi.GetType().getAggregate() == mwi.Meth().getClass()); if (mwi.TypeArgs.size > 0) { CheckConstraintsCore(checker, errCtx, mwi.Meth(), mwi.Meth().typeVars, mwi.TypeArgs, mwi.GetType().GetTypeArgsAll(), mwi.TypeArgs, CheckConstraintsFlags.None); } }
//////////////////////////////////////////////////////////////////////////////// // Binds a call to a method, return type is an error or an EXPRCALL. // // tree - ParseTree for error messages // pObject - pObject to call method on // pmwi - Meth to bind to. This will be morphed when we remap to an override. // args - arguments // exprFlags - Flags to put on the generated expr internal EXPRCALL BindToMethod(MethWithInst mwi, EXPR pArguments, EXPRMEMGRP pMemGroup, MemLookFlags flags) { Debug.Assert(mwi.Sym != null && mwi.Sym.IsMethodSymbol() && (!mwi.Meth().isOverride || mwi.Meth().isHideByName)); Debug.Assert(pMemGroup != null); bool fConstrained; bool bIsMatchingStatic; EXPR pObject = pMemGroup.GetOptionalObject(); CType callingObjectType = pObject != null ? pObject.type : null; PostBindMethod((flags & MemLookFlags.BaseCall) != 0, ref mwi, pObject); pObject = AdjustMemberObject(mwi, pObject, out fConstrained, out bIsMatchingStatic); pMemGroup.SetOptionalObject(pObject); CType pReturnType = null; if ((flags & (MemLookFlags.Ctor | MemLookFlags.NewObj)) == (MemLookFlags.Ctor | MemLookFlags.NewObj)) { pReturnType = mwi.Ats; } else { pReturnType = GetTypes().SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs); } EXPRCALL pResult = GetExprFactory().CreateCall(0, pReturnType, pArguments, pMemGroup, mwi); if (!bIsMatchingStatic) { pResult.SetMismatchedStaticBit(); } if (!pResult.isOK()) { return pResult; } // Set the return type and flags for constructors. if ((flags & MemLookFlags.Ctor) != 0) { if ((flags & MemLookFlags.NewObj) != 0) { pResult.flags |= EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL; } else { Debug.Assert(pResult.type == getVoidType()); } } if ((flags & MemLookFlags.BaseCall) != 0) { pResult.flags |= EXPRFLAG.EXF_BASECALL; } else if (fConstrained && pObject != null) { // Use the constrained prefix. pResult.flags |= EXPRFLAG.EXF_CONSTRAINED; } verifyMethodArgs(pResult, callingObjectType); return pResult; }
protected EXPR bindIndexer(EXPR pObject, EXPR args, BindingFlag bindFlags) { CType type = pObject.type; if (!type.IsAggregateType() && !type.IsTypeParameterType()) { ErrorContext.Error(ErrorCode.ERR_BadIndexLHS, type); MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(pObject, mwi); EXPRCALL rval = GetExprFactory().CreateCall(0, type, args, pMemGroup, null); rval.SetError(); return rval; } Name pName = GetSymbolLoader().GetNameManager().GetPredefName(PredefinedName.PN_INDEXERINTERNAL); MemberLookup mem = new MemberLookup(); if (!mem.Lookup(GetSemanticChecker(), type, pObject, ContextForMemberLookup(), pName, 0, (bindFlags & BindingFlag.BIND_BASECALL) != 0 ? (MemLookFlags.BaseCall | MemLookFlags.Indexer) : MemLookFlags.Indexer)) { mem.ReportErrors(); type = GetTypes().GetErrorSym(); Symbol pSymbol = null; if (mem.SwtInaccessible().Sym != null) { Debug.Assert(mem.SwtInaccessible().Sym.IsMethodOrPropertySymbol()); type = mem.SwtInaccessible().MethProp().RetType; pSymbol = mem.SwtInaccessible().Sym; } EXPRMEMGRP memgrp = null; if (pSymbol != null) { memgrp = GetExprFactory().CreateMemGroup((EXPRFLAG)mem.GetFlags(), pName, BSYMMGR.EmptyTypeArray(), pSymbol.getKind(), mem.GetSourceType(), null/*pMPS*/, mem.GetObject(), mem.GetResults()); memgrp.SetInaccessibleBit(); } else { MethWithInst mwi = new MethWithInst(null, null); memgrp = GetExprFactory().CreateMemGroup(mem.GetObject(), mwi); } EXPRCALL rval = GetExprFactory().CreateCall(0, type, args, memgrp, null); rval.SetError(); return rval; } Debug.Assert(mem.SymFirst().IsPropertySymbol() && mem.SymFirst().AsPropertySymbol().isIndexer()); EXPRMEMGRP grp = GetExprFactory().CreateMemGroup((EXPRFLAG)mem.GetFlags(), pName, BSYMMGR.EmptyTypeArray(), mem.SymFirst().getKind(), mem.GetSourceType(), null/*pMPS*/, mem.GetObject(), mem.GetResults()); EXPR pResult = BindMethodGroupToArguments(bindFlags, grp, args); Debug.Assert(pResult.HasObject()); if (pResult.getObject() == null) { // We must be in an error scenario where the object was not allowed. // This can happen if the user tries to access the indexer off the // type and not an instance or if the incorrect type/number of arguments // were passed for binding. pResult.SetObject(pObject); pResult.SetError(); } return pResult; }
public static ExprCall CreateCall(EXPRFLAG flags, CType type, Expr arguments, ExprMemberGroup memberGroup, MethWithInst method) => new ExprCall(type, flags, arguments, memberGroup, method);
public ExprCall CreateCall(EXPRFLAG nFlags, CType pType, Expr pOptionalArguments, ExprMemberGroup pMemberGroup, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY ) )); ExprCall rval = new ExprCall(); rval.Kind = ExpressionKind.EK_CALL; rval.Type = pType; rval.Flags = nFlags; rval.OptionalArguments = pOptionalArguments; rval.MemberGroup = pMemberGroup; rval.NullableCallLiftKind = NullableCallLiftKind.NotLifted; rval.CastOfNonLiftedResultToLiftedType = null; rval.MethWithInst = MWI; Debug.Assert(rval != null); return(rval); }
/*************************************************************************************************** * Called by BindImplicitConversion when the destination type is Nullable<T>. The following * conversions are handled by this method: * * For S in { object, ValueType, interfaces implemented by underlying type} there is an explicit * unboxing conversion S => T? * System.Enum => T? there is an unboxing conversion if T is an enum type * null => T? implemented as default(T?) * * Implicit T?* => T?+ implemented by either wrapping or calling GetValueOrDefault the * appropriate number of times. * If imp/exp S => T then imp/exp S => T?+ implemented by converting to T then wrapping the * appropriate number of times. * If imp/exp S => T then imp/exp S?+ => T?+ implemented by calling GetValueOrDefault (m-1) times * then calling HasValue, producing a null if it returns false, otherwise calling Value, * converting to T then wrapping the appropriate number of times. * * The 3 rules above can be summarized with the following recursive rules: * * If imp/exp S => T? then imp/exp S? => T? implemented as * qs.HasValue ? (T?)(qs.Value) : default(T?) * If imp/exp S => T then imp/exp S => T? implemented as new T?((T)s) * * This method also handles calling bindUserDefinedConverion. This method does NOT handle * the following conversions: * * Implicit boxing conversion from S? to { object, ValueType, Enum, ifaces implemented by S }. (Handled by BindImplicitConversion.) * If imp/exp S => T then explicit S?+ => T implemented by calling Value the appropriate number * of times. (Handled by BindExplicitConversion.) * * The recursive equivalent is: * * If imp/exp S => T and T is not nullable then explicit S? => T implemented as qs.Value * * Some nullable conversion are NOT standard conversions. In particular, if S => T is implicit * then S? => T is not standard. Similarly if S => T is not implicit then S => T? is not standard. ***************************************************************************************************/ private bool BindNubConversion(NullableType nubDst) { // This code assumes that STANDARD and ISEXPLICIT are never both set. // bindUserDefinedConversion should ensure this! Debug.Assert(0 != (~flags & (CONVERTTYPE.STANDARD | CONVERTTYPE.ISEXPLICIT))); Debug.Assert(exprSrc == null || exprSrc.type == typeSrc); Debug.Assert(!needsExprDest || exprSrc != null); Debug.Assert(typeSrc != nubDst); // BindImplicitConversion should have taken care of this already. AggregateType atsDst = nubDst.GetAts(GetErrorContext()); if (atsDst == null) { return(false); } // Check for the unboxing conversion. This takes precedence over the wrapping conversions. if (GetSymbolLoader().HasBaseConversion(nubDst.GetUnderlyingType(), typeSrc) && !CConversions.FWrappingConv(typeSrc, nubDst)) { // These should be different! Fix the caller if typeSrc is an AggregateType of Nullable. Debug.Assert(atsDst != typeSrc); // typeSrc is a base type of the destination nullable type so there is an explicit // unboxing conversion. if (0 == (flags & CONVERTTYPE.ISEXPLICIT)) { return(false); } if (needsExprDest) { binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, EXPRFLAG.EXF_UNBOX); } return(true); } int cnubDst; int cnubSrc; CType typeDstBase = nubDst.StripNubs(out cnubDst); EXPRCLASS exprTypeDstBase = GetExprFactory().MakeClass(typeDstBase); CType typeSrcBase = typeSrc.StripNubs(out cnubSrc); ConversionFunc pfn = (flags & CONVERTTYPE.ISEXPLICIT) != 0 ? (ConversionFunc)binder.BindExplicitConversion : (ConversionFunc)binder.BindImplicitConversion; if (cnubSrc == 0) { Debug.Assert(typeSrc == typeSrcBase); // The null type can be implicitly converted to T? as the default value. if (typeSrc.IsNullType()) { // If we have the constant null, generate it as a default value of T?. If we have // some crazy expression which has been determined to be always null, like (null??null) // keep it in its expression form and transform it in the nullable rewrite pass. if (needsExprDest) { if (exprSrc.isCONSTANT_OK()) { exprDest = GetExprFactory().CreateZeroInit(nubDst); } else { exprDest = GetExprFactory().CreateCast(0x00, typeDest, exprSrc); } } return(true); } EXPR exprTmp = exprSrc; // If there is an implicit/explicit S => T then there is an implicit/explicit S => T? if (typeSrc == typeDstBase || pfn(exprSrc, typeSrc, exprTypeDstBase, nubDst, needsExprDest, out exprTmp, flags | CONVERTTYPE.NOUDC)) { if (needsExprDest) { // UNDONE: This is a premature realization of the nullable conversion as // UNDONE: a constructor. Rather than flagging this, can we simply emit it // UNDONE: as a cast node and have the operator rewrite pass turn it into // UNDONE: a constructor call? EXPRUSERDEFINEDCONVERSION exprUDC = exprTmp.kind == ExpressionKind.EK_USERDEFINEDCONVERSION ? exprTmp.asUSERDEFINEDCONVERSION() : null; if (exprUDC != null) { exprTmp = exprUDC.UserDefinedCall; } // This logic is left over from the days when T?? was legal. However there are error/LAF cases that necessitates the loop. // typeSrc is not nullable so just wrap the required number of times. For legal code (cnubDst <= 0). for (int i = 0; i < cnubDst; i++) { exprTmp = binder.BindNubNew(exprTmp); exprTmp.asCALL().nubLiftKind = NullableCallLiftKind.NullableConversionConstructor; } if (exprUDC != null) { exprUDC.UserDefinedCall = exprTmp; exprUDC.setType((CType)exprTmp.type); exprTmp = exprUDC; } Debug.Assert(exprTmp.type == nubDst); exprDest = exprTmp; } return(true); } // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (flags & CONVERTTYPE.NOUDC) && binder.bindUserDefinedConversion(exprSrc, typeSrc, nubDst, needsExprDest, out exprDest, 0 == (flags & CONVERTTYPE.ISEXPLICIT))); } // Both are Nullable so there is only a conversion if there is a conversion between the base types. // That is, if there is an implicit/explicit S => T then there is an implicit/explicit S?+ => T?+. if (typeSrcBase != typeDstBase && !pfn(null, typeSrcBase, exprTypeDstBase, nubDst, false, out exprDest, flags | CONVERTTYPE.NOUDC)) { // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (flags & CONVERTTYPE.NOUDC) && binder.bindUserDefinedConversion(exprSrc, typeSrc, nubDst, needsExprDest, out exprDest, 0 == (flags & CONVERTTYPE.ISEXPLICIT))); } if (needsExprDest) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL exprDst = GetExprFactory().CreateCall(0, nubDst, exprSrc, pMemGroup, null); // Here we want to first check whether or not the conversions work on the base types. EXPR arg1 = binder.mustCast(exprSrc, typeSrcBase); EXPRCLASS arg2 = GetExprFactory().MakeClass(typeDstBase); bool convertible; if (0 != (flags & CONVERTTYPE.ISEXPLICIT)) { convertible = binder.BindExplicitConversion(arg1, arg1.type, arg2, typeDstBase, out arg1, flags | CONVERTTYPE.NOUDC); } else { convertible = binder.BindImplicitConversion(arg1, arg1.type, arg2, typeDstBase, out arg1, flags | CONVERTTYPE.NOUDC); } if (!convertible) { VSFAIL("bind(Im|Ex)plicitConversion failed unexpectedly"); return(false); } exprDst.castOfNonLiftedResultToLiftedType = binder.mustCast(arg1, nubDst, 0); exprDst.nubLiftKind = NullableCallLiftKind.NullableConversion; exprDst.pConversions = exprDst.castOfNonLiftedResultToLiftedType; exprDest = exprDst; } return(true); }
public ExprFuncPtr CreateFunctionPointer(EXPRFLAG nFlags, CType pType, Expr pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); ExprFuncPtr rval = new ExprFuncPtr(); rval.Kind = ExpressionKind.EK_FUNCPTR; rval.Type = pType; rval.Flags = nFlags; rval.OptionalObject = pObject; rval.MethWithInst = new MethWithInst(MWI); Debug.Assert(rval != null); return(rval); }
/*************************************************************************************************** * Called by BindImplicitConversion when the destination type is Nullable<T>. The following * conversions are handled by this method: * * For S in { object, ValueType, interfaces implemented by underlying type} there is an explicit * unboxing conversion S => T? * System.Enum => T? there is an unboxing conversion if T is an enum type * null => T? implemented as default(T?) * * Implicit T?* => T?+ implemented by either wrapping or calling GetValueOrDefault the * appropriate number of times. * If imp/exp S => T then imp/exp S => T?+ implemented by converting to T then wrapping the * appropriate number of times. * If imp/exp S => T then imp/exp S?+ => T?+ implemented by calling GetValueOrDefault (m-1) times * then calling HasValue, producing a null if it returns false, otherwise calling Value, * converting to T then wrapping the appropriate number of times. * * The 3 rules above can be summarized with the following recursive rules: * * If imp/exp S => T? then imp/exp S? => T? implemented as * qs.HasValue ? (T?)(qs.Value) : default(T?) * If imp/exp S => T then imp/exp S => T? implemented as new T?((T)s) * * This method also handles calling bindUserDefinedConverion. This method does NOT handle * the following conversions: * * Implicit boxing conversion from S? to { object, ValueType, Enum, ifaces implemented by S }. (Handled by BindImplicitConversion.) * If imp/exp S => T then explicit S?+ => T implemented by calling Value the appropriate number * of times. (Handled by BindExplicitConversion.) * * The recursive equivalent is: * * If imp/exp S => T and T is not nullable then explicit S? => T implemented as qs.Value * * Some nullable conversion are NOT standard conversions. In particular, if S => T is implicit * then S? => T is not standard. Similarly if S => T is not implicit then S => T? is not standard. ***************************************************************************************************/ private bool BindNubConversion(NullableType nubDst) { // This code assumes that STANDARD and ISEXPLICIT are never both set. // bindUserDefinedConversion should ensure this! Debug.Assert(0 != (~_flags & (CONVERTTYPE.STANDARD | CONVERTTYPE.ISEXPLICIT))); Debug.Assert(_exprSrc == null || _exprSrc.Type == _typeSrc); Debug.Assert(!_needsExprDest || _exprSrc != null); Debug.Assert(_typeSrc != nubDst); // BindImplicitConversion should have taken care of this already. AggregateType atsDst = nubDst.GetAts(); // Check for the unboxing conversion. This takes precedence over the wrapping conversions. if (GetSymbolLoader().HasBaseConversion(nubDst.GetUnderlyingType(), _typeSrc) && !CConversions.FWrappingConv(_typeSrc, nubDst)) { // These should be different! Fix the caller if typeSrc is an AggregateType of Nullable. Debug.Assert(atsDst != _typeSrc); // typeSrc is a base type of the destination nullable type so there is an explicit // unboxing conversion. if (0 == (_flags & CONVERTTYPE.ISEXPLICIT)) { return(false); } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_UNBOX); } return(true); } bool dstWasNullable; bool srcWasNullable; CType typeDstBase = nubDst.StripNubs(out dstWasNullable); CType typeSrcBase = _typeSrc.StripNubs(out srcWasNullable); ConversionFunc pfn = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? (ConversionFunc)_binder.BindExplicitConversion : (ConversionFunc)_binder.BindImplicitConversion; if (!srcWasNullable) { Debug.Assert(_typeSrc == typeSrcBase); // The null type can be implicitly converted to T? as the default value. if (_typeSrc is NullType) { // If we have the constant null, generate it as a default value of T?. If we have // some crazy expression which has been determined to be always null, like (null??null) // keep it in its expression form and transform it in the nullable rewrite pass. if (_needsExprDest) { if (_exprSrc.isCONSTANT_OK()) { _exprDest = GetExprFactory().CreateZeroInit(nubDst); } else { _exprDest = GetExprFactory().CreateCast(_typeDest, _exprSrc); } } return(true); } Expr exprTmp = _exprSrc; // If there is an implicit/explicit S => T then there is an implicit/explicit S => T? if (_typeSrc == typeDstBase || pfn(_exprSrc, _typeSrc, typeDstBase, _needsExprDest, out exprTmp, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { ExprUserDefinedConversion exprUDC = exprTmp as ExprUserDefinedConversion; if (exprUDC != null) { exprTmp = exprUDC.UserDefinedCall; } if (dstWasNullable) { ExprCall call = _binder.BindNubNew(exprTmp); exprTmp = call; call.NullableCallLiftKind = NullableCallLiftKind.NullableConversionConstructor; } if (exprUDC != null) { exprUDC.UserDefinedCall = exprTmp; exprTmp = exprUDC; } Debug.Assert(exprTmp.Type == nubDst); _exprDest = exprTmp; } return(true); } // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT))); } // Both are Nullable so there is only a conversion if there is a conversion between the base types. // That is, if there is an implicit/explicit S => T then there is an implicit/explicit S?+ => T?+. if (typeSrcBase != typeDstBase && !pfn(null, typeSrcBase, typeDstBase, false, out _exprDest, _flags | CONVERTTYPE.NOUDC)) { // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT))); } if (_needsExprDest) { MethWithInst mwi = new MethWithInst(null, null); ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); ExprCall exprDst = GetExprFactory().CreateCall(0, nubDst, _exprSrc, pMemGroup, null); // Here we want to first check whether or not the conversions work on the base types. Expr arg1 = _binder.mustCast(_exprSrc, typeSrcBase); bool convertible = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? _binder.BindExplicitConversion( arg1, arg1.Type, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC) : _binder.BindImplicitConversion( arg1, arg1.Type, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC); if (!convertible) { Debug.Fail("bind(Im|Ex)plicitConversion failed unexpectedly"); return(false); } exprDst.CastOfNonLiftedResultToLiftedType = _binder.mustCast(arg1, nubDst, 0); exprDst.NullableCallLiftKind = NullableCallLiftKind.NullableConversion; exprDst.PConversions = exprDst.CastOfNonLiftedResultToLiftedType; _exprDest = exprDst; } return(true); }
//////////////////////////////////////////////////////////////////////////////// // Check the constraints on the method instantiation. public static void CheckMethConstraints(CSemanticChecker checker, ErrorHandling errCtx, MethWithInst mwi) { Debug.Assert(mwi.Meth() != null && mwi.GetType() != null && mwi.TypeArgs != null); Debug.Assert(mwi.Meth().typeVars.Count == mwi.TypeArgs.Count); Debug.Assert(mwi.GetType().getAggregate() == mwi.Meth().getClass()); if (mwi.TypeArgs.Count > 0) { CheckConstraintsCore(checker, errCtx, mwi.Meth(), mwi.Meth().typeVars, mwi.TypeArgs, mwi.GetType().GetTypeArgsAll(), mwi.TypeArgs, CheckConstraintsFlags.None); } }
private EXPR BindUserBoolOp(ExpressionKind kind, EXPRCALL pCall) { RETAILVERIFY(pCall != null); RETAILVERIFY(pCall.mwi.Meth() != null); RETAILVERIFY(pCall.GetOptionalArguments() != null); Debug.Assert(kind == ExpressionKind.EK_LOGAND || kind == ExpressionKind.EK_LOGOR); CType typeRet = pCall.type; Debug.Assert(pCall.mwi.Meth().Params.size == 2); if (!GetTypes().SubstEqualTypes(typeRet, pCall.mwi.Meth().Params.Item(0), typeRet) || !GetTypes().SubstEqualTypes(typeRet, pCall.mwi.Meth().Params.Item(1), typeRet)) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL pCallTF = GetExprFactory().CreateCall(0, null, null, pMemGroup, null); pCallTF.SetError(); GetErrorContext().Error(ErrorCode.ERR_BadBoolOp, pCall.mwi); return GetExprFactory().CreateUserLogOpError(typeRet, pCallTF, pCall); } Debug.Assert(pCall.GetOptionalArguments().isLIST()); EXPR pExpr = pCall.GetOptionalArguments().asLIST().GetOptionalElement(); EXPR pExprWrap = WrapShortLivedExpression(pExpr); pCall.GetOptionalArguments().asLIST().SetOptionalElement(pExprWrap); // Reflection load the true and false methods. SymbolLoader.RuntimeBinderSymbolTable.PopulateSymbolTableWithName(SpecialNames.CLR_True, null, pExprWrap.type.AssociatedSystemType); SymbolLoader.RuntimeBinderSymbolTable.PopulateSymbolTableWithName(SpecialNames.CLR_False, null, pExprWrap.type.AssociatedSystemType); EXPR pCallT = bindUDUnop(ExpressionKind.EK_TRUE, pExprWrap); EXPR pCallF = bindUDUnop(ExpressionKind.EK_FALSE, pExprWrap); if (pCallT == null || pCallF == null) { EXPR pCallTorF = pCallT != null ? pCallT : pCallF; if (pCallTorF == null) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); pCallTorF = GetExprFactory().CreateCall(0, null, pExprWrap, pMemGroup, null); pCall.SetError(); } GetErrorContext().Error(ErrorCode.ERR_MustHaveOpTF, typeRet); return GetExprFactory().CreateUserLogOpError(typeRet, pCallTorF, pCall); } pCallT = mustConvert(pCallT, GetReqPDT(PredefinedType.PT_BOOL)); pCallF = mustConvert(pCallF, GetReqPDT(PredefinedType.PT_BOOL)); return GetExprFactory().CreateUserLogOp(typeRet, kind == ExpressionKind.EK_LOGAND ? pCallF : pCallT, pCall); }
public ExprFuncPtr CreateFunctionPointer(EXPRFLAG flags, CType type, Expr obj, MethWithInst method) => new ExprFuncPtr(type, flags, obj, method);
private 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 = GetSymbolLoader().GetTypeManager().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 = GetSymbolLoader().GetTypeManager().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 = GetExprFactory().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 EXPRUSERDEFINEDCONVERSION CreateUserDefinedConversion(EXPR arg, EXPR call, MethWithInst mwi) { Debug.Assert(arg != null); Debug.Assert(call != null); EXPRUSERDEFINEDCONVERSION rval = new EXPRUSERDEFINEDCONVERSION(); rval.kind = ExpressionKind.EK_USERDEFINEDCONVERSION; rval.type = call.type; rval.flags = 0; rval.Argument = arg; rval.UserDefinedCall = call; rval.UserDefinedCallMethod = mwi; if (call.HasError()) { rval.SetError(); } Debug.Assert(rval != null); return rval; }
///////////////////////////////////////////////////////////////////////////////// // Expression types. protected override EXPR VisitBOUNDLAMBDA(EXPRBOUNDLAMBDA anonmeth) { Debug.Assert(anonmeth != null); EXPRBOUNDLAMBDA prevAnonMeth = currentAnonMeth; currentAnonMeth = anonmeth; MethodSymbol lambdaMethod = GetPreDefMethod(PREDEFMETH.PM_EXPRESSION_LAMBDA); CType delegateType = anonmeth.DelegateType(); TypeArray lambdaTypeParams = GetSymbolLoader().getBSymmgr().AllocParams(1, new CType[] { delegateType }); AggregateType expressionType = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); MethWithInst mwi = new MethWithInst(lambdaMethod, expressionType, lambdaTypeParams); EXPR createParameters = CreateWraps(anonmeth); EXPR body = RewriteLambdaBody(anonmeth); EXPR parameters = RewriteLambdaParameters(anonmeth); EXPR args = GetExprFactory().CreateList(body, parameters); CType typeRet = GetSymbolLoader().GetTypeManager().SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPR callLambda = GetExprFactory().CreateCall(0, typeRet, args, pMemGroup, mwi); callLambda.asCALL().PredefinedMethod = PREDEFMETH.PM_EXPRESSION_LAMBDA; currentAnonMeth = prevAnonMeth; if (createParameters != null) { callLambda = GetExprFactory().CreateSequence(createParameters, callLambda); } EXPR expr = DestroyWraps(anonmeth, callLambda); // If we are already inside an expression tree rewrite and this is an expression tree lambda // then it needs to be quoted. if (currentAnonMeth != null) { expr = GenerateCall(PREDEFMETH.PM_EXPRESSION_QUOTE, expr); } return expr; }
public EXPRUSERDEFINEDCONVERSION CreateUserDefinedConversion(EXPR arg, EXPR call, MethWithInst mwi) { Debug.Assert(arg != null); Debug.Assert(call != null); EXPRUSERDEFINEDCONVERSION rval = new EXPRUSERDEFINEDCONVERSION(); rval.kind = ExpressionKind.EK_USERDEFINEDCONVERSION; rval.type = call.type; rval.flags = 0; rval.Argument = arg; rval.UserDefinedCall = call; rval.UserDefinedCallMethod = mwi; if (call.HasError()) { rval.SetError(); } Debug.Assert(rval != null); return(rval); }
protected EXPRCALL GenerateCall(PREDEFMETH pdm, EXPR arg1, EXPR arg2, EXPR arg3, EXPR arg4) { MethodSymbol method = GetPreDefMethod(pdm); if (method == null) return null; AggregateType expressionType = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); EXPR args = GetExprFactory().CreateList(arg1, arg2, arg3, arg4); MethWithInst mwi = new MethWithInst(method, expressionType); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi); call.PredefinedMethod = pdm; return call; }
public EXPRCALL CreateCall(EXPRFLAG nFlags, CType pType, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY ) )); EXPRCALL rval = new EXPRCALL(); rval.kind = ExpressionKind.EK_CALL; rval.type = pType; rval.flags = nFlags; rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); rval.nubLiftKind = NullableCallLiftKind.NotLifted; rval.castOfNonLiftedResultToLiftedType = null; rval.mwi = MWI; Debug.Assert(rval != null); return(rval); }
protected virtual 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 = GetSymbolLoader().GetTypeManager().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 = GetSymbolLoader().GetTypeManager().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 = GetExprFactory().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 EXPRFUNCPTR CreateFunctionPointer(EXPRFLAG nFlags, CType pType, EXPR pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); EXPRFUNCPTR rval = new EXPRFUNCPTR(); rval.kind = ExpressionKind.EK_FUNCPTR; rval.type = pType; rval.flags = nFlags; rval.OptionalObject = pObject; rval.mwi = new MethWithInst(MWI); Debug.Assert(rval != null); return(rval); }
/*************************************************************************************************** Called by BindImplicitConversion when the destination type is Nullable<T>. The following conversions are handled by this method: * For S in { object, ValueType, interfaces implemented by underlying type} there is an explicit unboxing conversion S => T? * System.Enum => T? there is an unboxing conversion if T is an enum type * null => T? implemented as default(T?) * Implicit T?* => T?+ implemented by either wrapping or calling GetValueOrDefault the appropriate number of times. * If imp/exp S => T then imp/exp S => T?+ implemented by converting to T then wrapping the appropriate number of times. * If imp/exp S => T then imp/exp S?+ => T?+ implemented by calling GetValueOrDefault (m-1) times then calling HasValue, producing a null if it returns false, otherwise calling Value, converting to T then wrapping the appropriate number of times. The 3 rules above can be summarized with the following recursive rules: * If imp/exp S => T? then imp/exp S? => T? implemented as qs.HasValue ? (T?)(qs.Value) : default(T?) * If imp/exp S => T then imp/exp S => T? implemented as new T?((T)s) This method also handles calling bindUserDefinedConverion. This method does NOT handle the following conversions: * Implicit boxing conversion from S? to { object, ValueType, Enum, ifaces implemented by S }. (Handled by BindImplicitConversion.) * If imp/exp S => T then explicit S?+ => T implemented by calling Value the appropriate number of times. (Handled by BindExplicitConversion.) The recursive equivalent is: * If imp/exp S => T and T is not nullable then explicit S? => T implemented as qs.Value Some nullable conversion are NOT standard conversions. In particular, if S => T is implicit then S? => T is not standard. Similarly if S => T is not implicit then S => T? is not standard. ***************************************************************************************************/ private bool BindNubConversion(NullableType nubDst) { // This code assumes that STANDARD and ISEXPLICIT are never both set. // bindUserDefinedConversion should ensure this! Debug.Assert(0 != (~_flags & (CONVERTTYPE.STANDARD | CONVERTTYPE.ISEXPLICIT))); Debug.Assert(_exprSrc == null || _exprSrc.type == _typeSrc); Debug.Assert(!_needsExprDest || _exprSrc != null); Debug.Assert(_typeSrc != nubDst); // BindImplicitConversion should have taken care of this already. AggregateType atsDst = nubDst.GetAts(GetErrorContext()); if (atsDst == null) return false; // Check for the unboxing conversion. This takes precedence over the wrapping conversions. if (GetSymbolLoader().HasBaseConversion(nubDst.GetUnderlyingType(), _typeSrc) && !CConversions.FWrappingConv(_typeSrc, nubDst)) { // These should be different! Fix the caller if typeSrc is an AggregateType of Nullable. Debug.Assert(atsDst != _typeSrc); // typeSrc is a base type of the destination nullable type so there is an explicit // unboxing conversion. if (0 == (_flags & CONVERTTYPE.ISEXPLICIT)) { return false; } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_UNBOX); } return true; } int cnubDst; int cnubSrc; CType typeDstBase = nubDst.StripNubs(out cnubDst); EXPRCLASS exprTypeDstBase = GetExprFactory().MakeClass(typeDstBase); CType typeSrcBase = _typeSrc.StripNubs(out cnubSrc); ConversionFunc pfn = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? (ConversionFunc)_binder.BindExplicitConversion : (ConversionFunc)_binder.BindImplicitConversion; if (cnubSrc == 0) { Debug.Assert(_typeSrc == typeSrcBase); // The null type can be implicitly converted to T? as the default value. if (_typeSrc.IsNullType()) { // If we have the constant null, generate it as a default value of T?. If we have // some crazy expression which has been determined to be always null, like (null??null) // keep it in its expression form and transform it in the nullable rewrite pass. if (_needsExprDest) { if (_exprSrc.isCONSTANT_OK()) { _exprDest = GetExprFactory().CreateZeroInit(nubDst); } else { _exprDest = GetExprFactory().CreateCast(0x00, _typeDest, _exprSrc); } } return true; } EXPR exprTmp = _exprSrc; // If there is an implicit/explicit S => T then there is an implicit/explicit S => T? if (_typeSrc == typeDstBase || pfn(_exprSrc, _typeSrc, exprTypeDstBase, nubDst, _needsExprDest, out exprTmp, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { EXPRUSERDEFINEDCONVERSION exprUDC = exprTmp.kind == ExpressionKind.EK_USERDEFINEDCONVERSION ? exprTmp.asUSERDEFINEDCONVERSION() : null; if (exprUDC != null) { exprTmp = exprUDC.UserDefinedCall; } // This logic is left over from the days when T?? was legal. However there are error/LAF cases that necessitates the loop. // typeSrc is not nullable so just wrap the required number of times. For legal code (cnubDst <= 0). for (int i = 0; i < cnubDst; i++) { exprTmp = _binder.BindNubNew(exprTmp); exprTmp.asCALL().nubLiftKind = NullableCallLiftKind.NullableConversionConstructor; } if (exprUDC != null) { exprUDC.UserDefinedCall = exprTmp; exprUDC.setType((CType)exprTmp.type); exprTmp = exprUDC; } Debug.Assert(exprTmp.type == nubDst); _exprDest = exprTmp; } return true; } // No builtin conversion. Maybe there is a user defined conversion.... return 0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT)); } // Both are Nullable so there is only a conversion if there is a conversion between the base types. // That is, if there is an implicit/explicit S => T then there is an implicit/explicit S?+ => T?+. if (typeSrcBase != typeDstBase && !pfn(null, typeSrcBase, exprTypeDstBase, nubDst, false, out _exprDest, _flags | CONVERTTYPE.NOUDC)) { // No builtin conversion. Maybe there is a user defined conversion.... return 0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT)); } if (_needsExprDest) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(null, mwi); EXPRCALL exprDst = GetExprFactory().CreateCall(0, nubDst, _exprSrc, pMemGroup, null); // Here we want to first check whether or not the conversions work on the base types. EXPR arg1 = _binder.mustCast(_exprSrc, typeSrcBase); EXPRCLASS arg2 = GetExprFactory().MakeClass(typeDstBase); bool convertible; if (0 != (_flags & CONVERTTYPE.ISEXPLICIT)) { convertible = _binder.BindExplicitConversion(arg1, arg1.type, arg2, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC); } else { convertible = _binder.BindImplicitConversion(arg1, arg1.type, arg2, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC); } if (!convertible) { VSFAIL("bind(Im|Ex)plicitConversion failed unexpectedly"); return false; } exprDst.castOfNonLiftedResultToLiftedType = _binder.mustCast(arg1, nubDst, 0); exprDst.nubLiftKind = NullableCallLiftKind.NullableConversion; exprDst.pConversions = exprDst.castOfNonLiftedResultToLiftedType; _exprDest = exprDst; } return true; }
public EXPRCALL BindNew(EXPR pExprSrc) { Debug.Assert(pExprSrc != null); NullableType pNubSourceType = GetSymbolLoader().GetTypeManager().GetNullable(pExprSrc.type); AggregateType pSourceType = pNubSourceType.GetAts(GetErrorContext()); if (pSourceType == null) { MethWithInst mwi = new MethWithInst(null, null); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(pExprSrc, mwi); EXPRCALL rval = GetExprFactory().CreateCall(0, pNubSourceType, null, pMemGroup, null); rval.SetError(); return rval; } MethodSymbol meth = GetSymbolLoader().getBSymmgr().methNubCtor; if (meth == null) { meth = GetSymbolLoader().getPredefinedMembers().GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR); GetSymbolLoader().getBSymmgr().methNubCtor = meth; } MethWithInst methwithinst = new MethWithInst(meth, pSourceType, BSYMMGR.EmptyTypeArray()); EXPRMEMGRP memgroup = GetExprFactory().CreateMemGroup(null, methwithinst); EXPRCALL pExprRes = GetExprFactory().CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, pExprSrc, memgroup, methwithinst); if (meth == null) { pExprRes.SetError(); } return pExprRes; }