• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
2// See LICENSE.txt in the project root for complete license information.
3
4///<reference path='typescript.ts' />
5
6module TypeScript {
7    export class Continuation {
8        public exceptionBlock = -1;
9        constructor (public normalBlock: number) { }
10    }
11
12    function getBaseTypeLinks(bases: ASTList, baseTypeLinks: TypeLink[]) {
13        if (bases) {
14            var len = bases.members.length;
15            if (baseTypeLinks == null) {
16                baseTypeLinks = new TypeLink[];
17            }
18            for (var i = 0; i < len; i++) {
19                var baseExpr = bases.members[i];
20                var name = baseExpr;
21                var typeLink = new TypeLink();
22                typeLink.ast = name;
23                baseTypeLinks[baseTypeLinks.length] = typeLink;
24            }
25        }
26        return baseTypeLinks;
27    }
28
29    function getBases(type: Type, typeDecl: TypeDeclaration) {
30        type.extendsTypeLinks = getBaseTypeLinks(typeDecl.extendsList, type.extendsTypeLinks);
31        type.implementsTypeLinks = getBaseTypeLinks(typeDecl.implementsList, type.implementsTypeLinks);
32    }
33
34    function addPrototypeField(classType: Type, ast: AST, context: TypeCollectionContext) {
35        var field = new ValueLocation();
36        field.typeLink = new TypeLink();
37        field.typeLink.ast = ast;
38        field.typeLink.type = classType.instanceType;
39
40        var fieldSymbol =
41            new FieldSymbol("prototype", ast.minChar,
42                            context.checker.locationInfo.unitIndex, true, field);
43        fieldSymbol.flags |= (SymbolFlags.Property | SymbolFlags.BuiltIn);
44        field.symbol = fieldSymbol;
45        fieldSymbol.declAST = ast;
46        classType.members.addPublicMember("prototype", fieldSymbol);
47    }
48
49    export function createNewConstructGroupForType(type: Type) {
50        var signature = new Signature();
51        signature.returnType = new TypeLink();
52        signature.returnType.type = type.instanceType;
53        signature.parameters = [];
54
55        type.construct = new SignatureGroup();
56        type.construct.addSignature(signature);
57    }
58
59    export function cloneParentConstructGroupForChildType(child: Type, parent: Type) {
60        child.construct = new SignatureGroup();
61        var sig: Signature = null;
62
63        if (!parent.construct) {
64            createNewConstructGroupForType(parent);
65        }
66
67        for (var i = 0; i < parent.construct.signatures.length; i++) {
68            sig = new Signature();
69            sig.parameters = parent.construct.signatures[i].parameters;
70            sig.nonOptionalParameterCount = parent.construct.signatures[i].nonOptionalParameterCount;
71            sig.typeCheckStatus = parent.construct.signatures[i].typeCheckStatus;
72            sig.declAST = parent.construct.signatures[i].declAST;
73            sig.returnType = new TypeLink();
74            sig.returnType.type = child.instanceType;
75            child.construct.addSignature(sig);
76        }
77
78    }
79
80    export var globalId = "__GLO";
81
82    export interface IAliasScopeContext {
83        topLevelScope: ScopeChain;
84        members: IHashTable;
85        tcContext: TypeCollectionContext;
86    }
87
88    function findTypeSymbolInScopeChain(name: string, scopeChain: ScopeChain): Symbol {
89        var symbol = scopeChain.scope.find(name, false, true);
90
91        if (symbol == null && scopeChain.previous) {
92            symbol = findTypeSymbolInScopeChain(name, scopeChain.previous);
93        }
94
95        return symbol;
96    }
97
98    function findSymbolFromAlias(alias: AST, context: IAliasScopeContext): Symbol {
99        var symbol: Symbol = null;
100        switch (alias.nodeType) {
101            case NodeType.Name:
102                var name = (<Identifier>alias).text;
103                var isDynamic = isQuoted(name);
104
105                var findSym = (id: string) => {
106                    if (context.members) {
107                        return context.members.lookup(name);
108                    }
109                    else {
110                        return findTypeSymbolInScopeChain(name, context.topLevelScope);
111                    }
112                }
113
114                if (isDynamic) {
115                    symbol = context.tcContext.checker.findSymbolForDynamicModule(name, context.tcContext.script.locationInfo.filename, findSym);
116                }
117                else {
118                    symbol = findSym(name);
119                }
120
121                break;
122
123            case NodeType.Dot:
124                var dottedExpr = <BinaryExpression>alias;
125                var op1Sym = findSymbolFromAlias(dottedExpr.operand1, context);
126
127                if (op1Sym && op1Sym.getType()) {
128                    symbol = findSymbolFromAlias(dottedExpr.operand2, context);
129                }
130
131                break;
132
133            default:
134                break;
135        }
136
137        if (symbol) {
138            var symType = symbol.getType();
139            if (symType) {
140                var members = symType.members;
141                if (members) {
142                    context.members = members.publicMembers;
143                }
144            }
145        }
146
147        return symbol;
148    }
149
150    export function preCollectImportTypes(ast: AST, parent: AST, context: TypeCollectionContext) {
151        var scopeChain = context.scopeChain;
152        var typeSymbol: TypeSymbol = null;
153        var modType: ModuleType = null;
154        var importDecl = <ImportDeclaration>ast;
155        var isExported = hasFlag(importDecl.varFlags, VarFlags.Exported);
156
157        // REVIEW: technically, this call isn't strictly necessary, since we'll find the type during the call to resolveTypeMembers
158        var aliasedModSymbol = findSymbolFromAlias(importDecl.alias, { topLevelScope: scopeChain, members: null, tcContext: context });
159        var isGlobal = context.scopeChain.container == context.checker.gloMod;
160
161        if (aliasedModSymbol) {
162            var aliasedModType = aliasedModSymbol.getType();
163
164            if (aliasedModType) {
165                modType = <ModuleType>aliasedModType;
166            }
167        }
168
169        typeSymbol = new TypeSymbol(importDecl.id.text, importDecl.minChar,
170                                    context.checker.locationInfo.unitIndex, modType);
171
172        typeSymbol.aliasLink = importDecl;
173
174        if (context.scopeChain.moduleDecl) {
175            typeSymbol.declModule = context.scopeChain.moduleDecl;
176        }
177        typeSymbol.declAST = importDecl;
178        importDecl.id.sym = typeSymbol;
179        scopeChain.scope.enter(scopeChain.container, ast, typeSymbol,
180                                context.checker.errorReporter, isExported || isGlobal, true, false);
181        scopeChain.scope.enter(scopeChain.container, ast, typeSymbol,
182                                context.checker.errorReporter, isExported || isGlobal, false, false);
183        return true;
184    }
185
186    export function preCollectModuleTypes(ast: AST, parent: AST, context: TypeCollectionContext) {
187        var scopeChain = context.scopeChain;
188
189        var moduleDecl: ModuleDeclaration = <ModuleDeclaration>ast;
190
191        var isAmbient = hasFlag(moduleDecl.modFlags, ModuleFlags.Ambient);
192        var isEnum = hasFlag(moduleDecl.modFlags, ModuleFlags.IsEnum);
193        var isGlobal = context.scopeChain.container == context.checker.gloMod;
194        var isExported = hasFlag(moduleDecl.modFlags, ModuleFlags.Exported);
195        var modName = (<Identifier>moduleDecl.name).text;
196
197        var isDynamic = isQuoted(modName);
198
199        var symbol = scopeChain.scope.findLocal(modName, false, false);
200        var typeSymbol: TypeSymbol = null;
201        var modType: ModuleType = null;
202        if ((symbol == null) || (symbol.kind() != SymbolKind.Type)) {
203
204            if (modType == null) {
205                var enclosedTypes = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
206                var ambientEnclosedTypes = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
207                modType = new ModuleType(enclosedTypes, ambientEnclosedTypes);
208                if (isEnum) {
209                    modType.typeFlags |= TypeFlags.IsEnum;
210                }
211                modType.members = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
212                modType.ambientMembers = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
213                modType.setHasImplementation();
214            }
215
216            typeSymbol = new TypeSymbol(modName, moduleDecl.minChar,
217                                        context.checker.locationInfo.unitIndex, modType);
218
219            if (context.scopeChain.moduleDecl) {
220                typeSymbol.declModule = context.scopeChain.moduleDecl;
221            }
222            typeSymbol.declAST = moduleDecl;
223            typeSymbol.prettyName = moduleDecl.prettyName;
224            scopeChain.scope.enter(scopeChain.container, ast, typeSymbol,
225                                    context.checker.errorReporter, isExported || isGlobal, true, isAmbient);
226            scopeChain.scope.enter(scopeChain.container, ast, typeSymbol,
227                                    context.checker.errorReporter, isExported || isGlobal, false, isAmbient);
228            modType.symbol = typeSymbol;
229        }
230        else {
231            if (symbol && symbol.declAST && symbol.declAST.nodeType != NodeType.ModuleDeclaration) {
232                context.checker.errorReporter.simpleError(moduleDecl, "Conflicting symbol name for module '" + modName + "'");
233            }
234            typeSymbol = <TypeSymbol>symbol;
235
236            // initialize new private scope for the type
237            var publicEnclosedTypes = typeSymbol.type.getAllEnclosedTypes().publicMembers;
238            var publicEnclosedTypesTable = (publicEnclosedTypes == null) ? new StringHashTable() : publicEnclosedTypes;
239            var enclosedTypes = new ScopedMembers(new DualStringHashTable(publicEnclosedTypesTable, new StringHashTable()));
240
241            var publicEnclosedAmbientTypes = typeSymbol.type.getAllAmbientEnclosedTypes().publicMembers;
242            var publicAmbientEnclosedTypesTable = (publicEnclosedAmbientTypes == null) ? new StringHashTable() : publicEnclosedAmbientTypes;
243            var ambientEnclosedTypes = new ScopedMembers(new DualStringHashTable(publicAmbientEnclosedTypesTable, new StringHashTable()));
244
245            var publicMembers = typeSymbol.type.members.publicMembers;
246            var publicMembersTable = (publicMembers == null) ? new StringHashTable() : publicMembers;
247            var members = new ScopedMembers(new DualStringHashTable(publicMembersTable, new StringHashTable()));
248
249            var publicAmbientMembers = typeSymbol.type.ambientMembers.publicMembers;
250            var publicAmbientMembersTable = (publicAmbientMembers == null) ? new StringHashTable() : publicAmbientMembers;
251            var ambientMembers = new ScopedMembers(new DualStringHashTable(publicAmbientMembersTable, new StringHashTable()));
252
253            modType = new ModuleType(enclosedTypes, ambientEnclosedTypes);
254            if (isEnum) {
255                modType.typeFlags |= TypeFlags.IsEnum;
256            }
257            modType.members = members;
258            modType.ambientMembers = ambientMembers;
259            modType.setHasImplementation();
260            modType.symbol = typeSymbol;
261
262            typeSymbol.addLocation(moduleDecl.minChar);
263            typeSymbol.expansions.push(modType);
264
265        }
266        if (context.scopeChain.moduleDecl) {
267            context.scopeChain.moduleDecl.recordNonInterface();
268        }
269        // REVIEW: If multiple disparate module decls for the same module don't agree
270        // in export privileges, how should we handle it?
271        if (isExported) {
272            typeSymbol.flags |= SymbolFlags.Exported;
273        }
274        if ((context.scopeChain.moduleDecl) ||
275            (context.scopeChain.container == context.checker.gloMod)) {
276            typeSymbol.flags |= SymbolFlags.ModuleMember;
277        }
278
279        moduleDecl.mod = modType;
280        pushTypeCollectionScope(typeSymbol, modType.members,
281                                modType.ambientMembers,
282                                modType.enclosedTypes,
283                                modType.ambientEnclosedTypes,
284                                context, null, null, moduleDecl);
285
286        return true;
287    }
288
289    export function preCollectClassTypes(ast: AST, parent: AST, context: TypeCollectionContext) {
290        var scopeChain = context.scopeChain;
291        var classDecl = <ClassDeclaration>ast;
292
293        var classType: Type;
294        var instanceType: Type;
295        var typeSymbol: TypeSymbol = null;
296        var className = (<Identifier>classDecl.name).text;
297        var alreadyInScope = false;
298        var isAmbient = hasFlag(classDecl.varFlags, VarFlags.Ambient);
299        var isExported = hasFlag(classDecl.varFlags, VarFlags.Exported);
300        var isGlobal = context.scopeChain.container == context.checker.gloMod;
301        var containerMod = <TypeSymbol>scopeChain.container;
302        var foundValSymbol = false;
303
304        typeSymbol = <TypeSymbol>scopeChain.scope.findLocal(className, false, true);
305
306        // check the value space, since an override may have been declared with the type's name
307        // REVIEW-CLASSES
308        if (!typeSymbol) {
309            var valTypeSymbol = scopeChain.scope.findLocal(className, false, false);
310
311            if (valTypeSymbol &&
312                valTypeSymbol.isType() &&
313                valTypeSymbol.declAST &&
314                valTypeSymbol.declAST.nodeType == NodeType.FuncDecl &&
315                (<FuncDecl>valTypeSymbol.declAST).isSignature()) {
316
317                typeSymbol = <TypeSymbol>valTypeSymbol;
318                foundValSymbol = true;
319
320                if (isExported) {
321                    typeSymbol.flags |= SymbolFlags.Exported;
322                }
323
324                if (isAmbient) {
325                    typeSymbol.flags |= SymbolFlags.Ambient;
326                }
327
328                // the class was never entered into type space, so add it
329                context.scopeChain.scope.enter(context.scopeChain.container, ast, typeSymbol,
330                                            context.checker.errorReporter, isExported || isGlobal, true, isAmbient);
331            }
332        }
333
334        if (typeSymbol && !foundValSymbol && (typeSymbol.declAST != classDecl)) {
335            typeSymbol = null;
336        }
337
338        if (typeSymbol == null) {
339            var valueSymbol = scopeChain.scope.findLocal(className, false, false);
340            classType = new Type();
341            classType.setHasImplementation();
342            instanceType = new Type();
343            instanceType.setHasImplementation();
344            classType.instanceType = instanceType;
345            classType.members = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
346            classType.ambientMembers = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
347            addPrototypeField(classType, classDecl, context);
348            instanceType.members = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
349            instanceType.ambientMembers = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
350            typeSymbol = new TypeSymbol(className, classDecl.minChar,
351                                        context.checker.locationInfo.unitIndex, classType);
352            typeSymbol.declAST = classDecl;
353            typeSymbol.instanceType = instanceType;
354            classType.symbol = typeSymbol;
355            instanceType.symbol = typeSymbol;
356
357            if (context.scopeChain.moduleDecl) {
358                context.scopeChain.moduleDecl.recordNonInterface();
359                typeSymbol.declModule = context.scopeChain.moduleDecl;
360                typeSymbol.flags |= SymbolFlags.ModuleMember;
361            }
362
363            if (isExported) {
364                typeSymbol.flags |= SymbolFlags.Exported;
365            }
366
367            if (isAmbient) {
368                typeSymbol.flags |= SymbolFlags.Ambient;
369            }
370
371            ast.type = classType;
372
373            // class in both name spaces (type for instance type; constructor representative in value space)
374            context.scopeChain.scope.enter(context.scopeChain.container, ast, typeSymbol,
375                                            context.checker.errorReporter, isExported || isGlobal, true, isAmbient);
376
377            if (valueSymbol == null) {
378                context.scopeChain.scope.enter(context.scopeChain.container, ast, typeSymbol,
379                                            context.checker.errorReporter, isExported || isGlobal, false, isAmbient);
380            }
381        }
382        else {
383            classType = typeSymbol.type;
384
385            // If the instance type is null, a call overload was likely declared before the class constructor
386            if (classType.instanceType == null) {
387                classType.instanceType = new Type();
388                classType.instanceType.setHasImplementation();
389                classType.instanceType.members = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
390                classType.instanceType.symbol = classType.symbol;
391                classType.members = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
392                classType.ambientMembers = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
393            }
394
395            instanceType = classType.instanceType;
396            ast.type = classType;
397        }
398
399        // if the class has no declared constructor, either create a default signature or adapt
400        // it's base class's signature group
401        if (!classDecl.constructorDecl) {
402
403            if (typeSymbol && typeSymbol.declAST && typeSymbol.declAST.type && typeSymbol.declAST.type.call && !(<FuncDecl>typeSymbol.declAST).isOverload) {
404                context.checker.errorReporter.duplicateIdentifier(typeSymbol.declAST, typeSymbol.name);
405            }
406
407            createNewConstructGroupForType(classDecl.type);
408        }
409
410        classType.typeFlags |= TypeFlags.IsClass;
411        instanceType.typeFlags |= TypeFlags.IsClass;
412
413        getBases(instanceType, classDecl);
414        pushTypeCollectionScope(typeSymbol, instanceType.members, instanceType.ambientMembers, null, null,
415                                context, instanceType, classType, null);
416        return true;
417    }
418
419    export function preCollectInterfaceTypes(ast: AST, parent: AST, context: TypeCollectionContext) {
420        var scopeChain = context.scopeChain;
421        var interfaceDecl = <InterfaceDeclaration>ast;
422        var interfaceSymbol: TypeSymbol = null;
423        var interfaceType: Type = null;
424        var isExported = hasFlag(interfaceDecl.varFlags, VarFlags.Exported);
425        var isGlobal = context.scopeChain.container == context.checker.gloMod;
426        var alreadyInScope = true;
427
428        alreadyInScope = false;
429        var interfaceName = (<Identifier>interfaceDecl.name).text;
430        interfaceSymbol = <TypeSymbol>scopeChain.scope.findLocal(interfaceName, false, true);
431        if (interfaceSymbol == null) {
432            interfaceType = new Type();
433            interfaceSymbol = new TypeSymbol(interfaceName,
434                                        ast.minChar,
435                                        context.checker.locationInfo.unitIndex,
436                                        interfaceType);
437            interfaceType.symbol = interfaceSymbol;
438            // REVIEW: Shouldn't allocate another table for interface privates
439            interfaceType.members = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
440            interfaceType.ambientMembers = new ScopedMembers(new DualStringHashTable(new StringHashTable(), new StringHashTable()));
441            interfaceSymbol.declAST = interfaceDecl;
442            interfaceSymbol.declModule = context.scopeChain.moduleDecl;
443        }
444        else {
445            alreadyInScope = true;
446            interfaceType = interfaceSymbol.type;
447        }
448
449        if (!interfaceType) {
450            interfaceType = context.checker.anyType;
451        }
452
453        ast.type = interfaceType;
454        getBases(interfaceType, interfaceDecl);
455
456        if (isExported) {
457            interfaceSymbol.flags |= SymbolFlags.Exported;
458        }
459
460        if (context.scopeChain.moduleDecl) {
461            interfaceSymbol.flags |= SymbolFlags.ModuleMember;
462        }
463
464        if (!alreadyInScope) {
465            context.scopeChain.scope.enter(context.scopeChain.container, ast,
466                                            interfaceSymbol, context.checker.errorReporter, isGlobal || isExported, true, false); // REVIEW: Technically, interfaces should be ambient
467        }
468        pushTypeCollectionScope(interfaceSymbol, interfaceType.members, interfaceType.ambientMembers, null, null,
469                                context, interfaceType, null, null);
470        return true;
471    }
472
473    export function preCollectArgDeclTypes(ast: AST, parent: AST, context: TypeCollectionContext) {
474        var scopeChain = context.scopeChain;
475        var argDecl = <ArgDecl>ast;
476        if (hasFlag(argDecl.varFlags, VarFlags.Public | VarFlags.Private)) {
477            var field = new ValueLocation();
478            var isPrivate = hasFlag(argDecl.varFlags, VarFlags.Private);
479            var fieldSymbol =
480                new FieldSymbol(argDecl.id.text, argDecl.minChar,
481                                context.checker.locationInfo.unitIndex,
482                                !hasFlag(argDecl.varFlags, VarFlags.Readonly),
483                                field);
484            fieldSymbol.transferVarFlags(argDecl.varFlags);
485            field.symbol = fieldSymbol;
486            fieldSymbol.declAST = ast;
487            argDecl.parameterPropertySym = fieldSymbol;
488
489            context.scopeChain.scope.enter(context.scopeChain.container, ast,
490                                            fieldSymbol, context.checker.errorReporter, !isPrivate, false, false);
491
492            field.typeLink = getTypeLink(argDecl.typeExpr, context.checker, argDecl.init == null);
493            argDecl.sym = fieldSymbol;
494        }
495        return false;
496    }
497
498    export function preCollectVarDeclTypes(ast: AST, parent: AST, context: TypeCollectionContext) {
499        var scopeChain = context.scopeChain;
500        var varDecl = <VarDecl>ast;
501        var isAmbient = hasFlag(varDecl.varFlags, VarFlags.Ambient);
502        var isExported = hasFlag(varDecl.varFlags, VarFlags.Exported);
503        var isGlobal = context.scopeChain.container == context.checker.gloMod;
504        var isProperty = hasFlag(varDecl.varFlags, VarFlags.Property);
505        var isStatic = hasFlag(varDecl.varFlags, VarFlags.Static);
506        var isPrivate = hasFlag(varDecl.varFlags, VarFlags.Private);
507        var isOptional = hasFlag(varDecl.id.flags, ASTFlags.OptionalName);
508
509        if (context.scopeChain.moduleDecl) {
510            context.scopeChain.moduleDecl.recordNonInterface();
511        }
512        if (isProperty ||
513            isExported ||
514            (context.scopeChain.container == context.checker.gloMod) ||
515            context.scopeChain.moduleDecl) {
516            if (isAmbient) {
517                var existingSym =
518                    <FieldSymbol>scopeChain.scope.findLocal(varDecl.id.text, false, false);
519                if (existingSym) {
520                    varDecl.sym = existingSym;
521                    return false;
522                }
523            }
524
525            // Defensive error detection...
526            if (varDecl.id == null) {
527                context.checker.errorReporter.simpleError(varDecl, "Expected variable identifier at this location");
528                return false;
529            }
530
531            var field = new ValueLocation();
532            var fieldSymbol =
533                new FieldSymbol(varDecl.id.text, varDecl.minChar,
534                                context.checker.locationInfo.unitIndex,
535                                (varDecl.varFlags & VarFlags.Readonly) == VarFlags.None,
536                                field);
537            fieldSymbol.transferVarFlags(varDecl.varFlags);
538            if (isOptional) {
539                fieldSymbol.flags |= SymbolFlags.Optional;
540            }
541            field.symbol = fieldSymbol;
542            fieldSymbol.declAST = ast;
543            if ((context.scopeChain.moduleDecl) ||
544                (context.scopeChain.container == context.checker.gloMod)) {
545                fieldSymbol.flags |= SymbolFlags.ModuleMember;
546                fieldSymbol.declModule = context.scopeChain.moduleDecl;
547            }
548
549            // if it's static, enter it into the class's member list directly
550            if (hasFlag(varDecl.varFlags, VarFlags.Property) && isStatic && context.scopeChain.classType) {
551                if (!context.scopeChain.classType.members.publicMembers.add(varDecl.id.text, fieldSymbol)) {
552                    context.checker.errorReporter.duplicateIdentifier(ast, fieldSymbol.name);
553                }
554                fieldSymbol.container = context.scopeChain.classType.symbol;
555            }
556            else {
557                context.scopeChain.scope.enter(context.scopeChain.container,
558                                                ast,
559                                                fieldSymbol,
560                                                context.checker.errorReporter,
561                                                !isPrivate && (isProperty || isExported || isGlobal || isStatic),
562                                                false,
563                                                isAmbient);
564            }
565
566            if (hasFlag(varDecl.varFlags, VarFlags.Exported)) {
567                fieldSymbol.flags |= SymbolFlags.Exported;
568            }
569
570            field.typeLink = getTypeLink(varDecl.typeExpr, context.checker,
571                                        varDecl.init == null);
572            varDecl.sym = fieldSymbol;
573        }
574        return false;
575    }
576
577    export function preCollectFuncDeclTypes(ast: AST, parent: AST, context: TypeCollectionContext) {
578        var scopeChain = context.scopeChain;
579
580        // REVIEW: This will have to change when we move to "export"
581        if (context.scopeChain.moduleDecl) {
582            context.scopeChain.moduleDecl.recordNonInterface();
583        }
584
585        var funcDecl = <FuncDecl>ast;
586        var fgSym: TypeSymbol = null;
587        var nameText = funcDecl.getNameText();
588        var isExported = hasFlag(funcDecl.fncFlags, FncFlags.Exported | FncFlags.ClassPropertyMethodExported);
589        var isStatic = hasFlag(funcDecl.fncFlags, FncFlags.Static);
590        var isPrivate = hasFlag(funcDecl.fncFlags, FncFlags.Private);
591        var isConstructor = funcDecl.isConstructMember() || funcDecl.isConstructor;
592        var containerSym:TypeSymbol = <TypeSymbol> (((funcDecl.isMethod() && isStatic) || funcDecl.isAccessor()) && context.scopeChain.classType ? context.scopeChain.classType.symbol : context.scopeChain.container);
593        var containerScope: SymbolScope = context.scopeChain.scope;
594        var isGlobal = containerSym == context.checker.gloMod;
595        var isOptional = funcDecl.name && hasFlag(funcDecl.name.flags, ASTFlags.OptionalName);
596        var go = false;
597        var foundSymbol = false;
598
599        // If this is a class constructor, the "container" is actually the class declaration
600        if (isConstructor && hasFlag(funcDecl.fncFlags, FncFlags.ClassMethod)) {
601            containerSym = <TypeSymbol>containerSym.container;
602            containerScope = scopeChain.previous.scope;
603        }
604
605        funcDecl.unitIndex = context.checker.locationInfo.unitIndex;
606
607        // If the parent is the constructor, and this isn't an instance method, skip it.
608        // That way, we'll set the type during scope assignment, and can be sure that the
609        // function will be placed in the constructor-local scope
610        if (!funcDecl.isConstructor &&
611            containerSym &&
612            containerSym.declAST &&
613            containerSym.declAST.nodeType == NodeType.FuncDecl &&
614            (<FuncDecl>containerSym.declAST).isConstructor &&
615            !funcDecl.isMethod()) {
616            return go;
617        }
618
619        // Interfaces and overloads
620        if (hasFlag(funcDecl.fncFlags, FncFlags.Signature)) {
621            var instType = context.scopeChain.thisType;
622
623            // If the function is static, search in the class type's
624            if (nameText && nameText != "__missing") {
625                if (isStatic) {
626                    fgSym = containerSym.type.members.allMembers.lookup(nameText);
627                }
628                else {
629                    // REVIEW: This logic should be symmetric with preCollectClassTypes
630                    fgSym = <TypeSymbol>containerScope.findLocal(nameText, false, false);
631
632                    // If we could not find the function symbol in the value context, look
633                    // in the type context.
634                    // This would be the case, for example, if a class constructor override
635                    // were declared before a call override for a given class
636                    if (fgSym == null) {
637                        fgSym = <TypeSymbol>containerScope.findLocal(nameText, false, true);
638                    }
639                }
640
641                if (fgSym) {
642                    foundSymbol = true;
643
644                    // We'll combine ambient and non-ambient funcdecls during typecheck (for contextual typing).,
645                    // So, if they don't agree, don't use the symbol we've found
646                    if (!funcDecl.isSignature() && (hasFlag(funcDecl.fncFlags, FncFlags.Ambient) != hasFlag(fgSym.flags, SymbolFlags.Ambient))) {
647                       fgSym = null;
648                    }
649                }
650            }
651
652            // a function with this symbol has not yet been declared in this scope
653            // REVIEW: In the code below, we need to ensure that only function overloads are considered
654            //  (E.g., if a vardecl has the same id as a function or class, we may use the vardecl symbol
655            //  as the overload.)  Defensively, however, the vardecl won't have a type yet, so it should
656            //  suffice to just check for a null type when considering the overload symbol in
657            //  createFunctionSignature
658            if (fgSym == null) {
659                if (!(funcDecl.isSpecialFn())) {
660                    fgSym = context.checker.createFunctionSignature(funcDecl, containerSym, containerScope, null, !foundSymbol).declAST.type.symbol;
661                }
662                else {
663                    fgSym = context.checker.createFunctionSignature(funcDecl, containerSym, containerScope, containerSym, false).declAST.type.symbol;
664                }
665
666                // set the symbol's declAST, which will point back to the first declaration (symbol or otherwise)
667                // related to this symbol
668                if (fgSym.declAST == null || !funcDecl.isSpecialFn()) {
669                    fgSym.declAST = ast;
670                }
671            }
672            else { // there exists a symbol with this name
673
674                if ((fgSym.kind() == SymbolKind.Type)) {
675
676                    fgSym = context.checker.createFunctionSignature(funcDecl, containerSym, containerScope, fgSym, false).declAST.type.symbol;
677                }
678                else {
679                    context.checker.errorReporter.simpleError(funcDecl, "Function or method '" + funcDecl.name.actualText + "' already declared as a property");
680                }
681            }
682
683            if (funcDecl.isSpecialFn() && !isStatic) {
684                funcDecl.type = instType ? instType : fgSym.type;
685            }
686            else {
687                funcDecl.type = fgSym.type;
688            }
689        }
690        else {
691            // declarations
692
693            if (nameText) {
694                if (isStatic) {
695                    fgSym = containerSym.type.members.allMembers.lookup(nameText);
696                }
697                else {
698                    // in the constructor case, we want to check the parent scope for overloads
699                    if (funcDecl.isConstructor && context.scopeChain.previous) {
700                        fgSym = <TypeSymbol>context.scopeChain.previous.scope.findLocal(nameText, false, false);
701                    }
702
703                    if (fgSym == null) {
704                        fgSym = <TypeSymbol>containerScope.findLocal(nameText, false, false);
705                    }
706                }
707                if (fgSym) {
708                    foundSymbol = true;
709
710                    if (!isConstructor && fgSym.declAST.nodeType == NodeType.FuncDecl && !(<FuncDecl>fgSym.declAST).isAccessor() && !(<FuncDecl>fgSym.declAST).isSignature()) {
711                        fgSym = null;
712                        foundSymbol = false;
713                    }
714                }
715            }
716
717            // REVIEW: Move this check into the typecheck phase?  It's only being run over properties...
718            if (fgSym &&
719                !fgSym.isAccessor() &&
720                fgSym.type &&
721                fgSym.type.construct &&
722                fgSym.type.construct.signatures != [] &&
723                (fgSym.type.construct.signatures[0].declAST == null ||
724                    !hasFlag(fgSym.type.construct.signatures[0].declAST.fncFlags, FncFlags.Ambient)) &&
725                !funcDecl.isConstructor) {
726                context.checker.errorReporter.simpleError(funcDecl, "Functions may not have class overloads");
727            }
728
729            if (fgSym && !(fgSym.kind() == SymbolKind.Type) && funcDecl.isMethod() && !funcDecl.isAccessor() && !funcDecl.isConstructor) {
730                context.checker.errorReporter.simpleError(funcDecl, "Function or method '" + funcDecl.name.actualText + "' already declared as a property");
731                fgSym.type = context.checker.anyType;
732            }
733            var sig = context.checker.createFunctionSignature(funcDecl, containerSym, containerScope, fgSym, !foundSymbol);
734
735            // it's a getter or setter function
736            if (((!fgSym || fgSym.declAST.nodeType != NodeType.FuncDecl) && funcDecl.isAccessor()) || (fgSym && fgSym.isAccessor())) {
737                funcDecl.accessorSymbol = context.checker.createAccessorSymbol(funcDecl, fgSym, containerSym.type, (funcDecl.isMethod() && isStatic), true, containerScope, containerSym);
738            }
739
740            funcDecl.type.symbol.declAST = ast;
741            if (funcDecl.isConstructor) { // REVIEW: Remove when classes completely replace oldclass
742                go = true;
743            };
744        }
745        if (isExported) {
746            if (funcDecl.type.call) {
747                funcDecl.type.symbol.flags |= SymbolFlags.Exported;
748            }
749
750            // Accessors are set to 'exported' above
751            if (fgSym && !fgSym.isAccessor() && fgSym.kind() == SymbolKind.Type && fgSym.type.call) {
752                fgSym.flags |= SymbolFlags.Exported;
753            }
754        }
755        if (context.scopeChain.moduleDecl && !funcDecl.isSpecialFn()) {
756            funcDecl.type.symbol.flags |= SymbolFlags.ModuleMember;
757            funcDecl.type.symbol.declModule = context.scopeChain.moduleDecl;
758        }
759
760        if (fgSym && isOptional) {
761            fgSym.flags |= SymbolFlags.Optional;
762        }
763
764        return go;
765    }
766
767    export function preCollectTypes(ast: AST, parent: AST, walker: IAstWalker) {
768        var context: TypeCollectionContext = walker.state;
769        var go = false;
770        var scopeChain = context.scopeChain;
771
772        if (ast.nodeType == NodeType.Script) {
773            var script: Script = <Script>ast;
774            context.script = script;
775            go = true;
776        }
777        else if (ast.nodeType == NodeType.List) {
778            go = true;
779        }
780        else if (ast.nodeType == NodeType.ImportDeclaration) {
781            go = preCollectImportTypes(ast, parent, context);
782        }
783        else if (ast.nodeType == NodeType.With) {
784            go = false;
785        }
786        else if (ast.nodeType == NodeType.ModuleDeclaration) {
787            go = preCollectModuleTypes(ast, parent, context);
788        }
789        else if (ast.nodeType == NodeType.ClassDeclaration) {
790            go = preCollectClassTypes(ast, parent, context);
791        }
792        else if (ast.nodeType == NodeType.Block) {
793            go = true;
794        }
795        else if (ast.nodeType == NodeType.InterfaceDeclaration) {
796            go = preCollectInterfaceTypes(ast, parent, context);
797        }
798        // This will be a constructor arg because this pass only traverses
799        // constructor arg lists
800        else if (ast.nodeType == NodeType.ArgDecl) {
801            go = preCollectArgDeclTypes(ast, parent, context);
802        }
803        else if (ast.nodeType == NodeType.VarDecl) {
804            go = preCollectVarDeclTypes(ast, parent, context);
805        }
806        else if (ast.nodeType == NodeType.FuncDecl) {
807            go = preCollectFuncDeclTypes(ast, parent, context);
808        }
809        else {
810            if (ast.isStatementOrExpression() && context.scopeChain.moduleDecl) {
811                context.scopeChain.moduleDecl.recordNonInterface();
812            }
813        }
814        walker.options.goChildren = go;
815        return ast;
816    }
817
818    export function postCollectTypes(ast: AST, parent: AST, walker: IAstWalker) {
819        var context: TypeCollectionContext = walker.state;
820
821        if (ast.nodeType == NodeType.ModuleDeclaration) {
822            popTypeCollectionScope(context);
823        }
824        else if (ast.nodeType == NodeType.ClassDeclaration) {
825            popTypeCollectionScope(context);
826        }
827        else if (ast.nodeType == NodeType.InterfaceDeclaration) {
828            popTypeCollectionScope(context);
829        }
830        return ast;
831    }
832
833}