@@ -156,11 +156,6 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
156
156
Debug . Assert ( virtualMethodAccess is not null || virtualMethodAccessFailure is not null , "We need either a virtual method access or a failure message." ) ;
157
157
}
158
158
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
-
164
159
// Create base contexts
165
160
TrampolineContext functionContext = new ( outputGenerator , this , writer , context , declaration ) ;
166
161
TrampolineContext parameterContext = functionContext with { Context = functionContext . Context . Add ( declaration ) } ;
@@ -248,19 +243,13 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
248
243
// Emit function signature
249
244
//===========================================================================================================================================
250
245
{
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 )
254
247
{
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 ) ;
261
251
}
262
-
263
- if ( constructorName is null )
252
+ else
264
253
{
265
254
writer . Write ( Accessibility . ToCSharpKeyword ( ) ) ;
266
255
@@ -280,12 +269,6 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
280
269
// Write out the function name
281
270
writer . WriteIdentifier ( Name ) ;
282
271
}
283
- else
284
- {
285
- writer . Write ( Accessibility . ToCSharpKeyword ( ) ) ;
286
- writer . Write ( ' ' ) ;
287
- writer . WriteIdentifier ( constructorName ) ;
288
- }
289
272
290
273
// Write out the parameter list
291
274
writer . Write ( '(' ) ;
@@ -366,38 +349,16 @@ internal void Write(ICSharpOutputGenerator outputGenerator, VisitorContext conte
366
349
else
367
350
{ ReturnAdapter . WriteResultCapture ( functionContext , writer ) ; }
368
351
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
-
394
352
if ( virtualMethodAccess is not null )
395
353
{
396
354
Debug . Assert ( declaration . IsVirtual ) ;
397
355
writer . Write ( virtualMethodAccess ) ;
398
356
}
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
+ }
401
362
else
402
363
//TODO: Need to handle constructor dispatch
403
364
{ writer . WriteIdentifier ( Target . Name ) ; }
@@ -489,4 +450,39 @@ private void EmitMethodImplAttribute(TranslatedFunction declaration, CSharpCodeW
489
450
490
451
writer . WriteLine ( ")]" ) ;
491
452
}
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
+ }
492
488
}
0 commit comments