Просмотр исходного кода

Track the arguments and witnesses on values indirectly. (#1335)

This avoids the need to make copies of potentially large maps when
the same bindings are used in multiple values, such as when forming
a bound method value.
Richard Smith 3 лет назад
Родитель
Сommit
a1be2a8a38

+ 10 - 0
explorer/ast/BUILD

@@ -89,6 +89,15 @@ cc_library(
     ],
 )
 
+cc_library(
+    name = "bindings",
+    srcs = ["bindings.cpp"],
+    hdrs = ["bindings.h"],
+    deps = [
+        "//explorer/common:nonnull",
+    ],
+)
+
 cc_library(
     name = "declaration",
     srcs = ["declaration.cpp"],
@@ -153,6 +162,7 @@ cc_library(
     hdrs = ["expression.h", "pattern.h"],
     deps = [
         ":ast_node",
+        ":bindings",
         ":member",
         ":paren_contents",
         ":static_scope",

+ 14 - 0
explorer/ast/bindings.cpp

@@ -0,0 +1,14 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "explorer/ast/bindings.h"
+
+namespace Carbon {
+
+auto Bindings::None() -> Nonnull<const Bindings*> {
+  static Nonnull<const Bindings*> bindings = new Bindings({}, {});
+  return bindings;
+}
+
+}  // namespace Carbon

+ 57 - 0
explorer/ast/bindings.h

@@ -0,0 +1,57 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CARBON_EXPLORER_AST_BINDINGS_H_
+#define CARBON_EXPLORER_AST_BINDINGS_H_
+
+#include <map>
+
+#include "explorer/common/nonnull.h"
+
+namespace Carbon {
+
+class ImplBinding;
+class GenericBinding;
+class Value;
+
+using BindingMap =
+    std::map<Nonnull<const GenericBinding*>, Nonnull<const Value*>>;
+using ImplWitnessMap =
+    std::map<Nonnull<const ImplBinding*>, Nonnull<const Value*>>;
+
+// A set of evaluated bindings in some context, such as a function or class.
+//
+// These are shared by a context and all unparameterized entities within that
+// context. For example, a class and the name of a method within that class
+// will have the same set of bindings.
+class Bindings {
+ public:
+  // Create an instantiated set of bindings for use during evaluation,
+  // containing both arguments and witnesses.
+  Bindings(BindingMap args, ImplWitnessMap witnesses)
+      : args_(args), witnesses_(witnesses) {}
+
+  enum NoWitnessesTag { NoWitnesses };
+
+  // Create a set of bindings for use during type-checking, containing only the
+  // arguments but not the corresponding witnesses.
+  Bindings(BindingMap args, NoWitnessesTag) : args_(args), witnesses_() {}
+
+  // Argument values corresponding to generic bindings.
+  auto args() const -> const BindingMap& { return args_; }
+
+  // Witnesses corresponding to impl bindings.
+  auto witnesses() const -> const ImplWitnessMap& { return witnesses_; }
+
+  // An empty set of bindings.
+  static auto None() -> Nonnull<const Bindings*>;
+
+ private:
+  BindingMap args_;
+  ImplWitnessMap witnesses_;
+};
+
+}  // namespace Carbon
+
+#endif  // CARBON_EXPLORER_AST_BINDINGS_H_

+ 1 - 5
explorer/ast/expression.h

@@ -13,6 +13,7 @@
 
 #include "common/ostream.h"
 #include "explorer/ast/ast_node.h"
+#include "explorer/ast/bindings.h"
 #include "explorer/ast/member.h"
 #include "explorer/ast/paren_contents.h"
 #include "explorer/ast/static_scope.h"
@@ -510,11 +511,6 @@ class PrimitiveOperatorExpression : public Expression {
   std::vector<Nonnull<Expression*>> arguments_;
 };
 
-class GenericBinding;
-
-using BindingMap =
-    std::map<Nonnull<const GenericBinding*>, Nonnull<const Value*>>;
-
 using ImplExpMap = std::map<Nonnull<const ImplBinding*>, Nonnull<Expression*>>;
 
 class CallExpression : public Expression {

+ 1 - 0
explorer/interpreter/BUILD

@@ -24,6 +24,7 @@ cc_library(
         ":stack",
         "//common:check",
         "//common:ostream",
+        "//explorer/ast:bindings",
         "//explorer/ast:declaration",
         "//explorer/ast:expression",
         "//explorer/ast:member",

+ 42 - 21
explorer/interpreter/interpreter.cpp

@@ -109,10 +109,16 @@ class Interpreter {
   auto InstantiateType(Nonnull<const Value*> type, SourceLocation source_loc)
       -> ErrorOr<Nonnull<const Value*>>;
 
+  // Instantiate a set of bindings by replacing all type variables that occur
+  // within it by the current values of those variables.
+  auto InstantiateBindings(Nonnull<const Bindings*> bindings,
+                           SourceLocation source_loc)
+      -> ErrorOr<Nonnull<const Bindings*>>;
+
   // Call the function `fun` with the given `arg` and the `witnesses`
   // for the function's impl bindings.
   auto CallFunction(const CallExpression& call, Nonnull<const Value*> fun,
-                    Nonnull<const Value*> arg, const ImplWitnessMap& witnesses)
+                    Nonnull<const Value*> arg, ImplWitnessMap&& witnesses)
       -> ErrorOr<Success>;
 
   void PrintState(llvm::raw_ostream& out);
@@ -464,26 +470,38 @@ auto Interpreter::InstantiateType(Nonnull<const Value*> type,
     }
     case Value::Kind::NominalClassType: {
       const auto& class_type = cast<NominalClassType>(*type);
-      BindingMap inst_type_args;
-      for (const auto& [ty_var, ty_arg] : class_type.type_args()) {
-        CARBON_ASSIGN_OR_RETURN(inst_type_args[ty_var],
-                                InstantiateType(ty_arg, source_loc));
-      }
-      ImplWitnessMap witnesses = class_type.witnesses();
-      for (auto& [bind, witness] : witnesses) {
-        if (auto* sym = dyn_cast<SymbolicWitness>(witness)) {
-          CARBON_ASSIGN_OR_RETURN(witness,
-                                  EvalExpRecursively(&sym->impl_expression()));
-        }
-      }
-      return arena_->New<NominalClassType>(&class_type.declaration(),
-                                           inst_type_args, witnesses);
+      CARBON_ASSIGN_OR_RETURN(
+          Nonnull<const Bindings*> bindings,
+          InstantiateBindings(&class_type.bindings(), source_loc));
+      return arena_->New<NominalClassType>(&class_type.declaration(), bindings);
     }
     default:
       return type;
   }
 }
 
+auto Interpreter::InstantiateBindings(Nonnull<const Bindings*> bindings,
+                                      SourceLocation source_loc)
+    -> ErrorOr<Nonnull<const Bindings*>> {
+  BindingMap args = bindings->args();
+  for (auto& [var, arg] : args) {
+    CARBON_ASSIGN_OR_RETURN(arg, InstantiateType(arg, source_loc));
+  }
+
+  ImplWitnessMap witnesses = bindings->witnesses();
+  for (auto& [bind, witness] : witnesses) {
+    if (auto* sym = dyn_cast<SymbolicWitness>(witness)) {
+      CARBON_ASSIGN_OR_RETURN(witness,
+                              EvalExpRecursively(&sym->impl_expression()));
+    }
+  }
+
+  if (args == bindings->args() && witnesses == bindings->witnesses()) {
+    return bindings;
+  }
+  return arena_->New<Bindings>(std::move(args), std::move(witnesses));
+}
+
 auto Interpreter::Convert(Nonnull<const Value*> value,
                           Nonnull<const Value*> destination_type,
                           SourceLocation source_loc)
@@ -609,8 +627,7 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
 auto Interpreter::CallFunction(const CallExpression& call,
                                Nonnull<const Value*> fun,
                                Nonnull<const Value*> arg,
-                               const ImplWitnessMap& witnesses)
-    -> ErrorOr<Success> {
+                               ImplWitnessMap&& witnesses) -> ErrorOr<Success> {
   if (trace_stream_) {
     **trace_stream_ << "calling function: " << *fun << "\n";
   }
@@ -703,13 +720,15 @@ auto Interpreter::CallFunction(const CallExpression& call,
       CARBON_CHECK(PatternMatch(&name.params().value(), arg, call.source_loc(),
                                 &params_scope, generic_args, trace_stream_,
                                 this->arena_));
+      Nonnull<const Bindings*> bindings =
+          arena_->New<Bindings>(std::move(generic_args), std::move(witnesses));
       switch (decl.kind()) {
         case DeclarationKind::ClassDeclaration:
           return todo_.FinishAction(arena_->New<NominalClassType>(
-              &cast<ClassDeclaration>(decl), generic_args, witnesses));
+              &cast<ClassDeclaration>(decl), bindings));
         case DeclarationKind::InterfaceDeclaration:
           return todo_.FinishAction(arena_->New<InterfaceType>(
-              &cast<InterfaceDeclaration>(decl), generic_args, witnesses));
+              &cast<InterfaceDeclaration>(decl), bindings));
         default:
           CARBON_FATAL() << "unknown kind of ParameterizedEntityName " << decl;
       }
@@ -751,7 +770,9 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
           ++i;
         }
         return todo_.FinishAction(arena_->New<ImplWitness>(
-            &generic_witness->declaration(), inst_impl.type_args(), witnesses));
+            &generic_witness->declaration(),
+            arena_->New<Bindings>(inst_impl.type_args(),
+                                  std::move(witnesses))));
       }
     }
     case ExpressionKind::IndexExpression: {
@@ -1000,7 +1021,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
           }
         }
         return CallFunction(call, act.results()[0], act.results()[1],
-                            witnesses);
+                            std::move(witnesses));
       } else if (act.pos() == 3 + int(num_impls)) {
         if (act.results().size() < 3 + num_impls) {
           // Control fell through without explicit return.

+ 18 - 11
explorer/interpreter/type_checker.cpp

@@ -448,14 +448,17 @@ auto TypeChecker::GetBuiltinInterfaceType(SourceLocation source_loc,
   if (has_parameters != has_arguments) {
     return bad_builtin();
   }
-  BindingMap bindings;
+  BindingMap binding_args;
   if (has_arguments) {
     TupleValue args(interface.arguments);
     if (!PatternMatch(&iface_decl->params().value()->value(), &args, source_loc,
-                      std::nullopt, bindings, trace_stream_, this->arena_)) {
+                      std::nullopt, binding_args, trace_stream_,
+                      this->arena_)) {
       return bad_builtin();
     }
   }
+  Nonnull<const Bindings*> bindings =
+      arena_->New<Bindings>(std::move(binding_args), Bindings::NoWitnesses);
   return arena_->New<InterfaceType>(iface_decl, bindings);
 }
 
@@ -875,12 +878,13 @@ class ConstraintTypeBuilder {
 auto TypeChecker::Substitute(
     const std::map<Nonnull<const GenericBinding*>, Nonnull<const Value*>>& dict,
     Nonnull<const Value*> type) const -> Nonnull<const Value*> {
-  auto SubstituteIntoBindingMap = [&](const BindingMap& map) -> BindingMap {
+  auto SubstituteIntoBindings =
+      [&](const Bindings& bindings) -> Nonnull<const Bindings*> {
     BindingMap result;
-    for (const auto& [name, value] : map) {
+    for (const auto& [name, value] : bindings.args()) {
       result[name] = Substitute(dict, value);
     }
-    return result;
+    return arena_->New<Bindings>(std::move(result), Bindings::NoWitnesses);
   };
 
   switch (type->kind()) {
@@ -971,14 +975,14 @@ auto TypeChecker::Substitute(
       Nonnull<const NominalClassType*> new_class_type =
           arena_->New<NominalClassType>(
               &class_type.declaration(),
-              SubstituteIntoBindingMap(class_type.type_args()));
+              SubstituteIntoBindings(class_type.bindings()));
       return new_class_type;
     }
     case Value::Kind::InterfaceType: {
       const auto& iface_type = cast<InterfaceType>(*type);
       Nonnull<const InterfaceType*> new_iface_type = arena_->New<InterfaceType>(
           &iface_type.declaration(),
-          SubstituteIntoBindingMap(iface_type.args()));
+          SubstituteIntoBindings(iface_type.bindings()));
       return new_iface_type;
     }
     case Value::Kind::ConstraintType: {
@@ -1975,13 +1979,15 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
           CARBON_RETURN_IF_ERROR(DeduceCallBindings(
               call, &param_name.params().static_type(), generic_parameters,
               /*deduced_bindings=*/llvm::None, impl_bindings, impl_scope));
+          Nonnull<const Bindings*> bindings =
+              arena_->New<Bindings>(call.deduced_args(), Bindings::NoWitnesses);
 
           const Declaration& decl = param_name.declaration();
           switch (decl.kind()) {
             case DeclarationKind::ClassDeclaration: {
               Nonnull<NominalClassType*> inst_class_type =
                   arena_->New<NominalClassType>(&cast<ClassDeclaration>(decl),
-                                                call.deduced_args());
+                                                bindings);
               call.set_static_type(
                   arena_->New<TypeOfClassType>(inst_class_type));
               call.set_value_category(ValueCategory::Let);
@@ -1990,7 +1996,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
             case DeclarationKind::InterfaceDeclaration: {
               Nonnull<InterfaceType*> inst_iface_type =
                   arena_->New<InterfaceType>(&cast<InterfaceDeclaration>(decl),
-                                             call.deduced_args());
+                                             bindings);
               call.set_static_type(
                   arena_->New<TypeOfInterfaceType>(inst_iface_type));
               call.set_value_category(ValueCategory::Let);
@@ -2892,8 +2898,9 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
     // above and/or by any enclosing generic classes.
     generic_args[binding] = *binding->symbolic_identity();
   }
-  Nonnull<NominalClassType*> self_type =
-      arena_->New<NominalClassType>(class_decl, generic_args);
+  Nonnull<NominalClassType*> self_type = arena_->New<NominalClassType>(
+      class_decl,
+      arena_->New<Bindings>(std::move(generic_args), Bindings::NoWitnesses));
   SetConstantValue(self, self_type);
   self->set_static_type(arena_->New<TypeOfClassType>(self_type));
 

+ 5 - 10
explorer/interpreter/value.cpp

@@ -46,14 +46,12 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
           const auto& fun_decl = cast<FunctionDeclaration>(**mem_decl);
           if (fun_decl.is_method()) {
             return arena->New<BoundMethodValue>(&fun_decl, v,
-                                                impl_witness->type_args(),
-                                                impl_witness->witnesses());
+                                                &impl_witness->bindings());
           } else {
             // Class function.
             auto* fun = cast<FunctionValue>(*fun_decl.constant_value());
             return arena->New<FunctionValue>(&fun->declaration(),
-                                             impl_witness->type_args(),
-                                             impl_witness->witnesses());
+                                             &impl_witness->bindings());
           }
         } else {
           return CompilationError(source_loc)
@@ -101,13 +99,11 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
           // Found a method. Turn it into a bound method.
           const FunctionValue& m = cast<FunctionValue>(**func);
           return arena->New<BoundMethodValue>(&m.declaration(), me_value,
-                                              class_type.type_args(),
-                                              class_type.witnesses());
+                                              &class_type.bindings());
         } else {
           // Found a class function
           return arena->New<FunctionValue>(&(*func)->declaration(),
-                                           class_type.type_args(),
-                                           class_type.witnesses());
+                                           &class_type.bindings());
         }
       }
     }
