public GroupToArgsBinder(ExpressionBinder exprBinder, BindingFlag bindFlags, EXPRMEMGRP grp, ArgInfos args, ArgInfos originalArgs, bool bHasNamedArguments, AggregateType atsDelegate) { Debug.Assert(grp != null); Debug.Assert(exprBinder != null); Debug.Assert(args != null); _pExprBinder = exprBinder; _fCandidatesUnsupported = false; _fBindFlags = bindFlags; _pGroup = grp; _pArguments = args; _pOriginalArguments = originalArgs; _bHasNamedArguments = bHasNamedArguments; _pDelegate = atsDelegate; _pCurrentType = null; _pCurrentSym = null; _pCurrentTypeArgs = null; _pCurrentParameters = null; _pBestParameters = null; _nArgBest = -1; _nWrongCount = 0; _bIterateToEndOfNsList = false; _bBindingCollectionAddArgs = false; _results = new GroupToArgsBinderResult(); _methList = new List<CandidateFunctionMember>(); _mpwiParamTypeConstraints = new MethPropWithInst(); _mpwiBogus = new MethPropWithInst(); _mpwiCantInferInstArg = new MethPropWithInst(); _mwtBadArity = new MethWithType(); _HiddenTypes = new List<CType>(); }
public EXPRPROP CreateProperty(CType pType, EXPR pOptionalObject) { MethPropWithInst mwi = new MethPropWithInst(); EXPRMEMGRP pMemGroup = CreateMemGroup(pOptionalObject, mwi); return(CreateProperty(pType, null, null, pMemGroup, null, null, null)); }
public EXPRMEMGRP CreateMemGroup(EXPRFLAG nFlags, Name pName, TypeArray pTypeArgs, SYMKIND symKind, CType pTypePar, MethodOrPropertySymbol pMPS, EXPR pObject, CMemberLookupResults memberLookupResults) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_INDEXER | EXPRFLAG.EXF_OPERATOR | EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_DELEGATE | EXPRFLAG.EXF_USERCALLABLE | EXPRFLAG.EXF_MASK_ANY ) )); EXPRMEMGRP rval = new EXPRMEMGRP(); rval.kind = ExpressionKind.EK_MEMGRP; rval.type = GetTypes().GetMethGrpType(); rval.flags = nFlags; rval.name = pName; rval.typeArgs = pTypeArgs; rval.sk = symKind; rval.SetParentType(pTypePar); rval.SetOptionalObject(pObject); rval.SetMemberLookupResults(memberLookupResults); rval.SetOptionalLHS(null); if (rval.typeArgs == null) { rval.typeArgs = BSYMMGR.EmptyTypeArray(); } Debug.Assert(rval != null); return(rval); }
// Value public EXPR BindValue(EXPR exprSrc) { Debug.Assert(exprSrc != null && exprSrc.type.IsNullableType()); // For new T?(x), the answer is x. if (CNullable.IsNullableConstructor(exprSrc)) { Debug.Assert(exprSrc.asCALL().GetOptionalArguments() != null && !exprSrc.asCALL().GetOptionalArguments().isLIST()); return(exprSrc.asCALL().GetOptionalArguments()); } CType typeBase = exprSrc.type.AsNullableType().GetUnderlyingType(); AggregateType ats = exprSrc.type.AsNullableType().GetAts(GetErrorContext()); if (ats == null) { EXPRPROP rval = GetExprFactory().CreateProperty(typeBase, exprSrc); rval.SetError(); return(rval); } // UNDONE: move this to transform pass ... PropertySymbol prop = GetSymbolLoader().getBSymmgr().propNubValue; if (prop == null) { prop = GetSymbolLoader().getPredefinedMembers().GetProperty(PREDEFPROP.PP_G_OPTIONAL_VALUE); GetSymbolLoader().getBSymmgr().propNubValue = prop; } PropWithType pwt = new PropWithType(prop, ats); MethWithType mwt = new MethWithType(prop != null ? prop.methGet : null, ats); MethPropWithInst mpwi = new MethPropWithInst(prop, ats); EXPRMEMGRP pMemGroup = GetExprFactory().CreateMemGroup(exprSrc, mpwi); EXPRPROP exprRes = GetExprFactory().CreateProperty(typeBase, null, null, pMemGroup, pwt, mwt, null); if (prop == null) { exprRes.SetError(); } return(exprRes); }
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 EXPRPROP CreateProperty(CType pType, EXPR pOptionalObjectThrough, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, PropWithType pwtSlot, MethWithType mwtGet, MethWithType mwtSet) { EXPRPROP rval = new EXPRPROP(); rval.kind = ExpressionKind.EK_PROP; rval.type = pType; rval.flags = 0; rval.SetOptionalObjectThrough(pOptionalObjectThrough); rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); if (pwtSlot != null) { rval.pwtSlot = pwtSlot; } if (mwtSet != null) { rval.mwtSet = mwtSet; } Debug.Assert(rval != null); return(rval); }
//////////////////////////////////////////////////////////////////////////////// internal EXPR BindToProperty(EXPR pObject, PropWithType pwt, BindingFlag bindFlags, EXPR args, AggregateType pOtherType, EXPRMEMGRP pMemGroup) { Debug.Assert(pwt.Sym != null && pwt.Sym.IsPropertySymbol() && pwt.GetType() != null && pwt.Prop().getClass() == pwt.GetType().getAggregate()); Debug.Assert(pwt.Prop().Params.size == 0 || pwt.Prop().isIndexer()); Debug.Assert(pOtherType == null || !pwt.Prop().isIndexer() && pOtherType.getAggregate() == pwt.Prop().RetType.getAggregate()); bool fConstrained; MethWithType mwtGet; MethWithType mwtSet; EXPR pObjectThrough = null; // We keep track of the type of the pObject which we're doing the call through so that we can report // protection access errors later, either below when binding the get, or later when checking that // the setter is actually an lvalue. If we're actually doing a base.prop call then we do not // need to ensure that the left side of the dot is an instance of the derived class, otherwise // we save it away for later. if (0 == (bindFlags & BindingFlag.BIND_BASECALL)) { pObjectThrough = pObject; } bool bIsMatchingStatic; PostBindProperty((bindFlags & BindingFlag.BIND_BASECALL) != 0, pwt, pObject, out mwtGet, out mwtSet); if (mwtGet && (!mwtSet || mwtSet.GetType() == mwtGet.GetType() || GetSymbolLoader().HasBaseConversion(mwtGet.GetType(), mwtSet.GetType()) ) ) { pObject = AdjustMemberObject(mwtGet, pObject, out fConstrained, out bIsMatchingStatic); } else if (mwtSet) { pObject = AdjustMemberObject(mwtSet, pObject, out fConstrained, out bIsMatchingStatic); } else { pObject = AdjustMemberObject(pwt, pObject, out fConstrained, out bIsMatchingStatic); } pMemGroup.SetOptionalObject(pObject); CType pReturnType = GetTypes().SubstType(pwt.Prop().RetType, pwt.GetType()); Debug.Assert(pOtherType == pReturnType || pOtherType == null); if (pObject != null && !pObject.isOK()) { EXPRPROP pResult = GetExprFactory().CreateProperty(pReturnType, pObjectThrough, args, pMemGroup, pwt, null, null); if (!bIsMatchingStatic) { pResult.SetMismatchedStaticBit(); } pResult.SetError(); return pResult; } // if we are doing a get on this thing, and there is no get, and // most importantly, we are not leaving the arguments to be bound by the array index // then error... if ((bindFlags & BindingFlag.BIND_RVALUEREQUIRED) != 0) { if (!mwtGet) { if (pOtherType != null) { return GetExprFactory().MakeClass(pOtherType); } ErrorContext.ErrorRef(ErrorCode.ERR_PropertyLacksGet, pwt); } else if (((bindFlags & BindingFlag.BIND_BASECALL) != 0) && mwtGet.Meth().isAbstract) { // if the get exists, but is abstract, forbid the call as well... if (pOtherType != null) { return GetExprFactory().MakeClass(pOtherType); } ErrorContext.Error(ErrorCode.ERR_AbstractBaseCall, pwt); } else { CType type = null; if (pObjectThrough != null) { type = pObjectThrough.type; } ACCESSERROR error = SemanticChecker.CheckAccess2(mwtGet.Meth(), mwtGet.GetType(), ContextForMemberLookup(), type); if (error != ACCESSERROR.ACCESSERROR_NOERROR) { // if the get exists, but is not accessible, give an error. if (pOtherType != null) { return GetExprFactory().MakeClass(pOtherType); } if (error == ACCESSERROR.ACCESSERROR_NOACCESSTHRU) { ErrorContext.Error(ErrorCode.ERR_BadProtectedAccess, pwt, type, ContextForMemberLookup()); } else { ErrorContext.ErrorRef(ErrorCode.ERR_InaccessibleGetter, pwt); } } } } EXPRPROP result = GetExprFactory().CreateProperty(pReturnType, pObjectThrough, args, pMemGroup, pwt, mwtGet, mwtSet); if (!bIsMatchingStatic) { result.SetMismatchedStaticBit(); } Debug.Assert(EXPRFLAG.EXF_BASECALL == (EXPRFLAG)BindingFlag.BIND_BASECALL); if ((EXPRFLAG.EXF_BASECALL & (EXPRFLAG)bindFlags) != 0) { result.flags |= EXPRFLAG.EXF_BASECALL; } else if (fConstrained && pObject != null) { // Use the constrained prefix. result.flags |= EXPRFLAG.EXF_CONSTRAINED; } if (result.GetOptionalArguments() != null) { verifyMethodArgs(result, pObjectThrough != null ? pObjectThrough.type : null); } if (mwtSet && objectIsLvalue(result.GetMemberGroup().GetOptionalObject())) { result.flags |= EXPRFLAG.EXF_LVALUE; } if (pOtherType != null) { result.flags |= EXPRFLAG.EXF_SAMENAMETYPE; } return result; }
protected virtual EXPR VisitMEMGRP(EXPRMEMGRP pExpr) { return VisitEXPR(pExpr); }
protected virtual EXPR VisitMEMGRP(EXPRMEMGRP pExpr) { return(VisitEXPR(pExpr)); }
public static CType GetTypeQualifier(EXPRMEMGRP pGroup) { Debug.Assert(pGroup != null); CType rval = null; if (0 != (pGroup.flags & EXPRFLAG.EXF_BASECALL)) { rval = null; } else if (0 != (pGroup.flags & EXPRFLAG.EXF_CTOR)) { rval = pGroup.GetParentType(); } else if (pGroup.GetOptionalObject() != null) { rval = pGroup.GetOptionalObject().type; } else { rval = null; } return rval; }
internal static bool ReOrderArgsForNamedArguments( MethodOrPropertySymbol methprop, TypeArray pCurrentParameters, AggregateType pCurrentType, EXPRMEMGRP pGroup, ArgInfos pArguments, TypeManager typeManager, ExprFactory exprFactory, SymbolLoader symbolLoader) { // We use the param count from pCurrentParameters because they may have been resized // for param arrays. int numParameters = pCurrentParameters.size; EXPR[] pExprArguments = new EXPR[numParameters]; // Now go through the parameters. First set all positional arguments in the new argument // set, then for the remainder, look for a named argument with a matching name. int index = 0; EXPR paramArrayArgument = null; TypeArray @params = typeManager.SubstTypeArray( pCurrentParameters, pCurrentType, pGroup.typeArgs); foreach (Name name in methprop.ParameterNames) { // This can happen if we had expanded our param array to size 0. if (index >= pCurrentParameters.size) { break; } // If: // (1) we have a param array method // (2) we're on the last arg // (3) the thing we have is an array init thats generated for param array // then let us through. if (methprop.isParamArray && index < pArguments.carg && pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray) { paramArrayArgument = pArguments.prgexpr[index]; } // Positional. if (index < pArguments.carg && !pArguments.prgexpr[index].isNamedArgumentSpecification() && !(pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray)) { pExprArguments[index] = pArguments.prgexpr[index++]; continue; } // Look for names. EXPR pNewArg = FindArgumentWithName(pArguments, name); if (pNewArg == null) { if (methprop.IsParameterOptional(index)) { pNewArg = GenerateOptionalArgument(symbolLoader, exprFactory, methprop, @params.Item(index), index); } else if (paramArrayArgument != null && index == methprop.Params.Count - 1) { // If we have a param array argument and we're on the last one, then use it. pNewArg = paramArrayArgument; } else { // No name and no default value. return false; } } pExprArguments[index++] = pNewArg; } // Here we've found all the arguments, or have default values for them. CType[] prgTypes = new CType[pCurrentParameters.size]; for (int i = 0; i < numParameters; i++) { if (i < pArguments.prgexpr.Count) { pArguments.prgexpr[i] = pExprArguments[i]; } else { pArguments.prgexpr.Add(pExprArguments[i]); } prgTypes[i] = pArguments.prgexpr[i].type; } pArguments.carg = pCurrentParameters.size; pArguments.types = symbolLoader.getBSymmgr().AllocParams(pCurrentParameters.size, prgTypes); return true; }
//////////////////////////////////////////////////////////////////////////////// // Given a method group or indexer group, bind it to the arguments for an // invocation. This method can change the arguments to bind with Extension // Methods private bool BindMethodGroupToArgumentsCore(out GroupToArgsBinderResult pResults, BindingFlag bindFlags, EXPRMEMGRP grp, ref EXPR args, int carg, bool bindingCollectionAdd, bool bHasNamedArgumentSpecifiers) { ArgInfos pargInfo = new ArgInfos {carg = carg}; FillInArgInfoFromArgList(pargInfo, args); ArgInfos pOriginalArgInfo = new ArgInfos {carg = carg}; FillInArgInfoFromArgList(pOriginalArgInfo, args); GroupToArgsBinder binder = new GroupToArgsBinder(this, bindFlags, grp, pargInfo, pOriginalArgInfo, bHasNamedArgumentSpecifiers, null/*atsDelegate*/); bool retval = bindingCollectionAdd ? binder.BindCollectionAddArgs() : binder.Bind(true /*ReportErrors*/); pResults = binder.GetResultsOfBind(); return retval; }
public EXPRMEMGRP CreateMemGroup(EXPRFLAG nFlags, Name pName, TypeArray pTypeArgs, SYMKIND symKind, CType pTypePar, MethodOrPropertySymbol pMPS, EXPR pObject, CMemberLookupResults memberLookupResults) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_INDEXER | EXPRFLAG.EXF_OPERATOR | EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_DELEGATE | EXPRFLAG.EXF_USERCALLABLE | EXPRFLAG.EXF_MASK_ANY ) )); EXPRMEMGRP rval = new EXPRMEMGRP(); rval.kind = ExpressionKind.EK_MEMGRP; rval.type = GetTypes().GetMethGrpType(); rval.flags = nFlags; rval.name = pName; rval.typeArgs = pTypeArgs; rval.sk = symKind; rval.SetParentType(pTypePar); rval.SetOptionalObject(pObject); rval.SetMemberLookupResults(memberLookupResults); rval.SetOptionalLHS(null); if (rval.typeArgs == null) { rval.typeArgs = BSYMMGR.EmptyTypeArray(); } Debug.Assert(rval != null); return (rval); }
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); }
//////////////////////////////////////////////////////////////////////////////// // 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; }
//////////////////////////////////////////////////////////////////////////////// // Given a method group or indexer group, bind it to the arguments for an // invocation. internal EXPR BindMethodGroupToArguments(BindingFlag bindFlags, EXPRMEMGRP grp, EXPR args) { Debug.Assert(grp.sk == SYMKIND.SK_MethodSymbol || grp.sk == SYMKIND.SK_PropertySymbol && ((grp.flags & EXPRFLAG.EXF_INDEXER) != 0)); // Count the args. bool argTypeErrors; int carg = CountArguments(args, out argTypeErrors); // We need to store the object because BindMethodGroupToArgumentsCore will // null it out in the case of an extension method, which is then consumed // by BindToMethod. After that, we want to set the object back. EXPR pObject = grp.GetOptionalObject(); // If we weren't given a pName, then we couldn't bind the method pName, so we should // just bail out of here. if (grp.name == null) { EXPRCALL rval = GetExprFactory().CreateCall(0, GetTypes().GetErrorSym(), args, grp, null); rval.SetError(); return rval; } // If we have named arguments specified, make sure we have them all appearing after // fixed arguments. bool bSeenNamed = false; if (!VerifyNamedArgumentsAfterFixed(args, out bSeenNamed)) { EXPRCALL rval = GetExprFactory().CreateCall(0, GetTypes().GetErrorSym(), args, grp, null); rval.SetError(); return rval; } GroupToArgsBinderResult result; if (!BindMethodGroupToArgumentsCore(out result, bindFlags, grp, ref args, carg, false, bSeenNamed)) { Debug.Assert(false, "Why didn't BindMethodGroupToArgumentsCore throw an error?"); return null; } EXPR exprRes; MethPropWithInst mpwiBest = result.GetBestResult(); if (grp.sk == SYMKIND.SK_PropertySymbol) { Debug.Assert((grp.flags & EXPRFLAG.EXF_INDEXER) != 0); //PropWithType pwt = new PropWithType(mpwiBest.Prop(), mpwiBest.GetType()); exprRes = BindToProperty(grp.GetOptionalObject(), new PropWithType(mpwiBest), (bindFlags | (BindingFlag)(grp.flags & EXPRFLAG.EXF_BASECALL)), args, null/*typeOther*/, grp); } else { exprRes = BindToMethod(new MethWithInst(mpwiBest), args, grp, (MemLookFlags)grp.flags); } return exprRes; }
/*************************************************************************************************** * 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 EXPRPROP CreateProperty(CType pType, EXPR pOptionalObjectThrough, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, PropWithType pwtSlot, MethWithType mwtGet, MethWithType mwtSet) { EXPRPROP rval = new EXPRPROP(); rval.kind = ExpressionKind.EK_PROP; rval.type = pType; rval.flags = 0; rval.SetOptionalObjectThrough(pOptionalObjectThrough); rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); if (pwtSlot != null) { rval.pwtSlot = pwtSlot; } if (mwtSet != null) { rval.mwtSet = mwtSet; } Debug.Assert(rval != null); return (rval); }