static_scope.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. void StaticScope::Print(llvm::raw_ostream& out) const {
  33. if (ast_node_) {
  34. ast_node_.value()->Print(out);
  35. } else {
  36. *trace_stream_ << "package";
  37. }
  38. }
  39. void StaticScope::PrintID(llvm::raw_ostream& out) const {
  40. if (ast_node_) {
  41. ast_node_.value()->PrintID(out);
  42. } else {
  43. *trace_stream_ << "package";
  44. }
  45. }
  46. void StaticScope::MarkDeclared(std::string_view name) {
  47. auto it = declared_names_.find(name);
  48. CARBON_CHECK(it != declared_names_.end()) << name << " not found";
  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()) << name << " not found";
  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) {
  125. return {it->second.entity};
  126. }
  127. switch (it->second.status) {
  128. case NameStatus::KnownButNotDeclared:
  129. return ProgramError(source_loc)
  130. << "'" << name << "' has not been declared yet";
  131. case NameStatus::DeclaredButNotUsable:
  132. return ProgramError(source_loc) << "'" << name
  133. << "' is not usable until after it "
  134. "has been completely declared";
  135. case NameStatus::Usable:
  136. return {it->second.entity};
  137. }
  138. }
  139. auto StaticScope::AddReturnedVar(ValueNodeView returned_var_def_view)
  140. -> ErrorOr<Success> {
  141. std::optional<ValueNodeView> resolved_returned_var = ResolveReturned();
  142. if (resolved_returned_var.has_value()) {
  143. return ProgramError(returned_var_def_view.base().source_loc())
  144. << "Duplicate definition of returned var also found at "
  145. << resolved_returned_var->base().source_loc();
  146. }
  147. returned_var_def_view_ = std::move(returned_var_def_view);
  148. return Success();
  149. }
  150. auto StaticScope::ResolveReturned() const -> std::optional<ValueNodeView> {
  151. for (const StaticScope* scope = this; scope;
  152. scope = scope->parent_scope_.value_or(nullptr)) {
  153. if (scope->returned_var_def_view_.has_value()) {
  154. return scope->returned_var_def_view_;
  155. }
  156. }
  157. return std::nullopt;
  158. }
  159. } // namespace Carbon