Skip to content

Commit 08075c6

Browse files
authored
Always register non-MVP types and check on actual use (#1194)
1 parent 9e05906 commit 08075c6

File tree

4 files changed

+164
-7
lines changed

4 files changed

+164
-7
lines changed

src/compiler.ts

+91-5
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ import {
6060
CommonNames,
6161
INDEX_SUFFIX,
6262
Feature,
63-
Target
63+
Target,
64+
featureToString
6465
} from "./common";
6566

6667
import {
@@ -113,6 +114,7 @@ import {
113114
DecoratorKind,
114115
AssertionKind,
115116
SourceKind,
117+
FunctionTypeNode,
116118

117119
Statement,
118120
BlockStatement,
@@ -961,6 +963,7 @@ export class Compiler extends DiagnosticEmitter {
961963
return false;
962964
}
963965
global.setType(resolvedType);
966+
this.checkTypeSupported(global.type, typeNode);
964967

965968
// Otherwise infer type from initializer
966969
} else if (initializerNode) {
@@ -1268,6 +1271,9 @@ export class Compiler extends DiagnosticEmitter {
12681271
var module = this.module;
12691272
var signature = instance.signature;
12701273
var bodyNode = instance.prototype.bodyNode;
1274+
var declarationNode = instance.declaration;
1275+
assert(declarationNode.kind == NodeKind.FUNCTIONDECLARATION || declarationNode.kind == NodeKind.METHODDECLARATION);
1276+
this.checkSignatureSupported(instance.signature, (<FunctionDeclaration>declarationNode).signature);
12711277

12721278
var funcRef: FunctionRef;
12731279

@@ -1343,7 +1349,7 @@ export class Compiler extends DiagnosticEmitter {
13431349
// imported function
13441350
} else if (instance.is(CommonFlags.AMBIENT)) {
13451351
instance.set(CommonFlags.MODULE_IMPORT);
1346-
mangleImportName(instance, instance.declaration); // TODO: check for duplicates
1352+
mangleImportName(instance, declarationNode); // TODO: check for duplicates
13471353
module.addFunctionImport(
13481354
instance.internalName,
13491355
mangleImportName_moduleName,
@@ -1576,7 +1582,12 @@ export class Compiler extends DiagnosticEmitter {
15761582
);
15771583
if (type.isManaged) valueExpr = this.makeRetain(valueExpr);
15781584
instance.getterRef = module.addFunction(instance.internalGetterName, nativeThisType, nativeValueType, null, valueExpr);
1579-
if (instance.setterRef) instance.set(CommonFlags.COMPILED);
1585+
if (instance.setterRef) {
1586+
instance.set(CommonFlags.COMPILED);
1587+
} else {
1588+
let typeNode = instance.typeNode;
1589+
if (typeNode) this.checkTypeSupported(instance.type, typeNode);
1590+
}
15801591
return true;
15811592
}
15821593

@@ -1624,7 +1635,12 @@ export class Compiler extends DiagnosticEmitter {
16241635
nativeValueType, instance.memoryOffset
16251636
)
16261637
);
1627-
if (instance.getterRef) instance.set(CommonFlags.COMPILED);
1638+
if (instance.getterRef) {
1639+
instance.set(CommonFlags.COMPILED);
1640+
} else {
1641+
let typeNode = instance.typeNode;
1642+
if (typeNode) this.checkTypeSupported(instance.type, typeNode);
1643+
}
16281644
return true;
16291645
}
16301646

@@ -2856,6 +2872,8 @@ export class Compiler extends DiagnosticEmitter {
28562872
makeMap(flow.contextualTypeArguments)
28572873
);
28582874
if (!type) continue;
2875+
this.checkTypeSupported(type, typeNode);
2876+
28592877
if (initializerNode) {
28602878
initExpr = this.compileExpression(initializerNode, type, // reports
28612879
Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN
@@ -6228,6 +6246,12 @@ export class Compiler extends DiagnosticEmitter {
62286246
var thisType = (<Class>field.parent).type;
62296247
var nativeThisType = thisType.toNativeType();
62306248

6249+
if (!field.is(CommonFlags.COMPILED)) {
6250+
field.set(CommonFlags.COMPILED);
6251+
let typeNode = field.typeNode;
6252+
if (typeNode) this.checkTypeSupported(field.type, typeNode);
6253+
}
6254+
62316255
if (fieldType.isManaged && thisType.isManaged) {
62326256
let tempThis = flow.getTempLocal(thisType, findUsedLocals(valueExpr));
62336257
// set before and read after valueExpr executes below ^
@@ -8818,7 +8842,6 @@ export class Compiler extends DiagnosticEmitter {
88188842
for (let i = 0; i < numParameters; ++i) {
88198843
operands[i + 1] = module.local_get(i + 1, parameterTypes[i].toNativeType());
88208844
}
8821-
// TODO: base constructor might be inlined, but makeCallDirect can't do this
88228845
stmts.push(
88238846
module.local_set(0,
88248847
this.makeCallDirect(assert(baseClass.constructorInstance), operands, reportNode, false, true)
@@ -8927,6 +8950,11 @@ export class Compiler extends DiagnosticEmitter {
89278950
);
89288951
}
89298952
}
8953+
if (!fieldInstance.is(CommonFlags.COMPILED)) {
8954+
fieldInstance.set(CommonFlags.COMPILED);
8955+
let typeNode = fieldInstance.typeNode;
8956+
if (typeNode) this.checkTypeSupported(fieldInstance.type, typeNode);
8957+
}
89308958
this.currentType = fieldType;
89318959
return module.load(
89328960
fieldType.byteSize,
@@ -9849,6 +9877,62 @@ export class Compiler extends DiagnosticEmitter {
98499877
parentFunction.debugLocations.push(range);
98509878
}
98519879

9880+
/** Checks whether a particular feature is enabled. */
9881+
checkFeatureEnabled(feature: Feature, reportNode: Node): bool {
9882+
if (!this.options.hasFeature(feature)) {
9883+
this.error(
9884+
DiagnosticCode.Feature_0_is_not_enabled,
9885+
reportNode.range, featureToString(feature)
9886+
);
9887+
return false;
9888+
}
9889+
return true;
9890+
}
9891+
9892+
/** Checks whether a particular type is supported. */
9893+
checkTypeSupported(type: Type, reportNode: Node): bool {
9894+
switch (type.kind) {
9895+
case TypeKind.V128: return this.checkFeatureEnabled(Feature.SIMD, reportNode);
9896+
case TypeKind.ANYREF: return this.checkFeatureEnabled(Feature.REFERENCE_TYPES, reportNode);
9897+
}
9898+
if (type.is(TypeFlags.REFERENCE)) {
9899+
let classReference = type.classReference;
9900+
while (classReference) {
9901+
let typeArguments = classReference.typeArguments;
9902+
if (typeArguments) {
9903+
for (let i = 0, k = typeArguments.length; i < k; ++i) {
9904+
if (!this.checkTypeSupported(typeArguments[i], reportNode)) {
9905+
return false;
9906+
}
9907+
}
9908+
}
9909+
classReference = classReference.base;
9910+
}
9911+
}
9912+
return true;
9913+
}
9914+
9915+
/** Checks whether a particular function signature is supported. */
9916+
checkSignatureSupported(signature: Signature, reportNode: FunctionTypeNode): bool {
9917+
var supported = true;
9918+
var explicitThisType = reportNode.explicitThisType;
9919+
if (explicitThisType) {
9920+
if (!this.checkTypeSupported(assert(signature.thisType), explicitThisType)) {
9921+
supported = false;
9922+
}
9923+
}
9924+
var parameterTypes = signature.parameterTypes;
9925+
for (let i = 0, k = parameterTypes.length; i < k; ++i) {
9926+
if (!this.checkTypeSupported(parameterTypes[i], reportNode.parameters[i])) {
9927+
supported = false;
9928+
}
9929+
}
9930+
if (!this.checkTypeSupported(signature.returnType, reportNode.returnType)) {
9931+
supported = false;
9932+
}
9933+
return supported;
9934+
}
9935+
98529936
// === Specialized code generation ==============================================================
98539937

98549938
/** Makes a constant zero of the specified type. */
@@ -10039,6 +10123,8 @@ export class Compiler extends DiagnosticEmitter {
1003910123
let initializerNode = fieldPrototype.initializerNode;
1004010124
let parameterIndex = fieldPrototype.parameterIndex;
1004110125
let initExpr: ExpressionRef;
10126+
let typeNode = field.typeNode;
10127+
if (typeNode) this.checkTypeSupported(fieldType, typeNode);
1004210128

1004310129
// if declared as a constructor parameter, use its value
1004410130
if (parameterIndex >= 0) {

src/program.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -725,8 +725,12 @@ export class Program extends DiagnosticEmitter {
725725
this.makeNativeTypeDeclaration(CommonNames.returnof, CommonFlags.EXPORT | CommonFlags.GENERIC),
726726
DecoratorFlags.BUILTIN
727727
));
728-
if (options.hasFeature(Feature.SIMD)) this.registerNativeType(CommonNames.v128, Type.v128);
729-
if (options.hasFeature(Feature.REFERENCE_TYPES)) this.registerNativeType(CommonNames.anyref, Type.anyref);
728+
729+
// The following types might not be enabled by compiler options, so the
730+
// compiler needs to check this condition whenever such a value is created
731+
// respectively stored or loaded.
732+
this.registerNativeType(CommonNames.v128, Type.v128);
733+
this.registerNativeType(CommonNames.anyref, Type.anyref);
730734

731735
// register compiler hints
732736
this.registerConstantInteger(CommonNames.ASC_TARGET, Type.i32,
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"asc_flags": [
3+
"--runtime none"
4+
],
5+
"stderr": [
6+
"AS103: Feature 'simd' is not enabled.",
7+
"var a: v128;",
8+
"AS103: Feature 'simd' is not enabled.",
9+
"var b = v128.",
10+
"AS103: Feature 'simd' is not enabled.",
11+
"var c: Array<v128>;",
12+
"AS103: Feature 'simd' is not enabled.",
13+
"var a: v128;",
14+
"AS103: Feature 'simd' is not enabled.",
15+
"var b = v128.",
16+
"AS103: Feature 'simd' is not enabled.",
17+
"let a: v128;",
18+
"AS103: Feature 'simd' is not enabled.",
19+
"let b = v128.",
20+
"AS103: Feature 'simd' is not enabled.",
21+
"a: v128",
22+
"AS103: Feature 'simd' is not enabled.",
23+
"): v128",
24+
"AS103: Feature 'simd' is not enabled.",
25+
"a: v128;",
26+
"AS103: Feature 'simd' is not enabled.",
27+
"b: Array<v128>;",
28+
"AS103: Feature 'simd' is not enabled.",
29+
"get c(): v128",
30+
"EOF"
31+
]
32+
}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
var a: v128; // type not enabled
2+
var b = v128.splat<i32>(1); // instruction not enabled
3+
var c: Array<v128>; // type not enabled
4+
5+
function test1(): void {
6+
var a: v128; // type not enabled
7+
var b = v128.splat<i32>(1); // instruction not enabled
8+
}
9+
test1();
10+
11+
function test2(): void {
12+
{
13+
let a: v128; // type not enabled
14+
let b = v128.splat<i32>(1); // instruction not enabled
15+
}
16+
}
17+
test2();
18+
19+
function test3(
20+
a: v128 // type not enabled
21+
): v128 { // type not enabled
22+
return unreachable();
23+
}
24+
test3(v128.splat<i32>(1)); // instruction not enabled
25+
26+
class Foo {
27+
a: v128; // type not enabled
28+
b: Array<v128>; // type not enabled
29+
get c(): v128 { // type not enabled
30+
return this.a;
31+
}
32+
}
33+
(new Foo()).c;
34+
35+
ERROR("EOF");

0 commit comments

Comments
 (0)