impl_scope.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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 EXECUTABLE_SEMANTICS_AST_IMPL_SCOPE_H_
  5. #define EXECUTABLE_SEMANTICS_AST_IMPL_SCOPE_H_
  6. #include "executable_semantics/ast/declaration.h"
  7. namespace Carbon {
  8. class Value;
  9. class TypeChecker;
  10. class InterfaceType;
  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. // impls will also be visible in the child scope.
  15. //
  16. // There is typically one instance of `ImplScope` class per scope
  17. // because the impls that are visible for a given type and interface
  18. // can vary from scope to scope. For example, consider the `bar` and
  19. // `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 is Fooable(T)) {
  23. // fn bar[me: Self](x: U, y : T) -> T{
  24. // return x.foo(y)
  25. // }
  26. // }
  27. // fn baz[me: 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. class ImplScope {
  37. public:
  38. // Associates `iface` and `type` with the `impl` in this scope.
  39. void Add(Nonnull<const Value*> iface, Nonnull<const Value*> type,
  40. Nonnull<Expression*> impl);
  41. // For a parameterized impl, associates `iface` and `type`
  42. // with the `impl` in this scope.
  43. void Add(Nonnull<const Value*> iface,
  44. llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
  45. Nonnull<const Value*> type,
  46. llvm::ArrayRef<Nonnull<const ImplBinding*>> impl_bindings,
  47. Nonnull<Expression*> impl);
  48. // Make `parent` a parent of this scope.
  49. // REQUIRES: `parent` is not already a parent of this scope.
  50. void AddParent(Nonnull<const ImplScope*> parent);
  51. // Returns the associated impl for the given `iface` and `type` in
  52. // the ancestor graph of this scope, or reports a compilation error
  53. // at `source_loc` there isn't exactly one matching impl.
  54. auto Resolve(Nonnull<const Value*> iface, Nonnull<const Value*> type,
  55. SourceLocation source_loc, const TypeChecker& type_checker) const
  56. -> ErrorOr<Nonnull<Expression*>>;
  57. void Print(llvm::raw_ostream& out) const;
  58. // The `Impl` struct is a key-value pair where the key is the
  59. // combination of a type and an interface, e.g., `List` and `Container`,
  60. // and the value is the result of statically resolving to the `impl`
  61. // for `List` as `Container`, which is an `Expression` that produces
  62. // the witness for that `impl`.
  63. // When the `impl` is parameterized, `deduced` and `impl_bindings`
  64. // are non-empty. The former contains the type parameters and the
  65. // later are impl bindings, that is, parameters for witnesses.
  66. struct Impl {
  67. Nonnull<const Value*> interface;
  68. std::vector<Nonnull<const GenericBinding*>> deduced;
  69. Nonnull<const Value*> type;
  70. std::vector<Nonnull<const ImplBinding*>> impl_bindings;
  71. Nonnull<Expression*> impl;
  72. };
  73. private:
  74. // Returns the associated impl for the given `iface` and `type` in
  75. // the ancestor graph of this scope, returns std::nullopt if there
  76. // is none, or reports a compilation error is there is not a most
  77. // specific impl for the given `iface` and `type`.
  78. // Use `original_scope` to satisfy requirements of any generic impl
  79. // that matches `iface` and `type`.
  80. auto TryResolve(Nonnull<const Value*> iface, Nonnull<const Value*> type,
  81. SourceLocation source_loc, const ImplScope& original_scope,
  82. const TypeChecker& type_checker) const
  83. -> ErrorOr<std::optional<Nonnull<Expression*>>>;
  84. // Returns the associated impl for the given `iface` and `type` in
  85. // this scope, returns std::nullopt if there is none, or reports
  86. // a compilation error is there is not a most specific impl for the
  87. // given `iface` and `type`.
  88. // Use `original_scope` to satisfy requirements of any generic impl
  89. // that matches `iface` and `type`.
  90. auto ResolveHere(Nonnull<const Value*> iface_type,
  91. Nonnull<const Value*> impl_type, SourceLocation source_loc,
  92. const ImplScope& original_scope,
  93. const TypeChecker& type_checker) const
  94. -> ErrorOr<std::optional<Nonnull<Expression*>>>;
  95. std::vector<Impl> impls_;
  96. std::vector<Nonnull<const ImplScope*>> parent_scopes_;
  97. };
  98. } // namespace Carbon
  99. #endif // EXECUTABLE_SEMANTICS_AST_IMPL_SCOPE_H_