@@ -6717,6 +6717,8 @@ export class Compiler extends DiagnosticEmitter {
6717
6717
// Compile omitted arguments with final argument locals blocked. Doesn't need to take care of
6718
6718
// side-effects within earlier expressions because these already happened on set.
6719
6719
this . currentFlow = flow ;
6720
+ var isConstructor = instance . is ( CommonFlags . CONSTRUCTOR ) ;
6721
+ if ( isConstructor ) flow . set ( FlowFlags . CTORPARAM_CONTEXT ) ;
6720
6722
for ( let i = numArguments ; i < numParameters ; ++ i ) {
6721
6723
let initType = parameterTypes [ i ] ;
6722
6724
let initExpr = this . compileExpression (
@@ -6729,12 +6731,13 @@ export class Compiler extends DiagnosticEmitter {
6729
6731
this . makeLocalAssignment ( argumentLocal , initExpr , initType , false )
6730
6732
) ;
6731
6733
}
6734
+ flow . unset ( FlowFlags . CTORPARAM_CONTEXT ) ;
6732
6735
6733
6736
// Compile the called function's body in the scope of the inlined flow
6734
6737
this . compileFunctionBody ( instance , body ) ;
6735
6738
6736
6739
// If a constructor, perform field init checks on its flow directly
6737
- if ( instance . is ( CommonFlags . CONSTRUCTOR ) ) {
6740
+ if ( isConstructor ) {
6738
6741
let parent = instance . parent ;
6739
6742
assert ( parent . kind == ElementKind . CLASS ) ;
6740
6743
this . checkFieldInitializationInFlow ( < Class > parent , flow ) ;
@@ -6815,6 +6818,7 @@ export class Compiler extends DiagnosticEmitter {
6815
6818
// accounting for additional locals and a proper `this` context.
6816
6819
var previousFlow = this . currentFlow ;
6817
6820
var flow = stub . flow ;
6821
+ if ( original . is ( CommonFlags . CONSTRUCTOR ) ) flow . set ( FlowFlags . CTORPARAM_CONTEXT ) ;
6818
6822
this . currentFlow = flow ;
6819
6823
6820
6824
// create a br_table switching over the number of optional parameters provided
@@ -7641,21 +7645,32 @@ export class Compiler extends DiagnosticEmitter {
7641
7645
this . currentType = this . options . usizeType ;
7642
7646
return module . unreachable ( ) ;
7643
7647
}
7644
- if ( actualFunction . is ( CommonFlags . CONSTRUCTOR ) && ! ( constraints & Constraints . IS_THIS ) ) {
7645
- let parent = actualFunction . parent ;
7646
- assert ( parent . kind == ElementKind . CLASS ) ;
7647
- this . checkFieldInitialization ( < Class > parent , expression ) ;
7648
+ if ( actualFunction . is ( CommonFlags . CONSTRUCTOR ) ) {
7649
+ if ( flow . is ( FlowFlags . CTORPARAM_CONTEXT ) ) {
7650
+ this . error (
7651
+ DiagnosticCode . _this_cannot_be_referenced_in_constructor_arguments ,
7652
+ expression . range
7653
+ ) ;
7654
+ }
7655
+ if ( ! ( constraints & Constraints . IS_THIS ) ) {
7656
+ let parent = actualFunction . parent ;
7657
+ assert ( parent . kind == ElementKind . CLASS ) ;
7658
+ this . checkFieldInitialization ( < Class > parent , expression ) ;
7659
+ }
7648
7660
}
7649
7661
let thisLocal = assert ( flow . lookupLocal ( CommonNames . this_ ) ) ;
7650
7662
flow . set ( FlowFlags . ACCESSES_THIS ) ;
7651
7663
this . currentType = thisType ;
7652
7664
return module . local_get ( thisLocal . index , thisType . toRef ( ) ) ;
7653
7665
}
7654
7666
case NodeKind . SUPER : {
7655
- let flow = this . currentFlow ;
7656
- let actualFunction = flow . actualFunction ;
7657
7667
if ( actualFunction . is ( CommonFlags . CONSTRUCTOR ) ) {
7658
- if ( ! flow . is ( FlowFlags . CALLS_SUPER ) ) {
7668
+ if ( flow . is ( FlowFlags . CTORPARAM_CONTEXT ) ) {
7669
+ this . error (
7670
+ DiagnosticCode . _super_cannot_be_referenced_in_constructor_arguments ,
7671
+ expression . range
7672
+ ) ;
7673
+ } else if ( ! flow . is ( FlowFlags . CALLS_SUPER ) ) {
7659
7674
// TS1034 in the parser effectively limits this to property accesses
7660
7675
this . error (
7661
7676
DiagnosticCode . _super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class ,
@@ -10292,10 +10307,9 @@ export class Compiler extends DiagnosticEmitter {
10292
10307
var module = this . module ;
10293
10308
var flow = this . currentFlow ;
10294
10309
var isInline = flow . isInline ;
10295
- var thisLocalIndex = isInline
10296
- ? flow . lookupLocal ( CommonNames . this_ ) ! . index
10297
- : 0 ;
10310
+ var thisLocalIndex = isInline ? flow . lookupLocal ( CommonNames . this_ ) ! . index : 0 ;
10298
10311
var sizeTypeRef = this . options . sizeTypeRef ;
10312
+ var nonParameterFields : Field [ ] | null = null ;
10299
10313
10300
10314
// TODO: for (let member of members.values()) {
10301
10315
for ( let _values = Map_values ( members ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
@@ -10304,44 +10318,57 @@ export class Compiler extends DiagnosticEmitter {
10304
10318
member . kind != ElementKind . FIELD || // not a field
10305
10319
member . parent != classInstance // inherited field
10306
10320
) continue ;
10307
-
10308
10321
let field = < Field > member ;
10309
10322
assert ( ! field . isAny ( CommonFlags . CONST ) ) ;
10310
- let fieldType = field . type ;
10311
- let fieldTypeRef = fieldType . toRef ( ) ;
10312
10323
let fieldPrototype = field . prototype ;
10313
- let initializerNode = fieldPrototype . initializerNode ;
10314
10324
let parameterIndex = fieldPrototype . parameterIndex ;
10315
- let initExpr : ExpressionRef ;
10316
- let typeNode = field . typeNode ;
10317
- if ( typeNode ) this . checkTypeSupported ( fieldType , typeNode ) ;
10318
-
10319
- // if declared as a constructor parameter, use its value
10320
- if ( parameterIndex >= 0 ) {
10321
- initExpr = module . local_get (
10322
- isInline
10323
- ? flow . lookupLocal ( field . name ) ! . index
10324
- : 1 + parameterIndex , // this is local 0
10325
- fieldTypeRef
10326
- ) ;
10327
-
10328
- // fall back to use initializer if present
10329
- } else if ( initializerNode ) {
10330
- initExpr = this . compileExpression ( initializerNode , fieldType , Constraints . CONV_IMPLICIT ) ;
10331
10325
10332
- // otherwise initialize with zero
10333
- } else {
10334
- initExpr = this . makeZero ( fieldType , fieldPrototype . declaration ) ;
10326
+ // Defer non-parameter fields until parameter fields are initialized
10327
+ if ( parameterIndex < 0 ) {
10328
+ if ( ! nonParameterFields ) nonParameterFields = new Array ( ) ;
10329
+ nonParameterFields . push ( field ) ;
10330
+ continue ;
10335
10331
}
10336
10332
10333
+ // Initialize constructor parameter field
10334
+ let fieldType = field . type ;
10335
+ let fieldTypeRef = fieldType . toRef ( ) ;
10336
+ assert ( ! fieldPrototype . initializerNode ) ;
10337
10337
this . compileFieldSetter ( field ) ;
10338
10338
stmts . push (
10339
10339
module . call ( field . internalSetterName , [
10340
10340
module . local_get ( thisLocalIndex , sizeTypeRef ) ,
10341
- initExpr
10341
+ module . local_get (
10342
+ isInline
10343
+ ? flow . lookupLocal ( field . name ) ! . index
10344
+ : 1 + parameterIndex , // `this` is local 0
10345
+ fieldTypeRef
10346
+ )
10342
10347
] , TypeRef . None )
10343
10348
) ;
10344
10349
}
10350
+
10351
+ // Initialize deferred non-parameter fields
10352
+ if ( nonParameterFields ) {
10353
+ for ( let i = 0 , k = nonParameterFields . length ; i < k ; ++ i ) {
10354
+ let field = unchecked ( nonParameterFields [ i ] ) ;
10355
+ let fieldType = field . type ;
10356
+ let fieldPrototype = field . prototype ;
10357
+ let initializerNode = fieldPrototype . initializerNode ;
10358
+ assert ( fieldPrototype . parameterIndex < 0 ) ;
10359
+ this . compileFieldSetter ( field ) ;
10360
+ stmts . push (
10361
+ module . call ( field . internalSetterName , [
10362
+ module . local_get ( thisLocalIndex , sizeTypeRef ) ,
10363
+ initializerNode // use initializer if present, otherwise initialize with zero
10364
+ ? this . compileExpression ( initializerNode , fieldType , Constraints . CONV_IMPLICIT )
10365
+ : this . makeZero ( fieldType , fieldPrototype . declaration )
10366
+ ] , TypeRef . None )
10367
+ ) ;
10368
+ }
10369
+ }
10370
+
10371
+ this . currentType = Type . void ;
10345
10372
return stmts ;
10346
10373
}
10347
10374
0 commit comments