Skip to content

Commit ff127ea

Browse files
committed
Better is-constructor-emit handling
1 parent eb59f3e commit ff127ea

File tree

1 file changed

+45
-49
lines changed

1 file changed

+45
-49
lines changed

Biohazrd.CSharp/Trampolines/Trampoline.cs

+45-49
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,6 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
156156
Debug.Assert(virtualMethodAccess is not null || virtualMethodAccessFailure is not null, "We need either a virtual method access or a failure message.");
157157
}
158158

159-
//if (declaration.IsVirtual && virtualFunctionAccess is null)
160-
//{ throw new ArgumentNullException(nameof(virtualFunctionAccess), "Virtual function access is required when emitting a virtual method."); }
161-
//else if (!declaration.IsVirtual && virtualFunctionAccess is not null)
162-
//{ throw new ArgumentException("Virtual function access should not be provided when emitting a non-virtual method.", nameof(virtualFunctionAccess)); }
163-
164159
// Create base contexts
165160
TrampolineContext functionContext = new(outputGenerator, this, writer, context, declaration);
166161
TrampolineContext parameterContext = functionContext with { Context = functionContext.Context.Add(declaration) };
@@ -248,19 +243,13 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
248243
// Emit function signature
249244
//===========================================================================================================================================
250245
{
251-
// If this is a constructor, determine if we'll emit it as an actual constructor
252-
string? constructorName = null;
253-
if (!IsNativeFunction && declaration.SpecialFunctionKind == SpecialFunctionKind.Constructor && context.ParentDeclaration is TranslatedRecord constructorType)
246+
if (GetConstructorName(outputGenerator, context, declaration) is string constructorName)
254247
{
255-
constructorName = constructorType.Name;
256-
257-
//TODO: This does not handle input-no-output adapters
258-
// Parameterless constructors require C# 10
259-
if (declaration.Parameters.Length == 0 && outputGenerator.Options.TargetLanguageVersion < TargetLanguageVersion.CSharp10)
260-
{ constructorName = null; }
248+
writer.Write(Accessibility.ToCSharpKeyword());
249+
writer.Write(' ');
250+
writer.WriteIdentifier(constructorName);
261251
}
262-
263-
if (constructorName is null)
252+
else
264253
{
265254
writer.Write(Accessibility.ToCSharpKeyword());
266255

@@ -280,12 +269,6 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
280269
// Write out the function name
281270
writer.WriteIdentifier(Name);
282271
}
283-
else
284-
{
285-
writer.Write(Accessibility.ToCSharpKeyword());
286-
writer.Write(' ');
287-
writer.WriteIdentifier(constructorName);
288-
}
289272

290273
// Write out the parameter list
291274
writer.Write('(');
@@ -366,38 +349,16 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
366349
else
367350
{ ReturnAdapter.WriteResultCapture(functionContext, writer); }
368351

369-
bool targetIsActuallyConstructor = false;
370-
if (declaration.SpecialFunctionKind == SpecialFunctionKind.Constructor && !Target.IsNativeFunction)
371-
{
372-
targetIsActuallyConstructor = true;
373-
bool anyTargetAdaptersAreInputs = false;
374-
375-
foreach (Adapter adapter in Target.Adapters)
376-
{
377-
if (adapter.AcceptsInput)
378-
{
379-
anyTargetAdaptersAreInputs = true;
380-
381-
if (adapter.SpecialKind == SpecialAdapterKind.ThisPointer)
382-
{
383-
targetIsActuallyConstructor = false;
384-
break;
385-
}
386-
}
387-
}
388-
389-
// If the target could be a constructor but it has no inputs, it will not be a constructor unless we're targeting C# 10 or newer
390-
if (targetIsActuallyConstructor && !anyTargetAdaptersAreInputs && outputGenerator.Options.TargetLanguageVersion < TargetLanguageVersion.CSharp10)
391-
{ targetIsActuallyConstructor = false; }
392-
}
393-
394352
if (virtualMethodAccess is not null)
395353
{
396354
Debug.Assert(declaration.IsVirtual);
397355
writer.Write(virtualMethodAccess);
398356
}
399-
else if (targetIsActuallyConstructor)
400-
{ writer.Write("this = new"); }
357+
else if (Target.GetConstructorName(outputGenerator, context, declaration) is string constructorName)
358+
{
359+
writer.Write("this = new ");
360+
writer.WriteIdentifier(constructorName);
361+
}
401362
else
402363
//TODO: Need to handle constructor dispatch
403364
{ writer.WriteIdentifier(Target.Name); }
@@ -489,4 +450,39 @@ private void EmitMethodImplAttribute(TranslatedFunction declaration, CSharpCodeW
489450

490451
writer.WriteLine(")]");
491452
}
453+
454+
private string? GetConstructorName(ICSharpOutputGenerator outputGenerator, VisitorContext context, TranslatedFunction declaration)
455+
{
456+
// Native functions are never emitted as constructors
457+
if (IsNativeFunction)
458+
{ return null; }
459+
460+
// Non-constructors are never emitted as constructors
461+
if (declaration.SpecialFunctionKind != SpecialFunctionKind.Constructor)
462+
{ return null; }
463+
464+
// If we don't have a parent record we don't know what type we're constructing
465+
if (context.ParentDeclaration is not TranslatedRecord constructorType)
466+
{ return null; }
467+
468+
// If none of our adaptors accept inputs, we won't emit any parameters. Parameterless constructors require C# 10 or newer
469+
if (outputGenerator.Options.TargetLanguageVersion < TargetLanguageVersion.CSharp10)
470+
{
471+
bool haveInputs = false;
472+
foreach (Adapter adapter in Adapters)
473+
{
474+
if (adapter.AcceptsInput)
475+
{
476+
haveInputs = true;
477+
break;
478+
}
479+
}
480+
481+
if (!haveInputs)
482+
{ return null; }
483+
}
484+
485+
// If we got this far we will emit as a constructor
486+
return constructorType.Name;
487+
}
492488
}

0 commit comments

Comments
 (0)