Introduce SubstituteLifetimes.

This method allows (constrained) manipulation of the lifetimes. It also has
well-defined (but not yet implemented) behaviour in the presence of HRTBs.

PiperOrigin-RevId: 440886942
diff --git a/lifetime_annotations/BUILD b/lifetime_annotations/BUILD
index 89c68db..e8082a8 100644
--- a/lifetime_annotations/BUILD
+++ b/lifetime_annotations/BUILD
@@ -35,6 +35,7 @@
     ],
     deps = [
         ":lifetime",
+        ":lifetime_substitutions",
         ":lifetime_symbol_table",
         ":pointee_type",
         "@absl//strings",
diff --git a/lifetime_annotations/function_lifetimes.cc b/lifetime_annotations/function_lifetimes.cc
index 81afb3f..560ec38 100644
--- a/lifetime_annotations/function_lifetimes.cc
+++ b/lifetime_annotations/function_lifetimes.cc
@@ -138,6 +138,17 @@
   return all_lifetimes;
 }
 
+void FunctionLifetimes::SubstituteLifetimes(
+    const LifetimeSubstitutions& subst) {
+  // TODO(veluca): this is incorrect in the presence of HRTBs.
+  std::for_each(param_lifetimes_.begin(), param_lifetimes_.end(),
+                [&subst](ValueLifetimes& v) { v.SubstituteLifetimes(subst); });
+  return_lifetimes_.SubstituteLifetimes(subst);
+  if (this_lifetimes_.has_value()) {
+    this_lifetimes_->SubstituteLifetimes(subst);
+  }
+}
+
 void FunctionLifetimes::Traverse(
     std::function<void(Lifetime&, Variance)> visitor) {
   for (auto& param : param_lifetimes_) {
diff --git a/lifetime_annotations/function_lifetimes.h b/lifetime_annotations/function_lifetimes.h
index f7be923..b1528c5 100644
--- a/lifetime_annotations/function_lifetimes.h
+++ b/lifetime_annotations/function_lifetimes.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <variant>
 
+#include "lifetime_annotations/lifetime_substitutions.h"
 #include "lifetime_annotations/type_lifetimes.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/AST/Decl.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
@@ -111,6 +112,14 @@
   // of the enclosing class.
   llvm::DenseSet<Lifetime> AllFreeLifetimes() const;
 
+  // Applies `subst` to all lifetimes in this FunctionLifetimes.
+  // Any lifetime parameter declarations will moved to the innermost location
+  // that is valid for the new lifetimes. Note that this operation is
+  // well-defined and declarations of lifetime parameters can only "move up";
+  // in particular, it results lifetime parameters being as tightly bound as
+  // possible, which is what we want inference to infer.
+  void SubstituteLifetimes(const LifetimeSubstitutions& subst);
+
   // Traverses all the lifetimes in the function signature, recursively. The
   // visit is done in post-order on the lifetime tree of this type.
   void Traverse(std::function<void(Lifetime&, Variance)> visitor);
diff --git a/lifetime_annotations/type_lifetimes.cc b/lifetime_annotations/type_lifetimes.cc
index 7581414..cb82bc0 100644
--- a/lifetime_annotations/type_lifetimes.cc
+++ b/lifetime_annotations/type_lifetimes.cc
@@ -338,6 +338,28 @@
   return false;
 }
 
+void ValueLifetimes::SubstituteLifetimes(const LifetimeSubstitutions& subst) {
+  for (auto& tmpl_arg_at_depth : template_argument_lifetimes_) {
+    for (std::optional<ValueLifetimes>& tmpl_arg : tmpl_arg_at_depth) {
+      if (tmpl_arg) {
+        tmpl_arg->SubstituteLifetimes(subst);
+      }
+    }
+  }
+  if (pointee_lifetimes_) {
+    pointee_lifetimes_->SubstituteLifetimes(subst);
+  }
+  for (const auto& lftm_arg : GetLifetimeParameters(type_)) {
+    std::optional<Lifetime> lifetime =
+        lifetime_parameters_by_name_.LookupName(lftm_arg);
+    assert(lifetime.has_value());
+    lifetime_parameters_by_name_.Rebind(lftm_arg, subst.Substitute(*lifetime));
+  }
+  if (function_lifetimes_) {
+    function_lifetimes_->SubstituteLifetimes(subst);
+  }
+}
+
 void ValueLifetimes::Traverse(std::function<void(Lifetime&, Variance)> visitor,
                               Variance variance) {
   for (auto& tmpl_arg_at_depth : template_argument_lifetimes_) {
@@ -541,6 +563,11 @@
   return predicate(lifetime_) || value_lifetimes_.HasAny(predicate);
 }
 
+void ObjectLifetimes::SubstituteLifetimes(const LifetimeSubstitutions& subst) {
+  lifetime_ = subst.Substitute(lifetime_);
+  value_lifetimes_.SubstituteLifetimes(subst);
+}
+
 void ObjectLifetimes::Traverse(std::function<void(Lifetime&, Variance)> visitor,
                                Variance variance,
                                clang::QualType indirection_type) {
diff --git a/lifetime_annotations/type_lifetimes.h b/lifetime_annotations/type_lifetimes.h
index f9580af..206f92b 100644
--- a/lifetime_annotations/type_lifetimes.h
+++ b/lifetime_annotations/type_lifetimes.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "lifetime_annotations/lifetime.h"
+#include "lifetime_annotations/lifetime_substitutions.h"
 #include "lifetime_annotations/lifetime_symbol_table.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
 #include "third_party/llvm/llvm-project/clang/include/clang/AST/TypeOrdering.h"
@@ -131,6 +132,10 @@
   // the `ValueLifetimes`.
   bool HasAny(const std::function<bool(Lifetime)>& predicate) const;
 
+  // Applies `subst` to all lifetimes in this ValueLifetimes.
+  // See FunctionLifetimes::SubstituteLifetimes() for details.
+  void SubstituteLifetimes(const LifetimeSubstitutions& subst);
+
   // Traverses all the lifetimes in the object, recursively. The
   // visit is done in post-order on the lifetime tree of this type.
   // The callback may mutate the lifetime in an arbitrary way; `variance` will
@@ -215,6 +220,10 @@
   // the `ObjectLifetimes`.
   bool HasAny(const std::function<bool(Lifetime)>& predicate) const;
 
+  // Applies `subst` to all lifetimes in this ObjectLifetimes.
+  // See FunctionLifetimes::SubstituteLifetimes() for details.
+  void SubstituteLifetimes(const LifetimeSubstitutions& subst);
+
   // Traverses all the lifetimes in the object, recursively. The
   // visit is done in post-order on the lifetime tree of this type.
   // The callback may mutate the lifetime in an arbitrary way; `variance` will