///////////////////////////////////////////////////////////////////////////////// internal SymWithType LookupMember( string name, EXPR callingObject, ParentSymbol context, int arity, MemberLookup mem, bool allowSpecialNames, bool requireInvocable) { CType type = callingObject.type; if (type.IsArrayType()) { type = _semanticChecker.GetSymbolLoader().GetReqPredefType(PredefinedType.PT_ARRAY); } if (type.IsNullableType()) { type = type.AsNullableType().GetAts(_semanticChecker.GetSymbolLoader().GetErrorContext()); } if (!mem.Lookup( _semanticChecker, type, callingObject, context, GetName(name), arity, MemLookFlags.TypeVarsAllowed | (allowSpecialNames ? 0 : MemLookFlags.UserCallable) | (name == SpecialNames.Indexer ? MemLookFlags.Indexer : 0) | (name == SpecialNames.Constructor ? MemLookFlags.Ctor : 0) | (requireInvocable ? MemLookFlags.MustBeInvocable : 0))) { return null; } return mem.SwtFirst(); }
private bool DeferBinding( DynamicMetaObjectBinder payload, ArgumentObject[] arguments, DynamicMetaObject[] args, Dictionary<int, LocalVariableSymbol> dictionary, out DynamicMetaObject deferredBinding) { // This method deals with any deferrals we need to do. We check deferrals up front // and bail early if we need to do them. // (1) InvokeMember deferral. // // This is the deferral for the d.Foo() scenario where Foo actually binds to a // field or property, and not a method group that is invocable. We defer to // the standard GetMember/Invoke pattern. if (payload is CSharpInvokeMemberBinder) { ICSharpInvokeOrInvokeMemberBinder callPayload = payload as ICSharpInvokeOrInvokeMemberBinder; int arity = callPayload.TypeArguments != null ? callPayload.TypeArguments.Count : 0; MemberLookup mem = new MemberLookup(); EXPR callingObject = CreateCallingObjectForCall(callPayload, arguments, dictionary); Debug.Assert(_bindingContext.ContextForMemberLookup() != null); SymWithType swt = _symbolTable.LookupMember( callPayload.Name, callingObject, _bindingContext.ContextForMemberLookup(), arity, mem, (callPayload.Flags & CSharpCallFlags.EventHookup) != 0, true); if (swt != null && swt.Sym.getKind() != SYMKIND.SK_MethodSymbol) { // The GetMember only has one argument, and we need to just take the first arg info. CSharpGetMemberBinder getMember = new CSharpGetMemberBinder(callPayload.Name, false, callPayload.CallingContext, new CSharpArgumentInfo[] { callPayload.ArgumentInfo[0] }); // The Invoke has the remaining argument infos. However, we need to redo the first one // to correspond to the GetMember result. CSharpArgumentInfo[] argInfos = new CSharpArgumentInfo[callPayload.ArgumentInfo.Count]; callPayload.ArgumentInfo.CopyTo(argInfos, 0); argInfos[0] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null); CSharpInvokeBinder invoke = new CSharpInvokeBinder(callPayload.Flags, callPayload.CallingContext, argInfos); DynamicMetaObject[] newArgs = new DynamicMetaObject[args.Length - 1]; Array.Copy(args, 1, newArgs, 0, args.Length - 1); deferredBinding = invoke.Defer(getMember.Defer(args[0]), newArgs); return true; } } deferredBinding = null; return false; }
///////////////////////////////////////////////////////////////////////////////// private EXPR BindIsEvent( CSharpIsEventBinder binder, ArgumentObject[] arguments, Dictionary<int, LocalVariableSymbol> dictionary) { // The IsEvent binder will never be called without an instance object. This // is because the compiler only gen's this code for dynamic dots. EXPR callingObject = CreateLocal(arguments[0].Type, false, dictionary[0]); MemberLookup mem = new MemberLookup(); CType boolType = SymbolLoader.GetReqPredefType(PredefinedType.PT_BOOL); bool result = false; if (arguments[0].Value == null) { throw Error.NullReferenceOnMemberException(); } Debug.Assert(_bindingContext.ContextForMemberLookup() != null); SymWithType swt = _symbolTable.LookupMember( binder.Name, callingObject, _bindingContext.ContextForMemberLookup(), 0, mem, false, false); // If lookup returns an actual event, then this is an event. if (swt != null && swt.Sym.getKind() == SYMKIND.SK_EventSymbol) { result = true; } // If lookup returns the backing field of a field-like event, then // this is an event. This is due to the Dev10 design change around // the binding of +=, and the fact that the "IsEvent" binding question // is only ever asked about the LHS of a += or -=. if (swt != null && swt.Sym.getKind() == SYMKIND.SK_FieldSymbol && swt.Sym.AsFieldSymbol().isEvent) { result = true; } return _exprFactory.CreateConstant(boolType, ConstValFactory.GetBool(result)); }
///////////////////////////////////////////////////////////////////////////////// private EXPR BindProperty( DynamicMetaObjectBinder payload, ArgumentObject argument, LocalVariableSymbol local, EXPR optionalIndexerArguments, bool fEventsPermitted) { // If our argument is a static type, then we're calling a static property. EXPR callingObject = argument.Info.IsStaticType ? _exprFactory.CreateClass(_symbolTable.GetCTypeFromType(argument.Value as Type), null, null) : CreateLocal(argument.Type, argument.Info.IsOut, local); if (!argument.Info.UseCompileTimeType && argument.Value == null) { throw Error.NullReferenceOnMemberException(); } // If our argument is a struct type, unbox it. if (argument.Type.GetTypeInfo().IsValueType && callingObject.isCAST()) { // If we have a struct type, unbox it. callingObject.flags |= EXPRFLAG.EXF_UNBOXRUNTIME; } string name = GetName(payload); BindingFlag bindFlags = GetBindingFlags(payload); MemberLookup mem = new MemberLookup(); SymWithType swt = _symbolTable.LookupMember(name, callingObject, _bindingContext.ContextForMemberLookup(), 0, mem, false, false); if (swt == null) { if (optionalIndexerArguments != null) { int numIndexArguments = ExpressionIterator.Count(optionalIndexerArguments); // We could have an array access here. See if its just an array. if ((argument.Type.IsArray && argument.Type.GetArrayRank() == numIndexArguments) || argument.Type == typeof(string)) { return CreateArray(callingObject, optionalIndexerArguments); } } mem.ReportErrors(); Debug.Assert(false, "Why didn't member lookup report an error?"); } switch (swt.Sym.getKind()) { case SYMKIND.SK_MethodSymbol: throw Error.BindPropertyFailedMethodGroup(name); case SYMKIND.SK_PropertySymbol: if (swt.Sym is IndexerSymbol) { return CreateIndexer(swt, callingObject, optionalIndexerArguments, bindFlags); } else { BindingFlag flags = 0; if (payload is CSharpGetMemberBinder || payload is CSharpGetIndexBinder) { flags = BindingFlag.BIND_RVALUEREQUIRED; } // Properties can be LValues. callingObject.flags |= EXPRFLAG.EXF_LVALUE; return CreateProperty(swt, callingObject, flags); } case SYMKIND.SK_FieldSymbol: return CreateField(swt, callingObject); case SYMKIND.SK_EventSymbol: if (fEventsPermitted) { return CreateEvent(swt, callingObject); } else { throw Error.BindPropertyFailedEvent(name); } default: Debug.Assert(false, "Unexpected type returned from lookup"); throw Error.InternalCompilerError(); } }
///////////////////////////////////////////////////////////////////////////////// private EXPR BindCall( ICSharpInvokeOrInvokeMemberBinder payload, EXPR callingObject, ArgumentObject[] arguments, Dictionary<int, LocalVariableSymbol> dictionary) { if (payload is InvokeBinder && !callingObject.type.isDelegateType()) { throw Error.BindInvokeFailedNonDelegate(); } EXPR pResult = null; int arity = payload.TypeArguments != null ? payload.TypeArguments.Count : 0; MemberLookup mem = new MemberLookup(); Debug.Assert(_bindingContext.ContextForMemberLookup() != null); SymWithType swt = _symbolTable.LookupMember( payload.Name, callingObject, _bindingContext.ContextForMemberLookup(), arity, mem, (payload.Flags & CSharpCallFlags.EventHookup) != 0, true); if (swt == null) { mem.ReportErrors(); Debug.Assert(false, "Why didn't member lookup report an error?"); } if (swt.Sym.getKind() != SYMKIND.SK_MethodSymbol) { Debug.Assert(false, "Unexpected type returned from lookup"); throw Error.InternalCompilerError(); } // At this point, we're set up to do binding. We need to do the following: // // 1) Create the EXPRLOCALs for the arguments, linking them to the local // variable symbols defined above. // 2) Create the EXPRMEMGRP for the call and the EXPRLOCAL for the object // of the call, and link the correct local variable symbol as above. // 3) Do overload resolution to get back an EXPRCALL. // // Our caller takes care of the rest. // First we need to check the sym that we got back. If we got back a static // method, then we may be in the situation where the user called the method // via a simple name call through the phantom overload. If thats the case, // then we want to sub in a type instead of the object. EXPRMEMGRP memGroup = CreateMemberGroupEXPR(payload.Name, payload.TypeArguments, callingObject, swt.Sym.getKind()); if ((payload.Flags & CSharpCallFlags.SimpleNameCall) != 0) { callingObject.flags |= EXPRFLAG.EXF_SIMPLENAME; } if ((payload.Flags & CSharpCallFlags.EventHookup) != 0) { mem = new MemberLookup(); SymWithType swtEvent = _symbolTable.LookupMember( payload.Name.Split('_')[1], callingObject, _bindingContext.ContextForMemberLookup(), arity, mem, (payload.Flags & CSharpCallFlags.EventHookup) != 0, true); if (swtEvent == null) { mem.ReportErrors(); Debug.Assert(false, "Why didn't member lookup report an error?"); } CType eventCType = null; if (swtEvent.Sym.getKind() == SYMKIND.SK_FieldSymbol) { eventCType = swtEvent.Field().GetType(); } else if (swtEvent.Sym.getKind() == SYMKIND.SK_EventSymbol) { eventCType = swtEvent.Event().type; } Type eventType = SymbolLoader.GetTypeManager().SubstType(eventCType, swtEvent.Ats).AssociatedSystemType; if (eventType != null) { // If we have an event hookup, first find the event itself. BindImplicitConversion(new ArgumentObject[] { arguments[1] }, eventType, dictionary, false); } memGroup.flags &= ~EXPRFLAG.EXF_USERCALLABLE; if (swtEvent.Sym.getKind() == SYMKIND.SK_EventSymbol && swtEvent.Event().IsWindowsRuntimeEvent) { return BindWinRTEventAccessor( new EventWithType(swtEvent.Event(), swtEvent.Ats), callingObject, arguments, dictionary, payload.Name.StartsWith("add_", StringComparison.Ordinal)); //isAddAccessor? } } // Check if we have a potential call to an indexed property accessor. // If so, we'll flag overload resolution to let us call non-callables. if ((payload.Name.StartsWith("set_", StringComparison.Ordinal) && swt.Sym.AsMethodSymbol().Params.Size > 1) || (payload.Name.StartsWith("get_", StringComparison.Ordinal) && swt.Sym.AsMethodSymbol().Params.Size > 0)) { memGroup.flags &= ~EXPRFLAG.EXF_USERCALLABLE; } pResult = _binder.BindMethodGroupToArguments(// Tree BindingFlag.BIND_RVALUEREQUIRED | BindingFlag.BIND_STMTEXPRONLY, memGroup, CreateArgumentListEXPR(arguments, dictionary, 1, arguments.Length)); // If overload resolution failed, throw an error. if (pResult == null || !pResult.isOK()) { throw Error.BindCallFailedOverloadResolution(); } CheckForConditionalMethodError(pResult); return ReorderArgumentsForNamedAndOptional(callingObject, 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; }