@@ -129,8 +125,7 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
                << "class function " << f << " not in " << *v;
       }
       return arena->New<FunctionValue>(&(*fun)->declaration(),
-                                       class_type.type_args(),
-                                       class_type.witnesses());
+                                       &class_type.bindings());
     }
     default:
       CARBON_FATAL() << "field access not allowed for value " << *v;

+ 55 - 61
explorer/interpreter/value.h

@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "common/ostream.h"
+#include "explorer/ast/bindings.h"
 #include "explorer/ast/declaration.h"
 #include "explorer/ast/member.h"
 #include "explorer/ast/statement.h"
@@ -127,9 +128,6 @@ class IntValue : public Value {
   int value_;
 };
 
-using ImplWitnessMap =
-    std::map<Nonnull<const ImplBinding*>, Nonnull<const Value*>>;
-
 // A function value.
 class FunctionValue : public Value {
  public:
@@ -137,12 +135,10 @@ class FunctionValue : public Value {
       : Value(Kind::FunctionValue), declaration_(declaration) {}
 
   explicit FunctionValue(Nonnull<const FunctionDeclaration*> declaration,
-                         const BindingMap& type_args,
-                         const ImplWitnessMap& wits)
+                         Nonnull<const Bindings*> bindings)
       : Value(Kind::FunctionValue),
         declaration_(declaration),
-        type_args_(type_args),
-        witnesses_(wits) {}
+        bindings_(bindings) {}
 
   static auto classof(const Value* value) -> bool {
     return value->kind() == Kind::FunctionValue;
@@ -152,14 +148,17 @@ class FunctionValue : public Value {
     return *declaration_;
   }
 
-  auto type_args() const -> const BindingMap& { return type_args_; }
+  auto bindings() const -> const Bindings& { return *bindings_; }
+
+  auto type_args() const -> const BindingMap& { return bindings_->args(); }
 
-  auto witnesses() const -> const ImplWitnessMap& { return witnesses_; }
+  auto witnesses() const -> const ImplWitnessMap& {
+    return bindings_->witnesses();
+  }
 
  private:
   Nonnull<const FunctionDeclaration*> declaration_;
-  BindingMap type_args_;
-  ImplWitnessMap witnesses_;
+  Nonnull<const Bindings*> bindings_ = Bindings::None();
 };
 
 // A bound method value. It includes the receiver object.
@@ -173,13 +172,11 @@ class BoundMethodValue : public Value {
 
   explicit BoundMethodValue(Nonnull<const FunctionDeclaration*> declaration,
                             Nonnull<const Value*> receiver,
-                            const BindingMap& type_args,
-                            const ImplWitnessMap& wits)
+                            Nonnull<const Bindings*> bindings)
       : Value(Kind::BoundMethodValue),
         declaration_(declaration),
         receiver_(receiver),
-        type_args_(type_args),
-        witnesses_(wits) {}
+        bindings_(bindings) {}
 
   static auto classof(const Value* value) -> bool {
     return value->kind() == Kind::BoundMethodValue;
@@ -191,15 +188,18 @@ class BoundMethodValue : public Value {
 
   auto receiver() const -> Nonnull<const Value*> { return receiver_; }
 
-  auto type_args() const -> const BindingMap& { return type_args_; }
+  auto bindings() const -> const Bindings& { return *bindings_; }
 
-  auto witnesses() const -> const ImplWitnessMap& { return witnesses_; }
+  auto type_args() const -> const BindingMap& { return bindings_->args(); }
+
+  auto witnesses() const -> const ImplWitnessMap& {
+    return bindings_->witnesses();
+  }
 
  private:
   Nonnull<const FunctionDeclaration*> declaration_;
   Nonnull<const Value*> receiver_;
-  BindingMap type_args_;
-  ImplWitnessMap witnesses_;
+  Nonnull<const Bindings*> bindings_ = Bindings::None();
 };
 
 // The value of a location in memory.
@@ -549,40 +549,36 @@ class NominalClassType : public Value {
         << "missing arguments for parameterized class type";
   }
 
-  // Construct a class type that represents the result of applying the
-  // given generic class to the `type_args`.
-  explicit NominalClassType(Nonnull<const ClassDeclaration*> declaration,
-                            const BindingMap& type_args)
-      : Value(Kind::NominalClassType),
-        declaration_(declaration),
-        type_args_(type_args) {}
-
   // Construct a fully instantiated generic class type to represent the
   // run-time type of an object.
   explicit NominalClassType(Nonnull<const ClassDeclaration*> declaration,
-                            const BindingMap& type_args,
-                            const ImplWitnessMap& wits)
+                            Nonnull<const Bindings*> bindings)
       : Value(Kind::NominalClassType),
         declaration_(declaration),
-        type_args_(type_args),
-        witnesses_(wits) {}
+        bindings_(bindings) {}
 
   static auto classof(const Value* value) -> bool {
     return value->kind() == Kind::NominalClassType;
   }
 
   auto declaration() const -> const ClassDeclaration& { return *declaration_; }
-  auto type_args() const -> const BindingMap& { return type_args_; }
 
-  // Maps each of the class's impl bindings to the witness table
-  // for the corresponding argument. Should only be called on a fully
-  // instantiated runtime type of a generic class.
-  auto witnesses() const -> const ImplWitnessMap& { return witnesses_; }
+  auto bindings() const -> const Bindings& { return *bindings_; }
+
+  auto type_args() const -> const BindingMap& { return bindings_->args(); }
+
+  // Witnesses for each of the class's impl bindings. These will not in general
+  // be set for class types that are only intended to be used within
+  // type-checking and not at runtime, such as in the static_type() of an
+  // expression or the type in a TypeOfClassType.
+  auto witnesses() const -> const ImplWitnessMap& {
+    return bindings_->witnesses();
+  }
 
   // Returns whether this a parameterized class. That is, a class with
   // parameters and no corresponding arguments.
   auto IsParameterized() const -> bool {
-    return declaration_->type_params().has_value() && type_args_.empty();
+    return declaration_->type_params().has_value() && type_args().empty();
   }
 
   // Returns the value of the function named `name` in this class, or
@@ -592,8 +588,7 @@ class NominalClassType : public Value {
 
  private:
   Nonnull<const ClassDeclaration*> declaration_;
-  BindingMap type_args_;
-  ImplWitnessMap witnesses_;
+  Nonnull<const Bindings*> bindings_ = Bindings::None();
 };
 
 // Return the declaration of the member with the given name.
@@ -602,7 +597,6 @@ auto FindMember(std::string_view name,
     -> std::optional<Nonnull<const Declaration*>>;
 
 // An interface type.
-// TODO: Consider removing this once ConstraintType is ready.
 class InterfaceType : public Value {
  public:
   explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration)
@@ -611,14 +605,10 @@ class InterfaceType : public Value {
         << "missing arguments for parameterized interface type";
   }
   explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration,
-                         const BindingMap& args)
-      : Value(Kind::InterfaceType), declaration_(declaration), args_(args) {}
-  explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration,
-                         const BindingMap& args, const ImplWitnessMap& wits)
+                         Nonnull<const Bindings*> bindings)
       : Value(Kind::InterfaceType),
         declaration_(declaration),
