Explorer: Prevent copies when initializing a let binding from reference expression (#2946)

Prevent copies when initializing value expression from reference
expression. This is based on
https://github.com/carbon-language/carbon-lang/pull/2006, which
introduces expression categories, and how it is possible to convert
to/from those different categories. Continuation of
https://github.com/carbon-language/carbon-lang/pull/2907

## Functional changes

* Initializing a value expression from a reference expression takes its
value without a copy
* Reading from the value expression causes an error if the value changed
from the time it was initialized
* In this situation, prevents a copy both for variable definitions, and
call parameter bindings

## Main implementation changes

* Add new `ExpressionCategoryAction`, which evaluates an expression and
returns an `ExpressionValue` containing its category and address (if
any), in addition to the resulting `Value*`
* `ExpressionAction`s now invokes `ExpressionCategoryAction` and unwraps
the returned `ExpressionValue`
* `RuntimeScope::BindAndPin` method, and corresponding when attempting
to read a `value_node`.

## Next work

* Avoid unnecessary copies from value expression to value expression,
after ensuring that even value expression temporaries are registered for
destruction (https://github.com/Pixep/carbon-lang/pull/9)
This commit is contained in:
Adrien Leravat
2023-07-17 23:26:01 +00:00
committed by GitHub
parent 9e149a21c1
commit d02366f881
28 changed files with 757 additions and 178 deletions
+10 -9
View File
@@ -49,15 +49,15 @@ auto ActionStack::ValueOfNode(ValueNodeView value_node,
// with that node. This will help keep unwanted dynamic-scoping behavior
// from sneaking in.
if (action->scope().has_value()) {
std::optional<Nonnull<const Value*>> result =
action->scope()->Get(value_node);
CARBON_ASSIGN_OR_RETURN(auto result,
action->scope()->Get(value_node, source_loc));
if (result.has_value()) {
return *result;
}
}
}
if (globals_.has_value()) {
std::optional<Nonnull<const Value*>> result = globals_->Get(value_node);
CARBON_ASSIGN_OR_RETURN(auto result, globals_->Get(value_node, source_loc));
if (result.has_value()) {
return *result;
}
@@ -110,6 +110,7 @@ enum class FinishActionKind {
static auto FinishActionKindFor(Action::Kind kind) -> FinishActionKind {
switch (kind) {
case Action::Kind::ValueExpressionAction:
case Action::Kind::ExpressionAction:
case Action::Kind::WitnessAction:
case Action::Kind::LocationAction:
@@ -207,8 +208,8 @@ auto ActionStack::UnwindToWithCaptureScopesToDestroy(
auto item = todo_.Pop();
auto& scope = item->scope();
if (scope && item->kind() != Action::Kind::CleanUpAction) {
std::unique_ptr<Action> cleanup_action =
std::make_unique<CleanUpAction>(std::move(*scope));
std::unique_ptr<Action> cleanup_action = std::make_unique<CleanUpAction>(
std::move(*scope), ast_node->source_loc());
scopes_to_destroy.push(std::move(cleanup_action));
}
}
@@ -274,8 +275,8 @@ void ActionStack::PushCleanUpActions(
while (!actions.empty()) {
auto& act = actions.top();
if (act->scope()) {
std::unique_ptr<Action> cleanup_action =
std::make_unique<CleanUpAction>(std::move(*act->scope()));
std::unique_ptr<Action> cleanup_action = std::make_unique<CleanUpAction>(
std::move(*act->scope()), SourceLocation("stack cleanup", 1));
todo_.Push(std::move(cleanup_action));
}
actions.pop();
@@ -285,8 +286,8 @@ void ActionStack::PushCleanUpActions(
void ActionStack::PushCleanUpAction(std::unique_ptr<Action> act) {
auto& scope = act->scope();
if (scope && act->kind() != Action::Kind::CleanUpAction) {
std::unique_ptr<Action> cleanup_action =
std::make_unique<CleanUpAction>(std::move(*scope));
std::unique_ptr<Action> cleanup_action = std::make_unique<CleanUpAction>(
std::move(*scope), SourceLocation("stack cleanup", 1));
todo_.Push(std::move(cleanup_action));
}
}