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>(); }
///////////////////////////////////////////////////////////////////////////////// private EXPR CreateProperty( SymWithType swt, EXPR callingObject, BindingFlag flags) { // For a property, we simply create the EXPRPROP for the thing, call the // expression tree rewriter, rewrite it, and send it on its way. PropertySymbol property = swt.Prop(); AggregateType propertyType = swt.GetType(); PropWithType pwt = new PropWithType(property, propertyType); EXPRMEMGRP pMemGroup = CreateMemberGroupEXPR(property.name.Text, null, callingObject, SYMKIND.SK_PropertySymbol); return _binder.BindToProperty(// For a static property instance, don't set the object. callingObject.isCLASS() ? null : callingObject, pwt, flags, null, null, pMemGroup); }
///////////////////////////////////////////////////////////////////////////////// private EXPR CreateIndexer(SymWithType swt, EXPR callingObject, EXPR arguments, BindingFlag bindFlags) { IndexerSymbol index = swt.Sym as IndexerSymbol; AggregateType ctype = swt.GetType(); EXPRMEMGRP memgroup = CreateMemberGroupEXPR(index.name.Text, null, callingObject, SYMKIND.SK_PropertySymbol); EXPR result = _binder.BindMethodGroupToArguments(bindFlags, memgroup, arguments); return ReorderArgumentsForNamedAndOptional(callingObject, result); }
//////////////////////////////////////////////////////////////////////////////// internal EXPR BindToField(EXPR pOptionalObject, FieldWithType fwt, BindingFlag bindFlags, EXPR pOptionalLHS) { Debug.Assert(fwt.GetType() != null && fwt.Field().getClass() == fwt.GetType().getAggregate()); CType pFieldType = GetTypes().SubstType(fwt.Field().GetType(), fwt.GetType()); if (pOptionalObject != null && !pOptionalObject.isOK()) { EXPRFIELD pField = GetExprFactory().CreateField(0, pFieldType, pOptionalObject, 0, fwt, pOptionalLHS); pField.SetError(); return pField; } EXPR pOriginalObject = pOptionalObject; bool bIsMatchingStatic; bool pfConstrained; pOptionalObject = AdjustMemberObject(fwt, pOptionalObject, out pfConstrained, out bIsMatchingStatic); checkUnsafe(pFieldType); // added to the binder so we don't bind to pointer ops EXPRFIELD pResult; { bool isLValue = false; if ((pOptionalObject != null && pOptionalObject.type.IsPointerType()) || objectIsLvalue(pOptionalObject)) { isLValue = true; } // Exception: a readonly field is not an lvalue unless we're in the constructor/static constructor appropriate // for the field. if (RespectReadonly() && fwt.Field().isReadOnly) { if (ContainingAgg() == null || !InMethod() || !InConstructor() || fwt.Field().getClass() != ContainingAgg() || InStaticMethod() != fwt.Field().isStatic || (pOptionalObject != null && !isThisPointer(pOptionalObject)) || InAnonymousMethod()) { isLValue = false; } } pResult = GetExprFactory().CreateField(isLValue ? EXPRFLAG.EXF_LVALUE : 0, pFieldType, pOptionalObject, 0, fwt, pOptionalLHS); if (!bIsMatchingStatic) { pResult.SetMismatchedStaticBit(); } if (pFieldType.IsErrorType()) { pResult.SetError(); } Debug.Assert(BindingFlag.BIND_MEMBERSET == (BindingFlag)EXPRFLAG.EXF_MEMBERSET); pResult.flags |= (EXPRFLAG)(bindFlags & BindingFlag.BIND_MEMBERSET); } // If this field is the backing field of a WindowsRuntime event then we need to bind to its // invocationlist property which is a delegate containing all the handlers. if (pResult.isFIELD() && fwt.Field().isEvent && fwt.Field().getEvent(GetSymbolLoader()) != null && fwt.Field().getEvent(GetSymbolLoader()).IsWindowsRuntimeEvent) { CType fieldType = fwt.Field().GetType(); if (fieldType.IsAggregateType()) { // Access event backing field (EventRegistrationTokenTable<T>) using // EventRegistrationTokenTable<T>.GetOrCreateEventRegistrationTokenTable() // to ensure non-null pResult.setType(GetTypes().GetParameterModifier(pResult.type, false)); Name getOrCreateMethodName = GetSymbolLoader().GetNameManager().GetPredefName(PredefinedName.PN_GETORCREATEEVENTREGISTRATIONTOKENTABLE); GetSymbolLoader().RuntimeBinderSymbolTable.PopulateSymbolTableWithName(getOrCreateMethodName.Text, null, fieldType.AssociatedSystemType); MethodSymbol getOrCreateMethod = GetSymbolLoader().LookupAggMember(getOrCreateMethodName, fieldType.getAggregate(), symbmask_t.MASK_MethodSymbol).AsMethodSymbol(); MethPropWithInst getOrCreatempwi = new MethPropWithInst(getOrCreateMethod, fieldType.AsAggregateType()); EXPRMEMGRP getOrCreateGrp = GetExprFactory().CreateMemGroup(null, getOrCreatempwi); EXPR getOrCreateCall = BindToMethod(new MethWithInst(getOrCreatempwi), pResult, getOrCreateGrp, (MemLookFlags)MemLookFlags.None); AggregateSymbol fieldTypeSymbol = fieldType.AsAggregateType().GetOwningAggregate(); Name invocationListName = GetSymbolLoader().GetNameManager().GetPredefName(PredefinedName.PN_INVOCATIONLIST); // InvocationList might not be populated in the symbol table as no one would have called it. GetSymbolLoader().RuntimeBinderSymbolTable.PopulateSymbolTableWithName(invocationListName.Text, null, fieldType.AssociatedSystemType); PropertySymbol invocationList = GetSymbolLoader().LookupAggMember( invocationListName, fieldTypeSymbol, symbmask_t.MASK_PropertySymbol).AsPropertySymbol(); MethPropWithInst mpwi = new MethPropWithInst(invocationList, fieldType.AsAggregateType()); EXPRMEMGRP memGroup = GetExprFactory().CreateMemGroup(getOrCreateCall, mpwi); PropWithType pwt = new PropWithType(invocationList, fieldType.AsAggregateType()); EXPR propertyExpr = BindToProperty(getOrCreateCall, pwt, bindFlags, null, null, memGroup); return propertyExpr; } } return pResult; }
//////////////////////////////////////////////////////////////////////////////// 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; }
//////////////////////////////////////////////////////////////////////////////// // Construct the EXPR node which corresponds to a field expression // for a given field and pObject pointer. internal EXPR BindToField(EXPR pObject, FieldWithType fwt, BindingFlag bindFlags) { return BindToField(pObject, fwt, bindFlags, null/*OptionalLHS*/); }
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; }
internal EXPR BindArrayIndexCore(BindingFlag bindFlags, EXPR pOp1, EXPR pOp2) { EXPR pExpr; bool bIsError = false; if (!pOp1.isOK() || !pOp2.isOK()) { bIsError = true; } CType pIntType = GetReqPDT(PredefinedType.PT_INT); // Array indexing must occur on an array type. if (!pOp1.type.IsArrayType()) { Debug.Assert(!pOp1.type.IsPointerType()); pExpr = bindIndexer(pOp1, pOp2, bindFlags); if (bIsError) { pExpr.SetError(); } return pExpr; } ArrayType pArrayType = pOp1.type.AsArrayType(); checkUnsafe(pArrayType.GetElementType()); // added to the binder so we don't bind to pointer ops // Check the rank of the array against the number of indices provided, and // convert the indexes to ints CType pDestType = chooseArrayIndexType(pOp2); if (null == pDestType) { // using int as the type will allow us to give a better error... pDestType = pIntType; } int rank = pArrayType.rank; int cIndices = 0; EXPR transformedIndices = pOp2.Map(GetExprFactory(), (EXPR x) => { cIndices++; EXPR pTemp = mustConvert(x, pDestType); if (pDestType == pIntType) return pTemp; #if CSEE EXPRFLAG flag = 0; #else EXPRFLAG flag = EXPRFLAG.EXF_INDEXEXPR; #endif EXPRCLASS exprType = GetExprFactory().MakeClass(pDestType); return GetExprFactory().CreateCast(flag, exprType, pTemp); }); if (cIndices != rank) { ErrorContext.Error(ErrorCode.ERR_BadIndexCount, rank); pExpr = GetExprFactory().CreateArrayIndex(pOp1, transformedIndices); pExpr.SetError(); return pExpr; } // Allocate a new expression, the type is the element type of the array. // Array index operations are always lvalues. pExpr = GetExprFactory().CreateArrayIndex(pOp1, transformedIndices); pExpr.flags |= EXPRFLAG.EXF_LVALUE | EXPRFLAG.EXF_ASSGOP; if (bIsError) { pExpr.SetError(); } return pExpr; }
//////////////////////////////////////////////////////////////////////////////// // 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; }
//////////////////////////////////////////////////////////////////////////////// // 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; }