@@ -6717,6 +6717,8 @@ export class Compiler extends DiagnosticEmitter {
67176717 // Compile omitted arguments with final argument locals blocked. Doesn't need to take care of
67186718 // side-effects within earlier expressions because these already happened on set.
67196719 this . currentFlow = flow ;
6720+ var isConstructor = instance . is ( CommonFlags . CONSTRUCTOR ) ;
6721+ if ( isConstructor ) flow . set ( FlowFlags . CTORPARAM_CONTEXT ) ;
67206722 for ( let i = numArguments ; i < numParameters ; ++ i ) {
67216723 let initType = parameterTypes [ i ] ;
67226724 let initExpr = this . compileExpression (
@@ -6729,12 +6731,13 @@ export class Compiler extends DiagnosticEmitter {
67296731 this . makeLocalAssignment ( argumentLocal , initExpr , initType , false )
67306732 ) ;
67316733 }
6734+ flow . unset ( FlowFlags . CTORPARAM_CONTEXT ) ;
67326735
67336736 // Compile the called function's body in the scope of the inlined flow
67346737 this . compileFunctionBody ( instance , body ) ;
67356738
67366739 // If a constructor, perform field init checks on its flow directly
6737- if ( instance . is ( CommonFlags . CONSTRUCTOR ) ) {
6740+ if ( isConstructor ) {
67386741 let parent = instance . parent ;
67396742 assert ( parent . kind == ElementKind . CLASS ) ;
67406743 this . checkFieldInitializationInFlow ( < Class > parent , flow ) ;
@@ -6815,6 +6818,7 @@ export class Compiler extends DiagnosticEmitter {
68156818 // accounting for additional locals and a proper `this` context.
68166819 var previousFlow = this . currentFlow ;
68176820 var flow = stub . flow ;
6821+ if ( original . is ( CommonFlags . CONSTRUCTOR ) ) flow . set ( FlowFlags . CTORPARAM_CONTEXT ) ;
68186822 this . currentFlow = flow ;
68196823
68206824 // create a br_table switching over the number of optional parameters provided
@@ -7641,21 +7645,32 @@ export class Compiler extends DiagnosticEmitter {
76417645 this . currentType = this . options . usizeType ;
76427646 return module . unreachable ( ) ;
76437647 }
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+ }
76487660 }
76497661 let thisLocal = assert ( flow . lookupLocal ( CommonNames . this_ ) ) ;
76507662 flow . set ( FlowFlags . ACCESSES_THIS ) ;
76517663 this . currentType = thisType ;
76527664 return module . local_get ( thisLocal . index , thisType . toRef ( ) ) ;
76537665 }
76547666 case NodeKind . SUPER : {
7655- let flow = this . currentFlow ;
7656- let actualFunction = flow . actualFunction ;
76577667 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 ) ) {
76597674 // TS1034 in the parser effectively limits this to property accesses
76607675 this . error (
76617676 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 {
1029210307 var module = this . module ;
1029310308 var flow = this . currentFlow ;
1029410309 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 ;
1029810311 var sizeTypeRef = this . options . sizeTypeRef ;
10312+ var nonParameterFields : Field [ ] | null = null ;
1029910313
1030010314 // TODO: for (let member of members.values()) {
1030110315 for ( let _values = Map_values ( members ) , i = 0 , k = _values . length ; i < k ; ++ i ) {
@@ -10304,44 +10318,57 @@ export class Compiler extends DiagnosticEmitter {
1030410318 member . kind != ElementKind . FIELD || // not a field
1030510319 member . parent != classInstance // inherited field
1030610320 ) continue ;
10307-
1030810321 let field = < Field > member ;
1030910322 assert ( ! field . isAny ( CommonFlags . CONST ) ) ;
10310- let fieldType = field . type ;
10311- let fieldTypeRef = fieldType . toRef ( ) ;
1031210323 let fieldPrototype = field . prototype ;
10313- let initializerNode = fieldPrototype . initializerNode ;
1031410324 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 ) ;
1033110325
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 ;
1033510331 }
1033610332
10333+ // Initialize constructor parameter field
10334+ let fieldType = field . type ;
10335+ let fieldTypeRef = fieldType . toRef ( ) ;
10336+ assert ( ! fieldPrototype . initializerNode ) ;
1033710337 this . compileFieldSetter ( field ) ;
1033810338 stmts . push (
1033910339 module . call ( field . internalSetterName , [
1034010340 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+ )
1034210347 ] , TypeRef . None )
1034310348 ) ;
1034410349 }
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 ;
1034510372 return stmts ;
1034610373 }
1034710374
0 commit comments