Skip to content

Commit

Permalink
Implement emission of warning upon generic function/class export (#570)
Browse files Browse the repository at this point in the history
  • Loading branch information
9oelM committed Nov 30, 2019
1 parent 241a7f5 commit af4d261
Show file tree
Hide file tree
Showing 9 changed files with 1,742 additions and 23 deletions.
1 change: 1 addition & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ under the licensing terms detailed in LICENSE:
* Emil Laine <laine.emil@gmail.com>
* Stephen Paul Weber <stephen.weber@shopify.com>
* Jay Phelps <hello@jayphelps.com>
* Joel Mun <hj923@hotmail.com>

Portions of this software are derived from third-party works licensed under
the following terms:
Expand Down
16 changes: 13 additions & 3 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,13 +680,23 @@ export class Compiler extends DiagnosticEmitter {
break;
}
case ElementKind.FUNCTION_PROTOTYPE: {
if (!element.is(CommonFlags.GENERIC)) {
if (element.is(CommonFlags.GENERIC)) {
this.warning(
DiagnosticCode.Generic_functions_or_classes_cannot_be_compiled_to_wasm,
(<FunctionPrototype>element).identifierNode.range,
);
} else {
this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
}
break;
}
case ElementKind.CLASS_PROTOTYPE: {
if (!element.is(CommonFlags.GENERIC)) {
if (element.is(CommonFlags.GENERIC)) {
this.warning(
DiagnosticCode.Generic_functions_or_classes_cannot_be_compiled_to_wasm,
(<ClassPrototype>element).identifierNode.range,
);
} else {
this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
}
break;
Expand All @@ -712,7 +722,7 @@ export class Compiler extends DiagnosticEmitter {
}

/** Compiles an element's members. */
compileMembers(element: Element): void {
compileMembers(element: Element,): void {
var members = element.members;
if (members) for (let element of members.values()) this.compileElement(element);
}
Expand Down
2 changes: 2 additions & 0 deletions src/diagnosticMessages.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export enum DiagnosticCode {
Module_0_has_no_exported_member_1 = 2305,
Generic_type_0_requires_1_type_argument_s = 2314,
Type_0_is_not_generic = 2315,
Generic_functions_or_classes_cannot_be_compiled_to_wasm = 2316,
Type_0_is_not_assignable_to_type_1 = 2322,
Index_signature_is_missing_in_type_0 = 2329,
_this_cannot_be_referenced_in_current_location = 2332,
Expand Down Expand Up @@ -242,6 +243,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2305: return "Module '{0}' has no exported member '{1}'.";
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
case 2315: return "Type '{0}' is not generic.";
case 2316: return "Generic functions or classes cannot be compiled to wasm";
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
case 2329: return "Index signature is missing in type '{0}'.";
case 2332: return "'this' cannot be referenced in current location.";
Expand Down
1 change: 1 addition & 0 deletions src/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"Module '{0}' has no exported member '{1}'.": 2305,
"Generic type '{0}' requires {1} type argument(s).": 2314,
"Type '{0}' is not generic.": 2315,
"Generic functions or classes cannot be compiled to wasm": 2316,
"Type '{0}' is not assignable to type '{1}'.": 2322,
"Index signature is missing in type '{0}'.": 2329,
"'this' cannot be referenced in current location.": 2332,
Expand Down
52 changes: 32 additions & 20 deletions tests/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,32 +156,44 @@ function runTest(basename) {
}, err => {
console.log();

// check expected stderr patterns in order
// check expected stderr and stdout patterns in order
let expectStderr = config.stderr;
if (expectStderr) {
const stderrString = stderr.toString();
if (typeof expectStderr === "string") expectStderr = [ expectStderr ];
let lastIndex = 0;
let failed = false;
expectStderr.forEach((substr, i) => {
var index = stderrString.indexOf(substr, lastIndex);
if (index < 0) {
console.log("Missing pattern #" + (i + 1) + " '" + substr + "' in stderr at " + lastIndex + "+.");
let expectStdout = config.stdout;
let hasExpected = false;
[
{ expected: expectStderr, text: 'stderr' },
{ expected: expectStdout, text: 'stdout' }
].forEach((stdPatterns) => {
let expected = stdPatterns.expected;
if (expected) {
hasExpected = true;
const stderrString = stderr.toString();
if (typeof expected === "string") expected = [ expected ];
let lastIndex = 0;
let failed = false;
expected.forEach((substr, i) => {
var index = stderrString.indexOf(substr, lastIndex);
if (index < 0) {
console.log("Missing pattern #" + (i + 1) + " '" + substr + "' in stderr at " + lastIndex + "+.");
failedTests.add(basename);
failed = true;
} else {
lastIndex = index + substr.length;
}
});
let text = stdPatterns.text;
if (failed) {
failedTests.add(basename);
failed = true;
failedMessages.set(basename, + text + " mismatch");
console.log("\n- " + colorsUtil.red(text + " MISMATCH") + "\n");
} else {
lastIndex = index + substr.length;
console.log("- " + colorsUtil.green(text + " MATCH") + "\n");
}
});
if (failed) {
failedTests.add(basename);
failedMessages.set(basename, "stderr mismatch");
console.log("\n- " + colorsUtil.red("stderr MISMATCH") + "\n");
} else {
console.log("- " + colorsUtil.green("stderr MATCH") + "\n");
return;
}
})
if (hasExpected)
return;
}

if (err)
stderr.write(err + os.EOL);
Expand Down
10 changes: 10 additions & 0 deletions tests/compiler/generic-export.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"asc_flags": [
"--runtime none"
],
"stdout": [
"TS2316: Generic functions or classes cannot be compiled to wasm", "export function genericExample<T>(a: T, b: T): Array<T> {",
"TS2316: Generic functions or classes cannot be compiled to wasm", "export class GenericNumber<T> {",
"TS2316: Generic functions or classes cannot be compiled to wasm", "export class GenericNumber2<T> {"
]
}
161 changes: 161 additions & 0 deletions tests/compiler/generic-export.optimized.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
(module
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
(type $FUNCSIG$vi (func (param i32)))
(type $FUNCSIG$ii (func (param i32) (result i32)))
(type $FUNCSIG$i (func (result i32)))
(type $FUNCSIG$v (func))
(memory $0 0)
(global $generic-export/okVariable i32 (i32.const 1))
(global $~lib/rt/stub/startOffset (mut i32) (i32.const 0))
(global $~lib/rt/stub/offset (mut i32) (i32.const 0))
(global $generic-export/OkClass i32 (i32.const 4))
(export "memory" (memory $0))
(export "genericExample<i32>" (func $generic-export/okFunction))
(export "okFunction" (func $generic-export/okFunction))
(export "OkClass" (global $generic-export/OkClass))
(export "OkClass#one" (func $generic-export/OkClass#one))
(export "okVariable" (global $generic-export/okVariable))
(export "functionThatUsesGenericFunction" (func $generic-export/functionThatUsesGenericFunction))
(start $start)
(func $~lib/rt/stub/maybeGrowMemory (; 0 ;) (type $FUNCSIG$vi) (param $0 i32)
(local $1 i32)
(local $2 i32)
local.get $0
memory.size
local.tee $2
i32.const 16
i32.shl
local.tee $1
i32.gt_u
if
local.get $2
local.get $0
local.get $1
i32.sub
i32.const 65535
i32.add
i32.const -65536
i32.and
i32.const 16
i32.shr_u
local.tee $1
local.get $2
local.get $1
i32.gt_s
select
memory.grow
i32.const 0
i32.lt_s
if
local.get $1
memory.grow
i32.const 0
i32.lt_s
if
unreachable
end
end
end
local.get $0
global.set $~lib/rt/stub/offset
)
(func $~lib/rt/stub/__alloc (; 1 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
(local $3 i32)
(local $4 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 15
i32.add
i32.const -16
i32.and
local.tee $2
i32.const 16
local.get $2
i32.const 16
i32.gt_u
select
local.tee $4
i32.add
call $~lib/rt/stub/maybeGrowMemory
local.get $3
i32.const 16
i32.sub
local.tee $2
local.get $4
i32.store
local.get $2
i32.const -1
i32.store offset=4
local.get $2
local.get $1
i32.store offset=8
local.get $2
local.get $0
i32.store offset=12
local.get $3
)
(func $~lib/rt/__allocArray (; 2 ;) (type $FUNCSIG$i) (result i32)
(local $0 i32)
(local $1 i32)
i32.const 16
i32.const 3
call $~lib/rt/stub/__alloc
local.tee $0
i32.const 8
i32.const 0
call $~lib/rt/stub/__alloc
local.tee $1
i32.store
local.get $0
local.get $1
i32.store offset=4
local.get $0
i32.const 8
i32.store offset=8
local.get $0
i32.const 2
i32.store offset=12
local.get $0
)
(func $generic-export/okFunction (; 3 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
(local $3 i32)
call $~lib/rt/__allocArray
local.tee $2
i32.load offset=4
local.tee $3
local.get $0
i32.store
local.get $3
local.get $1
i32.store offset=4
local.get $2
)
(func $generic-export/OkClass#one (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
i32.const 1
)
(func $generic-export/functionThatUsesGenericFunction (; 5 ;) (type $FUNCSIG$i) (result i32)
i32.const 1
i32.const 1
call $generic-export/okFunction
)
(func $start (; 6 ;) (type $FUNCSIG$v)
i32.const 16
global.set $~lib/rt/stub/startOffset
i32.const 16
global.set $~lib/rt/stub/offset
)
(func $null (; 7 ;) (type $FUNCSIG$v)
nop
)
)
31 changes: 31 additions & 0 deletions tests/compiler/generic-export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export function genericExample<T>(a: T, b: T): Array<T> {
return [a, b];
}

export function okFunction(a: i32, b: i32): Array<i32> {
return [a, b];
}

export class OkClass {
one(): i32 {
return 1;
}
}

export class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}

export namespace GenericNumberNamespace {
export class GenericNumber2<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
}

export const okVariable: i32 = 1;

export function functionThatUsesGenericFunction(): Array<i32> {
return genericExample<i32>(1, 1);
}
Loading

0 comments on commit af4d261

Please sign in to comment.