1 /** 2 * This file is part of DCD, a development tool for the D programming language. 3 * Copyright (C) 2014 Brian Schott 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 module dsymbol.conversion.second; 20 21 import dsymbol.semantic; 22 import dsymbol.string_interning; 23 import dsymbol.symbol; 24 import dsymbol.scope_; 25 import dsymbol.builtin.names; 26 import dsymbol.builtin.symbols; 27 import dsymbol.type_lookup; 28 import dsymbol.deferred; 29 import dsymbol.import_; 30 import dsymbol.modulecache; 31 import containers.unrolledlist; 32 import stdx.allocator; 33 import stdx.allocator.mallocator; 34 import std.experimental.logger; 35 import dparse.ast; 36 import dparse.lexer; 37 38 void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCache cache) 39 { 40 with (CompletionKind) final switch (currentSymbol.acSymbol.kind) 41 { 42 case className: 43 case interfaceName: 44 resolveInheritance(currentSymbol.acSymbol, currentSymbol.typeLookups, 45 moduleScope, cache); 46 break; 47 case withSymbol: 48 case variableName: 49 case memberVariableName: 50 case functionName: 51 case aliasName: 52 // type may not be null in the case of a renamed import 53 if (currentSymbol.acSymbol.type is null) 54 { 55 resolveType(currentSymbol.acSymbol, currentSymbol.typeLookups, 56 moduleScope, cache); 57 } 58 break; 59 case importSymbol: 60 if (currentSymbol.acSymbol.type is null) 61 resolveImport(currentSymbol.acSymbol, currentSymbol.typeLookups, cache); 62 break; 63 case variadicTmpParam: 64 currentSymbol.acSymbol.type = variadicTmpParamSymbol; 65 break; 66 case typeTmpParam: 67 currentSymbol.acSymbol.type = typeTmpParamSymbol; 68 break; 69 case structName: 70 case unionName: 71 case enumName: 72 case keyword: 73 case enumMember: 74 case packageName: 75 case moduleName: 76 case dummy: 77 case templateName: 78 case mixinTemplateName: 79 break; 80 } 81 82 foreach (child; currentSymbol.children) 83 secondPass(child, moduleScope, cache); 84 85 // Alias this and mixin templates are resolved after child nodes are 86 // resolved so that the correct symbol information will be available. 87 with (CompletionKind) switch (currentSymbol.acSymbol.kind) 88 { 89 case className: 90 case interfaceName: 91 case structName: 92 case unionName: 93 resolveAliasThis(currentSymbol.acSymbol, currentSymbol.typeLookups, moduleScope, cache); 94 resolveMixinTemplates(currentSymbol.acSymbol, currentSymbol.typeLookups, 95 moduleScope, cache); 96 break; 97 default: 98 break; 99 } 100 } 101 102 void resolveImport(DSymbol* acSymbol, ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, 103 ref ModuleCache cache) 104 in 105 { 106 assert(acSymbol.kind == CompletionKind.importSymbol); 107 assert(acSymbol.symbolFile !is null); 108 } 109 body 110 { 111 DSymbol* moduleSymbol = cache.cacheModule(acSymbol.symbolFile); 112 if (acSymbol.qualifier == SymbolQualifier.selectiveImport) 113 { 114 if (moduleSymbol is null) 115 { 116 tryAgain: 117 DeferredSymbol* deferred = Mallocator.instance.make!DeferredSymbol(acSymbol); 118 deferred.typeLookups.insert(typeLookups[]); 119 // Get rid of the old references to the lookups, this new deferred 120 // symbol owns them now 121 typeLookups.clear(); 122 cache.deferredSymbols.insert(deferred); 123 } 124 else 125 { 126 immutable size_t breadcrumbCount = typeLookups.front.breadcrumbs.length; 127 assert(breadcrumbCount <= 2 && breadcrumbCount > 0, "Malformed selective import"); 128 129 istring symbolName = typeLookups.front.breadcrumbs.front; 130 DSymbol* selected = moduleSymbol.getFirstPartNamed(symbolName); 131 if (selected is null) 132 goto tryAgain; 133 acSymbol.type = selected; 134 acSymbol.ownType = false; 135 136 // count of 1 means selective import 137 // count of 2 means a renamed selective import 138 if (breadcrumbCount == 2) 139 { 140 acSymbol.kind = CompletionKind.aliasName; 141 acSymbol.symbolFile = acSymbol.altFile; 142 } 143 } 144 } 145 else 146 { 147 if (moduleSymbol is null) 148 { 149 DeferredSymbol* deferred = Mallocator.instance.make!DeferredSymbol(acSymbol); 150 cache.deferredSymbols.insert(deferred); 151 } 152 else 153 { 154 acSymbol.type = moduleSymbol; 155 acSymbol.ownType = false; 156 } 157 } 158 } 159 160 void resolveTypeFromType(DSymbol* symbol, TypeLookup* lookup, Scope* moduleScope, 161 ref ModuleCache cache, UnrolledList!(DSymbol*, Mallocator, false)* imports) 162 in 163 { 164 if (imports !is null) 165 foreach (i; imports.opSlice()) 166 assert(i.kind == CompletionKind.importSymbol); 167 } 168 body 169 { 170 // The left-most suffix 171 DSymbol* suffix; 172 // The right-most suffix 173 DSymbol* lastSuffix; 174 175 // Create symbols for the type suffixes such as array and 176 // associative array 177 while (!lookup.breadcrumbs.empty) 178 { 179 auto back = lookup.breadcrumbs.back; 180 immutable bool isArr = back == ARRAY_SYMBOL_NAME; 181 immutable bool isAssoc = back == ASSOC_ARRAY_SYMBOL_NAME; 182 immutable bool isFunction = back == FUNCTION_SYMBOL_NAME; 183 if (back == POINTER_SYMBOL_NAME) 184 { 185 lastSuffix.isPointer = true; 186 lookup.breadcrumbs.popBack(); 187 continue; 188 } 189 if (!isArr && !isAssoc && !isFunction) 190 break; 191 immutable qualifier = isAssoc ? SymbolQualifier.assocArray : 192 (isFunction ? SymbolQualifier.func : SymbolQualifier.array); 193 lastSuffix = cache.symbolAllocator.make!DSymbol(back, CompletionKind.dummy, lastSuffix); 194 lastSuffix.qualifier = qualifier; 195 lastSuffix.ownType = true; 196 if (isFunction) 197 { 198 lookup.breadcrumbs.popBack(); 199 lastSuffix.callTip = lookup.breadcrumbs.back(); 200 } 201 else 202 lastSuffix.addChildren(isArr ? arraySymbols[] : assocArraySymbols[], false); 203 204 if (suffix is null) 205 suffix = lastSuffix; 206 lookup.breadcrumbs.popBack(); 207 } 208 209 UnrolledList!(DSymbol*, Mallocator, false) remainingImports; 210 211 DSymbol* currentSymbol; 212 213 void getSymbolFromImports(UnrolledList!(DSymbol*, Mallocator, false)* importList, istring name) 214 { 215 foreach (im; importList.opSlice()) 216 { 217 assert(im.symbolFile !is null); 218 // Try to find a cached version of the module 219 DSymbol* moduleSymbol = cache.getModuleSymbol(im.symbolFile); 220 // If the module has not been cached yet, store it in the 221 // remaining imports list 222 if (moduleSymbol is null) 223 { 224 remainingImports.insert(im); 225 continue; 226 } 227 // Try to get the symbol from the imported module 228 currentSymbol = moduleSymbol.getFirstPartNamed(name); 229 if (currentSymbol is null) 230 continue; 231 } 232 } 233 234 // Follow all the names and try to resolve them 235 size_t i = 0; 236 foreach (part; lookup.breadcrumbs[]) 237 { 238 if (i == 0) 239 { 240 if (moduleScope is null) 241 getSymbolFromImports(imports, part); 242 else 243 { 244 auto symbols = moduleScope.getSymbolsByNameAndCursor(part, symbol.location); 245 if (symbols.length > 0) 246 currentSymbol = symbols[0]; 247 else 248 return; 249 } 250 } 251 else 252 { 253 if (currentSymbol.kind == CompletionKind.aliasName) 254 currentSymbol = currentSymbol.type; 255 if (currentSymbol is null) 256 return; 257 if (currentSymbol.kind == CompletionKind.moduleName && currentSymbol.type !is null) 258 currentSymbol = currentSymbol.type; 259 if (currentSymbol is null) 260 return; 261 if (currentSymbol.kind == CompletionKind.importSymbol) 262 currentSymbol = currentSymbol.type; 263 if (currentSymbol is null) 264 return; 265 currentSymbol = currentSymbol.getFirstPartNamed(part); 266 } 267 ++i; 268 if (currentSymbol is null) 269 return; 270 } 271 272 if (lastSuffix !is null) 273 { 274 assert(suffix !is null); 275 suffix.type = currentSymbol; 276 suffix.ownType = false; 277 symbol.type = lastSuffix; 278 symbol.ownType = true; 279 if (currentSymbol is null && !remainingImports.empty) 280 { 281 // info("Deferring type resolution for ", symbol.name); 282 auto deferred = Mallocator.instance.make!DeferredSymbol(suffix); 283 // TODO: The scope has ownership of the import information 284 deferred.imports.insert(remainingImports[]); 285 deferred.typeLookups.insert(lookup); 286 cache.deferredSymbols.insert(deferred); 287 } 288 } 289 else if (currentSymbol !is null) 290 { 291 symbol.type = currentSymbol; 292 symbol.ownType = false; 293 } 294 else if (!remainingImports.empty) 295 { 296 auto deferred = Mallocator.instance.make!DeferredSymbol(symbol); 297 // info("Deferring type resolution for ", symbol.name); 298 // TODO: The scope has ownership of the import information 299 deferred.imports.insert(remainingImports[]); 300 deferred.typeLookups.insert(lookup); 301 cache.deferredSymbols.insert(deferred); 302 } 303 } 304 305 private: 306 307 void resolveInheritance(DSymbol* symbol, ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, 308 Scope* moduleScope, ref ModuleCache cache) 309 { 310 import std.algorithm : filter; 311 312 outer: foreach (TypeLookup* lookup; typeLookups[]) 313 { 314 if (lookup.kind != TypeLookupKind.inherit) 315 continue; 316 DSymbol* baseClass; 317 assert(lookup.breadcrumbs.length > 0); 318 319 // TODO: Delayed type lookup 320 auto symbolScope = moduleScope.getScopeByCursor( 321 symbol.location + symbol.name.length); 322 auto symbols = moduleScope.getSymbolsByNameAndCursor(lookup.breadcrumbs.front, 323 symbol.location); 324 if (symbols.length == 0) 325 continue; 326 327 baseClass = symbols[0]; 328 lookup.breadcrumbs.popFront(); 329 foreach (part; lookup.breadcrumbs[]) 330 { 331 symbols = baseClass.getPartsByName(part); 332 if (symbols.length == 0) 333 continue outer; 334 baseClass = symbols[0]; 335 } 336 337 DSymbol* imp = cache.symbolAllocator.make!DSymbol(IMPORT_SYMBOL_NAME, 338 CompletionKind.importSymbol, baseClass); 339 symbol.addChild(imp, true); 340 symbolScope.addSymbol(imp, false); 341 if (baseClass.kind == CompletionKind.className) 342 { 343 auto s = cache.symbolAllocator.make!DSymbol(SUPER_SYMBOL_NAME, 344 CompletionKind.variableName, baseClass); 345 symbolScope.addSymbol(s, true); 346 } 347 } 348 } 349 350 void resolveAliasThis(DSymbol* symbol, 351 ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, Scope* moduleScope, ref ModuleCache cache) 352 { 353 import std.algorithm : filter; 354 355 foreach (aliasThis; typeLookups[].filter!(a => a.kind == TypeLookupKind.aliasThis)) 356 { 357 assert(aliasThis.breadcrumbs.length > 0); 358 auto parts = symbol.getPartsByName(aliasThis.breadcrumbs.front); 359 if (parts.length == 0 || parts[0].type is null) 360 continue; 361 DSymbol* s = cache.symbolAllocator.make!DSymbol(IMPORT_SYMBOL_NAME, 362 CompletionKind.importSymbol, parts[0].type); 363 symbol.addChild(s, true); 364 auto symbolScope = moduleScope.getScopeByCursor(s.location); 365 if (symbolScope !is null) 366 symbolScope.addSymbol(s, false); 367 } 368 } 369 370 void resolveMixinTemplates(DSymbol* symbol, 371 ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, Scope* moduleScope, ref ModuleCache cache) 372 { 373 import std.algorithm : filter; 374 375 foreach (mix; typeLookups[].filter!(a => a.kind == TypeLookupKind.mixinTemplate)) 376 { 377 assert(mix.breadcrumbs.length > 0); 378 auto symbols = moduleScope.getSymbolsByNameAndCursor(mix.breadcrumbs.front, 379 symbol.location); 380 if (symbols.length == 0) 381 continue; 382 auto currentSymbol = symbols[0]; 383 mix.breadcrumbs.popFront(); 384 foreach (m; mix.breadcrumbs[]) 385 { 386 auto s = currentSymbol.getPartsByName(m); 387 if (s.length == 0) 388 { 389 currentSymbol = null; 390 break; 391 } 392 else 393 currentSymbol = s[0]; 394 } 395 if (currentSymbol !is null) 396 { 397 auto i = cache.symbolAllocator.make!DSymbol(IMPORT_SYMBOL_NAME, 398 CompletionKind.importSymbol, currentSymbol); 399 i.ownType = false; 400 symbol.addChild(i, true); 401 } 402 } 403 } 404 405 void resolveType(DSymbol* symbol, ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, 406 Scope* moduleScope, ref ModuleCache cache) 407 { 408 409 import std.conv; 410 411 if (typeLookups.length == 0) 412 return; 413 assert(typeLookups.length == 1); 414 auto lookup = typeLookups.front; 415 if (lookup.kind == TypeLookupKind.varOrFunType) 416 resolveTypeFromType(symbol, lookup, moduleScope, cache, null); 417 else if (lookup.kind == TypeLookupKind.initializer) 418 resolveTypeFromInitializer(symbol, lookup, moduleScope, cache); 419 // issue 94 420 else if (lookup.kind == TypeLookupKind.inherit) 421 resolveInheritance(symbol, typeLookups, moduleScope, cache); 422 else 423 assert(false, "How did this happen?"); 424 } 425 426 427 void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup, 428 Scope* moduleScope, ref ModuleCache cache) 429 { 430 if (lookup.breadcrumbs.length == 0) 431 return; 432 DSymbol* currentSymbol = null; 433 size_t i = 0; 434 435 auto crumbs = lookup.breadcrumbs[]; 436 foreach (crumb; crumbs) 437 { 438 if (i == 0) 439 { 440 currentSymbol = moduleScope.getFirstSymbolByNameAndCursor( 441 symbolNameToTypeName(crumb), symbol.location); 442 443 if (currentSymbol is null) 444 return; 445 } 446 else 447 if (crumb == ARRAY_LITERAL_SYMBOL_NAME) 448 { 449 auto arr = cache.symbolAllocator.make!(DSymbol)(ARRAY_LITERAL_SYMBOL_NAME, CompletionKind.dummy, currentSymbol); 450 arr.qualifier = SymbolQualifier.array; 451 currentSymbol = arr; 452 } 453 else if (crumb == ARRAY_SYMBOL_NAME) 454 { 455 typeSwap(currentSymbol); 456 if (currentSymbol is null) 457 return; 458 459 // Index expressions can be an array index or an AA index 460 if (currentSymbol.qualifier == SymbolQualifier.array 461 || currentSymbol.qualifier == SymbolQualifier.assocArray 462 || currentSymbol.kind == CompletionKind.aliasName) 463 { 464 if (currentSymbol.type !is null) 465 currentSymbol = currentSymbol.type; 466 else 467 return; 468 } 469 else 470 { 471 auto opIndex = currentSymbol.getFirstPartNamed(internString("opIndex")); 472 if (opIndex !is null) 473 currentSymbol = opIndex.type; 474 else 475 return; 476 } 477 } 478 else if (crumb == "foreach") 479 { 480 typeSwap(currentSymbol); 481 if (currentSymbol is null) 482 return; 483 if (currentSymbol.qualifier == SymbolQualifier.array 484 || currentSymbol.qualifier == SymbolQualifier.assocArray) 485 { 486 currentSymbol = currentSymbol.type; 487 break; 488 } 489 auto front = currentSymbol.getFirstPartNamed(internString("front")); 490 if (front !is null) 491 { 492 currentSymbol = front.type; 493 break; 494 } 495 auto opApply = currentSymbol.getFirstPartNamed(internString("opApply")); 496 if (opApply !is null) 497 { 498 currentSymbol = opApply.type; 499 break; 500 } 501 } 502 else 503 { 504 typeSwap(currentSymbol); 505 if (currentSymbol is null ) 506 return; 507 currentSymbol = currentSymbol.getFirstPartNamed(crumb); 508 } 509 ++i; 510 if (currentSymbol is null) 511 return; 512 } 513 typeSwap(currentSymbol); 514 symbol.type = currentSymbol; 515 symbol.ownType = false; 516 } 517 518 void typeSwap(ref DSymbol* currentSymbol) 519 { 520 while (currentSymbol !is null && currentSymbol.type !is currentSymbol 521 && (currentSymbol.kind == CompletionKind.variableName 522 || currentSymbol.kind == CompletionKind.importSymbol 523 || currentSymbol.kind == CompletionKind.withSymbol 524 || currentSymbol.kind == CompletionKind.aliasName)) 525 currentSymbol = currentSymbol.type; 526 }