@@ -361,6 +361,8 @@ export class Compiler extends DiagnosticEmitter {
361361 pendingClassInstanceOf : Set < ClassPrototype > = new Set ( ) ;
362362 /** Functions potentially involving a virtual call. */
363363 virtualCalls : Set < Function > = new Set ( ) ;
364+ /** Elements currently undergoing compilation. */
365+ pendingElements : Set < Element > = new Set ( ) ;
364366
365367 /** Compiles a {@link Program} to a {@link Module} using the specified options. */
366368 static compile ( program : Program ) : Module {
@@ -993,9 +995,12 @@ export class Compiler extends DiagnosticEmitter {
993995
994996 /** Compiles a global variable. */
995997 compileGlobal ( global : Global ) : bool {
996- if ( global . is ( CommonFlags . COMPILED ) ) return true ;
998+ if ( global . is ( CommonFlags . COMPILED ) ) return ! global . is ( CommonFlags . ERRORED ) ;
997999 global . set ( CommonFlags . COMPILED ) ;
9981000
1001+ var pendingElements = this . pendingElements ;
1002+ pendingElements . add ( global ) ;
1003+
9991004 var module = this . module ;
10001005 var initExpr : ExpressionRef = 0 ;
10011006 var typeNode = global . typeNode ;
@@ -1006,12 +1011,18 @@ export class Compiler extends DiagnosticEmitter {
10061011 // Resolve type if annotated
10071012 if ( typeNode ) {
10081013 let resolvedType = this . resolver . resolveType ( typeNode , global . parent ) ; // reports
1009- if ( ! resolvedType ) return false ;
1014+ if ( ! resolvedType ) {
1015+ global . set ( CommonFlags . ERRORED ) ;
1016+ pendingElements . delete ( global ) ;
1017+ return false ;
1018+ }
10101019 if ( resolvedType == Type . void ) {
10111020 this . error (
10121021 DiagnosticCode . Type_expected ,
10131022 typeNode . range
10141023 ) ;
1024+ global . set ( CommonFlags . ERRORED ) ;
1025+ pendingElements . delete ( global ) ;
10151026 return false ;
10161027 }
10171028 global . setType ( resolvedType ) ;
@@ -1032,6 +1043,8 @@ export class Compiler extends DiagnosticEmitter {
10321043 DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
10331044 initializerNode . range , this . currentType . toString ( ) , "<auto>"
10341045 ) ;
1046+ global . set ( CommonFlags . ERRORED ) ;
1047+ pendingElements . delete ( global ) ;
10351048 return false ;
10361049 }
10371050 global . setType ( this . currentType ) ;
@@ -1042,6 +1055,8 @@ export class Compiler extends DiagnosticEmitter {
10421055 DiagnosticCode . Type_expected ,
10431056 global . identifierNode . range . atEnd
10441057 ) ;
1058+ global . set ( CommonFlags . ERRORED ) ;
1059+ pendingElements . delete ( global ) ;
10451060 return false ;
10461061 }
10471062 }
@@ -1050,6 +1065,7 @@ export class Compiler extends DiagnosticEmitter {
10501065 if ( global . is ( CommonFlags . AMBIENT ) && global . hasDecorator ( DecoratorFlags . BUILTIN ) ) {
10511066 if ( global . internalName == BuiltinNames . heap_base ) this . runtimeFeatures |= RuntimeFeatures . HEAP ;
10521067 else if ( global . internalName == BuiltinNames . rtti_base ) this . runtimeFeatures |= RuntimeFeatures . RTTI ;
1068+ pendingElements . delete ( global ) ;
10531069 return true ;
10541070 }
10551071
@@ -1072,16 +1088,17 @@ export class Compiler extends DiagnosticEmitter {
10721088 nativeType ,
10731089 ! isDeclaredConstant
10741090 ) ;
1075- global . set ( CommonFlags . COMPILED ) ;
1091+ pendingElements . delete ( global ) ;
10761092 return true ;
1093+ }
10771094
10781095 // Importing mutable globals is not supported in the MVP
1079- } else {
1080- this . error (
1081- DiagnosticCode . Feature_0_is_not_enabled ,
1082- global . declaration . range , "mutable-globals"
1083- ) ;
1084- }
1096+ this . error (
1097+ DiagnosticCode . Feature_0_is_not_enabled ,
1098+ global . declaration . range , "mutable-globals"
1099+ ) ;
1100+ global . set ( CommonFlags . ERRORED ) ;
1101+ pendingElements . delete ( global ) ;
10851102 return false ;
10861103 }
10871104
@@ -1167,6 +1184,8 @@ export class Compiler extends DiagnosticEmitter {
11671184 }
11681185 default : {
11691186 assert ( false ) ;
1187+ global . set ( CommonFlags . ERRORED ) ;
1188+ pendingElements . delete ( global ) ;
11701189 return false ;
11711190 }
11721191 }
@@ -1200,16 +1219,20 @@ export class Compiler extends DiagnosticEmitter {
12001219 } else if ( ! isDeclaredInline ) { // compile normally
12011220 module . addGlobal ( internalName , nativeType , ! isDeclaredConstant , initExpr ) ;
12021221 }
1222+ pendingElements . delete ( global ) ;
12031223 return true ;
12041224 }
12051225
12061226 // === Enums ====================================================================================
12071227
12081228 /** Compiles an enum. */
12091229 compileEnum ( element : Enum ) : bool {
1210- if ( element . is ( CommonFlags . COMPILED ) ) return true ;
1230+ if ( element . is ( CommonFlags . COMPILED ) ) return ! element . is ( CommonFlags . ERRORED ) ;
12111231 element . set ( CommonFlags . COMPILED ) ;
12121232
1233+ var pendingElements = this . pendingElements ;
1234+ pendingElements . add ( element ) ;
1235+
12131236 var module = this . module ;
12141237 var previousParent = this . currentParent ;
12151238 this . currentParent = element ;
@@ -1305,6 +1328,7 @@ export class Compiler extends DiagnosticEmitter {
13051328 }
13061329 }
13071330 this . currentParent = previousParent ;
1331+ pendingElements . delete ( element ) ;
13081332 return true ;
13091333 }
13101334
@@ -1317,7 +1341,8 @@ export class Compiler extends DiagnosticEmitter {
13171341 /** Force compilation of stdlib alternative if a builtin. */
13181342 forceStdAlternative : bool = false
13191343 ) : bool {
1320- if ( instance . is ( CommonFlags . COMPILED ) ) return true ;
1344+ if ( instance . is ( CommonFlags . COMPILED ) ) return ! instance . is ( CommonFlags . ERRORED ) ;
1345+
13211346 if ( ! forceStdAlternative ) {
13221347 if ( instance . hasDecorator ( DecoratorFlags . BUILTIN ) ) return true ;
13231348 if ( instance . hasDecorator ( DecoratorFlags . LAZY ) ) {
@@ -1326,9 +1351,11 @@ export class Compiler extends DiagnosticEmitter {
13261351 }
13271352 }
13281353
1329- var previousType = this . currentType ;
13301354 instance . set ( CommonFlags . COMPILED ) ;
1355+ var pendingElements = this . pendingElements ;
1356+ pendingElements . add ( instance ) ;
13311357
1358+ var previousType = this . currentType ;
13321359 var module = this . module ;
13331360 var signature = instance . signature ;
13341361 var bodyNode = instance . prototype . bodyNode ;
@@ -1443,10 +1470,12 @@ export class Compiler extends DiagnosticEmitter {
14431470 instance . identifierNode . range
14441471 ) ;
14451472 funcRef = 0 ; // TODO?
1473+ instance . set ( CommonFlags . ERRORED ) ;
14461474 }
14471475
14481476 instance . finalize ( module , funcRef ) ;
14491477 this . currentType = previousType ;
1478+ pendingElements . delete ( instance ) ;
14501479 return true ;
14511480 }
14521481
@@ -2973,18 +3002,29 @@ export class Compiler extends DiagnosticEmitter {
29733002 this . checkTypeSupported ( type , typeNode ) ;
29743003
29753004 if ( initializerNode ) {
3005+ let pendingElements = this . pendingElements ;
3006+ let dummy = flow . addScopedDummyLocal ( name , type ) ; // pending dummy
3007+ pendingElements . add ( dummy ) ;
29763008 initExpr = this . compileExpression ( initializerNode , type , // reports
29773009 Constraints . CONV_IMPLICIT | Constraints . WILL_RETAIN
29783010 ) ;
29793011 initAutoreleaseSkipped = this . skippedAutoreleases . has ( initExpr ) ;
3012+ pendingElements . delete ( dummy ) ;
3013+ flow . freeScopedDummyLocal ( name ) ;
29803014 }
29813015
29823016 // Otherwise infer type from initializer
29833017 } else if ( initializerNode ) {
3018+ let pendingElements = this . pendingElements ;
3019+ let temp = flow . addScopedDummyLocal ( name , Type . auto ) ; // pending dummy
3020+ pendingElements . add ( temp ) ;
29843021 initExpr = this . compileExpression ( initializerNode , Type . auto ,
29853022 Constraints . WILL_RETAIN
29863023 ) ; // reports
29873024 initAutoreleaseSkipped = this . skippedAutoreleases . has ( initExpr ) ;
3025+ pendingElements . delete ( temp ) ;
3026+ flow . freeScopedDummyLocal ( name ) ;
3027+
29883028 if ( this . currentType == Type . void ) {
29893029 this . error (
29903030 DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
@@ -5916,6 +5956,14 @@ export class Compiler extends DiagnosticEmitter {
59165956 }
59175957 case ElementKind . LOCAL :
59185958 case ElementKind . FIELD : {
5959+ if ( this . pendingElements . has ( target ) ) {
5960+ this . error (
5961+ DiagnosticCode . Variable_0_used_before_its_declaration ,
5962+ expression . range ,
5963+ target . internalName
5964+ ) ;
5965+ return this . module . unreachable ( ) ;
5966+ }
59195967 targetType = ( < VariableLikeElement > target ) . type ;
59205968 if ( target . hasDecorator ( DecoratorFlags . UNSAFE ) ) this . checkUnsafe ( expression ) ;
59215969 break ;
@@ -8171,6 +8219,15 @@ export class Compiler extends DiagnosticEmitter {
81718219 let local = < Local > target ;
81728220 let localType = local . type ;
81738221 assert ( localType != Type . void ) ;
8222+ if ( this . pendingElements . has ( local ) ) {
8223+ this . error (
8224+ DiagnosticCode . Variable_0_used_before_its_declaration ,
8225+ expression . range ,
8226+ local . internalName
8227+ ) ;
8228+ this . currentType = localType ;
8229+ return module . unreachable ( ) ;
8230+ }
81748231 if ( local . is ( CommonFlags . INLINED ) ) {
81758232 return this . compileInlineConstant ( local , contextualType , constraints ) ;
81768233 }
@@ -8198,6 +8255,15 @@ export class Compiler extends DiagnosticEmitter {
81988255 return module . unreachable ( ) ;
81998256 }
82008257 let globalType = global . type ;
8258+ if ( this . pendingElements . has ( global ) ) {
8259+ this . error (
8260+ DiagnosticCode . Variable_0_used_before_its_declaration ,
8261+ expression . range ,
8262+ global . internalName
8263+ ) ;
8264+ this . currentType = globalType ;
8265+ return module . unreachable ( ) ;
8266+ }
82018267 assert ( globalType != Type . void ) ;
82028268 if ( global . is ( CommonFlags . INLINED ) ) {
82038269 return this . compileInlineConstant ( global , contextualType , constraints ) ;
@@ -9266,6 +9332,15 @@ export class Compiler extends DiagnosticEmitter {
92669332 if ( ! this . compileGlobal ( global ) ) return module . unreachable ( ) ; // reports
92679333 let globalType = global . type ;
92689334 assert ( globalType != Type . void ) ;
9335+ if ( this . pendingElements . has ( global ) ) {
9336+ this . error (
9337+ DiagnosticCode . Variable_0_used_before_its_declaration ,
9338+ expression . range ,
9339+ global . internalName
9340+ ) ;
9341+ this . currentType = globalType ;
9342+ return module . unreachable ( ) ;
9343+ }
92699344 if ( global . is ( CommonFlags . INLINED ) ) {
92709345 return this . compileInlineConstant ( global , ctxType , constraints ) ;
92719346 }
0 commit comments