@@ -361,6 +361,8 @@ export class Compiler extends DiagnosticEmitter {
361
361
pendingClassInstanceOf : Set < ClassPrototype > = new Set ( ) ;
362
362
/** Functions potentially involving a virtual call. */
363
363
virtualCalls : Set < Function > = new Set ( ) ;
364
+ /** Elements currently undergoing compilation. */
365
+ pendingElements : Set < Element > = new Set ( ) ;
364
366
365
367
/** Compiles a {@link Program} to a {@link Module} using the specified options. */
366
368
static compile ( program : Program ) : Module {
@@ -993,9 +995,12 @@ export class Compiler extends DiagnosticEmitter {
993
995
994
996
/** Compiles a global variable. */
995
997
compileGlobal ( global : Global ) : bool {
996
- if ( global . is ( CommonFlags . COMPILED ) ) return true ;
998
+ if ( global . is ( CommonFlags . COMPILED ) ) return ! global . is ( CommonFlags . ERRORED ) ;
997
999
global . set ( CommonFlags . COMPILED ) ;
998
1000
1001
+ var pendingElements = this . pendingElements ;
1002
+ pendingElements . add ( global ) ;
1003
+
999
1004
var module = this . module ;
1000
1005
var initExpr : ExpressionRef = 0 ;
1001
1006
var typeNode = global . typeNode ;
@@ -1006,12 +1011,18 @@ export class Compiler extends DiagnosticEmitter {
1006
1011
// Resolve type if annotated
1007
1012
if ( typeNode ) {
1008
1013
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
+ }
1010
1019
if ( resolvedType == Type . void ) {
1011
1020
this . error (
1012
1021
DiagnosticCode . Type_expected ,
1013
1022
typeNode . range
1014
1023
) ;
1024
+ global . set ( CommonFlags . ERRORED ) ;
1025
+ pendingElements . delete ( global ) ;
1015
1026
return false ;
1016
1027
}
1017
1028
global . setType ( resolvedType ) ;
@@ -1032,6 +1043,8 @@ export class Compiler extends DiagnosticEmitter {
1032
1043
DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
1033
1044
initializerNode . range , this . currentType . toString ( ) , "<auto>"
1034
1045
) ;
1046
+ global . set ( CommonFlags . ERRORED ) ;
1047
+ pendingElements . delete ( global ) ;
1035
1048
return false ;
1036
1049
}
1037
1050
global . setType ( this . currentType ) ;
@@ -1042,6 +1055,8 @@ export class Compiler extends DiagnosticEmitter {
1042
1055
DiagnosticCode . Type_expected ,
1043
1056
global . identifierNode . range . atEnd
1044
1057
) ;
1058
+ global . set ( CommonFlags . ERRORED ) ;
1059
+ pendingElements . delete ( global ) ;
1045
1060
return false ;
1046
1061
}
1047
1062
}
@@ -1050,6 +1065,7 @@ export class Compiler extends DiagnosticEmitter {
1050
1065
if ( global . is ( CommonFlags . AMBIENT ) && global . hasDecorator ( DecoratorFlags . BUILTIN ) ) {
1051
1066
if ( global . internalName == BuiltinNames . heap_base ) this . runtimeFeatures |= RuntimeFeatures . HEAP ;
1052
1067
else if ( global . internalName == BuiltinNames . rtti_base ) this . runtimeFeatures |= RuntimeFeatures . RTTI ;
1068
+ pendingElements . delete ( global ) ;
1053
1069
return true ;
1054
1070
}
1055
1071
@@ -1072,16 +1088,17 @@ export class Compiler extends DiagnosticEmitter {
1072
1088
nativeType ,
1073
1089
! isDeclaredConstant
1074
1090
) ;
1075
- global . set ( CommonFlags . COMPILED ) ;
1091
+ pendingElements . delete ( global ) ;
1076
1092
return true ;
1093
+ }
1077
1094
1078
1095
// 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 ) ;
1085
1102
return false ;
1086
1103
}
1087
1104
@@ -1167,6 +1184,8 @@ export class Compiler extends DiagnosticEmitter {
1167
1184
}
1168
1185
default : {
1169
1186
assert ( false ) ;
1187
+ global . set ( CommonFlags . ERRORED ) ;
1188
+ pendingElements . delete ( global ) ;
1170
1189
return false ;
1171
1190
}
1172
1191
}
@@ -1200,16 +1219,20 @@ export class Compiler extends DiagnosticEmitter {
1200
1219
} else if ( ! isDeclaredInline ) { // compile normally
1201
1220
module . addGlobal ( internalName , nativeType , ! isDeclaredConstant , initExpr ) ;
1202
1221
}
1222
+ pendingElements . delete ( global ) ;
1203
1223
return true ;
1204
1224
}
1205
1225
1206
1226
// === Enums ====================================================================================
1207
1227
1208
1228
/** Compiles an enum. */
1209
1229
compileEnum ( element : Enum ) : bool {
1210
- if ( element . is ( CommonFlags . COMPILED ) ) return true ;
1230
+ if ( element . is ( CommonFlags . COMPILED ) ) return ! element . is ( CommonFlags . ERRORED ) ;
1211
1231
element . set ( CommonFlags . COMPILED ) ;
1212
1232
1233
+ var pendingElements = this . pendingElements ;
1234
+ pendingElements . add ( element ) ;
1235
+
1213
1236
var module = this . module ;
1214
1237
var previousParent = this . currentParent ;
1215
1238
this . currentParent = element ;
@@ -1305,6 +1328,7 @@ export class Compiler extends DiagnosticEmitter {
1305
1328
}
1306
1329
}
1307
1330
this . currentParent = previousParent ;
1331
+ pendingElements . delete ( element ) ;
1308
1332
return true ;
1309
1333
}
1310
1334
@@ -1317,7 +1341,8 @@ export class Compiler extends DiagnosticEmitter {
1317
1341
/** Force compilation of stdlib alternative if a builtin. */
1318
1342
forceStdAlternative : bool = false
1319
1343
) : bool {
1320
- if ( instance . is ( CommonFlags . COMPILED ) ) return true ;
1344
+ if ( instance . is ( CommonFlags . COMPILED ) ) return ! instance . is ( CommonFlags . ERRORED ) ;
1345
+
1321
1346
if ( ! forceStdAlternative ) {
1322
1347
if ( instance . hasDecorator ( DecoratorFlags . BUILTIN ) ) return true ;
1323
1348
if ( instance . hasDecorator ( DecoratorFlags . LAZY ) ) {
@@ -1326,9 +1351,11 @@ export class Compiler extends DiagnosticEmitter {
1326
1351
}
1327
1352
}
1328
1353
1329
- var previousType = this . currentType ;
1330
1354
instance . set ( CommonFlags . COMPILED ) ;
1355
+ var pendingElements = this . pendingElements ;
1356
+ pendingElements . add ( instance ) ;
1331
1357
1358
+ var previousType = this . currentType ;
1332
1359
var module = this . module ;
1333
1360
var signature = instance . signature ;
1334
1361
var bodyNode = instance . prototype . bodyNode ;
@@ -1443,10 +1470,12 @@ export class Compiler extends DiagnosticEmitter {
1443
1470
instance . identifierNode . range
1444
1471
) ;
1445
1472
funcRef = 0 ; // TODO?
1473
+ instance . set ( CommonFlags . ERRORED ) ;
1446
1474
}
1447
1475
1448
1476
instance . finalize ( module , funcRef ) ;
1449
1477
this . currentType = previousType ;
1478
+ pendingElements . delete ( instance ) ;
1450
1479
return true ;
1451
1480
}
1452
1481
@@ -2973,18 +3002,29 @@ export class Compiler extends DiagnosticEmitter {
2973
3002
this . checkTypeSupported ( type , typeNode ) ;
2974
3003
2975
3004
if ( initializerNode ) {
3005
+ let pendingElements = this . pendingElements ;
3006
+ let dummy = flow . addScopedDummyLocal ( name , type ) ; // pending dummy
3007
+ pendingElements . add ( dummy ) ;
2976
3008
initExpr = this . compileExpression ( initializerNode , type , // reports
2977
3009
Constraints . CONV_IMPLICIT | Constraints . WILL_RETAIN
2978
3010
) ;
2979
3011
initAutoreleaseSkipped = this . skippedAutoreleases . has ( initExpr ) ;
3012
+ pendingElements . delete ( dummy ) ;
3013
+ flow . freeScopedDummyLocal ( name ) ;
2980
3014
}
2981
3015
2982
3016
// Otherwise infer type from initializer
2983
3017
} else if ( initializerNode ) {
3018
+ let pendingElements = this . pendingElements ;
3019
+ let temp = flow . addScopedDummyLocal ( name , Type . auto ) ; // pending dummy
3020
+ pendingElements . add ( temp ) ;
2984
3021
initExpr = this . compileExpression ( initializerNode , Type . auto ,
2985
3022
Constraints . WILL_RETAIN
2986
3023
) ; // reports
2987
3024
initAutoreleaseSkipped = this . skippedAutoreleases . has ( initExpr ) ;
3025
+ pendingElements . delete ( temp ) ;
3026
+ flow . freeScopedDummyLocal ( name ) ;
3027
+
2988
3028
if ( this . currentType == Type . void ) {
2989
3029
this . error (
2990
3030
DiagnosticCode . Type_0_is_not_assignable_to_type_1 ,
@@ -5916,6 +5956,14 @@ export class Compiler extends DiagnosticEmitter {
5916
5956
}
5917
5957
case ElementKind . LOCAL :
5918
5958
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
+ }
5919
5967
targetType = ( < VariableLikeElement > target ) . type ;
5920
5968
if ( target . hasDecorator ( DecoratorFlags . UNSAFE ) ) this . checkUnsafe ( expression ) ;
5921
5969
break ;
@@ -8171,6 +8219,15 @@ export class Compiler extends DiagnosticEmitter {
8171
8219
let local = < Local > target ;
8172
8220
let localType = local . type ;
8173
8221
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
+ }
8174
8231
if ( local . is ( CommonFlags . INLINED ) ) {
8175
8232
return this . compileInlineConstant ( local , contextualType , constraints ) ;
8176
8233
}
@@ -8198,6 +8255,15 @@ export class Compiler extends DiagnosticEmitter {
8198
8255
return module . unreachable ( ) ;
8199
8256
}
8200
8257
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
+ }
8201
8267
assert ( globalType != Type . void ) ;
8202
8268
if ( global . is ( CommonFlags . INLINED ) ) {
8203
8269
return this . compileInlineConstant ( global , contextualType , constraints ) ;
@@ -9266,6 +9332,15 @@ export class Compiler extends DiagnosticEmitter {
9266
9332
if ( ! this . compileGlobal ( global ) ) return module . unreachable ( ) ; // reports
9267
9333
let globalType = global . type ;
9268
9334
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
+ }
9269
9344
if ( global . is ( CommonFlags . INLINED ) ) {
9270
9345
return this . compileInlineConstant ( global , ctxType , constraints ) ;
9271
9346
}
0 commit comments