Support 'this' in static functions, fixes #45; Fix propagation of 'ambient' flag

This commit is contained in:
dcodeIO 2018-03-20 12:02:05 +01:00
parent fea8e65a41
commit 2c0ddf4f80
12 changed files with 163 additions and 86 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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);
} }
} }

View File

@ -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();

View 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)
)
)
)
)

View File

@ -0,0 +1,8 @@
class Foo {
static bar: i32 = 42;
static getBar(): i32 {
return this.bar;
}
}
assert(Foo.getBar() == 42);

View 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)
)
)
)
)

View File

@ -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;
}
} }
} }

View File

@ -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