impl_scope.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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/interpreter/impl_scope.h"
  5. #include "explorer/interpreter/type_checker.h"
  6. #include "explorer/interpreter/value.h"
  7. #include "llvm/ADT/StringExtras.h"
  8. #include "llvm/Support/Casting.h"
  9. using llvm::cast;
  10. using llvm::dyn_cast;
  11. namespace Carbon {
  12. void ImplScope::Add(Nonnull<const Value*> iface, Nonnull<const Value*> type,
  13. Nonnull<Expression*> impl,
  14. const TypeChecker& type_checker) {
  15. Add(iface, {}, type, {}, impl, type_checker);
  16. }
  17. void ImplScope::Add(Nonnull<const Value*> iface,
  18. llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
  19. Nonnull<const Value*> type,
  20. llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
  21. Nonnull<Expression*> impl_expr,
  22. const TypeChecker& type_checker) {
  23. if (auto* orig_constraint = dyn_cast<ConstraintType>(iface)) {
  24. BindingMap map;
  25. map[orig_constraint->self_binding()] = type;
  26. const ConstraintType* constraint =
  27. cast<ConstraintType>(type_checker.Substitute(map, orig_constraint));
  28. for (size_t i = 0; i != constraint->impl_constraints().size(); ++i) {
  29. ConstraintType::ImplConstraint impl = constraint->impl_constraints()[i];
  30. Add(impl.interface, deduced, impl.type, impl_bindings,
  31. type_checker.MakeConstraintWitnessAccess(impl_expr, i), type_checker);
  32. }
  33. // A parameterized impl declaration doesn't contribute any equality
  34. // constraints to the scope. Instead, we'll resolve the equality
  35. // constraints by resolving a witness when needed.
  36. if (deduced.empty()) {
  37. for (auto& equality_constraint : constraint->equality_constraints()) {
  38. equalities_.push_back(&equality_constraint);
  39. }
  40. }
  41. return;
  42. }
  43. impls_.push_back({.interface = cast<InterfaceType>(iface),
  44. .deduced = deduced,
  45. .type = type,
  46. .impl_bindings = impl_bindings,
  47. .impl = impl_expr});
  48. }
  49. void ImplScope::AddParent(Nonnull<const ImplScope*> parent) {
  50. parent_scopes_.push_back(parent);
  51. }
  52. auto ImplScope::Resolve(Nonnull<const Value*> constraint_type,
  53. Nonnull<const Value*> impl_type,
  54. SourceLocation source_loc,
  55. const TypeChecker& type_checker) const
  56. -> ErrorOr<Nonnull<Expression*>> {
  57. if (const auto* iface_type = dyn_cast<InterfaceType>(constraint_type)) {
  58. return ResolveInterface(iface_type, impl_type, source_loc, type_checker);
  59. }
  60. if (const auto* constraint = dyn_cast<ConstraintType>(constraint_type)) {
  61. std::vector<Nonnull<Expression*>> witnesses;
  62. BindingMap map;
  63. map[constraint->self_binding()] = impl_type;
  64. for (auto impl : constraint->impl_constraints()) {
  65. CARBON_ASSIGN_OR_RETURN(
  66. Nonnull<Expression*> result,
  67. ResolveInterface(
  68. cast<InterfaceType>(type_checker.Substitute(map, impl.interface)),
  69. type_checker.Substitute(map, impl.type), source_loc,
  70. type_checker));
  71. witnesses.push_back(result);
  72. }
  73. // TODO: Check satisfaction of same-type constraints.
  74. return type_checker.MakeConstraintWitness(*constraint, std::move(witnesses),
  75. source_loc);
  76. }
  77. CARBON_FATAL() << "expected a constraint, not " << *constraint_type;
  78. }
  79. auto ImplScope::VisitEqualValues(
  80. Nonnull<const Value*> value,
  81. llvm::function_ref<bool(Nonnull<const Value*>)> visitor) const -> bool {
  82. for (Nonnull<const ConstraintType::EqualityConstraint*> eq : equalities_) {
  83. if (!eq->VisitEqualValues(value, visitor)) {
  84. return false;
  85. }
  86. }
  87. for (Nonnull<const ImplScope*> parent : parent_scopes_) {
  88. if (!parent->VisitEqualValues(value, visitor)) {
  89. return false;
  90. }
  91. }
  92. return true;
  93. }
  94. auto ImplScope::ResolveInterface(Nonnull<const InterfaceType*> iface_type,
  95. Nonnull<const Value*> type,
  96. SourceLocation source_loc,
  97. const TypeChecker& type_checker) const
  98. -> ErrorOr<Nonnull<Expression*>> {
  99. CARBON_ASSIGN_OR_RETURN(
  100. std::optional<Nonnull<Expression*>> result,
  101. TryResolve(iface_type, type, source_loc, *this, type_checker));
  102. if (!result.has_value()) {
  103. return CompilationError(source_loc) << "could not find implementation of "
  104. << *iface_type << " for " << *type;
  105. }
  106. return *result;
  107. }
  108. auto ImplScope::TryResolve(Nonnull<const InterfaceType*> iface_type,
  109. Nonnull<const Value*> type,
  110. SourceLocation source_loc,
  111. const ImplScope& original_scope,
  112. const TypeChecker& type_checker) const
  113. -> ErrorOr<std::optional<Nonnull<Expression*>>> {
  114. CARBON_ASSIGN_OR_RETURN(
  115. std::optional<Nonnull<Expression*>> result,
  116. ResolveHere(iface_type, type, source_loc, original_scope, type_checker));
  117. for (Nonnull<const ImplScope*> parent : parent_scopes_) {
  118. CARBON_ASSIGN_OR_RETURN(std::optional<Nonnull<Expression*>> parent_result,
  119. parent->TryResolve(iface_type, type, source_loc,
  120. original_scope, type_checker));
  121. if (parent_result.has_value()) {
  122. if (result.has_value()) {
  123. return CompilationError(source_loc) << "ambiguous implementations of "
  124. << *iface_type << " for " << *type;
  125. } else {
  126. result = *parent_result;
  127. }
  128. }
  129. }
  130. return result;
  131. }
  132. auto ImplScope::ResolveHere(Nonnull<const InterfaceType*> iface_type,
  133. Nonnull<const Value*> impl_type,
  134. SourceLocation source_loc,
  135. const ImplScope& original_scope,
  136. const TypeChecker& type_checker) const
  137. -> ErrorOr<std::optional<Nonnull<Expression*>>> {
  138. std::optional<Nonnull<Expression*>> result = std::nullopt;
  139. for (const Impl& impl : impls_) {
  140. std::optional<Nonnull<Expression*>> m = type_checker.MatchImpl(
  141. *iface_type, impl_type, impl, original_scope, source_loc);
  142. if (m.has_value()) {
  143. if (result.has_value()) {
  144. return CompilationError(source_loc)
  145. << "ambiguous implementations of " << *iface_type << " for "
  146. << *impl_type;
  147. } else {
  148. result = *m;
  149. }
  150. }
  151. }
  152. return result;
  153. }
  154. // TODO: Add indentation when printing the parents.
  155. void ImplScope::Print(llvm::raw_ostream& out) const {
  156. out << "impls: ";
  157. llvm::ListSeparator sep;
  158. for (const Impl& impl : impls_) {
  159. out << sep << *(impl.type) << " as " << *(impl.interface);
  160. }
  161. for (Nonnull<const ConstraintType::EqualityConstraint*> eq : equalities_) {
  162. out << sep;
  163. llvm::ListSeparator equal(" == ");
  164. for (Nonnull<const Value*> value : eq->values) {
  165. out << equal << *value;
  166. }
  167. }
  168. out << "\n";
  169. for (const Nonnull<const ImplScope*>& parent : parent_scopes_) {
  170. out << *parent;
  171. }
  172. }
  173. } // namespace Carbon