protected override BitArray MapSpecialParameters(ParameterMapping/*!*/ mapping) { var infos = mapping.ParameterInfos; BitArray special = base.MapSpecialParameters(mapping); if (infos.Length > 0) { bool normalSeen = false; for (int i = 0; i < infos.Length; i++) { bool isSpecial = false; if (infos[i].ParameterType.IsSubclassOf(typeof(SiteLocalStorage))) { mapping.AddBuilder(new SiteLocalStorageBuilder(infos[i])); isSpecial = true; } else if (infos[i].ParameterType == typeof(CodeContext) && !normalSeen) { mapping.AddBuilder(new ContextArgBuilder(infos[i])); isSpecial = true; } else { normalSeen = true; } if (isSpecial) { (special = special ?? new BitArray(infos.Length))[i] = true; } } } return special; }
protected override BitArray MapSpecialParameters(ParameterMapping/*!*/ mapping) { var infos = mapping.ParameterInfos; var method = mapping.Method; var special = new BitArray(infos.Length); // Method signatures SelfCallConvention // RubyMethod/RubyCtor: [(CallSiteStorage)*, (RubyContext|RubyScope)?, (BlockParam)?, self, args] SelfIsParameter // static: [(CallSiteStorage)*, (RubyContext|RubyScope)?, (BlockParam)?, args] NoSelf // instance/extension/op: [self, (CallSiteStorage)*, (RubyContext|RubyScope)?, (BlockParam)?, args] SelfIsInstace var i = 0; if (_callConvention == SelfCallConvention.SelfIsInstance) { if (CompilerHelpers.IsStatic(method)) { Debug.Assert(RubyUtils.IsOperator(method) || CompilerHelpers.IsExtension(method)); // receiver maps to the first parameter: mapping.AddParameter(new ParameterWrapper(infos[i], infos[i].ParameterType, null, true, false, false, true)); mapping.AddBuilder(new SimpleArgBuilder(infos[i], mapping.ArgIndex)); special[i++] = true; } else { // receiver maps to the instance (no parameter info represents it): mapping.AddParameter(new ParameterWrapper(null, method.DeclaringType, null, true, false, false, true)); mapping.AddInstanceBuilder(new InstanceBuilder(mapping.ArgIndex)); } } else if (_callConvention == SelfCallConvention.NoSelf) { // instance methods on Object can be called with arbitrary receiver object including classes (static call): if (!method.IsStatic && method.DeclaringType == typeof(Object)) { // insert an InstanceBuilder that doesn't consume any arguments, only inserts the target expression as instance: mapping.AddInstanceBuilder(new ImplicitInstanceBuilder()); } } while (i < infos.Length && infos[i].ParameterType.IsSubclassOf(typeof(RubyCallSiteStorage))) { mapping.AddBuilder(new RubyCallSiteStorageBuilder(infos[i])); special[i++] = true; } if (i < infos.Length) { var info = infos[i]; if (info.ParameterType == typeof(RubyScope)) { mapping.AddBuilder(new RubyScopeArgBuilder(info)); special[i++] = true; } else if (info.ParameterType == typeof(RubyContext)) { mapping.AddBuilder(new RubyContextArgBuilder(info)); special[i++] = true; } else if (method.IsConstructor && info.ParameterType == typeof(RubyClass)) { mapping.AddBuilder(new RubyClassCtorArgBuilder(info)); special[i++] = true; } } // If the method overload doesn't have a BlockParam parameter, we inject MissingBlockParam parameter and arg builder. // The parameter is treated as a regular explicit mandatory parameter. // // The argument builder provides no value for the actual argument expression, which makes the default binder to skip it // when emitting a tree for the actual method call (this is necessary since the method doesn't in fact have the parameter). // // By injecting the missing block parameter we achieve that all overloads have either BlockParam, [NotNull]BlockParam or // MissingBlockParam parameter. MissingBlockParam and BlockParam are convertible to each other. Default binder prefers // those overloads where no conversion needs to happen, which ensures the desired semantics: // // conversions with desired priority (the less number the higher priority) // Parameters: call w/o block call with non-null block call with null block // (implicit, MBP, ... ) MBP -> MBP (1) BP -> MBP (3) BP -> MBP (2) // (implicit, BP, ... ) MBP -> BP (2) BP -> BP (2) BP -> BP (1) // (implicit, BP!, ... ) N/A BP -> BP! (1) N/A // if (i < infos.Length && infos[i].ParameterType == typeof(BlockParam)) { var info = infos[i]; mapping.AddBuilder(new SimpleArgBuilder(info, mapping.ArgIndex)); mapping.AddParameter(new ParameterWrapper(info, info.ParameterType, null, CompilerHelpers.ProhibitsNull(info), false, false, true)); special[i++] = true; } else if (i >= infos.Length || infos[i].ParameterType != typeof(BlockParam)) { mapping.AddBuilder(new MissingBlockArgBuilder(mapping.ArgIndex)); mapping.AddParameter(new ParameterWrapper(null, typeof(MissingBlockParam), null, false, false, false, true)); } if (_callConvention == SelfCallConvention.SelfIsParameter) { // Ruby library methods only: Debug.Assert(CompilerHelpers.IsStatic(method)); Debug.Assert(i < infos.Length); var info = infos[i]; // receiver maps to the first visible parameter: mapping.AddParameter(new ParameterWrapper(info, info.ParameterType, null, CompilerHelpers.ProhibitsNull(info), false, false, true)); mapping.AddBuilder(new SimpleArgBuilder(info, mapping.ArgIndex)); special[i++] = true; } return special; }
private void AddSimpleHiddenMapping(ParameterMapping mapping, ParameterInfo info, bool prohibitNull) { mapping.AddBuilder(new SimpleArgBuilder(info, info.ParameterType, mapping.ArgIndex, false, false)); mapping.AddParameter(new ParameterWrapper(info, info.ParameterType, null, ParameterBindingFlags.IsHidden | (prohibitNull ? ParameterBindingFlags.ProhibitNull : 0) )); }