Joos1W Compiler Framework
All Classes Functions Typedefs Pages
NameResolver.cc
1 #include "semantic/NameResolver.h"
2 
3 #include <utils/Assert.h>
4 
5 #include <iostream>
6 #include <memory_resource>
7 #include <string>
8 #include <string_view>
9 #include <unordered_map>
10 #include <variant>
11 #include <vector>
12 
13 #include "ast/AstNode.h"
14 #include "ast/DeclContext.h"
15 #include "ast/Type.h"
16 #include "diagnostics/Location.h"
17 #include "semantic/Semantic.h"
18 #include "utils/BumpAllocator.h"
19 
20 using ast::Decl;
21 using ast::UnresolvedType;
22 using std::string_view;
23 using std::pmr::string;
24 using std::pmr::unordered_map;
25 using std::pmr::vector;
26 
27 namespace semantic {
28 
29 static const std::pmr::string UNNAMED_PACKAGE{""};
30 
31 void NameResolver::buildSymbolTable() {
32  rootPkg_ = alloc.new_object<Pkg>(alloc);
33  // Add the unnamed package to the root package.
34  rootPkg_->children[UNNAMED_PACKAGE] = alloc.new_object<Pkg>(alloc);
35  // Grab the package type from the compilation unit.
36  for(auto cu : lu_->compliationUnits()) {
37  // Grab the CU's package and mark it as immutable
38  // Package should be an unresolved type
39  auto pkg = cast<UnresolvedType>(cu->package());
40  pkg->lock();
41  // Traverse the package name to find the leaf package.
42  Pkg* subPkg = rootPkg_;
43  for(auto const& id : pkg->parts()) {
44  // If the subpackage name is not in the symbol table, add it
45  // and continue to the next one.
46  if(subPkg->children.find(id) == subPkg->children.end()) {
47  auto newpkg = alloc.new_object<Pkg>(alloc, string_view{id});
48  subPkg->children[id] = newpkg;
49  subPkg = newpkg;
50  continue;
51  }
52  // If the subpackage does not hold a package, then it must be a
53  // a decl with the same name as the package. This is an error.
54  // cf. JLS 6.4.1.
55  Pkg::Child const& child = subPkg->children[id];
56  if(std::holds_alternative<Decl*>(child)) {
57  auto decl = std::get<Decl*>(child);
58  assert(decl && "Package node holds empty decl");
59  diag.ReportError(cu->location())
60  << "subpackage name cannot be the same as a declaration: " << id;
61  continue;
62  }
63  // Otherwise, we can traverse into the next subpackage.
64  subPkg = std::get<Pkg*>(child);
65  }
66  if(cu->isDefaultPackage()) {
67  subPkg = std::get<Pkg*>(rootPkg_->children[UNNAMED_PACKAGE]);
68  }
69  // If the CU has no body, then we can skip to the next CU.
70  if(!cu->body()) continue;
71  // Check that the declaration is unique, cf. JLS 6.4.1.
72  if(subPkg->children.find(cu->bodyAsDecl()->name().data()) !=
73  subPkg->children.end()) {
74  diag.ReportError(cu->bodyAsDecl()->location())
75  << "declaration name is not unique in the subpackage.";
76  }
77  // Now add the CU's declaration to the subpackage.
78  subPkg->children[cu->bodyAsDecl()->name().data()] = cu->mut_bodyAsDecl();
79  }
80  if(diag.Verbose(2)) {
81  // Put the string on the heap so we can print it out.
82  diag.ReportDebug(2) << "Symbol table built!";
83  rootPkg_->print(diag.ReportDebug(2).get(), 0);
84  }
85 }
86 
87 void NameResolver::populateJavaLangCache() {
88  // Resolve java.lang. into Pkg*
89  auto javaPkg = std::get<Pkg*>(rootPkg_->children["java"]);
90  auto langPkg = std::get<Pkg*>(javaPkg->children["lang"]);
91  auto ioPkg = std::get<Pkg*>(javaPkg->children["io"]);
92  // Now we can populate the java.lang.* cache
93  // FIXME(kevin): Implement better error handling here?
94  java_lang_.Boolean =
95  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Boolean"]));
96  java_lang_.Byte =
97  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Byte"]));
98  java_lang_.Character =
99  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Character"]));
100  java_lang_.Class =
101  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Class"]));
102  java_lang_.Cloneable = cast<ast::InterfaceDecl*>(
103  std::get<Decl*>(langPkg->children["Cloneable"]));
104  java_lang_.Integer =
105  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Integer"]));
106  java_lang_.Number =
107  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Number"]));
108  java_lang_.Object =
109  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Object"]));
110  java_lang_.Short =
111  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["Short"]));
112  java_lang_.String =
113  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["String"]));
114  java_lang_.System =
115  cast<ast::ClassDecl>(std::get<Decl*>(langPkg->children["System"]));
116  java_lang_.Serializable = cast<ast::InterfaceDecl>(
117  std::get<Decl*>(ioPkg->children["Serializable"]));
118  // Make sure they are all non-null
119  assert(java_lang_.Boolean && "java.lang.Boolean not valid (expected class)");
120  assert(java_lang_.Byte && "java.lang.Byte not valid (expected class)");
121  assert(java_lang_.Character &&
122  "java.lang.Character not valid (expected class)");
123  assert(java_lang_.Class && "java.lang.Class not valid (expected class)");
124  assert(java_lang_.Cloneable &&
125  "java.lang.Cloneable not valid (expected interface)");
126  assert(java_lang_.Integer && "java.lang.Integer not valid (expected class)");
127  assert(java_lang_.Number && "java.lang.Number not valid (expected class)");
128  assert(java_lang_.Object && "java.lang.Object not valid (expected class)");
129  assert(java_lang_.Short && "java.lang.Short not valid (expected class)");
130  assert(java_lang_.String && "java.lang.String not valid (expected class)");
131  assert(java_lang_.System && "java.lang.System not valid (expected class)");
132 
133  // Build the Java array prototype class
134  {
135  using namespace ast;
136  std::pmr::vector<ReferenceType*> interfaces{alloc};
137  std::pmr::vector<Decl*> body{alloc};
138  std::pmr::vector<VarDecl*> emptyParams{alloc};
139  std::pmr::vector<ImportDeclaration> emptyImports{alloc};
140  Modifiers lengthMod{};
141  lengthMod.set(ast::Modifiers::Type::Public);
142  // FIXME(kevin): Is this really static?
143  // lengthMod.set(ast::Modifiers::Type::Static);
144  lengthMod.set(ast::Modifiers::Type::Final);
145  Modifiers pubMod{};
146  pubMod.set(ast::Modifiers::Type::Public);
147  // clang-format off
148  auto intTy = sema_->BuildBuiltInType(parsetree::BasicType::Type::Int,SourceRange{});
149  auto length = sema_->BuildFieldDecl(lengthMod, SourceRange{}, intTy, "length", nullptr, true);
150  auto ctor = sema_->BuildMethodDecl(pubMod,
151  SourceRange{},
152  "[__builtin_array_proto",
153  nullptr,
154  emptyParams,
155  true,
156  sema_->BuildNullStmt());
157  body.push_back(length);
158  body.push_back(ctor);
159  // FIXME(kevin): There should be a clone() method that's overriden as well
160  arrayPrototype_ = sema_->BuildClassDecl(pubMod,
161  SourceRange{},
162  "[__builtin_array_proto",
163  nullptr,
164  interfaces,
165  body);
166  (void) sema_->BuildCompilationUnit(nullptr, emptyImports, SourceRange{}, arrayPrototype_);
167  // Now wrap it in a reference type
168  arrayClassType_ = alloc.new_object<ReferenceType>(arrayPrototype_, arrayPrototype_->location());
169  // clang-format on
170  }
171 }
172 
173 void NameResolver::BeginContext(ast::CompilationUnit* cu) {
174  // Set the current compilation unit and clear the imports map
175  auto& importsMap = importsMap_[cu];
176  currentCU_ = cu;
177  // Package should be an unresolved type
178  auto curPkg = cast<UnresolvedType>(cu->package());
179 
180  // We can populate the imports map by order of shadowing cf. JLS 6.3.1.
181  // 1. Package declarations, does not shadow anything.
182  // 2. Import-on-demand declarations, never causes any declaration to be
183  // shadowed (even with other IOD), but maybe shadow other packages.
184  // 3. All declarations in the same package (different CUs).
185  // 4. Single-type-import declarations, shadows any other decl in all CUs
186  // under the same package. It also shadows any import-on-demand decls.
187  // 4. All declarations in the current CU.
188  // We should also note the scope of types under the same package declarations
189  // cf. JLS 6.3 is visible across all CUs in the same package.
190 
191  // 1. Import-on-demand declarations. Populate this first so we can check
192  // if two import-on-demand declarations shadow each other.
193  for(auto const& imp : cu->imports()) {
194  if(!imp.isOnDemand) continue;
195  // First, resolve the subpackage subtree from the symbol table.
196  auto subPkg = resolveImport(static_cast<UnresolvedType const*>(imp.type));
197  // No value means an error has been reported, skip this import.
198  if(!subPkg) continue;
199  if(!std::holds_alternative<Pkg*>(subPkg.value())) {
200  diag.ReportError(imp.location())
201  << "failed to resolve import-on-demand as subpackage is a "
202  "declaration: \""
203  << imp.simpleName() << "\"";
204  continue;
205  }
206  // Grab the package as a Pkg*.
207  auto pkg = std::get<Pkg*>(subPkg.value());
208  // Second, add all the Decl from the subpackage to the imports map.
209  // We only add declarations, not subpackages. cf. JLS 7.5:
210  //
211  // > A type-import-on-demand declaration (§7.5.2) imports all the
212  // > accessible types of a named type or package as needed.
213  //
214  for(auto& kv : pkg->children) {
215  if(!std::holds_alternative<Decl*>(kv.second)) continue;
216  auto decl = std::get<Decl*>(kv.second);
217  if(importsMap.find(kv.first) != importsMap.end()) {
218  auto imported = importsMap[kv.first];
219  if(std::holds_alternative<Decl*>(imported) &&
220  std::get<Decl*>(imported) == decl)
221  continue; // Same declaration, no error
222  // FIXME(kevin): The import-on-demand shadows another
223  // import-on-demand, so we mark the declaration as a null pointer.
224  importsMap[kv.first] = static_cast<Decl*>(nullptr);
225  continue;
226  }
227  importsMap[kv.first] = Pkg::Child{decl};
228  }
229  }
230  // 2. Package declarations. We can ignore any duplicate names as they are
231  // shadowed by the import-on-demand declarations.
232  for(auto& kv : rootPkg_->children) {
233  if(!std::holds_alternative<Pkg*>(kv.second))
234  continue; // We only care about subpackages
235  if(importsMap.find(kv.first) != importsMap.end())
236  continue; // This package is shadowed by an import-on-demand
237  importsMap[kv.first] = Pkg::Child{std::get<Pkg*>(kv.second)};
238  }
239  // 3. All declarations in the same package (different CUs). We can shadow
240  // any declarations already existing.
241  {
242  auto curTree = resolveImport(curPkg);
243  assert(curTree && "Current package should exist!");
244  assert(std::holds_alternative<Pkg*>(curTree.value()));
245  for(auto& kv : std::get<Pkg*>(curTree.value())->children)
246  if(std::holds_alternative<Decl*>(kv.second))
247  importsMap[kv.first] = Pkg::Child{std::get<Decl*>(kv.second)};
248  }
249  // 4. Single-type-import declarations. This may also shadow anything existing.
250  for(auto const& imp : cu->imports()) {
251  if(imp.isOnDemand) continue;
252  // First, resolve the subpackage subtree from the symbol table.
253  auto subPkg = resolveImport(static_cast<UnresolvedType const*>(imp.type));
254  if(!subPkg) continue;
255  if(!std::holds_alternative<Decl*>(subPkg.value())) {
256  diag.ReportError(imp.location())
257  << "failed to resolve single-type-import as a declaration: \""
258  << imp.simpleName() << "\"";
259  continue;
260  }
261  // Second, add the Decl from the subpackage to the imports map.
262  auto decl = std::get<Decl*>(subPkg.value());
263  auto cuDecl = cu->bodyAsDecl();
264  // If the single-type-import name is the same as the class name, then it
265  // shadows the class name. This is an error.
266  if((decl->name() == cuDecl->name()) && (decl != cuDecl)) {
267  diag.ReportError(cu->location()) << "single-type-import is the same "
268  "as the class/interface name: "
269  << decl->name();
270  continue;
271  }
272  std::pmr::string name{imp.simpleName().data(), alloc};
273  importsMap[name] = decl;
274  }
275  // 5. All declarations in the current CU. This may also shadow anything.
276  if(cu->body())
277  importsMap[cu->bodyAsDecl()->name().data()] = cu->mut_bodyAsDecl();
278 }
279 
280 NameResolver::ChildOpt NameResolver::resolveImport(UnresolvedType const* t) const {
281  assert(t && "Type should not be null");
282  assert(!t->isResolved() && "Type should not be resolved");
283  if(t->parts().empty()) {
284  return rootPkg_->children[UNNAMED_PACKAGE];
285  }
286  Pkg::Child subPkg = rootPkg_;
287  for(auto const& id : t->parts()) {
288  // If the subpackage is a declaration, then the import is invalid.
289  if(std::holds_alternative<Decl*>(subPkg)) {
290  diag.ReportError(t->location())
291  << "failed to resolve import as subpackage is a declaration: \""
292  << id << "\"";
293  return std::nullopt;
294  }
295  // Now that we know it's not a decl, get it as a package.
296  auto pkg = std::get<Pkg*>(subPkg);
297  // If the subpackage does not exist, then the import is invalid.
298  if(pkg->children.find(id) == pkg->children.end()) {
299  diag.ReportError(t->location())
300  << "failed to resolve import as subpackage does not exist: \"" << id
301  << "\"";
302  return std::nullopt;
303  }
304  // Get the next subpackage.
305  subPkg = pkg->children[id];
306  }
307  // At the end, we either have a decl or a subpackage.
308  return subPkg;
309 }
310 
311 void NameResolver::ResolveType(UnresolvedType* ty) {
312  assert(ty && "Type should not be null");
313  assert(!ty->isResolved() && "Type should not be resolved");
314  if(ty->parts().empty()) return;
315  Pkg::Child subTy;
316  auto it = ty->parts().begin();
317  // Resolve the first level of the type against importMaps_
318  auto& importsMap = importsMap_[currentCU_];
319  if(auto it2 = importsMap.find(*it); it2 != importsMap.end()) {
320  subTy = it2->second;
321  } else {
322  diag.ReportError(ty->location())
323  << "failed to resolve type as subpackage does not exist: \"" << *it
324  << "\"";
325  return;
326  }
327  // Now resolve the remainder of the type against subTy
328  it = std::next(it);
329  for(; it != ty->parts().end(); it++) {
330  // If the subpackage is a declaration, then the import is invalid.
331  if(std::holds_alternative<Decl*>(subTy)) {
332  diag.ReportError(ty->location())
333  << "failed to resolve type as subpackage is a declaration: \""
334  << *it << "\"";
335  return;
336  }
337  // Now that we know it's not a decl, get it as a package.
338  auto pkg = std::get<Pkg*>(subTy);
339  // If the subpackage does not exist, then the import is invalid.
340  if(pkg->children.find(*it) == pkg->children.end()) {
341  diag.ReportError(ty->location())
342  << "failed to resolve type as subpackage does not exist: \"" << *it
343  << "\"";
344  return;
345  }
346  // Get the next subpackage.
347  subTy = pkg->children[*it];
348  }
349  // The final type should be a declaration.
350  if(!std::holds_alternative<Decl*>(subTy)) {
351  diag.ReportError(ty->location())
352  << "failed to resolve type, is not a declaration: \"" << ty->toString()
353  << "\"";
354  return;
355  }
356  // If subTy is nullptr, then an ambiguous import-on-demand has shadowed the
357  // declaration. This is an error.
358  if(!std::get<Decl*>(subTy)) {
359  ty->invalidate();
360  diag.ReportError(ty->location())
361  << "failed to resolve type, ambiguous import-on-demand: \""
362  << ty->toString() << "\"";
363  return;
364  }
365  // Now we can create a reference type to the declaration.
366  ty->resolveInternal(std::get<Decl*>(subTy));
367  // After, the type should be resolved
368  assert(ty->isResolved() && "Type should be resolved");
369 }
370 
371 std::ostream& NameResolver::Pkg::print(std::ostream& os, int indent) const {
372  for(auto const& [name, child] : children) {
373  for(int i = 0; i < indent; i++) os << " ";
374  if(std::holds_alternative<Decl*>(child)) {
375  os << name << std::endl;
376  } else {
377  if(name != UNNAMED_PACKAGE)
378  os << name;
379  else
380  os << "(default package)";
381  os << " ->" << std::endl;
382  std::get<Pkg*>(child)->print(os, indent + 1);
383  }
384  }
385  return os;
386 }
387 
388 void NameResolver::Pkg::dump() const { print(std::cout, 0); }
389 
390 void NameResolver::dump() const {
391  std::cout << "Symbol table:" << std::endl;
392  rootPkg_->dump();
393  std::cout << "Import table:" << std::endl;
395 }
396 
397 void NameResolver::dumpImports() const {
398  for(auto const* cu : lu_->compliationUnits()) dumpImports(cu);
399 }
400 
401 void NameResolver::dumpImports(ast::CompilationUnit const* cu) const {
402  if(cu && cu->bodyAsDecl() && cu->bodyAsDecl()->hasCanonicalName()) {
403  std::cout << "Current CU: " << cu->bodyAsDecl()->getCanonicalName()
404  << std::endl;
405  } else {
406  return;
407  }
408 
409  auto it = importsMap_.find(cu);
410  assert(it != importsMap_.end() && "Compilation unit not found in import map");
411  auto const& importsMap = it->second;
412 
413  if(importsMap.empty()) {
414  std::cout << "No imports" << std::endl;
415  return;
416  }
417 
418  for(auto const& [name, child] : importsMap) {
419  if(name == UNNAMED_PACKAGE)
420  std::cout << "(default package) -> ";
421  else
422  std::cout << name << " -> ";
423  if(std::holds_alternative<Decl*>(child)) {
424  auto* decl = std::get<Decl*>(child);
425  std::cout << "(Decl) ";
426  if(decl)
427  std::cout << decl->name();
428  else
429  std::cout << "<null>";
430  } else {
431  std::cout << "(subpackage)";
432  }
433  std::cout << std::endl;
434  }
435 }
436 
437 NameResolver::ConstImportOpt NameResolver::GetImport(
438  ast::CompilationUnit const* cu, std::string_view name,
439  std::pmr::memory_resource* r) const {
440  // Grab the import map
441  auto it = importsMap_.find(cu);
442  assert(it != importsMap_.end() && "Compilation unit not found in import map");
443  auto const& importsMap = it->second;
444 
445  // Grab the import from the map
446  BumpAllocator alloc1{r};
447  std::pmr::string str{name, alloc1};
448  auto it2 = importsMap.find(str);
449 
450  // If the import is not found, then we can return a null optional
451  if(it2 == importsMap.end()) return std::nullopt;
452 
453  // If the import is found, then we can return it
454  if(std::holds_alternative<Decl*>(it2->second)) {
455  return static_cast<Decl const*>(std::get<Decl*>(it2->second));
456  } else {
457  return static_cast<Pkg const*>(std::get<Pkg*>(it2->second));
458  }
459 }
460 
461 } // namespace semantic