public void BuildObjectConstructionNoFlow(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, string/*!*/ methodName) {
if (IsSingletonClass) {
metaBuilder.SetError(Methods.MakeVirtualClassInstantiatedError.OpCall());
return;
}
Type type = GetUnderlyingSystemType();
RubyMemberInfo initializer;
using (Context.ClassHierarchyLocker()) {
// check version of the class so that we invalidate the rule whenever the initializer changes:
metaBuilder.AddVersionTest(this);
initializer = ResolveMethodForSiteNoLock(Symbols.Initialize, VisibilityContext.AllVisible).Info;
// Initializer resolves to BasicObject#initialize unless overridden in a derived class.
// We ensure that initializer cannot be removed/undefined so that we don't ever fall back to method_missing (see RubyModule.RemoveMethodNoEvent).
Debug.Assert(initializer != null);
}
bool isLibraryMethod = initializer is RubyLibraryMethodInfo;
bool isRubyInitializer = initializer.IsRubyMember && !isLibraryMethod;
bool isLibraryInitializer = isLibraryMethod && !initializer.DeclaringModule.IsObjectClass && !initializer.DeclaringModule.IsBasicObjectClass;
if (isRubyInitializer || isLibraryInitializer && _isRubyClass) {
// allocate and initialize:
bool allocatorFound = BuildAllocatorCall(metaBuilder, args, () => AstUtils.Constant(Name));
if (metaBuilder.Error) {
return;
}
if (!allocatorFound) {
metaBuilder.SetError(Methods.MakeMissingDefaultConstructorError.OpCall(
Ast.Convert(args.TargetExpression, typeof(RubyClass)),
Ast.Constant(initializer.DeclaringModule.Name)
));
return;
}
if (!initializer.IsEmpty) {
BuildOverriddenInitializerCall(metaBuilder, args, initializer);
}
} else {
// construct:
OverloadInfo[] constructionOverloads;
SelfCallConvention callConvention = SelfCallConvention.SelfIsParameter;
bool implicitProtocolConversions = false;
if (typeof(Delegate).IsAssignableFrom(type)) {
BuildDelegateConstructorCall(metaBuilder, args, type);
return;
} else if (type.IsArray && type.GetArrayRank() == 1) {
constructionOverloads = GetClrVectorFactories();
} else if (_structInfo != null) {
constructionOverloads = new OverloadInfo[] { new ReflectionOverloadInfo(Methods.CreateStructInstance) };
} else if (_factories.Length != 0) {
constructionOverloads = ArrayUtils.ConvertAll(_factories, (d) => new ReflectionOverloadInfo(d.Method));
} else {
// TODO: handle protected constructors
constructionOverloads = GetConstructors(type == typeof(object) ? typeof(RubyObject) : type);
if (type.IsValueType) {
if (constructionOverloads.Length == 0 || GetConstructor(type) == null) {
constructionOverloads = ArrayUtils.Append(constructionOverloads, new ReflectionOverloadInfo(Methods.CreateDefaultInstance));
}
} else if (constructionOverloads.Length == 0) {
metaBuilder.SetError(Methods.MakeAllocatorUndefinedError.OpCall(Ast.Convert(args.TargetExpression, typeof(RubyClass))));
return;
}
callConvention = SelfCallConvention.NoSelf;
implicitProtocolConversions = true;
}
RubyMethodGroupInfo.BuildCallNoFlow(metaBuilder, args, methodName, constructionOverloads, callConvention, implicitProtocolConversions);
if (!metaBuilder.Error) {
metaBuilder.Result = MarkNewException(metaBuilder.Result);
// we need to handle break, which unwinds to a proc-converter that could be this method's frame:
if (args.Signature.HasBlock) {
metaBuilder.ControlFlowBuilder = RubyMethodGroupInfo.RuleControlFlowBuilder;
}
}
}
}