mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 23:12:19 +00:00
Support 'this' in static functions, fixes #45; Fix propagation of 'ambient' flag
This commit is contained in:
parent
fea8e65a41
commit
2c0ddf4f80
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
@ -2457,6 +2457,8 @@ function evaluateConstantOffset(compiler: Compiler, expression: Expression): i32
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allocateInternalName = "allocate_memory";
|
||||||
|
|
||||||
/** Compiles a memory allocation for an instance of the specified class. */
|
/** Compiles a memory allocation for an instance of the specified class. */
|
||||||
export function compileAllocate(
|
export function compileAllocate(
|
||||||
compiler: Compiler,
|
compiler: Compiler,
|
||||||
@ -2468,11 +2470,11 @@ export function compileAllocate(
|
|||||||
var module = compiler.module;
|
var module = compiler.module;
|
||||||
var options = compiler.options;
|
var options = compiler.options;
|
||||||
|
|
||||||
var prototype = program.elementsLookup.get(options.allocateImpl);
|
var prototype = program.elementsLookup.get(allocateInternalName);
|
||||||
if (!prototype) {
|
if (!prototype) {
|
||||||
program.error(
|
program.error(
|
||||||
DiagnosticCode.Cannot_find_name_0,
|
DiagnosticCode.Cannot_find_name_0,
|
||||||
reportNode.range, options.allocateImpl
|
reportNode.range, allocateInternalName
|
||||||
);
|
);
|
||||||
return module.createUnreachable();
|
return module.createUnreachable();
|
||||||
}
|
}
|
||||||
@ -2498,6 +2500,8 @@ export function compileAllocate(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const abortInternalName = "abort";
|
||||||
|
|
||||||
/** Compiles an abort wired to the conditionally imported 'abort' function. */
|
/** Compiles an abort wired to the conditionally imported 'abort' function. */
|
||||||
export function compileAbort(
|
export function compileAbort(
|
||||||
compiler: Compiler,
|
compiler: Compiler,
|
||||||
@ -2510,7 +2514,7 @@ export function compileAbort(
|
|||||||
var stringType = program.typesLookup.get("string"); // might be intended
|
var stringType = program.typesLookup.get("string"); // might be intended
|
||||||
if (!stringType) return module.createUnreachable();
|
if (!stringType) return module.createUnreachable();
|
||||||
|
|
||||||
var abortPrototype = program.elementsLookup.get("abort"); // might be intended
|
var abortPrototype = program.elementsLookup.get(abortInternalName); // might be intended
|
||||||
if (!abortPrototype || abortPrototype.kind != ElementKind.FUNCTION_PROTOTYPE) return module.createUnreachable();
|
if (!abortPrototype || abortPrototype.kind != ElementKind.FUNCTION_PROTOTYPE) return module.createUnreachable();
|
||||||
|
|
||||||
var abortInstance = (<FunctionPrototype>abortPrototype).resolve(); // reports
|
var abortInstance = (<FunctionPrototype>abortPrototype).resolve(); // reports
|
||||||
|
@ -142,10 +142,6 @@ export class Options {
|
|||||||
importMemory: bool = false;
|
importMemory: bool = false;
|
||||||
/** Static memory start offset. */
|
/** Static memory start offset. */
|
||||||
memoryBase: u32 = 0;
|
memoryBase: u32 = 0;
|
||||||
/** Memory allocation implementation to use. */
|
|
||||||
allocateImpl: string = "allocate_memory";
|
|
||||||
/** Memory freeing implementation to use. */
|
|
||||||
freeImpl: string = "free_memory";
|
|
||||||
/** If true, generates information necessary for source maps. */
|
/** If true, generates information necessary for source maps. */
|
||||||
sourceMap: bool = false;
|
sourceMap: bool = false;
|
||||||
|
|
||||||
@ -513,7 +509,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var isConstant = global.isAny(CommonFlags.CONST) || global.is(CommonFlags.STATIC | CommonFlags.READONLY);
|
var isConstant = global.isAny(CommonFlags.CONST) || global.is(CommonFlags.STATIC | CommonFlags.READONLY);
|
||||||
|
|
||||||
// handle imports
|
// handle imports
|
||||||
if (global.is(CommonFlags.DECLARE)) {
|
if (global.is(CommonFlags.AMBIENT)) {
|
||||||
|
|
||||||
// constant global
|
// constant global
|
||||||
if (isConstant) {
|
if (isConstant) {
|
||||||
@ -818,14 +814,14 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var declaration = instance.prototype.declaration;
|
var declaration = instance.prototype.declaration;
|
||||||
var body = declaration.body;
|
var body = declaration.body;
|
||||||
if (body) {
|
if (body) {
|
||||||
if (instance.is(CommonFlags.DECLARE)) {
|
if (instance.is(CommonFlags.AMBIENT)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
|
DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts,
|
||||||
declaration.name.range
|
declaration.name.range
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!instance.is(CommonFlags.DECLARE)) {
|
if (!instance.is(CommonFlags.AMBIENT)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
|
DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration,
|
||||||
declaration.name.range
|
declaration.name.range
|
||||||
@ -4231,7 +4227,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
var trampolineSignature = new Signature(trampolineParameterTypes, commonReturnType, commonThisType);
|
var trampolineSignature = new Signature(trampolineParameterTypes, commonReturnType, commonThisType);
|
||||||
var trampolineName = originalName + "|trampoline";
|
var trampolineName = originalName + "|trampoline";
|
||||||
trampolineSignature.requiredParameters = maxArguments + 1;
|
trampolineSignature.requiredParameters = maxArguments + 1;
|
||||||
trampoline = new Function(original.prototype, trampolineName, trampolineSignature, original.instanceMethodOf);
|
trampoline = new Function(original.prototype, trampolineName, trampolineSignature, original.memberOf);
|
||||||
trampoline.flags = original.flags;
|
trampoline.flags = original.flags;
|
||||||
trampoline.set(CommonFlags.COMPILED);
|
trampoline.set(CommonFlags.COMPILED);
|
||||||
original.trampoline = trampoline;
|
original.trampoline = trampoline;
|
||||||
@ -4463,7 +4459,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
case NodeKind.THIS: {
|
case NodeKind.THIS: {
|
||||||
let currentFunction = this.currentFunction;
|
let currentFunction = this.currentFunction;
|
||||||
if (currentFunction.is(CommonFlags.INSTANCE)) {
|
if (currentFunction.is(CommonFlags.INSTANCE)) {
|
||||||
let thisType = assert(currentFunction.instanceMethodOf).type;
|
let parent = assert(currentFunction.memberOf);
|
||||||
|
assert(parent.kind == ElementKind.CLASS);
|
||||||
|
let thisType = (<Class>parent).type;
|
||||||
this.currentType = thisType;
|
this.currentType = thisType;
|
||||||
return module.createGetLocal(0, thisType.toNativeType());
|
return module.createGetLocal(0, thisType.toNativeType());
|
||||||
}
|
}
|
||||||
@ -4477,7 +4475,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
case NodeKind.SUPER: {
|
case NodeKind.SUPER: {
|
||||||
let currentFunction = this.currentFunction;
|
let currentFunction = this.currentFunction;
|
||||||
if (currentFunction.is(CommonFlags.INSTANCE)) {
|
if (currentFunction.is(CommonFlags.INSTANCE)) {
|
||||||
let base = assert(currentFunction.instanceMethodOf).base;
|
let parent = assert(currentFunction.memberOf);
|
||||||
|
assert(parent.kind == ElementKind.CLASS);
|
||||||
|
let base = (<Class>parent).base;
|
||||||
if (base) {
|
if (base) {
|
||||||
let superType = base.type;
|
let superType = base.type;
|
||||||
this.currentType = superType;
|
this.currentType = superType;
|
||||||
@ -4971,10 +4971,12 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
)) {
|
)) {
|
||||||
return module.createUnreachable();
|
return module.createUnreachable();
|
||||||
}
|
}
|
||||||
if (instance.instanceMethodOf) {
|
if (instance.is(CommonFlags.INSTANCE)) {
|
||||||
|
let parent = assert(instance.memberOf);
|
||||||
|
assert(parent.kind == ElementKind.CLASS);
|
||||||
targetExpr = this.compileExpression(
|
targetExpr = this.compileExpression(
|
||||||
<Expression>resolved.targetExpression,
|
<Expression>resolved.targetExpression,
|
||||||
instance.instanceMethodOf.type
|
(<Class>parent).type
|
||||||
);
|
);
|
||||||
this.currentType = signature.returnType;
|
this.currentType = signature.returnType;
|
||||||
return this.compileCallDirect(instance, [], propertyAccess, targetExpr);
|
return this.compileCallDirect(instance, [], propertyAccess, targetExpr);
|
||||||
|
@ -87,10 +87,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
backlog: string[] = new Array();
|
backlog: string[] = new Array();
|
||||||
/** Log of source file names already processed. */
|
/** Log of source file names already processed. */
|
||||||
seenlog: Set<string> = new Set();
|
seenlog: Set<string> = new Set();
|
||||||
|
/** Optional handler to intercept comments while tokenizing. */
|
||||||
currentDeclareStart: i32 = 0;
|
|
||||||
currentDeclareEnd: i32 = 0;
|
|
||||||
|
|
||||||
onComment: CommentHandler | null = null;
|
onComment: CommentHandler | null = null;
|
||||||
|
|
||||||
/** Constructs a new parser. */
|
/** Constructs a new parser. */
|
||||||
@ -145,7 +142,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
/** Parses a top-level statement. */
|
/** Parses a top-level statement. */
|
||||||
parseTopLevelStatement(
|
parseTopLevelStatement(
|
||||||
tn: Tokenizer,
|
tn: Tokenizer,
|
||||||
isNamespaceMember: bool = false
|
namespace: Node | null = null
|
||||||
): Statement | null {
|
): Statement | null {
|
||||||
var flags = CommonFlags.NONE;
|
var flags = CommonFlags.NONE;
|
||||||
var startPos: i32 = -1;
|
var startPos: i32 = -1;
|
||||||
@ -188,11 +185,18 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
|
|
||||||
var declareStart: i32 = 0;
|
var declareStart: i32 = 0;
|
||||||
var declareEnd: i32 = 0;
|
var declareEnd: i32 = 0;
|
||||||
|
var contextIsAmbient = namespace != null && namespace.is(CommonFlags.AMBIENT);
|
||||||
if (tn.skip(Token.DECLARE)) {
|
if (tn.skip(Token.DECLARE)) {
|
||||||
if (startPos < 0) startPos = tn.tokenPos;
|
if (startPos < 0) startPos = tn.tokenPos;
|
||||||
flags |= CommonFlags.DECLARE;
|
if (contextIsAmbient) {
|
||||||
this.currentDeclareStart = declareStart = tn.tokenPos;
|
this.error(
|
||||||
this.currentDeclareEnd = declareEnd = tn.pos;
|
DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context,
|
||||||
|
tn.range()
|
||||||
|
); // recoverable
|
||||||
|
}
|
||||||
|
flags |= CommonFlags.DECLARE | CommonFlags.AMBIENT;
|
||||||
|
} else if (contextIsAmbient) {
|
||||||
|
flags |= CommonFlags.AMBIENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the statement
|
// parse the statement
|
||||||
@ -293,9 +297,9 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
tn.range(declareStart, declareEnd), "declare"
|
tn.range(declareStart, declareEnd), "declare"
|
||||||
); // recoverable
|
); // recoverable
|
||||||
}
|
}
|
||||||
if (!isNamespaceMember) {
|
if (!namespace) {
|
||||||
statement = this.parseStatement(tn, true);
|
statement = this.parseStatement(tn, true);
|
||||||
}
|
} // TODO: else?
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -761,7 +765,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
if (!initializer) return null;
|
if (!initializer) return null;
|
||||||
} else {
|
} else {
|
||||||
if (flags & CommonFlags.CONST) {
|
if (flags & CommonFlags.CONST) {
|
||||||
if (!(flags & CommonFlags.DECLARE)) {
|
if (!(flags & CommonFlags.AMBIENT)) {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode._const_declarations_must_be_initialized,
|
DiagnosticCode._const_declarations_must_be_initialized,
|
||||||
identifier.range
|
identifier.range
|
||||||
@ -1173,17 +1177,6 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
tn.range(signatureStart, tn.pos)
|
tn.range(signatureStart, tn.pos)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (flags & CommonFlags.DECLARE) {
|
|
||||||
if (flags & CommonFlags.AMBIENT) {
|
|
||||||
this.error(
|
|
||||||
DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context,
|
|
||||||
tn.range(this.currentDeclareStart, this.currentDeclareEnd)
|
|
||||||
); // recoverable
|
|
||||||
} else {
|
|
||||||
flags |= CommonFlags.AMBIENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: Statement | null = null;
|
var body: Statement | null = null;
|
||||||
if (tn.skip(Token.OPENBRACE)) {
|
if (tn.skip(Token.OPENBRACE)) {
|
||||||
if (flags & CommonFlags.AMBIENT) {
|
if (flags & CommonFlags.AMBIENT) {
|
||||||
@ -1393,17 +1386,6 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & CommonFlags.DECLARE) {
|
|
||||||
if (flags & CommonFlags.AMBIENT) {
|
|
||||||
this.error(
|
|
||||||
DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context,
|
|
||||||
tn.range(this.currentDeclareStart, this.currentDeclareEnd)
|
|
||||||
); // recoverable
|
|
||||||
} else {
|
|
||||||
flags |= CommonFlags.AMBIENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var members = new Array<DeclarationStatement>();
|
var members = new Array<DeclarationStatement>();
|
||||||
if (!tn.skip(Token.CLOSEBRACE)) {
|
if (!tn.skip(Token.CLOSEBRACE)) {
|
||||||
do {
|
do {
|
||||||
@ -1744,20 +1726,21 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
|
let identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
|
||||||
if (tn.skip(Token.OPENBRACE)) {
|
if (tn.skip(Token.OPENBRACE)) {
|
||||||
let members = new Array<Statement>();
|
let members = new Array<Statement>();
|
||||||
while (!tn.skip(Token.CLOSEBRACE)) {
|
let ns = Node.createNamespaceDeclaration(
|
||||||
let member = this.parseTopLevelStatement(tn, true);
|
|
||||||
if (!member) return null;
|
|
||||||
members.push(member);
|
|
||||||
}
|
|
||||||
let ret = Node.createNamespaceDeclaration(
|
|
||||||
identifier,
|
identifier,
|
||||||
members,
|
members,
|
||||||
decorators,
|
decorators,
|
||||||
flags,
|
flags,
|
||||||
tn.range(startPos, tn.pos)
|
tn.range(startPos, tn.pos)
|
||||||
);
|
);
|
||||||
|
while (!tn.skip(Token.CLOSEBRACE)) {
|
||||||
|
let member = this.parseTopLevelStatement(tn, ns);
|
||||||
|
if (!member) return null;
|
||||||
|
member.parent = ns;
|
||||||
|
members.push(member);
|
||||||
|
}
|
||||||
tn.skip(Token.SEMICOLON);
|
tn.skip(Token.SEMICOLON);
|
||||||
return ret;
|
return ns;
|
||||||
} else {
|
} else {
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode._0_expected,
|
DiagnosticCode._0_expected,
|
||||||
|
@ -579,7 +579,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
simpleName,
|
simpleName,
|
||||||
internalName,
|
internalName,
|
||||||
declaration,
|
declaration,
|
||||||
null
|
classPrototype
|
||||||
);
|
);
|
||||||
classPrototype.members.set(simpleName, prototype);
|
classPrototype.members.set(simpleName, prototype);
|
||||||
this.elementsLookup.set(internalName, prototype);
|
this.elementsLookup.set(internalName, prototype);
|
||||||
@ -1748,7 +1748,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// or inherited instance members on the cbase class while target is a class instance
|
// or inherited instance members on the base class while target is a class instance
|
||||||
} else if (target.kind == ElementKind.CLASS) {
|
} else if (target.kind == ElementKind.CLASS) {
|
||||||
if ((<Class>target).base) {
|
if ((<Class>target).base) {
|
||||||
target = <Class>(<Class>target).base;
|
target = <Class>(<Class>target).base;
|
||||||
@ -1836,11 +1836,11 @@ export class Program extends DiagnosticEmitter {
|
|||||||
case NodeKind.BINARY: { // TODO: string concatenation, mostly
|
case NodeKind.BINARY: { // TODO: string concatenation, mostly
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
case NodeKind.THIS: { // -> Class
|
case NodeKind.THIS: { // -> Class / ClassPrototype
|
||||||
let classType = contextualFunction.instanceMethodOf;
|
let parent = contextualFunction.memberOf;
|
||||||
if (classType) {
|
if (parent) {
|
||||||
if (!resolvedElement) resolvedElement = new ResolvedElement();
|
if (!resolvedElement) resolvedElement = new ResolvedElement();
|
||||||
return resolvedElement.set(classType);
|
return resolvedElement.set(parent);
|
||||||
}
|
}
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode._this_cannot_be_referenced_in_current_location,
|
DiagnosticCode._this_cannot_be_referenced_in_current_location,
|
||||||
@ -1849,10 +1849,10 @@ export class Program extends DiagnosticEmitter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case NodeKind.SUPER: { // -> Class
|
case NodeKind.SUPER: { // -> Class
|
||||||
let classType = contextualFunction.instanceMethodOf;
|
let parent = contextualFunction.memberOf;
|
||||||
if (classType && (classType = classType.base)) {
|
if (parent && parent.kind == ElementKind.CLASS && (parent = (<Class>parent).base)) {
|
||||||
if (!resolvedElement) resolvedElement = new ResolvedElement();
|
if (!resolvedElement) resolvedElement = new ResolvedElement();
|
||||||
return resolvedElement.set(classType);
|
return resolvedElement.set(parent);
|
||||||
}
|
}
|
||||||
this.error(
|
this.error(
|
||||||
DiagnosticCode._super_can_only_be_referenced_in_a_derived_class,
|
DiagnosticCode._super_can_only_be_referenced_in_a_derived_class,
|
||||||
@ -2294,6 +2294,7 @@ export class FunctionPrototype extends Element {
|
|||||||
|
|
||||||
var declaration = this.declaration;
|
var declaration = this.declaration;
|
||||||
var isInstance = this.is(CommonFlags.INSTANCE);
|
var isInstance = this.is(CommonFlags.INSTANCE);
|
||||||
|
var classPrototype = this.classPrototype;
|
||||||
|
|
||||||
// inherit contextual type arguments as provided. might be be overridden.
|
// inherit contextual type arguments as provided. might be be overridden.
|
||||||
var inheritedTypeArguments = contextualTypeArguments;
|
var inheritedTypeArguments = contextualTypeArguments;
|
||||||
@ -2310,7 +2311,8 @@ export class FunctionPrototype extends Element {
|
|||||||
// override with class type arguments if a partially resolved instance method
|
// override with class type arguments if a partially resolved instance method
|
||||||
var classTypeArguments = this.classTypeArguments;
|
var classTypeArguments = this.classTypeArguments;
|
||||||
if (classTypeArguments) { // set only if partially resolved
|
if (classTypeArguments) { // set only if partially resolved
|
||||||
let classDeclaration = (<ClassPrototype>assert(this.classPrototype)).declaration;
|
assert(this.is(CommonFlags.INSTANCE));
|
||||||
|
let classDeclaration = assert(classPrototype).declaration;
|
||||||
let classTypeParameters = classDeclaration.typeParameters;
|
let classTypeParameters = classDeclaration.typeParameters;
|
||||||
let numClassTypeParameters = classTypeParameters.length;
|
let numClassTypeParameters = classTypeParameters.length;
|
||||||
assert(numClassTypeParameters == classTypeArguments.length);
|
assert(numClassTypeParameters == classTypeArguments.length);
|
||||||
@ -2344,12 +2346,9 @@ export class FunctionPrototype extends Element {
|
|||||||
var classInstance: Class | null = null;
|
var classInstance: Class | null = null;
|
||||||
var thisType: Type | null = null;
|
var thisType: Type | null = null;
|
||||||
if (isInstance) {
|
if (isInstance) {
|
||||||
let classPrototype = assert(this.classPrototype);
|
classInstance = assert(classPrototype).resolve(classTypeArguments, contextualTypeArguments); // reports
|
||||||
classInstance = classPrototype.resolve(classTypeArguments, contextualTypeArguments); // reports
|
|
||||||
if (!classInstance) return null;
|
if (!classInstance) return null;
|
||||||
thisType = classInstance.type;
|
thisType = classInstance.type;
|
||||||
} else {
|
|
||||||
assert(!this.classPrototype);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve signature node
|
// resolve signature node
|
||||||
@ -2386,7 +2385,7 @@ export class FunctionPrototype extends Element {
|
|||||||
|
|
||||||
var internalName = this.internalName;
|
var internalName = this.internalName;
|
||||||
if (instanceKey.length) internalName += "<" + instanceKey + ">";
|
if (instanceKey.length) internalName += "<" + instanceKey + ">";
|
||||||
instance = new Function(this, internalName, signature, classInstance);
|
instance = new Function(this, internalName, signature, classInstance ? classInstance : classPrototype);
|
||||||
instance.contextualTypeArguments = contextualTypeArguments;
|
instance.contextualTypeArguments = contextualTypeArguments;
|
||||||
this.instances.set(instanceKey, instance);
|
this.instances.set(instanceKey, instance);
|
||||||
return instance;
|
return instance;
|
||||||
@ -2394,6 +2393,7 @@ export class FunctionPrototype extends Element {
|
|||||||
|
|
||||||
/** Resolves this prototype partially by applying the specified inherited class type arguments. */
|
/** Resolves this prototype partially by applying the specified inherited class type arguments. */
|
||||||
resolvePartial(classTypeArguments: Type[] | null): FunctionPrototype | null {
|
resolvePartial(classTypeArguments: Type[] | null): FunctionPrototype | null {
|
||||||
|
assert(this.is(CommonFlags.INSTANCE));
|
||||||
assert(this.classPrototype);
|
assert(this.classPrototype);
|
||||||
if (classTypeArguments && classTypeArguments.length) {
|
if (classTypeArguments && classTypeArguments.length) {
|
||||||
let partialPrototype = new FunctionPrototype(
|
let partialPrototype = new FunctionPrototype(
|
||||||
@ -2465,8 +2465,8 @@ export class Function extends Element {
|
|||||||
prototype: FunctionPrototype;
|
prototype: FunctionPrototype;
|
||||||
/** Function signature. */
|
/** Function signature. */
|
||||||
signature: Signature;
|
signature: Signature;
|
||||||
/** If an instance method, the concrete class it is a member of. */
|
/** If a member of another namespace-like element, the concrete element it is a member of. */
|
||||||
instanceMethodOf: Class | null;
|
memberOf: Element | null;
|
||||||
/** Map of locals by name. */
|
/** Map of locals by name. */
|
||||||
locals: Map<string,Local> = new Map();
|
locals: Map<string,Local> = new Map();
|
||||||
/** List of additional non-parameter locals. */
|
/** List of additional non-parameter locals. */
|
||||||
@ -2494,16 +2494,16 @@ export class Function extends Element {
|
|||||||
prototype: FunctionPrototype,
|
prototype: FunctionPrototype,
|
||||||
internalName: string,
|
internalName: string,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
instanceMethodOf: Class | null = null
|
memberOf: Element | null = null
|
||||||
) {
|
) {
|
||||||
super(prototype.program, prototype.simpleName, internalName);
|
super(prototype.program, prototype.simpleName, internalName);
|
||||||
this.prototype = prototype;
|
this.prototype = prototype;
|
||||||
this.signature = signature;
|
this.signature = signature;
|
||||||
this.instanceMethodOf = instanceMethodOf;
|
this.memberOf = memberOf;
|
||||||
this.flags = prototype.flags;
|
this.flags = prototype.flags;
|
||||||
if (!(prototype.is(CommonFlags.BUILTIN) || prototype.is(CommonFlags.DECLARE))) {
|
if (!(prototype.is(CommonFlags.BUILTIN) || prototype.is(CommonFlags.DECLARE))) {
|
||||||
let localIndex = 0;
|
let localIndex = 0;
|
||||||
if (instanceMethodOf) {
|
if (memberOf && memberOf.kind == ElementKind.CLASS) {
|
||||||
assert(this.is(CommonFlags.INSTANCE));
|
assert(this.is(CommonFlags.INSTANCE));
|
||||||
this.locals.set(
|
this.locals.set(
|
||||||
"this",
|
"this",
|
||||||
@ -2514,11 +2514,12 @@ export class Function extends Element {
|
|||||||
assert(signature.thisType)
|
assert(signature.thisType)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (instanceMethodOf.contextualTypeArguments) {
|
let contextualTypeArguments = (<Class>memberOf).contextualTypeArguments;
|
||||||
|
if (contextualTypeArguments) {
|
||||||
if (!this.contextualTypeArguments) {
|
if (!this.contextualTypeArguments) {
|
||||||
this.contextualTypeArguments = new Map();
|
this.contextualTypeArguments = new Map();
|
||||||
}
|
}
|
||||||
for (let [inheritedName, inheritedType] of instanceMethodOf.contextualTypeArguments) {
|
for (let [inheritedName, inheritedType] of contextualTypeArguments) {
|
||||||
this.contextualTypeArguments.set(inheritedName, inheritedType);
|
this.contextualTypeArguments.set(inheritedName, inheritedType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ declare const externalConstant: i32;
|
|||||||
externalFunction();
|
externalFunction();
|
||||||
assert(externalConstant == 1);
|
assert(externalConstant == 1);
|
||||||
|
|
||||||
namespace my {
|
declare namespace my {
|
||||||
export declare function externalFunction(): void;
|
function externalFunction(): void;
|
||||||
export declare const externalConstant: i32;
|
const externalConstant: i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
my.externalFunction();
|
my.externalFunction();
|
||||||
|
31
tests/compiler/static-this.optimized.wat
Normal file
31
tests/compiler/static-this.optimized.wat
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
(module
|
||||||
|
(type $i (func (result i32)))
|
||||||
|
(type $iiiiv (func (param i32 i32 i32 i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(import "env" "abort" (func $abort (param i32 i32 i32 i32)))
|
||||||
|
(global $static-this/Foo.bar (mut i32) (i32.const 42))
|
||||||
|
(memory $0 1)
|
||||||
|
(data (i32.const 4) "\0e\00\00\00s\00t\00a\00t\00i\00c\00-\00t\00h\00i\00s\00.\00t\00s")
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $static-this/Foo.getBar (; 1 ;) (type $i) (result i32)
|
||||||
|
(get_global $static-this/Foo.bar)
|
||||||
|
)
|
||||||
|
(func $start (; 2 ;) (type $v)
|
||||||
|
(if
|
||||||
|
(i32.ne
|
||||||
|
(call $static-this/Foo.getBar)
|
||||||
|
(i32.const 42)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 4)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
8
tests/compiler/static-this.ts
Normal file
8
tests/compiler/static-this.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class Foo {
|
||||||
|
static bar: i32 = 42;
|
||||||
|
static getBar(): i32 {
|
||||||
|
return this.bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Foo.getBar() == 42);
|
36
tests/compiler/static-this.untouched.wat
Normal file
36
tests/compiler/static-this.untouched.wat
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
(module
|
||||||
|
(type $i (func (result i32)))
|
||||||
|
(type $iiiiv (func (param i32 i32 i32 i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(import "env" "abort" (func $abort (param i32 i32 i32 i32)))
|
||||||
|
(global $static-this/Foo.bar (mut i32) (i32.const 42))
|
||||||
|
(global $HEAP_BASE i32 (i32.const 36))
|
||||||
|
(memory $0 1)
|
||||||
|
(data (i32.const 4) "\0e\00\00\00s\00t\00a\00t\00i\00c\00-\00t\00h\00i\00s\00.\00t\00s\00")
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $static-this/Foo.getBar (; 1 ;) (type $i) (result i32)
|
||||||
|
(return
|
||||||
|
(get_global $static-this/Foo.bar)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 2 ;) (type $v)
|
||||||
|
(if
|
||||||
|
(i32.eqz
|
||||||
|
(i32.eq
|
||||||
|
(call $static-this/Foo.getBar)
|
||||||
|
(i32.const 42)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(block
|
||||||
|
(call $abort
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 4)
|
||||||
|
(i32.const 8)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -2,10 +2,15 @@ declare namespace A {
|
|||||||
namespace B {
|
namespace B {
|
||||||
export namespace C {
|
export namespace C {
|
||||||
var aVar: i32;
|
var aVar: i32;
|
||||||
const aConst: i32 = 0;
|
const aConst: i32;
|
||||||
function aFunc(): void {}
|
const aConstInvalid: i32 = 0; // 1039: Initializers are not allowed in ambient contexts.
|
||||||
|
function aFunc(): void;
|
||||||
|
function aFuncInvalid(): void {} // 1183: An implementation cannot be declared in ambient contexts.
|
||||||
enum AnEnum {}
|
enum AnEnum {}
|
||||||
class AClass {}
|
class AClass {}
|
||||||
}
|
}
|
||||||
|
namespace D {
|
||||||
|
var aVar: i32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,17 @@ declare namespace A {
|
|||||||
namespace B {
|
namespace B {
|
||||||
export namespace C {
|
export namespace C {
|
||||||
var aVar: i32;
|
var aVar: i32;
|
||||||
const aConst: i32 = 0;
|
const aConst: i32;
|
||||||
function aFunc(): void {}
|
const aConstInvalid: i32 = 0;
|
||||||
|
function aFunc(): void;
|
||||||
|
function aFuncInvalid(): void {}
|
||||||
enum AnEnum {}
|
enum AnEnum {}
|
||||||
class AClass {}
|
class AClass {}
|
||||||
}
|
}
|
||||||
|
namespace D {
|
||||||
|
var aVar: i32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ERROR 1039: "Initializers are not allowed in ambient contexts." in namespace.ts:6:31
|
||||||
|
// ERROR 1183: "An implementation cannot be declared in ambient contexts." in namespace.ts:8:36
|
||||||
|
Loading…
x
Reference in New Issue
Block a user