matching_impl_set.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 "common/check.h"
  5. #include "common/error.h"
  6. #include "explorer/ast/declaration.h"
  7. #include "explorer/ast/value.h"
  8. #include "explorer/common/error_builders.h"
  9. #include "explorer/common/nonnull.h"
  10. #include "explorer/common/source_location.h"
  11. #include "explorer/interpreter/type_checker.h"
  12. namespace Carbon {
  13. // A visitor for type values that collects leaf 'labels', such as class names,
  14. // and adds them to the signature of a `Match` object.
  15. class MatchingImplSet::LeafCollector {
  16. public:
  17. explicit LeafCollector(Match* match) : match_(match) {}
  18. void Collect(const Value* value) {
  19. value->Visit<void>(
  20. [&](const auto* derived_value) { VisitValue(derived_value); });
  21. }
  22. void Collect(Label label) { ++match_->signature_[label]; }
  23. private:
  24. // Most kinds of value don't contribute to the signature.
  25. void VisitValue(const Value* /*unused*/) {}
  26. void VisitValue(const TypeType* /*unused*/) { Collect(Label::TypeType); }
  27. void VisitValue(const BoolType* /*unused*/) { Collect(Label::BoolType); }
  28. void VisitValue(const IntType* /*unused*/) { Collect(Label::IntType); }
  29. void VisitValue(const StringType* /*unused*/) { Collect(Label::StringType); }
  30. void VisitValue(const StaticArrayType* array) {
  31. Collect(Label::ArrayType);
  32. Collect(&array->element_type());
  33. }
  34. void VisitValue(const PointerType* pointer) {
  35. Collect(Label::PointerType);
  36. Collect(&pointer->pointee_type());
  37. }
  38. void VisitValue(const StructType* struct_type) {
  39. Collect(Label::StructType);
  40. for (auto [name, type] : struct_type->fields()) {
  41. Collect(type);
  42. }
  43. }
  44. void VisitValue(const TupleType* tuple_type) {
  45. Collect(Label::TupleType);
  46. for (const auto* elem_type : tuple_type->elements()) {
  47. Collect(elem_type);
  48. }
  49. }
  50. void VisitValue(const NominalClassType* class_type) {
  51. VisitDeclarationAndArgs(class_type->declaration(), class_type->bindings());
  52. }
  53. void VisitValue(const MixinPseudoType* mixin_type) {
  54. VisitDeclarationAndArgs(mixin_type->declaration(), mixin_type->bindings());
  55. }
  56. void VisitValue(const InterfaceType* iface_type) {
  57. VisitDeclarationAndArgs(iface_type->declaration(), iface_type->bindings());
  58. }
  59. void VisitValue(const NamedConstraintType* constraint_type) {
  60. VisitDeclarationAndArgs(constraint_type->declaration(),
  61. constraint_type->bindings());
  62. }
  63. void VisitValue(const ChoiceType* choice_type) {
  64. VisitDeclarationAndArgs(choice_type->declaration(),
  65. choice_type->bindings());
  66. }
  67. void VisitDeclarationAndArgs(const Declaration& declaration,
  68. const Bindings& bindings) {
  69. Collect(match_->parent_->GetLabelForDeclaration(declaration));
  70. for (auto [key, value] : bindings.args()) {
  71. Collect(value);
  72. }
  73. }
  74. Match* match_;
  75. };
  76. auto MatchingImplSet::GetLabelForDeclaration(const Declaration& declaration)
  77. -> Label {
  78. auto [it, added] = declaration_labels_.insert(
  79. {&declaration,
  80. static_cast<Label>(static_cast<int>(Label::FirstDeclarationLabel) +
  81. declaration_labels_.size())});
  82. return it->second;
  83. }
  84. MatchingImplSet::Match::Match(Nonnull<MatchingImplSet*> parent,
  85. Nonnull<const ImplScope::ImplFact*> impl,
  86. Nonnull<const Value*> type,
  87. Nonnull<const Value*> interface)
  88. : parent_(parent), impl_(impl), type_(type), interface_(interface) {
  89. // Build our signature.
  90. LeafCollector collector(this);
  91. collector.Collect(type);
  92. collector.Collect(interface);
  93. parent_->matches_.push_back(this);
  94. }
  95. MatchingImplSet::Match::~Match() {
  96. CARBON_CHECK(parent_->matches_.back() == this) << "match stack broken";
  97. parent_->matches_.pop_back();
  98. }
  99. auto MatchingImplSet::Match::DiagnosePotentialCycle(SourceLocation source_loc)
  100. -> ErrorOr<Success> {
  101. for (auto* match : parent_->matches_) {
  102. if (match != this && match->impl_ == impl_) {
  103. // Whether all labels appear a greater or equal number of times in this
  104. // match than in `match`.
  105. bool all_greater_or_equal = true;
  106. // Whether any label appears strictly more times in this match than in
  107. // `match`.
  108. bool any_greater = false;
  109. for (auto [key, value] : signature_) {
  110. int other_value = match->signature_.lookup(key);
  111. if (value < other_value) {
  112. all_greater_or_equal = false;
  113. break;
  114. }
  115. if (value > other_value) {
  116. any_greater = true;
  117. }
  118. }
  119. if (all_greater_or_equal) {
  120. if (any_greater) {
  121. return ProgramError(source_loc)
  122. << "impl matching recursively performed a more complex match "
  123. "using the same impl\n"
  124. << " outer match: " << *match->type_ << " as "
  125. << *match->interface_ << "\n"
  126. << " inner match: " << *type_ << " as " << *interface_;
  127. }
  128. if (ValueEqual(match->type_, type_, std::nullopt) &&
  129. ValueEqual(match->interface_, interface_, std::nullopt)) {
  130. return ProgramError(source_loc)
  131. << "impl matching for " << *type_ << " as " << *interface_
  132. << " recursively performed a match for the same type and "
  133. "interface";
  134. }
  135. }
  136. }
  137. }
  138. return Success();
  139. }
  140. } // namespace Carbon