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
+7
View File
@@ -91,6 +91,7 @@ struct NestedValueVisitor {
auto Visit(ValueNodeView) -> bool { return true; }
auto Visit(int) -> bool { return true; }
auto Visit(Address) -> bool { return true; }
auto Visit(ExpressionCategory) -> bool { return true; }
auto Visit(const std::string&) -> bool { return true; }
auto Visit(Nonnull<const NominalClassValue**>) -> bool {
// This is the pointer to the most-derived value within a class value,
@@ -567,6 +568,10 @@ void Value::Print(llvm::raw_ostream& out) const {
case Value::Kind::LocationValue:
out << "lval<" << cast<LocationValue>(*this).address() << ">";
break;
case Value::Kind::ReferenceExpressionValue:
out << "ref_expr<" << cast<ReferenceExpressionValue>(*this).address()
<< ">";
break;
case Value::Kind::BoolType:
out << "bool";
break;
@@ -997,6 +1002,7 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2,
case Value::Kind::StringValue:
case Value::Kind::PointerValue:
case Value::Kind::LocationValue:
case Value::Kind::ReferenceExpressionValue:
case Value::Kind::BindingPlaceholderValue:
case Value::Kind::AddrValue:
case Value::Kind::UninitializedValue:
@@ -1148,6 +1154,7 @@ auto ValueStructurallyEqual(
case Value::Kind::AlternativeConstructorValue:
case Value::Kind::PointerValue:
case Value::Kind::LocationValue:
case Value::Kind::ReferenceExpressionValue:
case Value::Kind::UninitializedValue:
case Value::Kind::MemberName:
// TODO: support pointer comparisons once we have a clearer distinction