Refactor resolve infrastructure to its own file

This has become a little clumsy over time. Doesn't hurt to have it in its own place to get a grasp of it more easily.
This commit is contained in:
dcodeIO 2018-07-13 00:22:22 +02:00
parent 585d246165
commit cd14b296ce
6 changed files with 1314 additions and 1064 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -2794,7 +2794,7 @@ export function compileAllocate(
return module.createUnreachable();
}
var allocateInstance = (<FunctionPrototype>allocatePrototype).resolve(); // reports
var allocateInstance = compiler.resolver.resolveFunction(<FunctionPrototype>allocatePrototype, null);
if (!(allocateInstance && compiler.compileFunction(allocateInstance))) return module.createUnreachable();
compiler.currentType = classInstance.type;
@ -2825,7 +2825,7 @@ export function compileAbort(
var abortPrototype = program.elementsLookup.get(abortInternalName); // might be intended
if (!abortPrototype || abortPrototype.kind != ElementKind.FUNCTION_PROTOTYPE) return module.createUnreachable();
var abortInstance = (<FunctionPrototype>abortPrototype).resolve(); // reports
var abortInstance = compiler.resolver.resolveFunction(<FunctionPrototype>abortPrototype, null);
if (!(abortInstance && compiler.compileFunction(abortInstance))) return module.createUnreachable();
var messageArg = message != null

@ -73,6 +73,10 @@ import {
DecoratorFlags
} from "./program";
import {
Resolver
} from "./resolver";
import {
Token,
operatorTokenToString
@ -250,6 +254,8 @@ export class Compiler extends DiagnosticEmitter {
/** Program reference. */
program: Program;
/** Resolver reference. */
resolver: Resolver;
/** Provided options. */
options: Options;
/** Module instance being compiled. */
@ -288,6 +294,7 @@ export class Compiler extends DiagnosticEmitter {
constructor(program: Program, options: Options | null = null) {
super(program.diagnostics);
this.program = program;
this.resolver = program.resolver;
if (!options) options = new Options();
this.options = options;
this.memoryOffset = i64_new(
@ -430,7 +437,7 @@ export class Compiler extends DiagnosticEmitter {
(noTreeShaking || (isEntry && statement.is(CommonFlags.EXPORT))) &&
!(<ClassDeclaration>statement).isGeneric
) {
this.compileClassDeclaration(<ClassDeclaration>statement, []);
this.compileClassDeclaration(<ClassDeclaration>statement, [], null);
}
break;
}
@ -514,7 +521,7 @@ export class Compiler extends DiagnosticEmitter {
// resolve now if annotated
if (declaration.type) {
let resolvedType = this.program.resolveType(declaration.type); // reports
let resolvedType = this.resolver.resolveType(declaration.type); // reports
if (!resolvedType) return false;
if (resolvedType == Type.void) {
this.error(
@ -827,7 +834,8 @@ export class Compiler extends DiagnosticEmitter {
outerScope: Flow | null,
reportNode: Node
): Function | null {
var instance = prototype.resolveUsingTypeArguments( // reports
var instance = this.resolver.resolveFunctionInclTypeArguments(
prototype,
typeArguments,
contextualTypeArguments,
reportNode
@ -1203,8 +1211,7 @@ export class Compiler extends DiagnosticEmitter {
compileClassDeclaration(
declaration: ClassDeclaration,
typeArguments: TypeNode[],
contextualTypeArguments: Map<string,Type> | null = null,
alternativeReportNode: Node | null = null
contextualTypeArguments: Map<string,Type> | null = null
): void {
var element = assert(this.program.elementsLookup.get(declaration.fileLevelInternalName));
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
@ -1212,7 +1219,7 @@ export class Compiler extends DiagnosticEmitter {
<ClassPrototype>element,
typeArguments,
contextualTypeArguments,
alternativeReportNode
declaration
);
}
@ -1222,10 +1229,11 @@ export class Compiler extends DiagnosticEmitter {
contextualTypeArguments: Map<string,Type> | null = null,
alternativeReportNode: Node | null = null
): void {
var instance = prototype.resolveUsingTypeArguments( // reports
var instance = this.resolver.resolveClassInclTypeArguments(
prototype,
typeArguments,
contextualTypeArguments,
alternativeReportNode
alternativeReportNode || prototype.declaration
);
if (!instance) return;
this.compileClass(instance);
@ -2002,13 +2010,14 @@ export class Compiler extends DiagnosticEmitter {
// other variables become locals
var initializers = new Array<ExpressionRef>();
var flow = this.currentFunction.flow;
var resolver = this.resolver;
for (let i = 0; i < numDeclarations; ++i) {
let declaration = declarations[i];
let name = declaration.name.text;
let type: Type | null = null;
let initExpr: ExpressionRef = 0;
if (declaration.type) {
type = program.resolveType( // reports
type = resolver.resolveType( // reports
declaration.type,
flow.contextualTypeArguments
);
@ -2609,7 +2618,7 @@ export class Compiler extends DiagnosticEmitter {
}
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
var toType = this.program.resolveType( // reports
var toType = this.resolver.resolveType( // reports
expression.toType,
this.currentFunction.flow.contextualTypeArguments
);
@ -3585,7 +3594,7 @@ export class Compiler extends DiagnosticEmitter {
break;
}
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f32PowInstance = instance = (<FunctionPrototype>prototype).resolve();
this.f32PowInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
// Math.pow otherwise (result is f64)
@ -3627,7 +3636,7 @@ export class Compiler extends DiagnosticEmitter {
break;
}
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f64PowInstance = instance = (<FunctionPrototype>prototype).resolve();
this.f64PowInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
}
if (!(instance && this.compileFunction(instance))) {
@ -3877,7 +3886,7 @@ export class Compiler extends DiagnosticEmitter {
break;
}
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f32ModInstance = instance = (<FunctionPrototype>prototype).resolve();
this.f32ModInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
if (!(instance && this.compileFunction(instance))) {
expr = module.createUnreachable();
@ -3908,7 +3917,7 @@ export class Compiler extends DiagnosticEmitter {
break;
}
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f64ModInstance = instance = (<FunctionPrototype>prototype).resolve();
this.f64ModInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
if (!(instance && this.compileFunction(instance))) {
expr = module.createUnreachable();
@ -4577,8 +4586,9 @@ export class Compiler extends DiagnosticEmitter {
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
var program = this.program;
var resolver = program.resolver;
var currentFunction = this.currentFunction;
var target = program.resolveExpression(expression, currentFunction); // reports
var target = resolver.resolveExpression(expression, currentFunction); // reports
if (!target) return this.module.createUnreachable();
// to compile just the value, we need to know the target's type
@ -4597,9 +4607,9 @@ export class Compiler extends DiagnosticEmitter {
break;
}
case ElementKind.PROPERTY: {
let prototype = (<Property>target).setterPrototype;
if (prototype) {
let instance = prototype.resolve(); // reports
let setterPrototype = (<Property>target).setterPrototype;
if (setterPrototype) {
let instance = this.resolver.resolveFunction(setterPrototype, null);
if (!instance) return this.module.createUnreachable();
assert(instance.signature.parameterTypes.length == 1); // parser must guarantee this
targetType = instance.signature.parameterTypes[0];
@ -4612,7 +4622,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable();
}
case ElementKind.CLASS: {
if (program.resolvedElementExpression) { // indexed access
if (resolver.resolvedElementExpression) { // indexed access
let isUnchecked = currentFunction.flow.is(FlowFlags.UNCHECKED_CONTEXT);
let indexedSet = (<Class>target).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
if (!indexedSet) {
@ -4661,7 +4671,7 @@ export class Compiler extends DiagnosticEmitter {
tee: bool = false
): ExpressionRef {
var module = this.module;
var target = this.program.resolveExpression(expression, this.currentFunction); // reports
var target = this.resolver.resolveExpression(expression, this.currentFunction); // reports
if (!target) return module.createUnreachable();
switch (target.kind) {
@ -4725,7 +4735,7 @@ export class Compiler extends DiagnosticEmitter {
);
return module.createUnreachable();
}
let thisExpression = assert(this.program.resolvedThisExpression);
let thisExpression = assert(this.resolver.resolvedThisExpression);
let thisExpr = this.compileExpressionRetainType(
thisExpression,
this.options.usizeType,
@ -4771,13 +4781,13 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.PROPERTY: {
let setterPrototype = (<Property>target).setterPrototype;
if (setterPrototype) {
let setterInstance = setterPrototype.resolve(); // reports
let setterInstance = this.resolver.resolveFunction(setterPrototype, null);
if (!setterInstance) return module.createUnreachable();
// call just the setter if the return value isn't of interest
if (!tee) {
if (setterInstance.is(CommonFlags.INSTANCE)) {
let thisExpression = assert(this.program.resolvedThisExpression);
let thisExpression = assert(this.resolver.resolvedThisExpression);
let thisExpr = this.compileExpressionRetainType(
thisExpression,
this.options.usizeType,
@ -4792,12 +4802,12 @@ export class Compiler extends DiagnosticEmitter {
// otherwise call the setter first, then the getter
let getterPrototype = (<Property>target).getterPrototype;
assert(getterPrototype != null); // must have one if there is a setter
let getterInstance = (<FunctionPrototype>getterPrototype).resolve(); // reports
let getterInstance = this.resolver.resolveFunction(<FunctionPrototype>getterPrototype, null);
if (!getterInstance) return module.createUnreachable();
let returnType = getterInstance.signature.returnType;
let nativeReturnType = returnType.toNativeType();
if (setterInstance.is(CommonFlags.INSTANCE)) {
let thisExpression = assert(this.program.resolvedThisExpression);
let thisExpression = assert(this.resolver.resolvedThisExpression);
let thisExpr = this.compileExpressionRetainType(
thisExpression,
this.options.usizeType,
@ -4830,7 +4840,7 @@ export class Compiler extends DiagnosticEmitter {
return module.createUnreachable();
}
case ElementKind.CLASS: {
let elementExpression = this.program.resolvedElementExpression;
let elementExpression = this.resolver.resolvedElementExpression;
if (elementExpression) {
let isUnchecked = this.currentFunction.flow.is(FlowFlags.UNCHECKED_CONTEXT);
let indexedGet = (<Class>target).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
@ -4851,7 +4861,7 @@ export class Compiler extends DiagnosticEmitter {
return module.createUnreachable();
}
let targetType = (<Class>target).type;
let thisExpression = assert(this.program.resolvedThisExpression);
let thisExpression = assert(this.resolver.resolvedThisExpression);
let thisExpr = this.compileExpressionRetainType(
thisExpression,
this.options.usizeType,
@ -4901,7 +4911,7 @@ export class Compiler extends DiagnosticEmitter {
compileCallExpression(expression: CallExpression, contextualType: Type): ExpressionRef {
var module = this.module;
var currentFunction = this.currentFunction;
var target = this.program.resolveExpression(expression.expression, currentFunction); // reports
var target = this.resolver.resolveExpression(expression.expression, currentFunction); // reports
if (!target) return module.createUnreachable();
var signature: Signature | null;
@ -4929,7 +4939,8 @@ export class Compiler extends DiagnosticEmitter {
);
return module.createUnreachable();
}
instance = prototype.resolveUsingTypeArguments( // reports
instance = this.resolver.resolveFunctionInclTypeArguments(
prototype,
typeArguments,
this.currentFunction.flow.contextualTypeArguments,
expression
@ -4984,10 +4995,9 @@ export class Compiler extends DiagnosticEmitter {
}
inferredTypes.set(name, inferredType);
} else {
let concreteType = this.program.resolveType(
let concreteType = this.resolver.resolveType(
parameterTypes[i].type,
this.currentFunction.flow.contextualTypeArguments,
true
this.currentFunction.flow.contextualTypeArguments
);
if (!concreteType) return module.createUnreachable();
argumentExprs[i] = this.compileExpression(
@ -5003,7 +5013,8 @@ export class Compiler extends DiagnosticEmitter {
let inferredType = assert(inferredTypes.get(typeParameters[i].name.text)); // TODO
resolvedTypeArguments[i] = inferredType;
}
instance = prototype.resolve(
instance = this.resolver.resolveFunction(
prototype,
resolvedTypeArguments,
this.currentFunction.flow.contextualTypeArguments
);
@ -5015,7 +5026,8 @@ export class Compiler extends DiagnosticEmitter {
// otherwise resolve the non-generic call as usual
} else {
instance = prototype.resolve(
instance = this.resolver.resolveFunction(
prototype,
null,
this.currentFunction.flow.contextualTypeArguments
);
@ -5026,7 +5038,7 @@ export class Compiler extends DiagnosticEmitter {
let thisExpr: ExpressionRef = 0;
if (instance.is(CommonFlags.INSTANCE)) {
thisExpr = this.compileExpressionRetainType(
assert(this.program.resolvedThisExpression),
assert(this.resolver.resolvedThisExpression),
this.options.usizeType,
WrapMode.NONE
);
@ -5069,7 +5081,7 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.FIELD: {
let type = (<Field>target).type;
if (signature = type.signatureReference) {
let thisExpression = assert(this.program.resolvedThisExpression);
let thisExpression = assert(this.resolver.resolvedThisExpression);
let thisExpr = this.compileExpressionRetainType(
thisExpression,
this.options.usizeType,
@ -5125,13 +5137,31 @@ export class Compiler extends DiagnosticEmitter {
expression: CallExpression,
contextualType: Type
): ExpressionRef {
var expr = compileBuiltinCall( // reports
var typeArguments: Type[] | null = null;
// builtins handle omitted type arguments on their own. if present, however, resolve them here
// and pass them to the builtin, even if it's still up to the builtin how to handle them.
var typeArgumentNodes = expression.typeArguments;
if (expression.typeArguments) {
if (!prototype.is(CommonFlags.GENERIC)) {
this.error(
DiagnosticCode.Type_0_is_not_generic,
expression.range, prototype.internalName
);
}
typeArguments = this.resolver.resolveTypeArguments(
assert(prototype.declaration.typeParameters),
typeArgumentNodes,
this.currentFunction.flow.contextualTypeArguments,
expression
);
}
// now compile the builtin, which usually returns a block of code that replaces the call.
var expr = compileBuiltinCall(
this,
prototype,
prototype.resolveBuiltinTypeArguments(
expression.typeArguments,
this.currentFunction.flow.contextualTypeArguments
),
typeArguments,
expression.arguments,
contextualType,
expression
@ -5733,7 +5763,7 @@ export class Compiler extends DiagnosticEmitter {
}
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef {
var target = this.program.resolveElementAccess(expression, this.currentFunction); // reports
var target = this.resolver.resolveElementAccess(expression, this.currentFunction); // reports
if (!target) return this.module.createUnreachable();
switch (target.kind) {
case ElementKind.CLASS: {
@ -5895,7 +5925,7 @@ export class Compiler extends DiagnosticEmitter {
}
// otherwise resolve
var target = this.program.resolveIdentifier( // reports
var target = this.resolver.resolveIdentifier( // reports
expression,
this.currentEnum || currentFunction
);
@ -5940,7 +5970,8 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createGetGlobal((<EnumValue>target).internalName, NativeType.I32);
}
case ElementKind.FUNCTION_PROTOTYPE: {
let instance = (<FunctionPrototype>target).resolve(
let instance = this.resolver.resolveFunction(
<FunctionPrototype>target,
null,
currentFunction.flow.contextualTypeArguments
);
@ -5967,7 +5998,7 @@ export class Compiler extends DiagnosticEmitter {
// possible in AS anyway.
var expr = this.compileExpressionRetainType(expression.expression, this.options.usizeType, WrapMode.NONE);
var type = this.currentType;
var isType = this.program.resolveType(expression.isType);
var isType = this.resolver.resolveType(expression.isType);
this.currentType = Type.bool;
if (!isType) return module.createUnreachable();
return type.is(TypeFlags.NULLABLE) && !isType.is(TypeFlags.NULLABLE)
@ -6161,7 +6192,7 @@ export class Compiler extends DiagnosticEmitter {
// obtain the array type
var arrayPrototype = assert(this.program.arrayPrototype);
if (!arrayPrototype || arrayPrototype.kind != ElementKind.CLASS_PROTOTYPE) return module.createUnreachable();
var arrayInstance = (<ClassPrototype>arrayPrototype).resolve([ elementType ]);
var arrayInstance = this.resolver.resolveClass(<ClassPrototype>arrayPrototype, [ elementType ]);
if (!arrayInstance) return module.createUnreachable();
var arrayType = arrayInstance.type;
@ -6367,7 +6398,7 @@ export class Compiler extends DiagnosticEmitter {
var currentFunction = this.currentFunction;
// obtain the class being instantiated
var target = this.program.resolveExpression( // reports
var target = this.resolver.resolveExpression( // reports
expression.expression,
currentFunction
);
@ -6388,12 +6419,14 @@ export class Compiler extends DiagnosticEmitter {
(classReference = contextualType.classReference) !== null &&
classReference.is(CommonFlags.GENERIC)
) {
classInstance = classPrototype.resolve(
classInstance = this.resolver.resolveClass(
classPrototype,
classReference.typeArguments,
currentFunction.flow.contextualTypeArguments
);
} else {
classInstance = classPrototype.resolveUsingTypeArguments( // reports
classInstance = this.resolver.resolveClassInclTypeArguments(
classPrototype,
typeArguments,
currentFunction.flow.contextualTypeArguments,
expression
@ -6448,10 +6481,9 @@ export class Compiler extends DiagnosticEmitter {
contextualType: Type,
retainConstantType: bool
): ExpressionRef {
var program = this.program;
var module = this.module;
var target = program.resolvePropertyAccess(propertyAccess, this.currentFunction); // reports
var target = this.resolver.resolvePropertyAccess(propertyAccess, this.currentFunction); // reports
if (!target) return module.createUnreachable();
switch (target.kind) {
@ -6480,7 +6512,7 @@ export class Compiler extends DiagnosticEmitter {
return module.createGetGlobal((<EnumValue>target).internalName, NativeType.I32);
}
case ElementKind.FIELD: { // instance field
let thisExpression = assert(program.resolvedThisExpression);
let thisExpression = assert(this.resolver.resolvedThisExpression);
assert((<Field>target).memoryOffset >= 0);
let thisExpr = this.compileExpressionRetainType(
thisExpression,
@ -6499,7 +6531,7 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.PROPERTY: { // instance property (here: getter)
let prototype = (<Property>target).getterPrototype;
if (prototype) {
let instance = prototype.resolve(null); // reports
let instance = this.resolver.resolveFunction(prototype, null);
if (!instance) return module.createUnreachable();
let signature = instance.signature;
if (!this.checkCallSignature( // reports
@ -6514,7 +6546,7 @@ export class Compiler extends DiagnosticEmitter {
if (instance.is(CommonFlags.INSTANCE)) {
let parent = assert(instance.parent);
assert(parent.kind == ElementKind.CLASS);
let thisExpression = assert(program.resolvedThisExpression);
let thisExpression = assert(this.resolver.resolvedThisExpression);
let thisExpr = this.compileExpressionRetainType(
thisExpression,
this.options.usizeType,

File diff suppressed because it is too large Load Diff

1168
src/resolver.ts Normal file

File diff suppressed because it is too large Load Diff