impl_scope.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. #ifndef CARBON_EXPLORER_INTERPRETER_IMPL_SCOPE_H_
  5. #define CARBON_EXPLORER_INTERPRETER_IMPL_SCOPE_H_
  6. #include "explorer/ast/declaration.h"
  7. #include "explorer/ast/value.h"
  8. #include "explorer/interpreter/type_structure.h"
  9. namespace Carbon {
  10. class TypeChecker;
  11. // The `ImplScope` class is responsible for mapping a type and
  12. // interface to the location of the witness table for the `impl` for
  13. // that type and interface. A scope may have parent scopes, whose
  14. // implementations will also be visible in the child scope.
  15. //
  16. // There is typically one instance of `ImplScope` class per scope
  17. // because the implementationss that are visible for a given type and
  18. // interface can vary from scope to scope. For example, consider the
  19. // `bar` and `baz` methods in the following class C and nested class D.
  20. //
  21. // class C(U:! type, T:! type) {
  22. // class D(V:! type where U impls Fooable(T)) {
  23. // fn bar[self: Self](x: U, y : T) -> T{
  24. // return x.foo(y)
  25. // }
  26. // }
  27. // fn baz[self: Self](x: U, y : T) -> T {
  28. // return x.foo(y);
  29. // }
  30. // }
  31. //
  32. // The call to `x.foo` in `bar` is valid because the `U is Fooable(T)`
  33. // impl is visible in the body of `bar`. In contrast, the call to
  34. // `x.foo` in `baz` is not valid because there is no visible impl for
  35. // `U` and `Fooable` in that scope.
  36. //
  37. // `ImplScope` also tracks the type equalities that are known in a particular
  38. // scope.
  39. class ImplScope : public Printable<ImplScope> {
  40. public:
  41. // The `ImplFact` struct is a key-value pair where the key is the
  42. // combination of a type and an interface, e.g., `List` and `Container`,
  43. // and the value is the result of statically resolving to the `impl`
  44. // for `List` as `Container`, which is an `Expression` that produces
  45. // the witness for that `impl`.
  46. //
  47. // When the `impl` is parameterized, `deduced` and `impl_bindings`
  48. // are non-empty. The former contains the type parameters and the
  49. // later are impl bindings, that is, parameters for witnesses. In this case,
  50. // `sort_key` indicates the order in which this impl should be considered
  51. // relative to other matching impls.
  52. struct ImplFact {
  53. Nonnull<const InterfaceType*> interface;
  54. std::vector<Nonnull<const GenericBinding*>> deduced;
  55. Nonnull<const Value*> type;
  56. std::vector<Nonnull<const ImplBinding*>> impl_bindings;
  57. Nonnull<const Witness*> witness;
  58. std::optional<TypeStructureSortKey> sort_key;
  59. };
  60. // Internal type used to represent the result of resolving a lookup in a
  61. // particular impl scope.
  62. struct ResolveResult {
  63. Nonnull<const ImplFact*> impl;
  64. Nonnull<const Witness*> witness;
  65. };
  66. explicit ImplScope() {}
  67. explicit ImplScope(Nonnull<const ImplScope*> parent)
  68. : parent_scope_(parent) {}
  69. // Associates `iface` and `type` with the `impl` in this scope. If `iface` is
  70. // a constraint type, it will be split into its constituent components, and
  71. // any references to `.Self` are expected to have been substituted for the
  72. // type implementing the constraint.
  73. void Add(Nonnull<const Value*> iface, Nonnull<const Value*> type,
  74. Nonnull<const Witness*> witness, const TypeChecker& type_checker);
  75. // For a parameterized impl, associates `iface` and `type`
  76. // with the `impl` in this scope. Otherwise, the same as the previous
  77. // overload.
  78. void Add(Nonnull<const Value*> iface,
  79. llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
  80. Nonnull<const Value*> type,
  81. llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
  82. Nonnull<const Witness*> witness, const TypeChecker& type_checker,
  83. std::optional<TypeStructureSortKey> sort_key = std::nullopt);
  84. // Adds a list of impls constraints from a constraint type into scope. Any
  85. // references to `.Self` are expected to have already been substituted for
  86. // the type implementing the constraint.
  87. void Add(llvm::ArrayRef<ImplsConstraint> impls_constraints,
  88. llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
  89. llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
  90. Nonnull<const Witness*> witness, const TypeChecker& type_checker);
  91. // Adds a type equality constraint.
  92. void AddEqualityConstraint(Nonnull<const EqualityConstraint*> equal) {
  93. equalities_.push_back(equal);
  94. }
  95. // Returns the associated impl for the given `constraint` and `type` in
  96. // the ancestor graph of this scope, or reports a compilation error
  97. // at `source_loc` there isn't exactly one matching impl.
  98. //
  99. // If any substitutions should be made into the constraint before resolving
  100. // it, those should be passed in `bindings`. The witness returned will be for
  101. // `constraint`, not for the result of substituting the bindings into the
  102. // constraint. The substituted type might in general have a different shape
  103. // of witness due to deduplication.
  104. auto Resolve(Nonnull<const Value*> constraint, Nonnull<const Value*> type,
  105. SourceLocation source_loc, const TypeChecker& type_checker,
  106. const Bindings& bindings = {}) const
  107. -> ErrorOr<Nonnull<const Witness*>>;
  108. // Same as Resolve, except that failure due to a missing implementation of a
  109. // constraint produces `nullopt` instead of an error if
  110. // `diagnose_missing_impl` is `false`. This is intended for cases where we're
  111. // selecting between options based on whether constraints are satisfied, such
  112. // as during `impl` selection.
  113. auto TryResolve(Nonnull<const Value*> constraint, Nonnull<const Value*> type,
  114. SourceLocation source_loc, const TypeChecker& type_checker,
  115. const Bindings& bindings, bool diagnose_missing_impl) const
  116. -> ErrorOr<std::optional<Nonnull<const Witness*>>>;
  117. // Visits the values that are a single step away from `value` according to an
  118. // equality constraint that is in scope. That is, the values `v` such that we
  119. // have a `value == v` equality constraint in scope.
  120. //
  121. // Stops and returns `false` if any call to the visitor returns `false`,
  122. // otherwise returns `true`.
  123. auto VisitEqualValues(
  124. Nonnull<const Value*> value,
  125. llvm::function_ref<bool(Nonnull<const Value*>)> visitor) const -> bool;
  126. void Print(llvm::raw_ostream& out) const;
  127. private:
  128. // Returns the associated impl for the given `iface` and `type` in
  129. // the ancestor graph of this scope. Reports a compilation error
  130. // at `source_loc` if there's an ambiguity, or if `diagnose_missing_impl` is
  131. // set and there's no matching impl.
  132. auto TryResolveInterface(Nonnull<const InterfaceType*> iface,
  133. Nonnull<const Value*> type,
  134. SourceLocation source_loc,
  135. const TypeChecker& type_checker,
  136. bool diagnose_missing_impl) const
  137. -> ErrorOr<std::optional<Nonnull<const Witness*>>>;
  138. // Returns the associated impl for the given `iface` and `type` in
  139. // the ancestor graph of this scope, returns std::nullopt if there
  140. // is none, or reports a compilation error is there is not a most
  141. // specific impl for the given `iface` and `type`.
  142. // Use `original_scope` to satisfy requirements of any generic impl
  143. // that matches `iface` and `type`.
  144. auto TryResolveInterfaceRecursively(Nonnull<const InterfaceType*> iface_type,
  145. Nonnull<const Value*> type,
  146. SourceLocation source_loc,
  147. const ImplScope& original_scope,
  148. const TypeChecker& type_checker) const
  149. -> ErrorOr<std::optional<ResolveResult>>;
  150. // Returns the associated impl for the given `iface` and `type` in
  151. // this scope, returns std::nullopt if there is none, or reports
  152. // a compilation error is there is not a most specific impl for the
  153. // given `iface` and `type`.
  154. // Use `original_scope` to satisfy requirements of any generic impl
  155. // that matches `iface` and `type`.
  156. auto TryResolveInterfaceHere(Nonnull<const InterfaceType*> iface_type,
  157. Nonnull<const Value*> impl_type,
  158. SourceLocation source_loc,
  159. const ImplScope& original_scope,
  160. const TypeChecker& type_checker) const
  161. -> ErrorOr<std::optional<ResolveResult>>;
  162. std::vector<ImplFact> impl_facts_;
  163. std::vector<Nonnull<const EqualityConstraint*>> equalities_;
  164. std::optional<Nonnull<const ImplScope*>> parent_scope_;
  165. };
  166. // An equality context that considers two values to be equal if they are a
  167. // single step apart according to an equality constraint in the given impl
  168. // scope.
  169. struct SingleStepEqualityContext : public EqualityContext {
  170. public:
  171. explicit SingleStepEqualityContext(Nonnull<const ImplScope*> impl_scope)
  172. : impl_scope_(impl_scope) {}
  173. // Visits the values that are equal to the given value and a single step away
  174. // according to an equality constraint that is in the given impl scope. Stops
  175. // and returns `false` if the visitor returns `false`, otherwise returns
  176. // `true`.
  177. auto VisitEqualValues(Nonnull<const Value*> value,
  178. llvm::function_ref<bool(Nonnull<const Value*>)> visitor)
  179. const -> bool override;
  180. private:
  181. Nonnull<const ImplScope*> impl_scope_;
  182. };
  183. } // namespace Carbon
  184. #endif // CARBON_EXPLORER_INTERPRETER_IMPL_SCOPE_H_