Tidy up program error messages

This commit is contained in:
dcodeIO 2018-01-02 03:54:06 +01:00
parent 3add4624c5
commit dc78fc8d20

View File

@ -286,14 +286,19 @@ export class Program extends DiagnosticEmitter {
// initialize members // initialize members
var memberDeclarations = declaration.members; var memberDeclarations = declaration.members;
for (var i = 0, k = memberDeclarations.length; i < k; ++i) { for (var i = 0, k = memberDeclarations.length; i < k; ++i) {
switch (memberDeclarations[i].kind) { var memberDeclaration = memberDeclarations[i];
switch (memberDeclaration.kind) {
case NodeKind.FIELD: case NodeKind.FIELD:
this.initializeField(<FieldDeclaration>memberDeclarations[i], prototype); this.initializeField(<FieldDeclaration>memberDeclaration, prototype);
break; break;
case NodeKind.METHOD: // also getter/setter case NodeKind.METHOD:
this.initializeMethod(<MethodDeclaration>memberDeclarations[i], prototype); var isGetter: bool;
if ((isGetter = hasModifier(ModifierKind.GET, memberDeclaration.modifiers)) || hasModifier(ModifierKind.SET, memberDeclaration.modifiers))
this.initializeAccessor(<MethodDeclaration>memberDeclaration, prototype, isGetter);
else
this.initializeMethod(<MethodDeclaration>memberDeclaration, prototype);
break; break;
default: default:
@ -338,11 +343,6 @@ export class Program extends DiagnosticEmitter {
} }
private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void { private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void {
var isGetter = false;
if ((isGetter = hasModifier(ModifierKind.GET, declaration.modifiers)) || hasModifier(ModifierKind.SET, declaration.modifiers)) {
this.initializeAccessor(declaration, classPrototype, isGetter);
return;
}
var name = declaration.name.name; var name = declaration.name.name;
var internalName = declaration.internalName; var internalName = declaration.internalName;
@ -603,7 +603,7 @@ export class Program extends DiagnosticEmitter {
} }
this.error(DiagnosticCode.Operation_not_supported, statement.range); // TODO this.error(DiagnosticCode.Operation_not_supported, statement.range); // TODO
} else } else
assert(false); throw new Error("imports must either define members or a namespace");
} }
private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void { private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
@ -680,14 +680,19 @@ export class Program extends DiagnosticEmitter {
var memberDeclarations = declaration.members; var memberDeclarations = declaration.members;
for (var i = 0, k = memberDeclarations.length; i < k; ++i) { for (var i = 0, k = memberDeclarations.length; i < k; ++i) {
switch (memberDeclarations[i].kind) { var memberDeclaration = memberDeclarations[i];
switch (memberDeclaration.kind) {
case NodeKind.FIELD: case NodeKind.FIELD:
this.initializeField(<FieldDeclaration>memberDeclarations[i], prototype); this.initializeField(<FieldDeclaration>memberDeclaration, prototype);
break; break;
case NodeKind.METHOD: case NodeKind.METHOD:
this.initializeMethod(<MethodDeclaration>memberDeclarations[i], prototype); var isGetter: bool;
if ((isGetter = hasModifier(ModifierKind.GET, memberDeclaration.modifiers)) || hasModifier(ModifierKind.SET, memberDeclaration.modifiers))
this.initializeAccessor(<MethodDeclaration>memberDeclaration, prototype, isGetter);
else
this.initializeMethod(<MethodDeclaration>memberDeclaration, prototype);
break; break;
default: default:
@ -748,7 +753,9 @@ export class Program extends DiagnosticEmitter {
break; break;
case NodeKind.TYPEDECLARATION: case NodeKind.TYPEDECLARATION:
this.initializeTypeAlias(<TypeDeclaration>members[i], namespace); // this.initializeTypeAlias(<TypeDeclaration>members[i], namespace);
// TODO: what about namespaced types?
this.error(DiagnosticCode.Operation_not_supported, members[i].range);
break; break;
case NodeKind.VARIABLE: case NodeKind.VARIABLE:
@ -756,7 +763,7 @@ export class Program extends DiagnosticEmitter {
break; break;
default: default:
throw new Error("unexpected namespace member"); throw new Error("namespace member expected");
} }
} }
} }
@ -922,21 +929,29 @@ export class Program extends DiagnosticEmitter {
resolvePropertyAccess(propertyAccess: PropertyAccessExpression, contextualFunction: Function): Element | null { resolvePropertyAccess(propertyAccess: PropertyAccessExpression, contextualFunction: Function): Element | null {
var expression = propertyAccess.expression; var expression = propertyAccess.expression;
var target: Element | null = null; var target: Element | null = null;
if (expression.kind == NodeKind.IDENTIFIER) { switch (expression.kind) {
target = this.resolveIdentifier(<IdentifierExpression>expression, contextualFunction);
} else if (expression.kind == NodeKind.PROPERTYACCESS) { case NodeKind.IDENTIFIER:
target = this.resolvePropertyAccess(<PropertyAccessExpression>expression, contextualFunction); target = this.resolveIdentifier(<IdentifierExpression>expression, contextualFunction);
} else break;
throw new Error("unexpected target kind");
case NodeKind.PROPERTYACCESS:
target = this.resolvePropertyAccess(<PropertyAccessExpression>expression, contextualFunction);
break;
default:
throw new Error("target must be an identifier or property access");
}
if (!target) if (!target)
return null; return null;
var propertyName = propertyAccess.property.name; var propertyName = propertyAccess.property.name;
switch (target.kind) { switch (target.kind) {
case ElementKind.GLOBAL: case ElementKind.GLOBAL:
case ElementKind.LOCAL: case ElementKind.LOCAL:
var type = (<VariableLikeElement>target).type; var type = (<VariableLikeElement>target).type;
assert(type != null); assert(type != null); // locals don't have lazy types, unlike globals
if ((<Type>type).classType) { if ((<Type>type).classType) {
target = <Class>(<Type>type).classType; target = <Class>(<Type>type).classType;
// fall-through // fall-through
@ -1338,9 +1353,10 @@ export class FunctionPrototype extends Element {
var instance = this.instances.get(instanceKey); var instance = this.instances.get(instanceKey);
if (instance) if (instance)
return instance; return instance;
var declaration = this.declaration; var declaration = this.declaration;
if (!declaration) if (!declaration)
throw new Error("declaration expected"); // cannot resolve built-ins throw new Error("cannot resolve built-ins");
// inherit contextual type arguments // inherit contextual type arguments
var inheritedTypeArguments = contextualTypeArguments; var inheritedTypeArguments = contextualTypeArguments;
@ -1351,14 +1367,16 @@ export class FunctionPrototype extends Element {
var i: i32, k: i32; var i: i32, k: i32;
// inherit class type arguments if a partially resolved instance method // inherit class type arguments if a partially resolved instance method (classTypeArguments is set)
if (this.classPrototype && this.classTypeArguments) { if (this.classTypeArguments) {
var classDeclaration = this.classPrototype.declaration; if (!this.classPrototype)
throw new Error("partially resolved instance method must reference its class prototype");
var classDeclaration = (<ClassPrototype>this.classPrototype).declaration;
if (!classDeclaration) if (!classDeclaration)
throw new Error("declaration expected"); // cannot resolve built-ins throw new Error("cannot resolve built-ins");
var classTypeParameters = classDeclaration.typeParameters; var classTypeParameters = classDeclaration.typeParameters;
if ((k = this.classTypeArguments.length) != classTypeParameters.length) if ((k = this.classTypeArguments.length) != classTypeParameters.length)
throw new Error("unexpected type argument count mismatch"); throw new Error("type argument count mismatch");
for (i = 0; i < k; ++i) for (i = 0; i < k; ++i)
contextualTypeArguments.set(classTypeParameters[i].identifier.name, this.classTypeArguments[i]); contextualTypeArguments.set(classTypeParameters[i].identifier.name, this.classTypeArguments[i]);
} }
@ -1367,7 +1385,7 @@ export class FunctionPrototype extends Element {
var functionTypeParameters = declaration.typeParameters; var functionTypeParameters = declaration.typeParameters;
if (functionTypeArguments && (k = functionTypeArguments.length)) { if (functionTypeArguments && (k = functionTypeArguments.length)) {
if (k != functionTypeParameters.length) if (k != functionTypeParameters.length)
throw new Error("unexpected type argument count mismatch"); throw new Error("type argument count mismatch");
for (i = 0; i < k; ++i) for (i = 0; i < k; ++i)
contextualTypeArguments.set(functionTypeParameters[i].identifier.name, functionTypeArguments[i]); contextualTypeArguments.set(functionTypeParameters[i].identifier.name, functionTypeArguments[i]);
} }
@ -1424,7 +1442,7 @@ export class FunctionPrototype extends Element {
if (this.isGeneric) { if (this.isGeneric) {
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0); assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
if (!this.declaration) if (!this.declaration)
throw new Error("declaration expected"); throw new Error("cannot resolve built-ins");
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode); resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
if (!resolvedTypeArguments) if (!resolvedTypeArguments)
return null; return null;
@ -1433,7 +1451,8 @@ export class FunctionPrototype extends Element {
} }
resolvePartial(classTypeArguments: Type[] | null): FunctionPrototype | null { resolvePartial(classTypeArguments: Type[] | null): FunctionPrototype | null {
assert(this.classPrototype != null); if (!this.classPrototype)
throw new Error("partially resolved instance method must reference its class prototype");
if (classTypeArguments && classTypeArguments.length) { if (classTypeArguments && classTypeArguments.length) {
var partialPrototype = new FunctionPrototype(this.program, this.simpleName, this.internalName, this.declaration, this.classPrototype); var partialPrototype = new FunctionPrototype(this.program, this.simpleName, this.internalName, this.declaration, this.classPrototype);
partialPrototype.flags = this.flags; partialPrototype.flags = this.flags;
@ -1484,7 +1503,7 @@ export class Function extends Element {
this.flags = prototype.flags; this.flags = prototype.flags;
var localIndex = 0; var localIndex = 0;
if (instanceMethodOf) { if (instanceMethodOf) {
assert(this.isInstance); assert(this.isInstance); // internal error
this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type)); this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type));
if (instanceMethodOf.contextualTypeArguments) { if (instanceMethodOf.contextualTypeArguments) {
if (!this.contextualTypeArguments) if (!this.contextualTypeArguments)
@ -1493,7 +1512,7 @@ export class Function extends Element {
this.contextualTypeArguments.set(inheritedName, inheritedType); this.contextualTypeArguments.set(inheritedName, inheritedType);
} }
} else } else
assert(!this.isInstance); assert(!this.isInstance); // internal error
for (var i = 0, k = parameters.length; i < k; ++i) { for (var i = 0, k = parameters.length; i < k; ++i) {
var parameter = parameters[i]; var parameter = parameters[i];
this.locals.set(parameter.name, new Local(prototype.program, parameter.name, localIndex++, parameter.type)); this.locals.set(parameter.name, new Local(prototype.program, parameter.name, localIndex++, parameter.type));
@ -1508,7 +1527,7 @@ export class Function extends Element {
var local = new Local(this.prototype.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type); var local = new Local(this.prototype.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
if (name) { if (name) {
if (this.locals.has(name)) if (this.locals.has(name))
throw new Error("unexpected duplicate local name"); throw new Error("duplicate local name");
this.locals.set(name, local); this.locals.set(name, local);
} }
this.additionalLocals.push(type); this.additionalLocals.push(type);
@ -1528,7 +1547,7 @@ export class Function extends Element {
case NativeType.I64: temps = this.tempI64s; break; case NativeType.I64: temps = this.tempI64s; break;
case NativeType.F32: temps = this.tempF32s; break; case NativeType.F32: temps = this.tempF32s; break;
case NativeType.F64: temps = this.tempF64s; break; case NativeType.F64: temps = this.tempF64s; break;
default: throw new Error("unexpected type"); default: throw new Error("concrete type expected");
} }
return temps && temps.length > 0 return temps && temps.length > 0
? temps.pop() ? temps.pop()
@ -1538,13 +1557,13 @@ export class Function extends Element {
/** Frees the temporary local for reuse. */ /** Frees the temporary local for reuse. */
freeTempLocal(local: Local): void { freeTempLocal(local: Local): void {
var temps: Local[]; var temps: Local[];
assert(local.type != null); assert(local.type != null); // internal error
switch ((<Type>local.type).toNativeType()) { switch ((<Type>local.type).toNativeType()) {
case NativeType.I32: temps = this.tempI32s || (this.tempI32s = []); break; case NativeType.I32: temps = this.tempI32s || (this.tempI32s = []); break;
case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break; case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break;
case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break; case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break;
case NativeType.F64: temps = this.tempF64s || (this.tempF64s = []); break; case NativeType.F64: temps = this.tempF64s || (this.tempF64s = []); break;
default: throw new Error("unexpected type"); default: throw new Error("concrete type expected");
} }
temps.push(local); temps.push(local);
} }
@ -1557,7 +1576,7 @@ export class Function extends Element {
case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break; case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break;
case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break; case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break;
case NativeType.F64: temps = this.tempF64s || (this.tempF64s = []); break; case NativeType.F64: temps = this.tempF64s || (this.tempF64s = []); break;
default: throw new Error("unexpected type"); default: throw new Error("concrete type expected");
} }
if (temps.length > 0) if (temps.length > 0)
return temps[temps.length - 1]; return temps[temps.length - 1];
@ -1592,7 +1611,7 @@ export class Function extends Element {
/** Finalizes the function once compiled, releasing no longer needed resources. */ /** Finalizes the function once compiled, releasing no longer needed resources. */
finalize(): void { finalize(): void {
assert(!this.breakStack || !this.breakStack.length, "break stack is not empty"); assert(!this.breakStack || !this.breakStack.length); // internal error
this.breakStack = null; this.breakStack = null;
this.breakContext = null; this.breakContext = null;
this.tempI32s = this.tempI64s = this.tempF32s = this.tempF64s = null; this.tempI32s = this.tempI64s = this.tempF32s = this.tempF64s = null;
@ -1628,7 +1647,7 @@ export class FieldPrototype extends Element {
case ModifierKind.PROTECTED: case ModifierKind.PROTECTED:
case ModifierKind.PUBLIC: case ModifierKind.PUBLIC:
case ModifierKind.STATIC: break; // already handled case ModifierKind.STATIC: break; // already handled
default: assert(false); default: throw new Error("unexpected modifier");
} }
} }
} }
@ -1726,7 +1745,7 @@ export class ClassPrototype extends Element {
var declaration = this.declaration; var declaration = this.declaration;
if (!declaration) if (!declaration)
throw new Error("declaration expected"); // cannot resolve built-ins throw new Error("cannot resolve built-ins");
// inherit contextual type arguments // inherit contextual type arguments
var inheritedTypeArguments = contextualTypeArguments; var inheritedTypeArguments = contextualTypeArguments;
@ -1740,9 +1759,13 @@ export class ClassPrototype extends Element {
// override call specific contextual type arguments if provided // override call specific contextual type arguments if provided
var i: i32, k: i32; var i: i32, k: i32;
if (typeArguments) if (typeArguments) {
for (var i = 0, k = typeArguments.length; i < k; ++i) if ((k = typeArguments.length) != declaration.typeParameters.length)
throw new Error("type argument count mismatch");
for (var i = 0; i < k; ++i)
contextualTypeArguments.set(declaration.typeParameters[i].identifier.name, typeArguments[i]); contextualTypeArguments.set(declaration.typeParameters[i].identifier.name, typeArguments[i]);
} else if (declaration.typeParameters.length)
throw new Error("type argument count mismatch");
var internalName = this.internalName; var internalName = this.internalName;
if (instanceKey.length) if (instanceKey.length)
@ -1762,7 +1785,7 @@ export class ClassPrototype extends Element {
instance.members = new Map(); instance.members = new Map();
var fieldDeclaration = (<FieldPrototype>member).declaration; var fieldDeclaration = (<FieldPrototype>member).declaration;
if (!fieldDeclaration) if (!fieldDeclaration)
throw new Error("declaration expected"); throw new Error("cannot resolve built-ins");
if (!fieldDeclaration.type) if (!fieldDeclaration.type)
throw new Error("type expected"); // TODO: check if parent class defines a type for it already throw new Error("type expected"); // TODO: check if parent class defines a type for it already
var fieldType = this.program.resolveType(fieldDeclaration.type, instance.contextualTypeArguments); // reports var fieldType = this.program.resolveType(fieldDeclaration.type, instance.contextualTypeArguments); // reports
@ -1794,23 +1817,21 @@ export class ClassPrototype extends Element {
} }
} }
instance.type.byteSize = memoryOffset; instance.type.byteSize = memoryOffset; // sizeof<this>() is its byte size in memory
return instance; return instance;
} }
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Class | null { resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Class | null {
var resolvedTypeArguments: Type[] | null; var resolvedTypeArguments: Type[] | null = null;
if (this.isGeneric) { if (this.isGeneric) {
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0); assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
if (!this.declaration) if (!this.declaration)
throw new Error("declaration expected"); // generic built-in throw new Error("cannot resolve built-ins");
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode); resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
if (!resolvedTypeArguments) if (!resolvedTypeArguments)
return null; return null;
} else { } else
assert(typeArgumentNodes == null || !typeArgumentNodes.length); assert(typeArgumentNodes == null || !typeArgumentNodes.length);
resolvedTypeArguments = [];
}
return this.resolve(resolvedTypeArguments, contextualTypeArguments); return this.resolve(resolvedTypeArguments, contextualTypeArguments);
} }
@ -1855,16 +1876,16 @@ export class Class extends Element {
if (declaration) { // irrelevant for built-ins if (declaration) { // irrelevant for built-ins
var typeParameters = declaration.typeParameters; var typeParameters = declaration.typeParameters;
if (typeArguments) { if (typeArguments) {
if (typeParameters.length != typeArguments.length) if ((k = typeArguments.length) != typeParameters.length)
throw new Error("unexpected type argument count mismatch"); throw new Error("type argument count mismatch");
if (k = typeArguments.length) { if (k) {
if (!this.contextualTypeArguments) if (!this.contextualTypeArguments)
this.contextualTypeArguments = new Map(); this.contextualTypeArguments = new Map();
for (i = 0; i < k; ++i) for (i = 0; i < k; ++i)
this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]); this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]);
} }
} else } else if (typeParameters.length)
throw new Error("unexpected type argument count mismatch"); throw new Error("type argument count mismatch");
} }
} }