mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-05-12 15:27:24 +00:00
Skip inlining and emit a warning when trying to inline a function into itself
This commit is contained in:
parent
3b0fd9aac2
commit
4b8500355a
2
dist/asc.js
vendored
2
dist/asc.js
vendored
File diff suppressed because one or more lines are too long
2
dist/asc.js.map
vendored
2
dist/asc.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -54,7 +54,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
ReportMode
|
ReportMode
|
||||||
} from "./resolver";
|
} from "./resolver";
|
||||||
import { CommonFlags } from "./common";
|
|
||||||
|
|
||||||
/** Compiles a call to a built-in function. */
|
/** Compiles a call to a built-in function. */
|
||||||
export function compileCall(
|
export function compileCall(
|
||||||
@ -73,7 +72,7 @@ export function compileCall(
|
|||||||
ret: ExpressionRef;
|
ret: ExpressionRef;
|
||||||
|
|
||||||
// NOTE that some implementations below make use of the select expression where straight-forward.
|
// NOTE that some implementations below make use of the select expression where straight-forward.
|
||||||
// whether worth or not should probably be tested once/ it's known if/how embedders handle it.
|
// whether worth or not should probably be tested once it's known if/how embedders handle it.
|
||||||
// search: createSelect
|
// search: createSelect
|
||||||
|
|
||||||
switch (prototype.internalName) {
|
switch (prototype.internalName) {
|
||||||
|
@ -265,6 +265,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
currentFunction: Function;
|
currentFunction: Function;
|
||||||
/** Current outer function in compilation, if compiling a function expression. */
|
/** Current outer function in compilation, if compiling a function expression. */
|
||||||
currentOuterFunction: Function | null = null;
|
currentOuterFunction: Function | null = null;
|
||||||
|
/** Current inline function in compilation. */
|
||||||
|
currentInlineFunction: Function | null = null;
|
||||||
/** Current enum in compilation. */
|
/** Current enum in compilation. */
|
||||||
currentEnum: Enum | null = null;
|
currentEnum: Enum | null = null;
|
||||||
/** Current type in compilation. */
|
/** Current type in compilation. */
|
||||||
@ -5257,7 +5259,21 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
// Inline if explicitly requested
|
// Inline if explicitly requested
|
||||||
if (inline) {
|
if (inline) {
|
||||||
assert(!instance.is(CommonFlags.TRAMPOLINE)); // doesn't make sense
|
assert(!instance.is(CommonFlags.TRAMPOLINE)); // doesn't make sense
|
||||||
return this.compileCallInlineUnchecked(instance, argumentExpressions, reportNode, thisArg);
|
if (instance === this.currentInlineFunction) {
|
||||||
|
// skip inlining when trying to inline a function into itself and print a warning when
|
||||||
|
// instead compiling the function the normal way.
|
||||||
|
if (instance === this.currentFunction) {
|
||||||
|
this.warning(
|
||||||
|
DiagnosticCode.Function_0_cannot_be_inlined_into_itself,
|
||||||
|
reportNode.range, instance.internalName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.currentInlineFunction = instance;
|
||||||
|
let ret = this.compileCallInlineUnchecked(instance, argumentExpressions, reportNode, thisArg);
|
||||||
|
this.currentInlineFunction = null;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise compile to just a call
|
// Otherwise compile to just a call
|
||||||
|
@ -26,6 +26,7 @@ export enum DiagnosticCode {
|
|||||||
An_allocator_must_be_declared_to_allocate_memory_Try_importing_allocator_arena_or_allocator_tlsf = 214,
|
An_allocator_must_be_declared_to_allocate_memory_Try_importing_allocator_arena_or_allocator_tlsf = 214,
|
||||||
Optional_parameter_must_have_an_initializer = 215,
|
Optional_parameter_must_have_an_initializer = 215,
|
||||||
Constructor_of_class_0_must_not_require_any_arguments = 216,
|
Constructor_of_class_0_must_not_require_any_arguments = 216,
|
||||||
|
Function_0_cannot_be_inlined_into_itself = 217,
|
||||||
Unterminated_string_literal = 1002,
|
Unterminated_string_literal = 1002,
|
||||||
Identifier_expected = 1003,
|
Identifier_expected = 1003,
|
||||||
_0_expected = 1005,
|
_0_expected = 1005,
|
||||||
@ -142,6 +143,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 214: return "An allocator must be declared to allocate memory. Try importing allocator/arena or allocator/tlsf.";
|
case 214: return "An allocator must be declared to allocate memory. Try importing allocator/arena or allocator/tlsf.";
|
||||||
case 215: return "Optional parameter must have an initializer.";
|
case 215: return "Optional parameter must have an initializer.";
|
||||||
case 216: return "Constructor of class '{0}' must not require any arguments.";
|
case 216: return "Constructor of class '{0}' must not require any arguments.";
|
||||||
|
case 217: return "Function '{0}' cannot be inlined into itself.";
|
||||||
case 1002: return "Unterminated string literal.";
|
case 1002: return "Unterminated string literal.";
|
||||||
case 1003: return "Identifier expected.";
|
case 1003: return "Identifier expected.";
|
||||||
case 1005: return "'{0}' expected.";
|
case 1005: return "'{0}' expected.";
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"An allocator must be declared to allocate memory. Try importing allocator/arena or allocator/tlsf.": 214,
|
"An allocator must be declared to allocate memory. Try importing allocator/arena or allocator/tlsf.": 214,
|
||||||
"Optional parameter must have an initializer.": 215,
|
"Optional parameter must have an initializer.": 215,
|
||||||
"Constructor of class '{0}' must not require any arguments.": 216,
|
"Constructor of class '{0}' must not require any arguments.": 216,
|
||||||
|
"Function '{0}' cannot be inlined into itself.": 217,
|
||||||
|
|
||||||
"Unterminated string literal.": 1002,
|
"Unterminated string literal.": 1002,
|
||||||
"Identifier expected.": 1003,
|
"Identifier expected.": 1003,
|
||||||
|
4
std/assembly/index.d.ts
vendored
4
std/assembly/index.d.ts
vendored
@ -304,9 +304,9 @@ declare function isReference<T>(value?: any): value is object | string;
|
|||||||
declare function isString<T>(value?: any): value is string | String;
|
declare function isString<T>(value?: any): value is string | String;
|
||||||
/** Tests if the specified type *or* expression can be used as an array. Compiles to a constant. */
|
/** Tests if the specified type *or* expression can be used as an array. Compiles to a constant. */
|
||||||
declare function isArray<T>(value?: any): value is Array<any>;
|
declare function isArray<T>(value?: any): value is Array<any>;
|
||||||
/** Tests if the specified expression resolves to a defined element. */
|
/** Tests if the specified expression resolves to a defined element. Compiles to a constant. */
|
||||||
declare function isDefined(expression: any): bool;
|
declare function isDefined(expression: any): bool;
|
||||||
/** Tests if the specified expression evaluates to a constant value. */
|
/** Tests if the specified expression evaluates to a constant value. Compiles to a constant. */
|
||||||
declare function isConstant(expression: any): bool;
|
declare function isConstant(expression: any): bool;
|
||||||
/** Traps if the specified value is not true-ish, otherwise returns the (non-nullable) value. */
|
/** Traps if the specified value is not true-ish, otherwise returns the (non-nullable) value. */
|
||||||
declare function assert<T>(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`?
|
declare function assert<T>(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`?
|
||||||
|
9
tests/compiler/inlining-recursive.optimized.wat
Normal file
9
tests/compiler/inlining-recursive.optimized.wat
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
(module
|
||||||
|
(type $v (func))
|
||||||
|
(memory $0 0)
|
||||||
|
(export "foo" (func $inlining-recursive/foo))
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(func $inlining-recursive/foo (; 0 ;) (type $v)
|
||||||
|
(call $inlining-recursive/foo)
|
||||||
|
)
|
||||||
|
)
|
4
tests/compiler/inlining-recursive.ts
Normal file
4
tests/compiler/inlining-recursive.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@inline
|
||||||
|
export function foo(): void {
|
||||||
|
foo();
|
||||||
|
}
|
12
tests/compiler/inlining-recursive.untouched.wat
Normal file
12
tests/compiler/inlining-recursive.untouched.wat
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
(module
|
||||||
|
(type $v (func))
|
||||||
|
(global $HEAP_BASE i32 (i32.const 8))
|
||||||
|
(memory $0 0)
|
||||||
|
(export "foo" (func $inlining-recursive/foo))
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(func $inlining-recursive/foo (; 0 ;) (type $v)
|
||||||
|
(block $inlining-recursive/foo|inlined.0
|
||||||
|
(call $inlining-recursive/foo)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user