static_scope.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "explorer/ast/static_scope.h"
  5. #include <optional>
  6. #include "common/ostream.h"
  7. #include "explorer/base/error_builders.h"
  8. #include "explorer/base/print_as_id.h"
  9. #include "llvm/ADT/ScopeExit.h"
  10. namespace Carbon {
  11. auto StaticScope::Add(std::string_view name, ValueNodeView entity,
  12. NameStatus status) -> ErrorOr<Success> {
  13. auto [it, inserted] = declared_names_.insert({name, {entity, status}});
  14. if (!inserted) {
  15. if (it->second.entity != entity) {
  16. return ProgramError(entity.base().source_loc())
  17. << "Duplicate name `" << name << "` also found at "
  18. << it->second.entity.base().source_loc();
  19. }
  20. if (static_cast<int>(status) > static_cast<int>(it->second.status)) {
  21. it->second.status = status;
  22. }
  23. } else {
  24. if (trace_stream_->is_enabled()) {
  25. trace_stream_->Result()
  26. << "declared `" << name << "` as `" << entity << "` in `"
  27. << PrintAsID(*this) << "` (" << entity.base().source_loc() << ")\n";
  28. }
  29. }
  30. return Success();
  31. }
  32. template <typename Action>
  33. void StaticScope::PrintCommon(Action action) const {
  34. if (ast_node_) {
  35. action(ast_node_.value());
  36. } else {
  37. *trace_stream_ << "package";
  38. }
  39. }
  40. void StaticScope::Print(llvm::raw_ostream& out) const {
  41. PrintCommon([&out](auto node) { node->Print(out); });
  42. }
  43. void StaticScope::PrintID(llvm::raw_ostream& out) const {
  44. PrintCommon([&out](auto node) { node->PrintID(out); });
  45. }
  46. void StaticScope::MarkDeclared(std::string_view name) {
  47. auto it = declared_names_.find(name);
  48. CARBON_CHECK(it != declared_names_.end(), "{0} not found", name);
  49. if (it->second.status == NameStatus::KnownButNotDeclared) {
  50. it->second.status = NameStatus::DeclaredButNotUsable;
  51. if (trace_stream_->is_enabled()) {
  52. trace_stream_->Result()
  53. << "marked `" << name << "` declared but not usable in `"
  54. << PrintAsID(*this) << "`\n";
  55. }
  56. }
  57. }
  58. void StaticScope::MarkUsable(std::string_view name) {
  59. auto it = declared_names_.find(name);
  60. CARBON_CHECK(it != declared_names_.end(), "{0} not found", name);
  61. it->second.status = NameStatus::Usable;
  62. if (trace_stream_->is_enabled()) {
  63. trace_stream_->Result()
  64. << "marked `" << name << "` usable in `" << PrintAsID(*this) << "`\n";
  65. }
  66. }
  67. auto StaticScope::Resolve(std::string_view name,
  68. SourceLocation source_loc) const
  69. -> ErrorOr<ValueNodeView> {
  70. CARBON_ASSIGN_OR_RETURN(std::optional<ValueNodeView> result,
  71. TryResolve(name, source_loc));
  72. if (!result) {
  73. return ProgramError(source_loc) << "could not resolve '" << name << "'";
  74. }
  75. return *result;
  76. }
  77. auto StaticScope::ResolveHere(std::optional<ValueNodeView> this_scope,
  78. std::string_view name, SourceLocation source_loc,
  79. bool allow_undeclared) const
  80. -> ErrorOr<ValueNodeView> {
  81. CARBON_ASSIGN_OR_RETURN(std::optional<ValueNodeView> result,
  82. TryResolveHere(name, source_loc, allow_undeclared));
  83. if (!result) {
  84. if (this_scope) {
  85. return ProgramError(source_loc)
  86. << "name '" << name << "' has not been declared in "
  87. << PrintAsID(this_scope->base());
  88. } else {
  89. return ProgramError(source_loc)
  90. << "name '" << name << "' has not been declared in this scope";
  91. }
  92. }
  93. return *result;
  94. }
  95. auto StaticScope::TryResolve(std::string_view name,
  96. SourceLocation source_loc) const
  97. -> ErrorOr<std::optional<ValueNodeView>> {
  98. for (const StaticScope* scope = this; scope;
  99. scope = scope->parent_scope_.value_or(nullptr)) {
  100. CARBON_ASSIGN_OR_RETURN(
  101. std::optional<ValueNodeView> value,
  102. scope->TryResolveHere(name, source_loc, /*allow_undeclared=*/false));
  103. if (value) {
  104. return value;
  105. }
  106. }
  107. return {std::nullopt};
  108. }
  109. auto StaticScope::TryResolveHere(std::string_view name,
  110. SourceLocation source_loc,
  111. bool allow_undeclared) const
  112. -> ErrorOr<std::optional<ValueNodeView>> {
  113. auto it = declared_names_.find(name);
  114. if (it == declared_names_.end()) {
  115. return {std::nullopt};
  116. }
  117. auto exit_scope_function = llvm::make_scope_exit([&]() {
  118. if (trace_stream_->is_enabled()) {
  119. trace_stream_->Result()
  120. << "resolved `" << name << "` as `" << it->second.entity << "` in `"
  121. << PrintAsID(*this) << "` (" << source_loc << ")\n";
  122. }
  123. });
  124. if (allow_undeclared || it->second.status == NameStatus::Usable) {
  125. return {it->second.entity};
  126. }
  127. return ProgramError(source_loc)
  128. << "'" << name
  129. << (it->second.status == NameStatus::KnownButNotDeclared
  130. ? "' has not been declared yet"
  131. : "' is not usable until after it has been completely "
  132. "declared");
  133. }
  134. auto StaticScope::AddReturnedVar(ValueNodeView returned_var_def_view)
  135. -> ErrorOr<Success> {
  136. std::optional<ValueNodeView> resolved_returned_var = ResolveReturned();
  137. if (resolved_returned_var.has_value()) {
  138. return ProgramError(returned_var_def_view.base().source_loc())
  139. << "Duplicate definition of returned var also found at "
  140. << resolved_returned_var->base().source_loc();
  141. }
  142. returned_var_def_view_ = std::move(returned_var_def_view);
  143. return Success();
  144. }
  145. auto StaticScope::ResolveReturned() const -> std::optional<ValueNodeView> {
  146. for (const StaticScope* scope = this; scope;
  147. scope = scope->parent_scope_.value_or(nullptr)) {
  148. if (scope->returned_var_def_view_.has_value()) {
  149. return scope->returned_var_def_view_;
  150. }
  151. }
  152. return std::nullopt;
  153. }
  154. } // namespace Carbon