@@ -1111,8 +1111,7 @@ export class Compiler extends DiagnosticEmitter {
1111
1111
assert ( instance . is ( CommonFlags . INSTANCE ) ) ;
1112
1112
let classInstance = assert ( instance . parent ) ; assert ( classInstance . kind == ElementKind . CLASS ) ;
1113
1113
1114
- // implicitly return `this` if the constructor doesn't always return on its own
1115
- if ( ! flow . is ( FlowFlags . RETURNS ) ) {
1114
+ if ( ! flow . isAny ( FlowFlags . ANY_TERMINATING ) ) {
1116
1115
1117
1116
// if `this` wasn't accessed before, allocate if necessary and initialize `this`
1118
1117
if ( ! flow . is ( FlowFlags . ALLOCATES ) ) {
@@ -1133,6 +1132,8 @@ export class Compiler extends DiagnosticEmitter {
1133
1132
) ;
1134
1133
this . makeFieldInitialization ( < Class > classInstance , stmts ) ;
1135
1134
}
1135
+
1136
+ // implicitly return `this`
1136
1137
stmts . push (
1137
1138
module . createGetLocal ( 0 , nativeSizeType )
1138
1139
) ;
@@ -5631,6 +5632,144 @@ export class Compiler extends DiagnosticEmitter {
5631
5632
: module . createNop ( ) ;
5632
5633
}
5633
5634
5635
+ makeCallInlineUnchecked (
5636
+ instance : Function ,
5637
+ argumentExpressions : Expression [ ] ,
5638
+ argumentLocals : Local [ ] ,
5639
+ thisArg : ExpressionRef = 0
5640
+ ) : ExpressionRef {
5641
+ var numArguments = argumentExpressions . length ;
5642
+ var signature = instance . signature ;
5643
+ var currentFunction = this . currentFunction ;
5644
+ var module = this . module ;
5645
+ var declaration = instance . prototype . declaration ;
5646
+
5647
+ // Create a new flow with its own scope and mark it for inlining
5648
+ var previousFlow = currentFunction . flow ;
5649
+ var returnLabel = instance . internalName + "|inlined." + ( instance . nextInlineId ++ ) . toString ( 10 ) ;
5650
+ var returnType = instance . signature . returnType ;
5651
+ var flow = Flow . create ( currentFunction ) ;
5652
+ flow . set ( FlowFlags . INLINE_CONTEXT ) ;
5653
+ flow . returnLabel = returnLabel ;
5654
+ flow . returnType = returnType ;
5655
+ flow . contextualTypeArguments = instance . contextualTypeArguments ;
5656
+
5657
+ // Convert provided call arguments to temporary locals. It is important that these are compiled
5658
+ // here, with their respective locals being blocked. There is no 'makeCallInline'.
5659
+ var body = [ ] ;
5660
+ if ( thisArg ) {
5661
+ let classInstance = assert ( instance . parent ) ; assert ( classInstance . kind == ElementKind . CLASS ) ;
5662
+ let thisType = assert ( instance . signature . thisType ) ;
5663
+ let classType = thisType . classReference ;
5664
+ let superType = classType
5665
+ ? classType . base
5666
+ ? classType . base . type
5667
+ : null
5668
+ : null ;
5669
+ if ( getExpressionId ( thisArg ) == ExpressionId . GetLocal ) { // reuse this var
5670
+ flow . addScopedLocalAlias ( getGetLocalIndex ( thisArg ) , thisType , "this" ) ;
5671
+ if ( superType ) flow . addScopedLocalAlias ( getGetLocalIndex ( thisArg ) , superType , "super" ) ;
5672
+ } else { // use a temp var
5673
+ let thisLocal = flow . addScopedLocal ( thisType , "this" , false ) ;
5674
+ body . push (
5675
+ module . createSetLocal ( thisLocal . index , thisArg )
5676
+ ) ;
5677
+ if ( superType ) flow . addScopedLocalAlias ( thisLocal . index , superType , "super" ) ;
5678
+ }
5679
+ }
5680
+ var parameterTypes = signature . parameterTypes ;
5681
+ for ( let i = 0 ; i < numArguments ; ++ i ) {
5682
+ let paramExpr = this . compileExpression (
5683
+ argumentExpressions [ i ] ,
5684
+ parameterTypes [ i ] ,
5685
+ ConversionKind . IMPLICIT ,
5686
+ WrapMode . NONE
5687
+ ) ;
5688
+ if ( getExpressionId ( paramExpr ) == ExpressionId . GetLocal ) {
5689
+ flow . addScopedLocalAlias (
5690
+ getGetLocalIndex ( paramExpr ) ,
5691
+ parameterTypes [ i ] ,
5692
+ signature . getParameterName ( i )
5693
+ ) ;
5694
+ // inherits wrap status
5695
+ } else {
5696
+ let argumentLocal = flow . addScopedLocal (
5697
+ parameterTypes [ i ] ,
5698
+ signature . getParameterName ( i ) ,
5699
+ ! flow . canOverflow ( paramExpr , parameterTypes [ i ] )
5700
+ ) ;
5701
+ body . push (
5702
+ module . createSetLocal ( argumentLocal . index , paramExpr )
5703
+ ) ;
5704
+ }
5705
+ }
5706
+
5707
+ // Compile optional parameter initializers in the scope of the inlined flow
5708
+ currentFunction . flow = flow ;
5709
+ var numParameters = signature . parameterTypes . length ;
5710
+ for ( let i = numArguments ; i < numParameters ; ++ i ) {
5711
+ let initExpr = this . compileExpression (
5712
+ assert ( declaration . signature . parameters [ i ] . initializer ) ,
5713
+ parameterTypes [ i ] ,
5714
+ ConversionKind . IMPLICIT ,
5715
+ WrapMode . WRAP
5716
+ ) ;
5717
+ let argumentLocal = flow . addScopedLocal (
5718
+ parameterTypes [ i ] ,
5719
+ signature . getParameterName ( i ) ,
5720
+ ! flow . canOverflow ( initExpr , parameterTypes [ i ] )
5721
+ ) ;
5722
+ body . push (
5723
+ module . createSetLocal ( argumentLocal . index , initExpr )
5724
+ ) ;
5725
+ }
5726
+
5727
+ // Compile the called function's body in the scope of the inlined flow
5728
+ var bodyStatement = assert ( declaration . body ) ;
5729
+ if ( bodyStatement . kind == NodeKind . BLOCK ) {
5730
+ let statements = ( < BlockStatement > bodyStatement ) . statements ;
5731
+ for ( let i = 0 , k = statements . length ; i < k ; ++ i ) {
5732
+ let stmt = this . compileStatement ( statements [ i ] ) ;
5733
+ if ( getExpressionId ( stmt ) != ExpressionId . Nop ) {
5734
+ body . push ( stmt ) ;
5735
+ if ( flow . isAny ( FlowFlags . ANY_TERMINATING ) ) break ;
5736
+ }
5737
+ }
5738
+ } else {
5739
+ body . push ( this . compileStatement ( bodyStatement ) ) ;
5740
+ }
5741
+
5742
+ // Free any new scoped locals and reset to the original flow
5743
+ var scopedLocals = flow . scopedLocals ;
5744
+ if ( scopedLocals ) {
5745
+ for ( let scopedLocal of scopedLocals . values ( ) ) {
5746
+ if ( scopedLocal . is ( CommonFlags . SCOPED ) ) { // otherwise an alias
5747
+ currentFunction . freeTempLocal ( scopedLocal ) ;
5748
+ }
5749
+ }
5750
+ flow . scopedLocals = null ;
5751
+ }
5752
+ flow . finalize ( ) ;
5753
+ this . currentFunction . flow = previousFlow ;
5754
+ this . currentType = returnType ;
5755
+
5756
+ // Check that all branches are terminated
5757
+ if ( returnType != Type . void && ! flow . isAny ( FlowFlags . ANY_TERMINATING ) ) {
5758
+ this . error (
5759
+ DiagnosticCode . A_function_whose_declared_type_is_not_void_must_return_a_value ,
5760
+ declaration . signature . returnType . range
5761
+ ) ;
5762
+ return module . createUnreachable ( ) ;
5763
+ }
5764
+ return flow . is ( FlowFlags . RETURNS )
5765
+ ? module . createBlock ( returnLabel , body , returnType . toNativeType ( ) )
5766
+ : body . length > 1
5767
+ ? module . createBlock ( null , body , returnType . toNativeType ( ) )
5768
+ : body . length
5769
+ ? body [ 0 ]
5770
+ : module . createNop ( ) ;
5771
+ }
5772
+
5634
5773
/** Gets the trampoline for the specified function. */
5635
5774
ensureTrampoline ( original : Function ) : Function {
5636
5775
// A trampoline is a function that takes a fixed amount of operands with some of them possibly
0 commit comments