1//// [parserRealSource9.ts] 2// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. 3// See LICENSE.txt in the project root for complete license information. 4 5///<reference path='typescript.ts' /> 6 7module TypeScript { 8 export class Binder { 9 constructor (public checker: TypeChecker) { } 10 public resolveBaseTypeLinks(typeLinks: TypeLink[], scope: SymbolScope) { 11 var extendsList: Type[] = null; 12 if (typeLinks) { 13 extendsList = new Type[]; 14 for (var i = 0, len = typeLinks.length; i < len; i++) { 15 var typeLink = typeLinks[i]; 16 this.checker.resolvingBases = true; 17 this.checker.resolveTypeLink(scope, typeLink, true); 18 this.checker.resolvingBases = false; 19 if (typeLink.type.isClass()) { 20 extendsList[i] = typeLink.type.instanceType; 21 } 22 else { 23 extendsList[i] = typeLink.type; 24 } 25 } 26 } 27 return extendsList; 28 } 29 30 public resolveBases(scope: SymbolScope, type: Type) { 31 type.extendsList = this.resolveBaseTypeLinks(type.extendsTypeLinks, scope); 32 33 var i = 0, len = type.extendsList.length; 34 var derivedIsClass = type.isClassInstance(); 35 for (; i < len; i++) { 36 var baseIsClass = type.extendsList[i].isClassInstance(); 37 if (type.extendsList[i] != this.checker.anyType) { 38 if (derivedIsClass) { 39 if (!baseIsClass) { 40 this.checker.errorReporter.simpleErrorFromSym(type.symbol, 41 "A export class may only extend other classes, " + type.extendsList[i].symbol.fullName() + " is an interface."); 42 } 43 } 44 else { 45 if (baseIsClass) { 46 this.checker.errorReporter.simpleErrorFromSym(type.symbol, 47 "An interface may only extend other interfaces, " + type.extendsList[i].symbol.fullName() + " is a class."); 48 } 49 } 50 } 51 } 52 53 type.implementsList = this.resolveBaseTypeLinks(type.implementsTypeLinks, scope); 54 55 if (type.implementsList) { 56 for (i = 0, len = type.implementsList.length; i < len; i++) { 57 var iface = type.implementsList[i]; 58 if (iface.isClassInstance()) { 59 if (derivedIsClass) { 60 this.checker.errorReporter.simpleErrorFromSym(type.symbol, 61 "A class may only implement an interface; " + iface.symbol.fullName() + " is a class."); 62 } 63 } 64 } 65 } 66 } 67 68 public resolveSignatureGroup(signatureGroup: SignatureGroup, scope: SymbolScope, instanceType: Type) { 69 var supplyVar = !(signatureGroup.hasImplementation); 70 for (var i = 0, len = signatureGroup.signatures.length; i < len; i++) { 71 var signature = signatureGroup.signatures[i]; 72 if (instanceType) { 73 signature.returnType.type = instanceType; 74 } 75 else { 76 this.checker.resolveTypeLink(scope, signature.returnType, supplyVar); 77 } 78 var paramLen = signature.parameters.length; 79 for (var j = 0; j < paramLen; j++) { 80 this.bindSymbol(scope, signature.parameters[j]); 81 } 82 if (signature.hasVariableArgList) { 83 // check that last parameter has an array type 84 var lastParam = <ParameterSymbol>signature.parameters[paramLen - 1]; 85 lastParam.argsOffset = paramLen - 1; 86 if (!lastParam.getType().isArray()) { 87 this.checker.errorReporter.simpleErrorFromSym(lastParam, 88 "... parameter must have array type"); 89 lastParam.parameter.typeLink.type = this.checker.makeArrayType(lastParam.parameter.typeLink.type); 90 } 91 } 92 } 93 } 94 95 public bindType(scope: SymbolScope, type: Type, instanceType: Type): void { 96 if (instanceType) { 97 this.bindType(scope, instanceType, null); 98 } 99 if (type.hasMembers()) { 100 var members = type.members; 101 var ambientMembers = type.ambientMembers; 102 var typeMembers = type.getAllEnclosedTypes(); // REVIEW: Should only be getting exported types? 103 var ambientTypeMembers = type.getAllAmbientEnclosedTypes(); // REVIEW: Should only be getting exported types? 104 var memberScope = new SymbolTableScope(members, ambientMembers, typeMembers, ambientTypeMembers, type.symbol); 105 var agg = new SymbolAggregateScope(type.symbol); 106 var prevCurrentModDecl = this.checker.currentModDecl; 107 var prevBindStatus = this.checker.inBind; 108 agg.addParentScope(memberScope); 109 agg.addParentScope(scope); 110 if (type.isModuleType()) { 111 this.checker.currentModDecl = <ModuleDeclaration>type.symbol.declAST; 112 this.checker.inBind = true; 113 } 114 if (members) { 115 this.bind(agg, type.members.allMembers); // REVIEW: Should only be getting exported types? 116 } 117 if (typeMembers) { 118 this.bind(agg, typeMembers.allMembers); 119 } 120 if (ambientMembers) { 121 this.bind(agg, ambientMembers.allMembers); 122 } 123 if (ambientTypeMembers) { 124 this.bind(agg, ambientTypeMembers.allMembers); 125 } 126 this.checker.currentModDecl = prevCurrentModDecl; 127 this.checker.inBind = prevBindStatus; 128 } 129 if (type.extendsTypeLinks) { 130 this.resolveBases(scope, type); 131 } 132 if (type.construct) { 133 this.resolveSignatureGroup(type.construct, scope, instanceType); 134 } 135 if (type.call) { 136 this.resolveSignatureGroup(type.call, scope, null); 137 } 138 if (type.index) { 139 this.resolveSignatureGroup(type.index, scope, null); 140 } 141 if (type.elementType) { 142 this.bindType(scope, type.elementType, null); 143 } 144 } 145 146 public bindSymbol(scope: SymbolScope, symbol: Symbol) { 147 if (!symbol.bound) { 148 var prevLocationInfo = this.checker.locationInfo; 149 if ((this.checker.units) && (symbol.unitIndex >= 0) && (symbol.unitIndex < this.checker.units.length)) { 150 this.checker.locationInfo = this.checker.units[symbol.unitIndex]; 151 } 152 switch (symbol.kind()) { 153 case SymbolKind.Type: 154 155 if (symbol.flags & SymbolFlags.Bound) { 156 break; 157 } 158 159 var typeSymbol = <TypeSymbol>symbol; 160 typeSymbol.flags |= SymbolFlags.Bound; 161 162 // Since type collection happens out of order, a dynamic module referenced by an import statement 163 // may not yet be in scope when the import symbol is created. In that case, we need to search 164 // out the module symbol now 165 // Note that we'll also want to do this in resolveTypeMembers, in case the symbol is set outside the 166 // context of a given module (E.g., an outer import statement) 167 if (typeSymbol.aliasLink && !typeSymbol.type && typeSymbol.aliasLink.alias.nodeType == NodeType.Name) { 168 var modPath = (<Identifier>typeSymbol.aliasLink.alias).text; 169 var modSym = this.checker.findSymbolForDynamicModule(modPath, this.checker.locationInfo.filename, (id) => scope.find(id, false, true)); 170 if (modSym) { 171 typeSymbol.type = modSym.getType(); 172 } 173 } 174 175 if (typeSymbol.type && typeSymbol.type != this.checker.gloModType) { 176 this.bindType(scope, typeSymbol.type, typeSymbol.instanceType); 177 178 // bind expansions on the parent type symbol 179 if (typeSymbol.type.isModuleType()) { 180 for (var i = 0; i < typeSymbol.expansions.length; i++) { 181 this.bindType(scope, typeSymbol.expansions[i], typeSymbol.instanceType); 182 } 183 } 184 } 185 break; 186 case SymbolKind.Field: 187 this.checker.resolveTypeLink(scope, (<FieldSymbol>symbol).field.typeLink, 188 false); 189 break; 190 case SymbolKind.Parameter: 191 this.checker.resolveTypeLink(scope, 192 (<ParameterSymbol>symbol).parameter.typeLink, 193 true); 194 break; 195 } 196 this.checker.locationInfo = prevLocationInfo; 197 } 198 symbol.bound = true; 199 } 200 201 public bind(scope: SymbolScope, table: IHashTable) { 202 table.map( 203 (key, sym, binder) => { 204 binder.bindSymbol(scope, sym); 205 }, 206 this); 207 } 208 } 209 210} 211 212//// [parserRealSource9.js] 213// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. 214// See LICENSE.txt in the project root for complete license information. 215///<reference path='typescript.ts' /> 216var TypeScript; 217(function (TypeScript) { 218 var Binder = /** @class */ (function () { 219 function Binder(checker) { 220 this.checker = checker; 221 } 222 Binder.prototype.resolveBaseTypeLinks = function (typeLinks, scope) { 223 var extendsList = null; 224 if (typeLinks) { 225 extendsList = new Type[]; 226 for (var i = 0, len = typeLinks.length; i < len; i++) { 227 var typeLink = typeLinks[i]; 228 this.checker.resolvingBases = true; 229 this.checker.resolveTypeLink(scope, typeLink, true); 230 this.checker.resolvingBases = false; 231 if (typeLink.type.isClass()) { 232 extendsList[i] = typeLink.type.instanceType; 233 } 234 else { 235 extendsList[i] = typeLink.type; 236 } 237 } 238 } 239 return extendsList; 240 }; 241 Binder.prototype.resolveBases = function (scope, type) { 242 type.extendsList = this.resolveBaseTypeLinks(type.extendsTypeLinks, scope); 243 var i = 0, len = type.extendsList.length; 244 var derivedIsClass = type.isClassInstance(); 245 for (; i < len; i++) { 246 var baseIsClass = type.extendsList[i].isClassInstance(); 247 if (type.extendsList[i] != this.checker.anyType) { 248 if (derivedIsClass) { 249 if (!baseIsClass) { 250 this.checker.errorReporter.simpleErrorFromSym(type.symbol, "A export class may only extend other classes, " + type.extendsList[i].symbol.fullName() + " is an interface."); 251 } 252 } 253 else { 254 if (baseIsClass) { 255 this.checker.errorReporter.simpleErrorFromSym(type.symbol, "An interface may only extend other interfaces, " + type.extendsList[i].symbol.fullName() + " is a class."); 256 } 257 } 258 } 259 } 260 type.implementsList = this.resolveBaseTypeLinks(type.implementsTypeLinks, scope); 261 if (type.implementsList) { 262 for (i = 0, len = type.implementsList.length; i < len; i++) { 263 var iface = type.implementsList[i]; 264 if (iface.isClassInstance()) { 265 if (derivedIsClass) { 266 this.checker.errorReporter.simpleErrorFromSym(type.symbol, "A class may only implement an interface; " + iface.symbol.fullName() + " is a class."); 267 } 268 } 269 } 270 } 271 }; 272 Binder.prototype.resolveSignatureGroup = function (signatureGroup, scope, instanceType) { 273 var supplyVar = !(signatureGroup.hasImplementation); 274 for (var i = 0, len = signatureGroup.signatures.length; i < len; i++) { 275 var signature = signatureGroup.signatures[i]; 276 if (instanceType) { 277 signature.returnType.type = instanceType; 278 } 279 else { 280 this.checker.resolveTypeLink(scope, signature.returnType, supplyVar); 281 } 282 var paramLen = signature.parameters.length; 283 for (var j = 0; j < paramLen; j++) { 284 this.bindSymbol(scope, signature.parameters[j]); 285 } 286 if (signature.hasVariableArgList) { 287 // check that last parameter has an array type 288 var lastParam = signature.parameters[paramLen - 1]; 289 lastParam.argsOffset = paramLen - 1; 290 if (!lastParam.getType().isArray()) { 291 this.checker.errorReporter.simpleErrorFromSym(lastParam, "... parameter must have array type"); 292 lastParam.parameter.typeLink.type = this.checker.makeArrayType(lastParam.parameter.typeLink.type); 293 } 294 } 295 } 296 }; 297 Binder.prototype.bindType = function (scope, type, instanceType) { 298 if (instanceType) { 299 this.bindType(scope, instanceType, null); 300 } 301 if (type.hasMembers()) { 302 var members = type.members; 303 var ambientMembers = type.ambientMembers; 304 var typeMembers = type.getAllEnclosedTypes(); // REVIEW: Should only be getting exported types? 305 var ambientTypeMembers = type.getAllAmbientEnclosedTypes(); // REVIEW: Should only be getting exported types? 306 var memberScope = new SymbolTableScope(members, ambientMembers, typeMembers, ambientTypeMembers, type.symbol); 307 var agg = new SymbolAggregateScope(type.symbol); 308 var prevCurrentModDecl = this.checker.currentModDecl; 309 var prevBindStatus = this.checker.inBind; 310 agg.addParentScope(memberScope); 311 agg.addParentScope(scope); 312 if (type.isModuleType()) { 313 this.checker.currentModDecl = type.symbol.declAST; 314 this.checker.inBind = true; 315 } 316 if (members) { 317 this.bind(agg, type.members.allMembers); // REVIEW: Should only be getting exported types? 318 } 319 if (typeMembers) { 320 this.bind(agg, typeMembers.allMembers); 321 } 322 if (ambientMembers) { 323 this.bind(agg, ambientMembers.allMembers); 324 } 325 if (ambientTypeMembers) { 326 this.bind(agg, ambientTypeMembers.allMembers); 327 } 328 this.checker.currentModDecl = prevCurrentModDecl; 329 this.checker.inBind = prevBindStatus; 330 } 331 if (type.extendsTypeLinks) { 332 this.resolveBases(scope, type); 333 } 334 if (type.construct) { 335 this.resolveSignatureGroup(type.construct, scope, instanceType); 336 } 337 if (type.call) { 338 this.resolveSignatureGroup(type.call, scope, null); 339 } 340 if (type.index) { 341 this.resolveSignatureGroup(type.index, scope, null); 342 } 343 if (type.elementType) { 344 this.bindType(scope, type.elementType, null); 345 } 346 }; 347 Binder.prototype.bindSymbol = function (scope, symbol) { 348 if (!symbol.bound) { 349 var prevLocationInfo = this.checker.locationInfo; 350 if ((this.checker.units) && (symbol.unitIndex >= 0) && (symbol.unitIndex < this.checker.units.length)) { 351 this.checker.locationInfo = this.checker.units[symbol.unitIndex]; 352 } 353 switch (symbol.kind()) { 354 case SymbolKind.Type: 355 if (symbol.flags & SymbolFlags.Bound) { 356 break; 357 } 358 var typeSymbol = symbol; 359 typeSymbol.flags |= SymbolFlags.Bound; 360 // Since type collection happens out of order, a dynamic module referenced by an import statement 361 // may not yet be in scope when the import symbol is created. In that case, we need to search 362 // out the module symbol now 363 // Note that we'll also want to do this in resolveTypeMembers, in case the symbol is set outside the 364 // context of a given module (E.g., an outer import statement) 365 if (typeSymbol.aliasLink && !typeSymbol.type && typeSymbol.aliasLink.alias.nodeType == NodeType.Name) { 366 var modPath = typeSymbol.aliasLink.alias.text; 367 var modSym = this.checker.findSymbolForDynamicModule(modPath, this.checker.locationInfo.filename, function (id) { return scope.find(id, false, true); }); 368 if (modSym) { 369 typeSymbol.type = modSym.getType(); 370 } 371 } 372 if (typeSymbol.type && typeSymbol.type != this.checker.gloModType) { 373 this.bindType(scope, typeSymbol.type, typeSymbol.instanceType); 374 // bind expansions on the parent type symbol 375 if (typeSymbol.type.isModuleType()) { 376 for (var i = 0; i < typeSymbol.expansions.length; i++) { 377 this.bindType(scope, typeSymbol.expansions[i], typeSymbol.instanceType); 378 } 379 } 380 } 381 break; 382 case SymbolKind.Field: 383 this.checker.resolveTypeLink(scope, symbol.field.typeLink, false); 384 break; 385 case SymbolKind.Parameter: 386 this.checker.resolveTypeLink(scope, symbol.parameter.typeLink, true); 387 break; 388 } 389 this.checker.locationInfo = prevLocationInfo; 390 } 391 symbol.bound = true; 392 }; 393 Binder.prototype.bind = function (scope, table) { 394 table.map(function (key, sym, binder) { 395 binder.bindSymbol(scope, sym); 396 }, this); 397 }; 398 return Binder; 399 }()); 400 TypeScript.Binder = Binder; 401})(TypeScript || (TypeScript = {})); 402