Joos1W Compiler Framework
All Classes Functions Typedefs Pages
semantic::NameResolver Class Referencefinal
Inheritance diagram for semantic::NameResolver:

Classes

struct  Pkg
 Represents a tree of packages. The leaf nodes are declarations. More...
 

Public Types

using ConstImport = std::variant< ast::Decl const *, Pkg const * >
 
using ConstImportOpt = std::optional< ConstImport >
 

Public Member Functions

 NameResolver (BumpAllocator &alloc, diagnostics::DiagnosticEngine &diag)
 Construct a new Name Resolver object. More...
 
void Init (ast::LinkingUnit *lu, ast::Semantic *sema)
 Initializes a new Name Resolver object given the entire linking unit (and all its symbols). After this, call Resolve() to resolve all types in the linking unit. More...
 
void ResolveType (ast::UnresolvedType *type) override
 Resolves the type in-place (does not return anything) More...
 
ConstImportOpt GetImport (ast::CompilationUnit const *cu, std::string_view name, std::pmr::memory_resource *r=std::pmr::get_default_resource()) const
 Get an import object from the import table of the given compilation unit. This object can either be a package or a declaration. More...
 
auto GetJavaLang () const
 Get a struct with all the java.lang.* classes and interfaces. Also includes java.io.Serializable for some reason. More...
 
auto GetArrayPrototype () const
 Get the Array Prototype object. This is a decl representing the prototype of the array class.
 
void BeginContext (ast::CompilationUnit *cu)
 Called to begin the resolution of a compilation unit. This will build the import table (and any other data structures) to help resolve types within the compilation unit. More...
 
void EndContext ()
 Called to end the resolution of a compilation unit. This will clear the current compilation unit being resolved.
 
void dump () const
 Dumps the symbol and import tables to the output stream.
 
void dumpImports (ast::CompilationUnit const *cu) const
 Dumps the import table to the output stream.
 
void dumpImports () const
 Dumps the import table to the output stream.
 

Detailed Description

Definition at line 29 of file NameResolver.h.

Constructor & Destructor Documentation

◆ NameResolver()

semantic::NameResolver::NameResolver ( BumpAllocator &  alloc,
diagnostics::DiagnosticEngine diag 
)
inline

Construct a new Name Resolver object.

Parameters
allocThe bump allocator to use for all allocations.
diagThe diagnostic engine to use for all diagnostics.

Definition at line 81 of file NameResolver.h.

82  : alloc{alloc}, diag{diag}, lu_{nullptr}, importsMap_{alloc} {}

Member Function Documentation

◆ BeginContext()

void semantic::NameResolver::BeginContext ( ast::CompilationUnit cu)

Called to begin the resolution of a compilation unit. This will build the import table (and any other data structures) to help resolve types within the compilation unit.

Parameters
cuThe compilation unit to begin resolution for.

Definition at line 173 of file NameResolver.cc.

173  {
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 }
Base class for all declarations.
Definition: AstNode.h:87
Represents an unresolved reference type. This means that the underlying reference type is not yet res...
Definition: Type.h:188

◆ GetImport()

NameResolver::ConstImportOpt semantic::NameResolver::GetImport ( ast::CompilationUnit const *  cu,
std::string_view  name,
std::pmr::memory_resource *  r = std::pmr::get_default_resource() 
) const

Get an import object from the import table of the given compilation unit. This object can either be a package or a declaration.

Parameters
cuThe compilation unit to get the import from.
nameThe name of the import to get.
rAn optional memory resource to use for allocations.
Returns
ConstImport Returns nullopt if the import is not found. Otheriwse, returns the import object from the import table. Note, the package object will never be null. However, a declaration object can be null if the import-on-demand results in an unresolvable declaration.

Definition at line 437 of file NameResolver.cc.

439  {
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 }

◆ GetJavaLang()

auto semantic::NameResolver::GetJavaLang ( ) const
inline

Get a struct with all the java.lang.* classes and interfaces. Also includes java.io.Serializable for some reason.

Returns
auto An anonymous struct with all the java.lang.* types.

Definition at line 126 of file NameResolver.h.

126 { return java_lang_; }

◆ Init()

void semantic::NameResolver::Init ( ast::LinkingUnit lu,
ast::Semantic sema 
)
inline

Initializes a new Name Resolver object given the entire linking unit (and all its symbols). After this, call Resolve() to resolve all types in the linking unit.

Parameters
luThe linking unit to resolve.

Definition at line 91 of file NameResolver.h.

91  {
92  lu_ = lu;
93  sema_ = sema;
94  buildSymbolTable();
95  populateJavaLangCache();
96  }

◆ ResolveType()

void semantic::NameResolver::ResolveType ( ast::UnresolvedType type)
overridevirtual

Resolves the type in-place (does not return anything)

Parameters
typeThe unresolved type to resolve.

Implements ast::TypeResolver.

Definition at line 311 of file NameResolver.cc.

311  {
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 }

References ast::ReferenceType::resolveInternal(), and ast::UnresolvedType::toString().


The documentation for this class was generated from the following files: