// method: internal RubyMethodInfo(RubyMethodBody/*!*/ body, RubyScope/*!*/ declaringScope, RubyModule/*!*/ declaringModule, RubyMemberFlags flags) : base(flags, declaringModule) { Assert.NotNull(body, declaringModule); _body = body; _declaringScope = declaringScope; }
// method: internal RubyMethodInfo(RubyMethodBody /*!*/ body, RubyScope /*!*/ declaringScope, RubyModule /*!*/ declaringModule, RubyMemberFlags flags) : base(flags, declaringModule) { Assert.NotNull(body, declaringModule); _body = body; _declaringScope = declaringScope; }
[Emitted] // MethodDeclaration: public static object DefineMethod(object targetOrSelf, RubyScope/*!*/ scope, RubyMethodBody/*!*/ body) { Assert.NotNull(body, scope); RubyModule instanceOwner, singletonOwner; RubyMemberFlags instanceFlags, singletonFlags; bool moduleFunction = false; if (body.HasTarget) { if (!RubyUtils.CanCreateSingleton(targetOrSelf)) { throw RubyExceptions.CreateTypeError("can't define singleton method for literals"); } instanceOwner = null; instanceFlags = RubyMemberFlags.Invalid; singletonOwner = scope.RubyContext.CreateSingletonClass(targetOrSelf); singletonFlags = RubyMemberFlags.Public; } else { var attributesScope = scope.GetMethodAttributesDefinitionScope(); if ((attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) { // Singleton module-function's scope points to the instance method's RubyMemberInfo. // This affects: // 1) super call // Super call is looking for Method.DeclaringModule while searching MRO, which would fail if the singleton module-function // was in MRO. Since module-function can only be used on module the singleton method could only be on module's singleton. // Module's singleton is never part of MRO so we are safe. // 2) trace // Method call trace reports non-singleton module. // MRI 1.8: instance method owner is self -> it is possible (via define_method) to define m.f. on a class (bug) // MRI 1.9: instance method owner GetMethodDefinitionOwner // MRI allows to define m.f. on classes but then doesn't work correctly with it. instanceOwner = scope.GetMethodDefinitionOwner(); if (instanceOwner.IsClass) { throw RubyExceptions.CreateTypeError("A module function cannot be defined on a class."); } instanceFlags = RubyMemberFlags.Private; singletonOwner = instanceOwner.SingletonClass; singletonFlags = RubyMemberFlags.Public; moduleFunction = true; } else { instanceOwner = scope.GetMethodDefinitionOwner(); instanceFlags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, body.Name); singletonOwner = null; singletonFlags = RubyMemberFlags.Invalid; } } RubyMethodInfo instanceMethod = null, singletonMethod = null; if (instanceOwner != null) { SetMethod(scope.RubyContext, instanceMethod = new RubyMethodInfo(body, scope, instanceOwner, instanceFlags) ); } if (singletonOwner != null) { SetMethod(scope.RubyContext, singletonMethod = new RubyMethodInfo(body, scope, singletonOwner, singletonFlags) ); } // the method's scope saves the result => singleton module-function uses instance-method var method = instanceMethod ?? singletonMethod; method.DeclaringModule.MethodAdded(body.Name); if (moduleFunction) { Debug.Assert(!method.DeclaringModule.IsClass); method.DeclaringModule.SingletonClass.MethodAdded(body.Name); } return null; }