-        args_(args),
-        witnesses_(wits) {}
+        bindings_(bindings) {}
 
   static auto classof(const Value* value) -> bool {
     return value->kind() == Kind::InterfaceType;
@@ -627,15 +617,18 @@ class InterfaceType : public Value {
   auto declaration() const -> const InterfaceDeclaration& {
     return *declaration_;
   }
-  auto args() const -> const BindingMap& { return args_; }
 
-  // TODO: These aren't used for anything yet.
-  auto witnesses() const -> const ImplWitnessMap& { return witnesses_; }
+  auto bindings() const -> const Bindings& { return *bindings_; }
+
+  auto args() const -> const BindingMap& { return bindings_->args(); }
+
+  auto witnesses() const -> const ImplWitnessMap& {
+    return bindings_->witnesses();
+  }
 
  private:
   Nonnull<const InterfaceDeclaration*> declaration_;
-  BindingMap args_;
-  ImplWitnessMap witnesses_;
+  Nonnull<const Bindings*> bindings_ = Bindings::None();
 };
 
 // A type-of-type for an unknown constrained type.
@@ -733,26 +726,27 @@ class ImplWitness : public Witness {
 
   // Construct an instantiated generic impl.
   explicit ImplWitness(Nonnull<const ImplDeclaration*> declaration,
-                       const BindingMap& type_args, const ImplWitnessMap& wits)
+                       Nonnull<const Bindings*> bindings)
       : Witness(Kind::ImplWitness),
         declaration_(declaration),
-        type_args_(type_args),
-        witnesses_(wits) {}
+        bindings_(bindings) {}
 
   static auto classof(const Value* value) -> bool {
     return value->kind() == Kind::ImplWitness;
   }
   auto declaration() const -> const ImplDeclaration& { return *declaration_; }
-  auto type_args() const -> const BindingMap& { return type_args_; }
-  // Maps each of the impl's impl bindings to the witness table
-  // for the corresponding argument. Should only be called on a fully
-  // instantiated runtime type of a generic class.
-  auto witnesses() const -> const ImplWitnessMap& { return witnesses_; }
+
+  auto bindings() const -> const Bindings& { return *bindings_; }
+
+  auto type_args() const -> const BindingMap& { return bindings_->args(); }
+
+  auto witnesses() const -> const ImplWitnessMap& {
+    return bindings_->witnesses();
+  }
 
  private:
   Nonnull<const ImplDeclaration*> declaration_;
-  BindingMap type_args_;
-  ImplWitnessMap witnesses_;
+  Nonnull<const Bindings*> bindings_ = Bindings::None();
 };
 
 // A witness table whose concrete value cannot be determined yet.