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