mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-28 08:22:15 +00:00
Tackle AS206
This commit is contained in:
parent
c06d5d9f9a
commit
bc0dd3a6fb
@ -779,7 +779,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
if (!global.is(CommonFlags.RESOLVED)) {
|
if (!global.is(CommonFlags.RESOLVED)) {
|
||||||
|
|
||||||
// resolve now if annotated
|
// Resolve type if annotated
|
||||||
if (typeNode) {
|
if (typeNode) {
|
||||||
let resolvedType = this.resolver.resolveType(typeNode, global.parent); // reports
|
let resolvedType = this.resolver.resolveType(typeNode, global.parent); // reports
|
||||||
if (!resolvedType) return false;
|
if (!resolvedType) return false;
|
||||||
@ -792,8 +792,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
global.setType(resolvedType);
|
global.setType(resolvedType);
|
||||||
|
|
||||||
// infer from initializer if not annotated
|
// Otherwise infer type from initializer
|
||||||
} else if (initializerNode) { // infer type using void/NONE for literal inference
|
} else if (initializerNode) {
|
||||||
let previousFlow = this.currentFlow;
|
let previousFlow = this.currentFlow;
|
||||||
if (global.hasDecorator(DecoratorFlags.LAZY)) {
|
if (global.hasDecorator(DecoratorFlags.LAZY)) {
|
||||||
this.currentFlow = global.file.startFunction.flow;
|
this.currentFlow = global.file.startFunction.flow;
|
||||||
@ -812,7 +812,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
global.setType(this.currentType);
|
global.setType(this.currentType);
|
||||||
|
|
||||||
// must either be annotated or have an initializer
|
// Error if there's neither a type nor an initializer
|
||||||
} else {
|
} else {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Type_expected,
|
DiagnosticCode.Type_expected,
|
||||||
@ -822,7 +822,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ambient builtins like 'HEAP_BASE' need to be resolved but are added explicitly
|
// Handle ambient builtins like 'HEAP_BASE' that need to be resolved but are added explicitly
|
||||||
if (global.is(CommonFlags.AMBIENT) && global.hasDecorator(DecoratorFlags.BUILTIN)) {
|
if (global.is(CommonFlags.AMBIENT) && global.hasDecorator(DecoratorFlags.BUILTIN)) {
|
||||||
if (global.internalName == BuiltinSymbols.HEAP_BASE) this.runtimeFeatures |= RuntimeFeatures.HEAP;
|
if (global.internalName == BuiltinSymbols.HEAP_BASE) this.runtimeFeatures |= RuntimeFeatures.HEAP;
|
||||||
else if (global.internalName == BuiltinSymbols.RTTI_BASE) this.runtimeFeatures |= RuntimeFeatures.RTTI;
|
else if (global.internalName == BuiltinSymbols.RTTI_BASE) this.runtimeFeatures |= RuntimeFeatures.RTTI;
|
||||||
@ -832,11 +832,12 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var type = global.type;
|
var type = global.type;
|
||||||
var nativeType = type.toNativeType();
|
var nativeType = type.toNativeType();
|
||||||
var isDeclaredConstant = global.is(CommonFlags.CONST) || global.is(CommonFlags.STATIC | CommonFlags.READONLY);
|
var isDeclaredConstant = global.is(CommonFlags.CONST) || global.is(CommonFlags.STATIC | CommonFlags.READONLY);
|
||||||
|
var isDeclaredInline = global.hasDecorator(DecoratorFlags.INLINE);
|
||||||
|
|
||||||
// handle imports
|
// Handle imports
|
||||||
if (global.is(CommonFlags.AMBIENT)) {
|
if (global.is(CommonFlags.AMBIENT)) {
|
||||||
|
|
||||||
// constant global
|
// Constant global or mutable globals enabled
|
||||||
if (isDeclaredConstant || this.options.hasFeature(Feature.MUTABLE_GLOBAL)) {
|
if (isDeclaredConstant || this.options.hasFeature(Feature.MUTABLE_GLOBAL)) {
|
||||||
global.set(CommonFlags.MODULE_IMPORT);
|
global.set(CommonFlags.MODULE_IMPORT);
|
||||||
mangleImportName(global, global.declaration);
|
mangleImportName(global, global.declaration);
|
||||||
@ -849,7 +850,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
global.set(CommonFlags.COMPILED);
|
global.set(CommonFlags.COMPILED);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// importing mutable globals is not supported in the MVP
|
// Importing mutable globals is not supported in the MVP
|
||||||
} else {
|
} else {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Operation_not_supported,
|
DiagnosticCode.Operation_not_supported,
|
||||||
@ -859,11 +860,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the MVP does not yet support initializer expressions other than constant values (and constant
|
// The MVP does not yet support initializer expressions other than constant values (and constant
|
||||||
// get_globals), hence such initializations must be performed in the start function for now.
|
// get_globals), hence such initializations must be performed in the start function for now.
|
||||||
var initializeInStart = false;
|
var initializeInStart = false;
|
||||||
|
|
||||||
// evaluate initializer if present
|
// Evaluate initializer if present
|
||||||
if (initializerNode) {
|
if (initializerNode) {
|
||||||
if (!initExpr) {
|
if (!initExpr) {
|
||||||
let previousFlow = this.currentFlow;
|
let previousFlow = this.currentFlow;
|
||||||
@ -880,21 +881,20 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
if (getExpressionId(initExpr) != ExpressionId.Const) {
|
if (getExpressionId(initExpr) != ExpressionId.Const) {
|
||||||
if (isDeclaredConstant) {
|
if (isDeclaredConstant) {
|
||||||
initExpr = module.precomputeExpression(initExpr);
|
initExpr = module.precomputeExpression(initExpr);
|
||||||
if (getExpressionId(initExpr) != ExpressionId.Const) {
|
if (getExpressionId(initExpr) != ExpressionId.Const) initializeInStart = true;
|
||||||
this.warning(
|
|
||||||
DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable,
|
|
||||||
initializerNode.range
|
|
||||||
);
|
|
||||||
initializeInStart = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
initializeInStart = true;
|
initializeInStart = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicitly inline if annotated
|
// Explicitly inline if annotated
|
||||||
if (global.hasDecorator(DecoratorFlags.INLINE)) {
|
if (isDeclaredInline) {
|
||||||
if (!initializeInStart) { // reported above
|
if (initializeInStart) {
|
||||||
|
this.warning(
|
||||||
|
DiagnosticCode.Mutable_value_cannot_be_inlined,
|
||||||
|
initializerNode.range
|
||||||
|
);
|
||||||
|
} else {
|
||||||
assert(getExpressionId(initExpr) == ExpressionId.Const);
|
assert(getExpressionId(initExpr) == ExpressionId.Const);
|
||||||
let exprType = getExpressionType(initExpr);
|
let exprType = getExpressionType(initExpr);
|
||||||
switch (exprType) {
|
switch (exprType) {
|
||||||
@ -930,7 +930,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize to zero if there's no initializer
|
// Initialize to zero if there's no initializer
|
||||||
} else {
|
} else {
|
||||||
initExpr = type.toNativeZero(module);
|
initExpr = type.toNativeZero(module);
|
||||||
}
|
}
|
||||||
@ -938,7 +938,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var internalName = global.internalName;
|
var internalName = global.internalName;
|
||||||
|
|
||||||
if (initializeInStart) { // initialize to mutable zero and set the actual value in start
|
if (initializeInStart) { // initialize to mutable zero and set the actual value in start
|
||||||
if (global.hasDecorator(DecoratorFlags.INLINE)) {
|
if (isDeclaredInline) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Decorator_0_is_not_valid_here,
|
DiagnosticCode.Decorator_0_is_not_valid_here,
|
||||||
assert(findDecorator(DecoratorKind.INLINE, global.decoratorNodes)).range, "inline"
|
assert(findDecorator(DecoratorKind.INLINE, global.decoratorNodes)).range, "inline"
|
||||||
@ -949,7 +949,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
this.currentBody.push(
|
this.currentBody.push(
|
||||||
module.global_set(internalName, initExpr)
|
module.global_set(internalName, initExpr)
|
||||||
);
|
);
|
||||||
} else if (!global.hasDecorator(DecoratorFlags.INLINE)) { // compile normally
|
} else if (!isDeclaredInline) { // compile normally
|
||||||
module.addGlobal(internalName, nativeType, !isDeclaredConstant, initExpr);
|
module.addGlobal(internalName, nativeType, !isDeclaredConstant, initExpr);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -2406,12 +2406,15 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var flow = this.currentFlow;
|
var flow = this.currentFlow;
|
||||||
var initializers = new Array<ExpressionRef>();
|
var initializers = new Array<ExpressionRef>();
|
||||||
var resolver = this.resolver;
|
var resolver = this.resolver;
|
||||||
|
|
||||||
for (let i = 0; i < numDeclarations; ++i) {
|
for (let i = 0; i < numDeclarations; ++i) {
|
||||||
let declaration = declarations[i];
|
let declaration = declarations[i];
|
||||||
let name = declaration.name.text;
|
let name = declaration.name.text;
|
||||||
let type: Type | null = null;
|
let type: Type | null = null;
|
||||||
let initExpr: ExpressionRef = 0;
|
let initExpr: ExpressionRef = 0;
|
||||||
let initAutoreleaseSkipped = false;
|
let initAutoreleaseSkipped = false;
|
||||||
|
|
||||||
|
// Resolve type if annotated
|
||||||
if (declaration.type) {
|
if (declaration.type) {
|
||||||
type = resolver.resolveType( // reports
|
type = resolver.resolveType( // reports
|
||||||
declaration.type,
|
declaration.type,
|
||||||
@ -2425,7 +2428,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
);
|
);
|
||||||
initAutoreleaseSkipped = this.skippedAutoreleases.has(initExpr);
|
initAutoreleaseSkipped = this.skippedAutoreleases.has(initExpr);
|
||||||
}
|
}
|
||||||
} else if (declaration.initializer) { // infer type using void/NONE for proper literal inference
|
|
||||||
|
// Otherwise infer type from initializer
|
||||||
|
} else if (declaration.initializer) {
|
||||||
initExpr = this.compileExpressionRetainType(declaration.initializer, Type.void,
|
initExpr = this.compileExpressionRetainType(declaration.initializer, Type.void,
|
||||||
ContextualFlags.SKIP_AUTORELEASE
|
ContextualFlags.SKIP_AUTORELEASE
|
||||||
); // reports
|
); // reports
|
||||||
@ -2438,6 +2443,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
type = this.currentType;
|
type = this.currentType;
|
||||||
|
|
||||||
|
// Error if there's neither a type nor an initializer
|
||||||
} else {
|
} else {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Type_expected,
|
DiagnosticCode.Type_expected,
|
||||||
@ -2445,8 +2452,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let isInlined = false;
|
|
||||||
if (declaration.is(CommonFlags.CONST)) {
|
// Handle constants, and try to inline if value is static
|
||||||
|
let isConst = declaration.is(CommonFlags.CONST);
|
||||||
|
let isStatic = false;
|
||||||
|
if (isConst) {
|
||||||
if (initExpr) {
|
if (initExpr) {
|
||||||
initExpr = module.precomputeExpression(initExpr);
|
initExpr = module.precomputeExpression(initExpr);
|
||||||
if (getExpressionId(initExpr) == ExpressionId.Const) {
|
if (getExpressionId(initExpr) == ExpressionId.Const) {
|
||||||
@ -2496,12 +2506,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
return this.module.unreachable();
|
return this.module.unreachable();
|
||||||
}
|
}
|
||||||
scopedLocals.set(name, local);
|
scopedLocals.set(name, local);
|
||||||
isInlined = true;
|
isStatic = true;
|
||||||
} else {
|
|
||||||
this.warning(
|
|
||||||
DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable,
|
|
||||||
declaration.range
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.error(
|
this.error(
|
||||||
@ -2510,13 +2515,16 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isInlined) {
|
|
||||||
|
// Otherwise compile as mutable
|
||||||
|
if (!isStatic) {
|
||||||
let local: Local;
|
let local: Local;
|
||||||
if (
|
if (
|
||||||
declaration.isAny(CommonFlags.LET | CommonFlags.CONST) ||
|
declaration.isAny(CommonFlags.LET | CommonFlags.CONST) ||
|
||||||
flow.is(FlowFlags.INLINE_CONTEXT)
|
flow.is(FlowFlags.INLINE_CONTEXT)
|
||||||
) { // here: not top-level
|
) { // here: not top-level
|
||||||
local = flow.addScopedLocal(name, type, declaration.name); // reports if duplicate
|
local = flow.addScopedLocal(name, type, declaration.name); // reports if duplicate
|
||||||
|
if (isConst) flow.setLocalFlag(local.index, LocalFlags.CONSTANT);
|
||||||
} else {
|
} else {
|
||||||
if (flow.lookupLocal(name)) {
|
if (flow.lookupLocal(name)) {
|
||||||
this.error(
|
this.error(
|
||||||
@ -2526,6 +2534,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
local = flow.parentFunction.addLocal(type, name, declaration);
|
local = flow.parentFunction.addLocal(type, name, declaration);
|
||||||
|
if (isConst) flow.setLocalFlag(local.index, LocalFlags.CONSTANT);
|
||||||
}
|
}
|
||||||
let isManaged = type.isManaged;
|
let isManaged = type.isManaged;
|
||||||
if (initExpr) {
|
if (initExpr) {
|
||||||
@ -5234,7 +5243,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
switch (target.kind) {
|
switch (target.kind) {
|
||||||
case ElementKind.LOCAL: {
|
case ElementKind.LOCAL: {
|
||||||
if (target.is(CommonFlags.CONST)) {
|
if (flow.isLocalFlag((<Local>target).index, LocalFlags.CONSTANT, true)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
|
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
|
||||||
valueExpression.range, target.internalName
|
valueExpression.range, target.internalName
|
||||||
@ -5246,7 +5255,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
case ElementKind.GLOBAL: {
|
case ElementKind.GLOBAL: {
|
||||||
if (!this.compileGlobal(<Global>target)) return module.unreachable();
|
if (!this.compileGlobal(<Global>target)) return module.unreachable();
|
||||||
if (target.is(CommonFlags.CONST)) {
|
if (target.isAny(CommonFlags.CONST | CommonFlags.READONLY)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
|
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
|
||||||
valueExpression.range,
|
valueExpression.range,
|
||||||
@ -7534,7 +7543,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
// compile value expressions and find out whether all are constant
|
// compile value expressions and find out whether all are constant
|
||||||
var length = expressions.length;
|
var length = expressions.length;
|
||||||
var values = new Array<ExpressionRef>(length);
|
var values = new Array<ExpressionRef>(length);
|
||||||
var allValuesAreConstant = true;
|
var isStatic = true;
|
||||||
var nativeElementType = elementType.toNativeType();
|
var nativeElementType = elementType.toNativeType();
|
||||||
for (let i = 0; i < length; ++i) {
|
for (let i = 0; i < length; ++i) {
|
||||||
let expression = expressions[i];
|
let expression = expressions[i];
|
||||||
@ -7548,19 +7557,13 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
if (getExpressionId(expr) == ExpressionId.Const) {
|
if (getExpressionId(expr) == ExpressionId.Const) {
|
||||||
assert(getExpressionType(expr) == nativeElementType);
|
assert(getExpressionType(expr) == nativeElementType);
|
||||||
} else {
|
} else {
|
||||||
if (isConst) {
|
isStatic = false;
|
||||||
this.warning(
|
|
||||||
DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable,
|
|
||||||
reportNode.range
|
|
||||||
);
|
|
||||||
}
|
|
||||||
allValuesAreConstant = false;
|
|
||||||
}
|
}
|
||||||
values[i] = expr;
|
values[i] = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the array is static, make a static arraybuffer segment
|
// if the array is static, make a static arraybuffer segment
|
||||||
if (allValuesAreConstant) {
|
if (isStatic) {
|
||||||
flow.freeTempLocal(tempThis);
|
flow.freeTempLocal(tempThis);
|
||||||
flow.freeTempLocal(tempDataStart);
|
flow.freeTempLocal(tempDataStart);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export enum DiagnosticCode {
|
|||||||
Type_0_cannot_be_reinterpreted_as_type_1 = 203,
|
Type_0_cannot_be_reinterpreted_as_type_1 = 203,
|
||||||
Basic_type_0_cannot_be_nullable = 204,
|
Basic_type_0_cannot_be_nullable = 204,
|
||||||
Cannot_export_a_mutable_global = 205,
|
Cannot_export_a_mutable_global = 205,
|
||||||
Compiling_constant_with_non_constant_initializer_as_mutable = 206,
|
Mutable_value_cannot_be_inlined = 206,
|
||||||
Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa = 207,
|
Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa = 207,
|
||||||
Unmanaged_classes_cannot_implement_interfaces = 208,
|
Unmanaged_classes_cannot_implement_interfaces = 208,
|
||||||
Invalid_regular_expression_flags = 209,
|
Invalid_regular_expression_flags = 209,
|
||||||
@ -154,7 +154,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 203: return "Type '{0}' cannot be reinterpreted as type '{1}'.";
|
case 203: return "Type '{0}' cannot be reinterpreted as type '{1}'.";
|
||||||
case 204: return "Basic type '{0}' cannot be nullable.";
|
case 204: return "Basic type '{0}' cannot be nullable.";
|
||||||
case 205: return "Cannot export a mutable global.";
|
case 205: return "Cannot export a mutable global.";
|
||||||
case 206: return "Compiling constant with non-constant initializer as mutable.";
|
case 206: return "Mutable value cannot be inlined.";
|
||||||
case 207: return "Unmanaged classes cannot extend managed classes and vice-versa.";
|
case 207: return "Unmanaged classes cannot extend managed classes and vice-versa.";
|
||||||
case 208: return "Unmanaged classes cannot implement interfaces.";
|
case 208: return "Unmanaged classes cannot implement interfaces.";
|
||||||
case 209: return "Invalid regular expression flags.";
|
case 209: return "Invalid regular expression flags.";
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"Type '{0}' cannot be reinterpreted as type '{1}'.": 203,
|
"Type '{0}' cannot be reinterpreted as type '{1}'.": 203,
|
||||||
"Basic type '{0}' cannot be nullable.": 204,
|
"Basic type '{0}' cannot be nullable.": 204,
|
||||||
"Cannot export a mutable global.": 205,
|
"Cannot export a mutable global.": 205,
|
||||||
"Compiling constant with non-constant initializer as mutable.": 206,
|
"Mutable value cannot be inlined.": 206,
|
||||||
"Unmanaged classes cannot extend managed classes and vice-versa.": 207,
|
"Unmanaged classes cannot extend managed classes and vice-versa.": 207,
|
||||||
"Unmanaged classes cannot implement interfaces.": 208,
|
"Unmanaged classes cannot implement interfaces.": 208,
|
||||||
"Invalid regular expression flags.": 209,
|
"Invalid regular expression flags.": 209,
|
||||||
|
21
src/flow.ts
21
src/flow.ts
@ -143,26 +143,29 @@ export enum LocalFlags {
|
|||||||
/** No specific conditions. */
|
/** No specific conditions. */
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
|
|
||||||
|
/** Local is constant. */
|
||||||
|
CONSTANT = 1 << 0,
|
||||||
/** Local is properly wrapped. Relevant for small integers. */
|
/** Local is properly wrapped. Relevant for small integers. */
|
||||||
WRAPPED = 1 << 0,
|
WRAPPED = 1 << 1,
|
||||||
/** Local is non-null. */
|
/** Local is non-null. */
|
||||||
NONNULL = 1 << 1,
|
NONNULL = 1 << 2,
|
||||||
/** Local is read from. */
|
/** Local is read from. */
|
||||||
READFROM = 1 << 2,
|
READFROM = 1 << 3,
|
||||||
/** Local is written to. */
|
/** Local is written to. */
|
||||||
WRITTENTO = 1 << 3,
|
WRITTENTO = 1 << 4,
|
||||||
/** Local is retained. */
|
/** Local is retained. */
|
||||||
RETAINED = 1 << 4,
|
RETAINED = 1 << 5,
|
||||||
|
|
||||||
/** Local is conditionally read from. */
|
/** Local is conditionally read from. */
|
||||||
CONDITIONALLY_READFROM = 1 << 5,
|
CONDITIONALLY_READFROM = 1 << 6,
|
||||||
/** Local is conditionally written to. */
|
/** Local is conditionally written to. */
|
||||||
CONDITIONALLY_WRITTENTO = 1 << 6,
|
CONDITIONALLY_WRITTENTO = 1 << 7,
|
||||||
/** Local must be conditionally retained. */
|
/** Local must be conditionally retained. */
|
||||||
CONDITIONALLY_RETAINED = 1 << 7,
|
CONDITIONALLY_RETAINED = 1 << 8,
|
||||||
|
|
||||||
/** Any categorical flag. */
|
/** Any categorical flag. */
|
||||||
ANY_CATEGORICAL = WRAPPED
|
ANY_CATEGORICAL = CONSTANT
|
||||||
|
| WRAPPED
|
||||||
| NONNULL
|
| NONNULL
|
||||||
| READFROM
|
| READFROM
|
||||||
| WRITTENTO
|
| WRITTENTO
|
||||||
|
5
tests/compiler/constant-assign.json
Normal file
5
tests/compiler/constant-assign.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"asc_flags": [
|
||||||
|
"--runtime none"
|
||||||
|
]
|
||||||
|
}
|
319
tests/compiler/constant-assign.optimized.wat
Normal file
319
tests/compiler/constant-assign.optimized.wat
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
(module
|
||||||
|
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
|
||||||
|
(type $FUNCSIG$v (func))
|
||||||
|
(type $FUNCSIG$vii (func (param i32 i32)))
|
||||||
|
(type $FUNCSIG$ii (func (param i32) (result i32)))
|
||||||
|
(memory $0 1)
|
||||||
|
(data (i32.const 8) "\04\00\00\00\01\00\00\00\00\00\00\00\04\00\00\00\02")
|
||||||
|
(data (i32.const 32) "\04\00\00\00\01\00\00\00\00\00\00\00\04\00\00\00\01")
|
||||||
|
(data (i32.const 56) "\04\00\00\00\01\00\00\00\00\00\00\00\04\00\00\00\02")
|
||||||
|
(global $~lib/rt/stub/startOffset (mut i32) (i32.const 0))
|
||||||
|
(global $~lib/rt/stub/offset (mut i32) (i32.const 0))
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $~lib/rt/stub/__alloc (; 0 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(local $2 i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i32)
|
||||||
|
(local $5 i32)
|
||||||
|
local.get $0
|
||||||
|
i32.const 1073741808
|
||||||
|
i32.gt_u
|
||||||
|
if
|
||||||
|
unreachable
|
||||||
|
end
|
||||||
|
global.get $~lib/rt/stub/offset
|
||||||
|
i32.const 16
|
||||||
|
i32.add
|
||||||
|
local.tee $3
|
||||||
|
local.get $0
|
||||||
|
i32.const 1
|
||||||
|
local.get $0
|
||||||
|
i32.const 1
|
||||||
|
i32.gt_u
|
||||||
|
select
|
||||||
|
i32.add
|
||||||
|
i32.const 15
|
||||||
|
i32.add
|
||||||
|
i32.const -16
|
||||||
|
i32.and
|
||||||
|
local.tee $2
|
||||||
|
memory.size
|
||||||
|
local.tee $4
|
||||||
|
i32.const 16
|
||||||
|
i32.shl
|
||||||
|
i32.gt_u
|
||||||
|
if
|
||||||
|
local.get $4
|
||||||
|
local.get $2
|
||||||
|
local.get $3
|
||||||
|
i32.sub
|
||||||
|
i32.const 65535
|
||||||
|
i32.add
|
||||||
|
i32.const -65536
|
||||||
|
i32.and
|
||||||
|
i32.const 16
|
||||||
|
i32.shr_u
|
||||||
|
local.tee $5
|
||||||
|
local.get $4
|
||||||
|
local.get $5
|
||||||
|
i32.gt_s
|
||||||
|
select
|
||||||
|
memory.grow
|
||||||
|
i32.const 0
|
||||||
|
i32.lt_s
|
||||||
|
if
|
||||||
|
local.get $5
|
||||||
|
memory.grow
|
||||||
|
i32.const 0
|
||||||
|
i32.lt_s
|
||||||
|
if
|
||||||
|
unreachable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local.get $2
|
||||||
|
global.set $~lib/rt/stub/offset
|
||||||
|
local.get $3
|
||||||
|
i32.const 16
|
||||||
|
i32.sub
|
||||||
|
local.tee $2
|
||||||
|
local.get $1
|
||||||
|
i32.store offset=8
|
||||||
|
local.get $2
|
||||||
|
local.get $0
|
||||||
|
i32.store offset=12
|
||||||
|
local.get $3
|
||||||
|
)
|
||||||
|
(func $~lib/memory/memory.copy (; 1 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
|
||||||
|
(local $2 i32)
|
||||||
|
(local $3 i32)
|
||||||
|
(local $4 i32)
|
||||||
|
block $~lib/util/memory/memmove|inlined.0
|
||||||
|
i32.const 4
|
||||||
|
local.set $2
|
||||||
|
local.get $0
|
||||||
|
local.get $1
|
||||||
|
i32.eq
|
||||||
|
br_if $~lib/util/memory/memmove|inlined.0
|
||||||
|
local.get $0
|
||||||
|
local.get $1
|
||||||
|
i32.lt_u
|
||||||
|
if
|
||||||
|
local.get $1
|
||||||
|
i32.const 7
|
||||||
|
i32.and
|
||||||
|
local.get $0
|
||||||
|
i32.const 7
|
||||||
|
i32.and
|
||||||
|
i32.eq
|
||||||
|
if
|
||||||
|
loop $continue|0
|
||||||
|
local.get $0
|
||||||
|
i32.const 7
|
||||||
|
i32.and
|
||||||
|
if
|
||||||
|
local.get $2
|
||||||
|
i32.eqz
|
||||||
|
br_if $~lib/util/memory/memmove|inlined.0
|
||||||
|
local.get $2
|
||||||
|
i32.const 1
|
||||||
|
i32.sub
|
||||||
|
local.set $2
|
||||||
|
local.get $0
|
||||||
|
local.tee $3
|
||||||
|
i32.const 1
|
||||||
|
i32.add
|
||||||
|
local.set $0
|
||||||
|
local.get $1
|
||||||
|
local.tee $4
|
||||||
|
i32.const 1
|
||||||
|
i32.add
|
||||||
|
local.set $1
|
||||||
|
local.get $3
|
||||||
|
local.get $4
|
||||||
|
i32.load8_u
|
||||||
|
i32.store8
|
||||||
|
br $continue|0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loop $continue|1
|
||||||
|
local.get $2
|
||||||
|
i32.const 8
|
||||||
|
i32.ge_u
|
||||||
|
if
|
||||||
|
local.get $0
|
||||||
|
local.get $1
|
||||||
|
i64.load
|
||||||
|
i64.store
|
||||||
|
local.get $2
|
||||||
|
i32.const 8
|
||||||
|
i32.sub
|
||||||
|
local.set $2
|
||||||
|
local.get $0
|
||||||
|
i32.const 8
|
||||||
|
i32.add
|
||||||
|
local.set $0
|
||||||
|
local.get $1
|
||||||
|
i32.const 8
|
||||||
|
i32.add
|
||||||
|
local.set $1
|
||||||
|
br $continue|1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loop $continue|2
|
||||||
|
local.get $2
|
||||||
|
if
|
||||||
|
local.get $0
|
||||||
|
local.tee $3
|
||||||
|
i32.const 1
|
||||||
|
i32.add
|
||||||
|
local.set $0
|
||||||
|
local.get $1
|
||||||
|
local.tee $4
|
||||||
|
i32.const 1
|
||||||
|
i32.add
|
||||||
|
local.set $1
|
||||||
|
local.get $3
|
||||||
|
local.get $4
|
||||||
|
i32.load8_u
|
||||||
|
i32.store8
|
||||||
|
local.get $2
|
||||||
|
i32.const 1
|
||||||
|
i32.sub
|
||||||
|
local.set $2
|
||||||
|
br $continue|2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local.get $1
|
||||||
|
i32.const 7
|
||||||
|
i32.and
|
||||||
|
local.get $0
|
||||||
|
i32.const 7
|
||||||
|
i32.and
|
||||||
|
i32.eq
|
||||||
|
if
|
||||||
|
loop $continue|3
|
||||||
|
local.get $0
|
||||||
|
local.get $2
|
||||||
|
i32.add
|
||||||
|
i32.const 7
|
||||||
|
i32.and
|
||||||
|
if
|
||||||
|
local.get $2
|
||||||
|
i32.eqz
|
||||||
|
br_if $~lib/util/memory/memmove|inlined.0
|
||||||
|
local.get $2
|
||||||
|
i32.const 1
|
||||||
|
i32.sub
|
||||||
|
local.tee $2
|
||||||
|
local.get $0
|
||||||
|
i32.add
|
||||||
|
local.get $1
|
||||||
|
local.get $2
|
||||||
|
i32.add
|
||||||
|
i32.load8_u
|
||||||
|
i32.store8
|
||||||
|
br $continue|3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loop $continue|4
|
||||||
|
local.get $2
|
||||||
|
i32.const 8
|
||||||
|
i32.ge_u
|
||||||
|
if
|
||||||
|
local.get $2
|
||||||
|
i32.const 8
|
||||||
|
i32.sub
|
||||||
|
local.tee $2
|
||||||
|
local.get $0
|
||||||
|
i32.add
|
||||||
|
local.get $1
|
||||||
|
local.get $2
|
||||||
|
i32.add
|
||||||
|
i64.load
|
||||||
|
i64.store
|
||||||
|
br $continue|4
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loop $continue|5
|
||||||
|
local.get $2
|
||||||
|
if
|
||||||
|
local.get $2
|
||||||
|
i32.const 1
|
||||||
|
i32.sub
|
||||||
|
local.tee $2
|
||||||
|
local.get $0
|
||||||
|
i32.add
|
||||||
|
local.get $1
|
||||||
|
local.get $2
|
||||||
|
i32.add
|
||||||
|
i32.load8_u
|
||||||
|
i32.store8
|
||||||
|
br $continue|5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
(func $~lib/rt/__allocArray (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
|
||||||
|
(local $1 i32)
|
||||||
|
(local $2 i32)
|
||||||
|
i32.const 16
|
||||||
|
i32.const 3
|
||||||
|
call $~lib/rt/stub/__alloc
|
||||||
|
local.tee $1
|
||||||
|
i32.const 4
|
||||||
|
i32.const 0
|
||||||
|
call $~lib/rt/stub/__alloc
|
||||||
|
local.tee $2
|
||||||
|
i32.store
|
||||||
|
local.get $1
|
||||||
|
local.get $2
|
||||||
|
i32.store offset=4
|
||||||
|
local.get $1
|
||||||
|
i32.const 4
|
||||||
|
i32.store offset=8
|
||||||
|
local.get $1
|
||||||
|
i32.const 1
|
||||||
|
i32.store offset=12
|
||||||
|
local.get $0
|
||||||
|
if
|
||||||
|
local.get $2
|
||||||
|
local.get $0
|
||||||
|
call $~lib/memory/memory.copy
|
||||||
|
end
|
||||||
|
local.get $1
|
||||||
|
)
|
||||||
|
(func $start:constant-assign (; 3 ;) (type $FUNCSIG$v)
|
||||||
|
i32.const 80
|
||||||
|
global.set $~lib/rt/stub/startOffset
|
||||||
|
global.get $~lib/rt/stub/startOffset
|
||||||
|
global.set $~lib/rt/stub/offset
|
||||||
|
i32.const 0
|
||||||
|
call $~lib/rt/__allocArray
|
||||||
|
i32.load offset=4
|
||||||
|
i32.const 1
|
||||||
|
i32.store
|
||||||
|
i32.const 24
|
||||||
|
call $~lib/rt/__allocArray
|
||||||
|
drop
|
||||||
|
i32.const 48
|
||||||
|
call $~lib/rt/__allocArray
|
||||||
|
drop
|
||||||
|
i32.const 72
|
||||||
|
call $~lib/rt/__allocArray
|
||||||
|
drop
|
||||||
|
)
|
||||||
|
(func $start (; 4 ;) (type $FUNCSIG$v)
|
||||||
|
block
|
||||||
|
call $start:constant-assign
|
||||||
|
end
|
||||||
|
)
|
||||||
|
(func $null (; 5 ;) (type $FUNCSIG$v)
|
||||||
|
nop
|
||||||
|
)
|
||||||
|
)
|
30
tests/compiler/constant-assign.ts
Normal file
30
tests/compiler/constant-assign.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Expect error: TS2540
|
||||||
|
// ^ TODO: Properly handle multiple
|
||||||
|
|
||||||
|
function localConst(a: i32): void {
|
||||||
|
const b = a + 1;
|
||||||
|
b = 3;
|
||||||
|
}
|
||||||
|
localConst(1);
|
||||||
|
|
||||||
|
function localConstInline(): void {
|
||||||
|
const a = 1;
|
||||||
|
a = 2;
|
||||||
|
}
|
||||||
|
localConstInline();
|
||||||
|
|
||||||
|
function localConstArray(a: i32): void {
|
||||||
|
const b: i32[] = [ a ];
|
||||||
|
b = [ 2 ];
|
||||||
|
}
|
||||||
|
localConstArray(1);
|
||||||
|
|
||||||
|
function localConstArrayInline(): void {
|
||||||
|
const a: i32[] = [ 1 ];
|
||||||
|
a = [ 2 ];
|
||||||
|
}
|
||||||
|
localConstArrayInline();
|
||||||
|
|
||||||
|
// globalConst
|
||||||
|
const a = 1;
|
||||||
|
a = 2;
|
0
tests/compiler/constant-assign.untouched.wat
Normal file
0
tests/compiler/constant-assign.untouched.wat
Normal file
Loading…
x
Reference in New Issue
Block a user