Explorer: rename value categories to expression categories (#2744)

Rename value categories to expression categories based on [Discord discussion](https://discord.com/channels/655572317891461132/753021843459538996/1092924035517665332) regarding naming and behavior.

>* let expression -> value expression
>* var expression -> reference expression
>* located expression -> initializing expression
>So:
>- "value expressions" produce values (with no associated location). "reference expressions" produce a location of an existing value. "initializing expressions" take a location and initialize it.
>- A let binding is initialized by a value expression, because lets represent values (with category conversions performed as needed, but if a conversion is performed from a different category of expression, the value of the object is pinned for the lifetime of the let).
>- A var binding is initialized by an initializing expression, without performing a copy (with category conversions performed as needed, calling a copy constructor if the initializer is a different expression category).
>- The & operator requires a reference expression, and it's an error to give it other kinds.
>- The left-hand side of . requires a value expression when calling a function with a non-addr receiver, and requires a reference expression when calling a function with an addr receiver (it's an error to give it a value expression, and for an initializing expression, a temporary is materialized).

Changes
* Rename "value category" to "expression category"
* Rename Var and Let value categories to Value, Reference, and Initializing expression
* Rename `lvalue` to `location` (most of the time)
This commit is contained in:
Adrien Leravat
2023-04-05 16:16:10 -07:00
committed by GitHub
parent 3f1515af55
commit d0645c6a85
32 changed files with 376 additions and 320 deletions
+3 -3
View File
@@ -43,9 +43,9 @@ cc_library(
"value_kinds.def",
],
deps = [
":expression_category",
":library_name",
":paren_contents",
":value_category",
"//common:check",
"//common:enum_base",
"//common:error",
@@ -155,6 +155,6 @@ cc_library(
)
cc_library(
name = "value_category",
hdrs = ["value_category.h"],
name = "expression_category",
hdrs = ["expression_category.h"],
)
+38 -16
View File
@@ -14,11 +14,11 @@
#include "common/ostream.h"
#include "explorer/ast/ast_node.h"
#include "explorer/ast/clone_context.h"
#include "explorer/ast/expression_category.h"
#include "explorer/ast/impl_binding.h"
#include "explorer/ast/pattern.h"
#include "explorer/ast/return_term.h"
#include "explorer/ast/statement.h"
#include "explorer/ast/value_category.h"
#include "explorer/ast/value_node.h"
#include "explorer/common/nonnull.h"
#include "explorer/common/source_location.h"
@@ -200,7 +200,9 @@ class NamespaceDeclaration : public Declaration {
}
auto name() const -> const DeclaredName& { return name_; }
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
private:
DeclaredName name_;
@@ -255,7 +257,9 @@ class CallableDeclaration : public Declaration {
auto body() -> std::optional<Nonnull<Block*>> { return body_; }
auto virt_override() const -> VirtualOverride { return virt_override_; }
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
auto is_method() const -> bool { return self_pattern_.has_value(); }
@@ -356,7 +360,9 @@ class SelfDeclaration : public Declaration {
}
static auto name() -> std::string_view { return "Self"; }
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
};
enum class ClassExtensibility { None, Base, Abstract };
@@ -410,7 +416,9 @@ class ClassDeclaration : public Declaration {
return std::nullopt;
}
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
auto base_expr() const -> std::optional<Nonnull<Expression*>> {
return base_expr_;
@@ -474,7 +482,9 @@ class MixinDeclaration : public Declaration {
return members_;
}
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
private:
DeclaredName name_;
@@ -600,7 +610,9 @@ class ChoiceDeclaration : public Declaration {
return alternatives_;
}
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
auto FindAlternative(std::string_view name) const
-> std::optional<const AlternativeSignature*>;
@@ -617,18 +629,18 @@ class VariableDeclaration : public Declaration {
VariableDeclaration(SourceLocation source_loc,
Nonnull<BindingPattern*> binding,
std::optional<Nonnull<Expression*>> initializer,
ValueCategory value_category)
ExpressionCategory expression_category)
: Declaration(AstNodeKind::VariableDeclaration, source_loc),
binding_(binding),
initializer_(initializer),
value_category_(value_category) {}
expression_category_(expression_category) {}
explicit VariableDeclaration(CloneContext& context,
const VariableDeclaration& other)
: Declaration(context, other),
binding_(context.Clone(other.binding_)),
initializer_(context.Clone(other.initializer_)),
value_category_(other.value_category_) {}
expression_category_(other.expression_category_) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromVariableDeclaration(node->kind());
@@ -638,7 +650,9 @@ class VariableDeclaration : public Declaration {
auto binding() -> BindingPattern& { return *binding_; }
auto initializer() const -> const Expression& { return **initializer_; }
auto initializer() -> Expression& { return **initializer_; }
auto value_category() const -> ValueCategory { return value_category_; }
auto expression_category() const -> ExpressionCategory {
return expression_category_;
}
auto has_initializer() const -> bool { return initializer_.has_value(); }
@@ -651,7 +665,7 @@ class VariableDeclaration : public Declaration {
private:
Nonnull<BindingPattern*> binding_;
std::optional<Nonnull<Expression*>> initializer_;
ValueCategory value_category_;
ExpressionCategory expression_category_;
};
// Base class for constraint and interface declarations. Interfaces and named
@@ -703,7 +717,9 @@ class ConstraintTypeDeclaration : public Declaration {
return members_;
}
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
// Get the constraint type corresponding to this interface, or nullopt if
// this interface is incomplete.
@@ -846,7 +862,9 @@ class AssociatedConstantDeclaration : public Declaration {
auto binding() const -> const GenericBinding& { return *binding_; }
auto binding() -> GenericBinding& { return *binding_; }
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
private:
Nonnull<GenericBinding*> binding_;
@@ -908,7 +926,9 @@ class ImplDeclaration : public Declaration {
auto members() const -> llvm::ArrayRef<Nonnull<Declaration*>> {
return members_;
}
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
void set_impl_bindings(llvm::ArrayRef<Nonnull<const ImplBinding*>> imps) {
impl_bindings_ = imps;
}
@@ -993,7 +1013,9 @@ class AliasDeclaration : public Declaration {
auto name() const -> const DeclaredName& { return name_; }
auto target() const -> const Expression& { return *target_; }
auto target() -> Expression& { return *target_; }
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
private:
DeclaredName name_;
+6 -6
View File
@@ -34,8 +34,8 @@ TEST_F(ElementTest, NamedElementType) {
src_loc,
arena.New<BindingPattern>(src_loc, "valuename",
arena.New<AutoPattern>(src_loc),
ValueCategory::Var),
std::nullopt, ValueCategory::Var};
ExpressionCategory::Reference),
std::nullopt, ExpressionCategory::Reference};
const auto* static_type = arena.New<IntValue>(1);
decl.set_static_type(static_type);
NamedElement element_decl(&decl);
@@ -53,8 +53,8 @@ TEST_F(ElementTest, NamedElementDeclaration) {
src_loc,
arena.New<BindingPattern>(src_loc, "valuename",
arena.New<AutoPattern>(src_loc),
ValueCategory::Var),
std::nullopt, ValueCategory::Var};
ExpressionCategory::Reference),
std::nullopt, ExpressionCategory::Reference};
const auto* static_type = arena.New<IntValue>(1);
NamedElement element_decl(&decl);
@@ -71,8 +71,8 @@ TEST_F(ElementTest, NamedElementIsNamed) {
src_loc,
arena.New<BindingPattern>(src_loc, "valuename",
arena.New<AutoPattern>(src_loc),
ValueCategory::Var),
std::nullopt, ValueCategory::Var};
ExpressionCategory::Reference),
std::nullopt, ExpressionCategory::Reference};
NamedElement member_decl(&decl);
EXPECT_TRUE(member_decl.IsNamed("valuename"));
EXPECT_FALSE(member_decl.IsNamed("anything"));
+16 -13
View File
@@ -16,8 +16,8 @@
#include "explorer/ast/ast_node.h"
#include "explorer/ast/bindings.h"
#include "explorer/ast/element.h"
#include "explorer/ast/expression_category.h"
#include "explorer/ast/paren_contents.h"
#include "explorer/ast/value_category.h"
#include "explorer/ast/value_node.h"
#include "explorer/common/arena.h"
#include "explorer/common/source_location.h"
@@ -66,20 +66,22 @@ class Expression : public AstNode {
// The value category of this expression. Cannot be called before
// typechecking.
auto value_category() const -> ValueCategory { return *value_category_; }
auto expression_category() const -> ExpressionCategory {
return *expression_category_;
}
// Sets the value category of this expression. Can be called multiple times,
// but the argument must have the same value each time.
void set_value_category(ValueCategory value_category) {
CARBON_CHECK(!value_category_.has_value() ||
value_category == *value_category_);
value_category_ = value_category;
void set_expression_category(ExpressionCategory expression_category) {
CARBON_CHECK(!expression_category_.has_value() ||
expression_category == *expression_category_);
expression_category_ = expression_category;
}
// Determines whether the expression has already been type-checked. Should
// only be used by type-checking.
auto is_type_checked() const -> bool {
return static_type_.has_value() && value_category_.has_value();
return static_type_.has_value() && expression_category_.has_value();
}
protected:
@@ -94,7 +96,7 @@ class Expression : public AstNode {
private:
std::optional<Nonnull<const Value*>> static_type_;
std::optional<ValueCategory> value_category_;
std::optional<ExpressionCategory> expression_category_;
};
// A mixin for expressions that can be rewritten to a different expression by
@@ -114,7 +116,7 @@ class RewritableMixin : public Base {
CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice";
rewritten_form_ = rewritten_form;
this->set_static_type(&rewritten_form->static_type());
this->set_value_category(rewritten_form->value_category());
this->set_expression_category(rewritten_form->expression_category());
}
// Get the rewritten form of this expression. A rewritten form is used when
@@ -477,7 +479,7 @@ class BaseAccessExpression : public MemberAccessExpression {
object),
base_(base) {
set_static_type(&base->type());
set_value_category(ValueCategory::Let);
set_expression_category(ExpressionCategory::Value);
}
explicit BaseAccessExpression(CloneContext& context,
@@ -849,10 +851,11 @@ class ValueLiteral : public ConstantValueLiteral {
// Value literals are created by type-checking, and so are created with their
// type and value category already known.
ValueLiteral(SourceLocation source_loc, Nonnull<const Value*> value,
Nonnull<const Value*> type, ValueCategory value_category)
Nonnull<const Value*> type,
ExpressionCategory expression_category)
: ConstantValueLiteral(AstNodeKind::ValueLiteral, source_loc, value) {
set_static_type(type);
set_value_category(value_category);
set_expression_category(expression_category);
}
explicit ValueLiteral(CloneContext& context, const ValueLiteral& other)
@@ -1140,7 +1143,7 @@ class BuiltinConvertExpression : public Expression {
source_expression->source_loc()),
source_expression_(source_expression) {
set_static_type(destination_type);
set_value_category(ValueCategory::Let);
set_expression_category(ExpressionCategory::Value);
}
explicit BuiltinConvertExpression(CloneContext& context,
+23
View File
@@ -0,0 +1,23 @@
// 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_EXPRESSION_CATEGORY_H_
#define CARBON_EXPLORER_AST_EXPRESSION_CATEGORY_H_
namespace Carbon {
// The category of a Carbon expression indicates whether it evaluates
// to a value, reference, or initialization.
enum class ExpressionCategory {
// A "value expression" produces a value (with no associated location).
Value,
// A "reference expression" produces a location of an existing value.
Reference,
// An "initializing expression" takes a location and initialize it.
Initializing,
};
} // namespace Carbon
#endif // CARBON_EXPLORER_AST_EXPRESSION_CATEGORY_H_
+4 -2
View File
@@ -10,7 +10,7 @@
#include "common/check.h"
#include "common/ostream.h"
#include "explorer/ast/ast_node.h"
#include "explorer/ast/value_category.h"
#include "explorer/ast/expression_category.h"
namespace Carbon {
@@ -77,7 +77,9 @@ class ImplBinding : public AstNode {
auto static_type() const -> const Value& {
CARBON_FATAL() << "an ImplBinding has no type";
}
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
// Return the original impl binding.
auto original() const -> Nonnull<const ImplBinding*> {
+18 -14
View File
@@ -14,7 +14,7 @@
#include "explorer/ast/ast_rtti.h"
#include "explorer/ast/clone_context.h"
#include "explorer/ast/expression.h"
#include "explorer/ast/value_category.h"
#include "explorer/ast/expression_category.h"
#include "explorer/ast/value_node.h"
#include "explorer/common/source_location.h"
#include "llvm/ADT/ArrayRef.h"
@@ -152,7 +152,9 @@ class VarPattern : public Pattern {
auto pattern() const -> const Pattern& { return *pattern_; }
auto pattern() -> Pattern& { return *pattern_; }
auto value_category() const -> ValueCategory { return ValueCategory::Var; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Reference;
}
private:
Nonnull<Pattern*> pattern_;
@@ -166,17 +168,17 @@ class BindingPattern : public Pattern {
BindingPattern(SourceLocation source_loc, std::string name,
Nonnull<Pattern*> type,
std::optional<ValueCategory> value_category)
std::optional<ExpressionCategory> expression_category)
: Pattern(AstNodeKind::BindingPattern, source_loc),
name_(std::move(name)),
type_(type),
value_category_(value_category) {}
expression_category_(expression_category) {}
explicit BindingPattern(CloneContext& context, const BindingPattern& other)
: Pattern(context, other),
name_(other.name_),
type_(context.Clone(other.type_)),
value_category_(other.value_category_) {}
expression_category_(other.expression_category_) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromBindingPattern(node->kind());
@@ -193,21 +195,21 @@ class BindingPattern : public Pattern {
// Returns the value category of this pattern. Can only be called after
// typechecking.
auto value_category() const -> ValueCategory {
return value_category_.value();
auto expression_category() const -> ExpressionCategory {
return expression_category_.value();
}
// Returns whether the value category has been set. Should only be called
// during typechecking.
auto has_value_category() const -> bool {
return value_category_.has_value();
auto has_expression_category() const -> bool {
return expression_category_.has_value();
}
// Sets the value category of the variable being bound. Can only be called
// once during typechecking
void set_value_category(ValueCategory vc) {
CARBON_CHECK(!value_category_.has_value());
value_category_ = vc;
void set_expression_category(ExpressionCategory vc) {
CARBON_CHECK(!expression_category_.has_value());
expression_category_ = vc;
}
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
@@ -220,7 +222,7 @@ class BindingPattern : public Pattern {
private:
std::string name_;
Nonnull<Pattern*> type_;
std::optional<ValueCategory> value_category_;
std::optional<ExpressionCategory> expression_category_;
};
class AddrPattern : public Pattern {
@@ -305,7 +307,9 @@ class GenericBinding : public Pattern {
index_ = index;
}
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return template_value_;
+12 -7
View File
@@ -12,9 +12,9 @@
#include "explorer/ast/ast_node.h"
#include "explorer/ast/clone_context.h"
#include "explorer/ast/expression.h"
#include "explorer/ast/expression_category.h"
#include "explorer/ast/pattern.h"
#include "explorer/ast/return_term.h"
#include "explorer/ast/value_category.h"
#include "explorer/ast/value_node.h"
#include "explorer/common/arena.h"
#include "explorer/common/source_location.h"
@@ -219,11 +219,12 @@ class VariableDefinition : public Statement {
VariableDefinition(SourceLocation source_loc, Nonnull<Pattern*> pattern,
std::optional<Nonnull<Expression*>> init,
ValueCategory value_category, DefinitionType def_type)
ExpressionCategory expression_category,
DefinitionType def_type)
: Statement(AstNodeKind::VariableDefinition, source_loc),
pattern_(pattern),
init_(init),
value_category_(value_category),
expression_category_(expression_category),
def_type_(def_type) {}
explicit VariableDefinition(CloneContext& context,
@@ -231,7 +232,7 @@ class VariableDefinition : public Statement {
: Statement(context, other),
pattern_(context.Clone(other.pattern_)),
init_(context.Clone(other.init_)),
value_category_(other.value_category_),
expression_category_(other.expression_category_),
def_type_(other.def_type_) {}
static auto classof(const AstNode* node) -> bool {
@@ -258,14 +259,16 @@ class VariableDefinition : public Statement {
init_ = init;
}
auto value_category() const -> ValueCategory { return value_category_; }
auto expression_category() const -> ExpressionCategory {
return expression_category_;
}
auto is_returned() const -> bool { return def_type_ == Returned; };
private:
Nonnull<Pattern*> pattern_;
std::optional<Nonnull<Expression*>> init_;
ValueCategory value_category_;
ExpressionCategory expression_category_;
const DefinitionType def_type_;
};
@@ -620,7 +623,9 @@ class Continuation : public Statement {
static_type_ = type;
}
auto value_category() const -> ValueCategory { return ValueCategory::Var; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Reference;
}
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return std::nullopt;
}
+4 -4
View File
@@ -479,8 +479,8 @@ void Value::Print(llvm::raw_ostream& out) const {
case Value::Kind::PointerValue:
out << "ptr<" << cast<PointerValue>(*this).address() << ">";
break;
case Value::Kind::LValue:
out << "lval<" << cast<LValue>(*this).address() << ">";
case Value::Kind::LocationValue:
out << "lval<" << cast<LocationValue>(*this).address() << ">";
break;
case Value::Kind::BoolType:
out << "bool";
@@ -895,7 +895,7 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2,
case Value::Kind::AlternativeConstructorValue:
case Value::Kind::StringValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::BindingPlaceholderValue:
case Value::Kind::AddrValue:
case Value::Kind::ContinuationValue:
@@ -1049,7 +1049,7 @@ auto ValueStructurallyEqual(
case Value::Kind::AlternativeConstructorValue:
case Value::Kind::ContinuationValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::UninitializedValue:
case Value::Kind::MemberName:
// TODO: support pointer comparisons once we have a clearer distinction
+6 -6
View File
@@ -68,8 +68,8 @@ class Value {
// Returns the sub-Value specified by `path`, which must be a valid element
// path for *this. If the sub-Value is a method and its self_pattern is an
// AddrPattern, then pass the LValue representing the receiver as `me_value`,
// otherwise pass `*this`.
// AddrPattern, then pass the LocationValue representing the receiver as
// `me_value`, otherwise pass `*this`.
auto GetElement(Nonnull<Arena*> arena, const ElementPath& path,
SourceLocation source_loc,
Nonnull<const Value*> me_value) const
@@ -237,13 +237,13 @@ class DestructorValue : public Value {
};
// The value of a location in memory.
class LValue : public Value {
class LocationValue : public Value {
public:
explicit LValue(Address value)
: Value(Kind::LValue), value_(std::move(value)) {}
explicit LocationValue(Address value)
: Value(Kind::LocationValue), value_(std::move(value)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::LValue;
return value->kind() == Kind::LocationValue;
}
template <typename F>
-22
View File
@@ -1,22 +0,0 @@
// 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_VALUE_CATEGORY_H_
#define CARBON_EXPLORER_AST_VALUE_CATEGORY_H_
namespace Carbon {
// The value category of a Carbon expression indicates whether it evaluates
// to a variable or a value. A variable can be mutated, and can have its
// address taken, whereas a value cannot.
enum class ValueCategory {
// A variable. This roughly corresponds to a C++ lvalue.
Var,
// A value. This roughly corresponds to a C++ rvalue.
Let,
};
} // namespace Carbon
#endif // CARBON_EXPLORER_AST_VALUE_CATEGORY_H_
+1 -1
View File
@@ -15,7 +15,7 @@ CARBON_VALUE_KIND(FunctionValue)
CARBON_VALUE_KIND(DestructorValue)
CARBON_VALUE_KIND(BoundMethodValue)
CARBON_VALUE_KIND(PointerValue)
CARBON_VALUE_KIND(LValue)
CARBON_VALUE_KIND(LocationValue)
CARBON_VALUE_KIND(BoolValue)
CARBON_VALUE_KIND(StructValue)
CARBON_VALUE_KIND(NominalClassValue)
+9 -9
View File
@@ -11,7 +11,7 @@
#include "explorer/ast/ast_node.h"
#include "explorer/ast/clone_context.h"
#include "explorer/ast/value_category.h"
#include "explorer/ast/expression_category.h"
#include "explorer/common/nonnull.h"
namespace Carbon {
@@ -44,7 +44,7 @@ static constexpr bool ImplementsValueNode = false;
// auto static_type() const -> const Value&;
//
// // Returns the value category of an IdentifierExpression that names *this.
// auto value_category() const -> ValueCategory;
// auto expression_category() const -> ExpressionCategory;
//
// // Print the node's identity (e.g. its name).
// void PrintID(llvm::raw_ostream& out) const;
@@ -81,8 +81,8 @@ class ValueNodeView {
static_type_([](const AstNode& base) -> const Value& {
return llvm::cast<NodeType>(base).static_type();
}),
value_category_([](const AstNode& base) -> ValueCategory {
return llvm::cast<NodeType>(base).value_category();
expression_category_([](const AstNode& base) -> ExpressionCategory {
return llvm::cast<NodeType>(base).expression_category();
}) {}
explicit ValueNodeView(CloneContext& context, const ValueNodeView& other)
@@ -92,7 +92,7 @@ class ValueNodeView {
symbolic_identity_(other.symbolic_identity_),
print_(other.print_),
static_type_(other.static_type_),
value_category_(other.value_category_) {}
expression_category_(other.expression_category_) {}
ValueNodeView(const ValueNodeView&) = default;
ValueNodeView(ValueNodeView&&) = default;
@@ -117,9 +117,9 @@ class ValueNodeView {
// Returns node->static_type()
auto static_type() const -> const Value& { return static_type_(*base_); }
// Returns node->value_category()
auto value_category() const -> ValueCategory {
return value_category_(*base_);
// Returns node->expression_category()
auto expression_category() const -> ExpressionCategory {
return expression_category_(*base_);
}
friend auto operator==(const ValueNodeView& lhs, const ValueNodeView& rhs)
@@ -145,7 +145,7 @@ class ValueNodeView {
symbolic_identity_;
std::function<void(const AstNode&, llvm::raw_ostream&)> print_;
std::function<const Value&(const AstNode&)> static_type_;
std::function<ValueCategory(const AstNode&)> value_category_;
std::function<ExpressionCategory(const AstNode&)> expression_category_;
};
} // namespace Carbon
+11 -9
View File
@@ -46,16 +46,17 @@ void RuntimeScope::Print(llvm::raw_ostream& out) const {
void RuntimeScope::Bind(ValueNodeView value_node, Nonnull<const Value*> value) {
CARBON_CHECK(!value_node.constant_value().has_value());
CARBON_CHECK(value->kind() != Value::Kind::LValue);
CARBON_CHECK(value->kind() != Value::Kind::LocationValue);
auto allocation_id = heap_->GetAllocationId(value);
if (!allocation_id) {
auto id = heap_->AllocateValue(value);
auto [it, success] =
locals_.insert({value_node, heap_->arena().New<LValue>(Address(id))});
auto [it, success] = locals_.insert(
{value_node, heap_->arena().New<LocationValue>(Address(id))});
CARBON_CHECK(success) << "Duplicate definition of " << value_node.base();
} else {
auto [it, success] = locals_.insert(
{value_node, heap_->arena().New<LValue>(Address(*allocation_id))});
{value_node,
heap_->arena().New<LocationValue>(Address(*allocation_id))});
CARBON_CHECK(success) << "Duplicate definition of " << value_node.base();
}
}
@@ -63,10 +64,11 @@ void RuntimeScope::Bind(ValueNodeView value_node, Nonnull<const Value*> value) {
void RuntimeScope::Initialize(ValueNodeView value_node,
Nonnull<const Value*> value) {
CARBON_CHECK(!value_node.constant_value().has_value());
CARBON_CHECK(value->kind() != Value::Kind::LValue);
CARBON_CHECK(value->kind() != Value::Kind::LocationValue);
allocations_.push_back(heap_->AllocateValue(value));
auto [it, success] = locals_.insert(
{value_node, heap_->arena().New<LValue>(Address(allocations_.back()))});
{value_node,
heap_->arena().New<LocationValue>(Address(allocations_.back()))});
CARBON_CHECK(success) << "Duplicate definition of " << value_node.base();
}
@@ -83,7 +85,7 @@ void RuntimeScope::Merge(RuntimeScope other) {
}
auto RuntimeScope::Get(ValueNodeView value_node) const
-> std::optional<Nonnull<const LValue*>> {
-> std::optional<Nonnull<const LocationValue*>> {
auto it = locals_.find(value_node);
if (it != locals_.end()) {
return it->second;
@@ -108,8 +110,8 @@ auto RuntimeScope::Capture(
void Action::Print(llvm::raw_ostream& out) const {
switch (kind()) {
case Action::Kind::LValAction:
out << cast<LValAction>(*this).expression() << " ";
case Action::Kind::LocationAction:
out << cast<LocationAction>(*this).expression() << " ";
break;
case Action::Kind::ExpressionAction:
out << cast<ExpressionAction>(*this).expression() << " ";
+19 -20
View File
@@ -60,7 +60,7 @@ class RuntimeScope {
// Returns the local storage for value_node, if it has storage local to
// this scope.
auto Get(ValueNodeView value_node) const
-> std::optional<Nonnull<const LValue*>>;
-> std::optional<Nonnull<const LocationValue*>>;
// Returns the local values in created order
auto allocations() const -> const std::vector<AllocationId>& {
@@ -68,7 +68,7 @@ class RuntimeScope {
}
private:
llvm::MapVector<ValueNodeView, Nonnull<const LValue*>,
llvm::MapVector<ValueNodeView, Nonnull<const LocationValue*>,
std::map<ValueNodeView, unsigned>>
locals_;
std::vector<AllocationId> allocations_;
@@ -90,7 +90,7 @@ class RuntimeScope {
class Action {
public:
enum class Kind {
LValAction,
LocationAction,
ExpressionAction,
WitnessAction,
StatementAction,
@@ -164,14 +164,14 @@ class Action {
};
// An Action which implements evaluation of an Expression to produce an
// LValue.
class LValAction : public Action {
// LocationValue.
class LocationAction : public Action {
public:
explicit LValAction(Nonnull<const Expression*> expression)
: Action(Kind::LValAction), expression_(expression) {}
explicit LocationAction(Nonnull<const Expression*> expression)
: Action(Kind::LocationAction), expression_(expression) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::LValAction;
return action->kind() == Kind::LocationAction;
}
// The Expression this Action evaluates.
@@ -181,8 +181,7 @@ class LValAction : public Action {
Nonnull<const Expression*> expression_;
};
// An Action which implements evaluation of an Expression to produce an
// rvalue. The result is expressed as a Value.
// An Action which implements evaluation of an Expression to produce a `Value*`.
class ExpressionAction : public Action {
public:
explicit ExpressionAction(Nonnull<const Expression*> expression)
@@ -298,26 +297,26 @@ class CleanUpAction : public Action {
// values.
class DestroyAction : public Action {
public:
// lvalue: Address of the object to be destroyed
// value: The value to be destroyed
// In most cases the lvalue address points to value
// In the case that the member of a class is to be destroyed,
// the lvalue points to the address of the class object
// and the value is the member of the class
explicit DestroyAction(Nonnull<const LValue*> lvalue,
// location: Location of the object to be destroyed
// value: The value to be destroyed
// In most cases the location address points to value
// In the case that the member of a class is to be destroyed,
// the location points to the address of the class object
// and the value is the member of the class
explicit DestroyAction(Nonnull<const LocationValue*> location,
Nonnull<const Value*> value)
: Action(Kind::DestroyAction), lvalue_(lvalue), value_(value) {}
: Action(Kind::DestroyAction), location_(location), value_(value) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::DestroyAction;
}
auto lvalue() const -> Nonnull<const LValue*> { return lvalue_; }
auto location() const -> Nonnull<const LocationValue*> { return location_; }
auto value() const -> Nonnull<const Value*> { return value_; }
private:
Nonnull<const LValue*> lvalue_;
Nonnull<const LocationValue*> location_;
Nonnull<const Value*> value_;
};
+1 -1
View File
@@ -129,7 +129,7 @@ static auto FinishActionKindFor(Action::Kind kind) -> FinishActionKind {
switch (kind) {
case Action::Kind::ExpressionAction:
case Action::Kind::WitnessAction:
case Action::Kind::LValAction:
case Action::Kind::LocationAction:
case Action::Kind::TypeInstantiationAction:
return FinishActionKind::Value;
case Action::Kind::StatementAction:
+1 -1
View File
@@ -49,7 +49,7 @@ class ActionStack {
void Initialize(ValueNodeView value_node, Nonnull<const Value*> value);
// Returns the value bound to `value_node`. If `value_node` is a local
// variable, this will be an LValue.
// variable, this will be an LocationValue.
auto ValueOfNode(ValueNodeView value_node, SourceLocation source_loc) const
-> ErrorOr<Nonnull<const Value*>>;
+65 -62
View File
@@ -84,7 +84,7 @@ class Interpreter {
// State transitions for expressions.
auto StepExp() -> ErrorOr<Success>;
// State transitions for lvalues.
auto StepLvalue() -> ErrorOr<Success>;
auto StepLocation() -> ErrorOr<Success>;
// State transitions for witnesses.
auto StepWitness() -> ErrorOr<Success>;
// State transition for statements.
@@ -249,7 +249,7 @@ auto Interpreter::EvalPrim(Operator op, Nonnull<const Value*> /*static_type*/,
case Operator::Deref:
return heap_.Read(cast<PointerValue>(*args[0]).address(), source_loc);
case Operator::AddressOf:
return arena_->New<PointerValue>(cast<LValue>(*args[0]).address());
return arena_->New<PointerValue>(cast<LocationValue>(*args[0]).address());
case Operator::As:
case Operator::Eq:
case Operator::NotEq:
@@ -299,10 +299,10 @@ auto PatternMatch(Nonnull<const Value*> p, Nonnull<const Value*> v,
}
case Value::Kind::AddrValue: {
const auto& addr = cast<AddrValue>(*p);
CARBON_CHECK(v->kind() == Value::Kind::LValue);
const auto& lvalue = cast<LValue>(*v);
CARBON_CHECK(v->kind() == Value::Kind::LocationValue);
const auto& location = cast<LocationValue>(*v);
return PatternMatch(
&addr.pattern(), arena->New<PointerValue>(lvalue.address()),
&addr.pattern(), arena->New<PointerValue>(location.address()),
source_loc, bindings, generic_args, trace_stream, arena);
}
case Value::Kind::VariableType: {
@@ -406,11 +406,11 @@ auto PatternMatch(Nonnull<const Value*> p, Nonnull<const Value*> v,
}
}
auto Interpreter::StepLvalue() -> ErrorOr<Success> {
auto Interpreter::StepLocation() -> ErrorOr<Success> {
Action& act = todo_.CurrentAction();
const Expression& exp = cast<LValAction>(act).expression();
const Expression& exp = cast<LocationAction>(act).expression();
if (trace_stream_->is_enabled()) {
*trace_stream_ << "--- step lvalue " << exp << " ." << act.pos() << "."
*trace_stream_ << "--- step location " << exp << " ." << act.pos() << "."
<< " (" << exp.source_loc() << ") --->\n";
}
switch (exp.kind()) {
@@ -421,19 +421,19 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
Nonnull<const Value*> value,
todo_.ValueOfNode(cast<IdentifierExpression>(exp).value_node(),
exp.source_loc()));
CARBON_CHECK(isa<LValue>(value)) << *value;
CARBON_CHECK(isa<LocationValue>(value)) << *value;
return todo_.FinishAction(value);
}
case ExpressionKind::SimpleMemberAccessExpression: {
const auto& access = cast<SimpleMemberAccessExpression>(exp);
const auto constant_value = access.constant_value();
if (auto rewrite = access.rewritten_form()) {
return todo_.ReplaceWith(std::make_unique<LValAction>(*rewrite));
return todo_.ReplaceWith(std::make_unique<LocationAction>(*rewrite));
}
if (act.pos() == 0) {
// { {e.f :: C, E, F} :: S, H}
// -> { e :: [].f :: C, E, F} :: S, H}
return todo_.Spawn(std::make_unique<LValAction>(&access.object()));
return todo_.Spawn(std::make_unique<LocationAction>(&access.object()));
} else if (act.pos() == 1 && constant_value) {
return todo_.Spawn(std::make_unique<TypeInstantiationAction>(
*constant_value, access.source_loc()));
@@ -443,9 +443,9 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
} else {
// { v :: [].f :: C, E, F} :: S, H}
// -> { { &v.f :: C, E, F} :: S, H }
Address object = cast<LValue>(*act.results()[0]).address();
Address object = cast<LocationValue>(*act.results()[0]).address();
Address member = object.ElementAddress(&access.member());
return todo_.FinishAction(arena_->New<LValue>(member));
return todo_.FinishAction(arena_->New<LocationValue>(member));
}
}
}
@@ -453,7 +453,7 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
const auto& access = cast<CompoundMemberAccessExpression>(exp);
const auto constant_value = access.constant_value();
if (act.pos() == 0) {
return todo_.Spawn(std::make_unique<LValAction>(&access.object()));
return todo_.Spawn(std::make_unique<LocationAction>(&access.object()));
}
if (act.pos() == 1 && constant_value) {
return todo_.Spawn(std::make_unique<TypeInstantiationAction>(
@@ -463,34 +463,35 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
return todo_.FinishAction(act.results().back());
}
CARBON_CHECK(!access.member().interface().has_value())
<< "unexpected lvalue interface member";
<< "unexpected location interface member";
CARBON_ASSIGN_OR_RETURN(
Nonnull<const Value*> val,
Convert(act.results()[0], *access.member().base_type(),
exp.source_loc()));
Address object = cast<LValue>(*val).address();
Address object = cast<LocationValue>(*val).address();
Address field = object.ElementAddress(&access.member().member());
return todo_.FinishAction(arena_->New<LValue>(field));
return todo_.FinishAction(arena_->New<LocationValue>(field));
}
}
case ExpressionKind::BaseAccessExpression: {
const auto& access = cast<BaseAccessExpression>(exp);
if (act.pos() == 0) {
// Get LValue for expression.
return todo_.Spawn(std::make_unique<LValAction>(&access.object()));
// Get LocationValue for expression.
return todo_.Spawn(std::make_unique<LocationAction>(&access.object()));
} else {
// Append `.base` element to the address, and return the new LValue.
Address object = cast<LValue>(*act.results()[0]).address();
// Append `.base` element to the address, and return the new
// LocationValue.
Address object = cast<LocationValue>(*act.results()[0]).address();
Address base = object.ElementAddress(&access.element());
return todo_.FinishAction(arena_->New<LValue>(base));
return todo_.FinishAction(arena_->New<LocationValue>(base));
}
}
case ExpressionKind::IndexExpression: {
if (act.pos() == 0) {
// { {e[i] :: C, E, F} :: S, H}
// -> { e :: [][i] :: C, E, F} :: S, H}
return todo_.Spawn(
std::make_unique<LValAction>(&cast<IndexExpression>(exp).object()));
return todo_.Spawn(std::make_unique<LocationAction>(
&cast<IndexExpression>(exp).object()));
} else if (act.pos() == 1) {
return todo_.Spawn(std::make_unique<ExpressionAction>(
@@ -498,28 +499,28 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
} else {
// { v :: [][i] :: C, E, F} :: S, H}
// -> { { &v[i] :: C, E, F} :: S, H }
Address object = cast<LValue>(*act.results()[0]).address();
Address object = cast<LocationValue>(*act.results()[0]).address();
const auto index = cast<IntValue>(*act.results()[1]).value();
Address field = object.ElementAddress(
arena_->New<PositionalElement>(index, &exp.static_type()));
return todo_.FinishAction(arena_->New<LValue>(field));
return todo_.FinishAction(arena_->New<LocationValue>(field));
}
}
case ExpressionKind::OperatorExpression: {
const auto& op = cast<OperatorExpression>(exp);
if (auto rewrite = op.rewritten_form()) {
return todo_.ReplaceWith(std::make_unique<LValAction>(*rewrite));
return todo_.ReplaceWith(std::make_unique<LocationAction>(*rewrite));
}
if (op.op() != Operator::Deref) {
CARBON_FATAL()
<< "Can't treat primitive operator expression as lvalue: " << exp;
<< "Can't treat primitive operator expression as location: " << exp;
}
if (act.pos() == 0) {
return todo_.Spawn(
std::make_unique<ExpressionAction>(op.arguments()[0]));
} else {
const auto& res = cast<PointerValue>(*act.results()[0]);
return todo_.FinishAction(arena_->New<LValue>(res.address()));
return todo_.FinishAction(arena_->New<LocationValue>(res.address()));
}
break;
}
@@ -543,7 +544,7 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
case ExpressionKind::DotSelfExpression:
case ExpressionKind::ArrayTypeLiteral:
case ExpressionKind::BuiltinConvertExpression:
CARBON_FATAL() << "Can't treat expression as lvalue: " << exp;
CARBON_FATAL() << "Can't treat expression as location: " << exp;
case ExpressionKind::UnimplementedExpression:
CARBON_FATAL() << "Unimplemented: " << exp;
}
@@ -624,9 +625,9 @@ auto Interpreter::InstantiateType(Nonnull<const Value*> type,
CARBON_ASSIGN_OR_RETURN(
Nonnull<const Value*> value,
todo_.ValueOfNode(&cast<VariableType>(*type).binding(), source_loc));
if (const auto* lvalue = dyn_cast<LValue>(value)) {
if (const auto* location = dyn_cast<LocationValue>(value)) {
CARBON_ASSIGN_OR_RETURN(value,
heap_.Read(lvalue->address(), source_loc));
heap_.Read(location->address(), source_loc));
}
return value;
}
@@ -735,7 +736,7 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
case Value::Kind::FunctionValue:
case Value::Kind::DestructorValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::BoolValue:
case Value::Kind::NominalClassValue:
case Value::Kind::AlternativeValue:
@@ -1169,7 +1170,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
if (act.pos() == 0) {
// First, evaluate the first operand.
if (access.is_addr_me_method()) {
return todo_.Spawn(std::make_unique<LValAction>(&access.object()));
return todo_.Spawn(
std::make_unique<LocationAction>(&access.object()));
} else {
return todo_.Spawn(
std::make_unique<ExpressionAction>(&access.object()));
@@ -1247,11 +1249,11 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
const Value* aggregate;
if (access.is_type_access()) {
aggregate = act.results().back();
} else if (const auto* lvalue =
dyn_cast<LValue>(act.results()[0])) {
} else if (const auto* location =
dyn_cast<LocationValue>(act.results()[0])) {
CARBON_ASSIGN_OR_RETURN(
aggregate,
this->heap_.Read(lvalue->address(), exp.source_loc()));
this->heap_.Read(location->address(), exp.source_loc()));
} else {
aggregate = act.results()[0];
}
@@ -1270,7 +1272,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
if (act.pos() == 0) {
// First, evaluate the first operand.
if (access.is_addr_me_method()) {
return todo_.Spawn(std::make_unique<LValAction>(&access.object()));
return todo_.Spawn(
std::make_unique<LocationAction>(&access.object()));
} else {
return todo_.Spawn(
std::make_unique<ExpressionAction>(&access.object()));
@@ -1384,9 +1387,9 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
CARBON_ASSIGN_OR_RETURN(
Nonnull<const Value*> value,
todo_.ValueOfNode(ident.value_node(), ident.source_loc()));
if (const auto* lvalue = dyn_cast<LValue>(value)) {
if (const auto* location = dyn_cast<LocationValue>(value)) {
CARBON_ASSIGN_OR_RETURN(
value, heap_.Read(lvalue->address(), exp.source_loc()));
value, heap_.Read(location->address(), exp.source_loc()));
}
return todo_.FinishAction(value);
}
@@ -1415,7 +1418,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
// -> { {e :: op(vs,v,[],es) :: C, E, F} :: S, H}
Nonnull<const Expression*> arg = op.arguments()[act.pos()];
if (op.op() == Operator::AddressOf) {
return todo_.Spawn(std::make_unique<LValAction>(arg));
return todo_.Spawn(std::make_unique<LocationAction>(arg));
} else if ((op.op() == Operator::And || op.op() == Operator::Or) &&
act.pos() == 1) {
// Short-circuit evaluation for 'and' & 'or'
@@ -1557,7 +1560,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
: ptr->address();
if (act.pos() == 1) {
return todo_.Spawn(std::make_unique<DestroyAction>(
arena_->New<LValue>(obj_addr), child_class_value));
arena_->New<LocationValue>(obj_addr), child_class_value));
} else {
heap_.Deallocate(obj_addr);
return todo_.FinishAction(TupleValue::Empty());
@@ -1565,7 +1568,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
} else {
if (act.pos() == 1) {
return todo_.Spawn(std::make_unique<DestroyAction>(
arena_->New<LValue>(ptr->address()), pointee));
arena_->New<LocationValue>(ptr->address()), pointee));
} else {
heap_.Deallocate(ptr->address());
return todo_.FinishAction(TupleValue::Empty());
@@ -1806,11 +1809,11 @@ auto Interpreter::StepWitness() -> ErrorOr<Success> {
CARBON_ASSIGN_OR_RETURN(
Nonnull<const Value*> value,
todo_.ValueOfNode(binding, binding->type_var()->source_loc()));
if (const auto* lvalue = dyn_cast<LValue>(value)) {
if (const auto* location = dyn_cast<LocationValue>(value)) {
// TODO: Why do we store values for impl bindings on the heap?
CARBON_ASSIGN_OR_RETURN(
value,
heap_.Read(lvalue->address(), binding->type_var()->source_loc()));
heap_.Read(location->address(), binding->type_var()->source_loc()));
}
return todo_.FinishAction(value);
}
@@ -1942,9 +1945,9 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
Nonnull<const Value*> assigned_array_element,
todo_.ValueOfNode(*(loop_var->value_node()), stmt.source_loc()));
const auto* lvalue = cast<LValue>(assigned_array_element);
const auto* location = cast<LocationValue>(assigned_array_element);
CARBON_RETURN_IF_ERROR(heap_.Write(
lvalue->address(), source_array->elements()[current_index],
location->address(), source_array->elements()[current_index],
stmt.source_loc()));
act.ReplaceResult(CurrentIndexPosInResult,
@@ -2069,7 +2072,7 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
if (act.pos() == 0) {
// { {(lv = e) :: C, E, F} :: S, H}
// -> { {lv :: ([] = e) :: C, E, F} :: S, H}
return todo_.Spawn(std::make_unique<LValAction>(&assign.lhs()));
return todo_.Spawn(std::make_unique<LocationAction>(&assign.lhs()));
} else if (act.pos() == 1) {
// { { a :: ([] = e) :: C, E, F} :: S, H}
// -> { { e :: (a = []) :: C, E, F} :: S, H}
@@ -2077,7 +2080,7 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
} else {
// { { v :: (a = []) :: C, E, F} :: S, H}
// -> { { C, E, F} :: S, H(a := v)}
const auto& lval = cast<LValue>(*act.results()[0]);
const auto& lval = cast<LocationValue>(*act.results()[0]);
CARBON_ASSIGN_OR_RETURN(
Nonnull<const Value*> rval,
Convert(act.results()[1], &assign.lhs().static_type(),
@@ -2136,9 +2139,9 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
}
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> value,
todo_.ValueOfNode(value_node, stmt.source_loc()));
if (const auto* lvalue = dyn_cast<LValue>(value)) {
if (const auto* location = dyn_cast<LocationValue>(value)) {
CARBON_ASSIGN_OR_RETURN(
value, heap_.Read(lvalue->address(), ret_var.source_loc()));
value, heap_.Read(location->address(), ret_var.source_loc()));
}
const CallableDeclaration& function = cast<Return>(stmt).function();
CARBON_ASSIGN_OR_RETURN(
@@ -2267,7 +2270,7 @@ auto Interpreter::StepDestroy() -> ErrorOr<Success> {
const int index = class_decl.members().size() - act.pos();
const auto& member = class_decl.members()[index];
if (const auto* var = dyn_cast<VariableDeclaration>(member)) {
const Address object = destroy_act.lvalue()->address();
const Address object = destroy_act.location()->address();
const Address var_addr =
object.ElementAddress(arena_->New<NamedElement>(var));
const auto v = heap_.Read(var_addr, SourceLocation("destructor", 1));
@@ -2275,18 +2278,18 @@ auto Interpreter::StepDestroy() -> ErrorOr<Success> {
<< "Failed to read member `" << var->binding().name()
<< "` from class `" << class_decl.name() << "`";
return todo_.Spawn(std::make_unique<DestroyAction>(
arena_->New<LValue>(var_addr), *v));
arena_->New<LocationValue>(var_addr), *v));
} else {
return todo_.RunAgain();
}
} else if (act.pos() == member_count + 1) {
// Destroy the parent, if there is one.
if (auto base = class_obj->base()) {
const Address obj_addr = destroy_act.lvalue()->address();
const Address obj_addr = destroy_act.location()->address();
const Address base_addr =
obj_addr.ElementAddress(arena_->New<BaseElement>(class_obj));
return todo_.Spawn(std::make_unique<DestroyAction>(
arena_->New<LValue>(base_addr), base.value()));
arena_->New<LocationValue>(base_addr), base.value()));
} else {
return todo_.RunAgain();
}
@@ -2301,13 +2304,13 @@ auto Interpreter::StepDestroy() -> ErrorOr<Success> {
if (static_cast<size_t>(act.pos()) < element_count) {
const size_t index = element_count - act.pos() - 1;
const auto& item = tuple->elements()[index];
const auto object_addr = destroy_act.lvalue()->address();
const auto object_addr = destroy_act.location()->address();
Address field_address = object_addr.ElementAddress(
arena_->New<PositionalElement>(index, item));
if (item->kind() == Value::Kind::NominalClassValue ||
item->kind() == Value::Kind::TupleValue) {
return todo_.Spawn(std::make_unique<DestroyAction>(
arena_->New<LValue>(field_address), item));
arena_->New<LocationValue>(field_address), item));
} else {
// The tuple element's type is an integral type (e.g., i32)
// or the type doesn't support destruction.
@@ -2333,12 +2336,12 @@ auto Interpreter::StepCleanUp() -> ErrorOr<Success> {
const size_t alloc_index = cleanup.allocations_count() - act.pos() / 2 - 1;
auto allocation = act.scope()->allocations()[alloc_index];
if (act.pos() % 2 == 0) {
auto* lvalue = arena_->New<LValue>(Address(allocation));
auto* location = arena_->New<LocationValue>(Address(allocation));
auto value =
heap_.Read(lvalue->address(), SourceLocation("destructor", 1));
heap_.Read(location->address(), SourceLocation("destructor", 1));
// Step over uninitialized values.
if (value.ok()) {
return todo_.Spawn(std::make_unique<DestroyAction>(lvalue, *value));
return todo_.Spawn(std::make_unique<DestroyAction>(location, *value));
} else {
return todo_.RunAgain();
}
@@ -2355,8 +2358,8 @@ auto Interpreter::StepCleanUp() -> ErrorOr<Success> {
auto Interpreter::Step() -> ErrorOr<Success> {
Action& act = todo_.CurrentAction();
switch (act.kind()) {
case Action::Kind::LValAction:
CARBON_RETURN_IF_ERROR(StepLvalue());
case Action::Kind::LocationAction:
CARBON_RETURN_IF_ERROR(StepLocation());
break;
case Action::Kind::ExpressionAction:
CARBON_RETURN_IF_ERROR(StepExp());
+115 -101
View File
@@ -88,7 +88,7 @@ static auto IsTypeOfType(Nonnull<const Value*> value) -> bool {
case Value::Kind::FunctionValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::BoolValue:
case Value::Kind::TupleValue:
case Value::Kind::StructValue:
@@ -150,7 +150,7 @@ static auto IsType(Nonnull<const Value*> value) -> bool {
case Value::Kind::DestructorValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::BoolValue:
case Value::Kind::TupleValue:
case Value::Kind::StructValue:
@@ -221,7 +221,7 @@ static auto ExpectCompleteType(SourceLocation source_loc,
case Value::Kind::DestructorValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::BoolValue:
case Value::Kind::StructValue:
case Value::Kind::TupleValue:
@@ -320,7 +320,7 @@ static auto TypeContainsAuto(Nonnull<const Value*> type) -> bool {
case Value::Kind::DestructorValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::BoolValue:
case Value::Kind::TupleValue:
case Value::Kind::StructValue:
@@ -773,7 +773,7 @@ auto TypeChecker::ImplicitlyConvert(std::string_view context,
source->source_loc(), *this));
return arena_->New<ValueLiteral>(source->source_loc(), converted_value,
destination_constraint,
ValueCategory::Let);
ExpressionCategory::Value);
}
if (IsTypeOfType(source_type) && IsTypeOfType(destination)) {
@@ -886,8 +886,9 @@ auto TypeChecker::BuildBuiltinMethodCall(const ImplScope& impl_scope,
}
// Build an expression to perform the call `source.(interface.method)(args)`.
Nonnull<Expression*> iface_expr = arena_->New<ValueLiteral>(
source_loc, iface_type, arena_->New<TypeType>(), ValueCategory::Let);
Nonnull<Expression*> iface_expr =
arena_->New<ValueLiteral>(source_loc, iface_type, arena_->New<TypeType>(),
ExpressionCategory::Value);
Nonnull<Expression*> iface_member = arena_->New<SimpleMemberAccessExpression>(
source_loc, iface_expr, method.name);
Nonnull<Expression*> method_access =
@@ -1246,7 +1247,7 @@ auto TypeChecker::ArgumentDeduction::Deduce(Nonnull<const Value*> param,
case Value::Kind::DestructorValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::StructValue:
case Value::Kind::TupleValue:
case Value::Kind::NominalClassValue:
@@ -2623,7 +2624,7 @@ auto TypeChecker::LookupRewriteInWitness(
// Rewrites a member access expression to produce the given constant value.
static void RewriteMemberAccess(Nonnull<MemberAccessExpression*> access,
Nonnull<const RewriteConstraint*> value) {
access->set_value_category(ValueCategory::Let);
access->set_expression_category(ExpressionCategory::Value);
access->set_static_type(value->unconverted_replacement_type);
access->set_constant_value(value->unconverted_replacement);
}
@@ -2665,10 +2666,11 @@ auto TypeChecker::CheckAddrMeAccess(
CARBON_RETURN_IF_ERROR(
ExpectExactType(access->source_loc(), "method access, receiver type",
me_type, &access->object().static_type(), impl_scope));
if (access->object().value_category() != ValueCategory::Var) {
if (access->object().expression_category() !=
ExpressionCategory::Reference) {
return ProgramError(access->source_loc())
<< "method " << *access
<< " requires its receiver to be an lvalue";
<< " requires its receiver to be a reference expression";
}
}
return Success();
@@ -2716,7 +2718,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
<< tuple_type;
}
index.set_static_type(tuple_type.elements()[i]);
index.set_value_category(index.object().value_category());
index.set_expression_category(index.object().expression_category());
return Success();
}
case Value::Kind::StaticArrayType: {
@@ -2726,7 +2728,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
&index.offset().static_type(), impl_scope));
index.set_static_type(
&cast<StaticArrayType>(object_type).element_type());
index.set_value_category(index.object().value_category());
index.set_expression_category(index.object().expression_category());
return Success();
}
default:
@@ -2744,7 +2746,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
arg_types.push_back(&arg->static_type());
}
e->set_static_type(arena_->New<TupleType>(std::move(arg_types)));
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case ExpressionKind::StructLiteral: {
@@ -2756,7 +2758,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
arg_types.push_back({arg.name(), &arg.expression().static_type()});
}
e->set_static_type(arena_->New<StructType>(std::move(arg_types)));
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case ExpressionKind::StructTypeLiteral: {
@@ -2769,7 +2771,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
fields.push_back({arg.name(), type});
}
struct_type.set_static_type(arena_->New<TypeType>());
struct_type.set_value_category(ValueCategory::Let);
struct_type.set_expression_category(ExpressionCategory::Value);
struct_type.set_constant_value(
arena_->New<StructType>(std::move(fields)));
return Success();
@@ -2799,7 +2801,8 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
if (access.member_name() == field.name) {
access.set_member(arena_->New<NamedElement>(&field));
access.set_static_type(field.value);
access.set_value_category(access.object().value_category());
access.set_expression_category(
access.object().expression_category());
return Success();
}
}
@@ -2822,13 +2825,14 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
access.set_is_type_access(!IsInstanceMember(&access.member()));
switch (member->kind()) {
case DeclarationKind::VariableDeclaration:
access.set_value_category(access.object().value_category());
access.set_expression_category(
access.object().expression_category());
break;
case DeclarationKind::FunctionDeclaration: {
const auto* func_decl = cast<FunctionDeclaration>(member);
CARBON_RETURN_IF_ERROR(CheckAddrMeAccess(
&access, func_decl, t_class.bindings(), impl_scope));
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
break;
}
default:
@@ -2956,7 +2960,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
// member accesses that name them.
access.set_static_type(
arena_->New<TypeOfMemberName>(NamedElement(result.member)));
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
} else {
// This is a non-instance member whose value is found directly via
// the witness table, such as a non-method function or an
@@ -2967,7 +2971,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> inst_member_type,
Substitute(bindings, &member_type));
access.set_static_type(inst_member_type);
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
}
return Success();
}
@@ -2986,7 +2990,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
access.set_member(arena_->New<NamedElement>(&field));
access.set_static_type(
arena_->New<TypeOfMemberName>(NamedElement(&field)));
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
return Success();
}
}
@@ -3011,7 +3015,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
arena_->New<NamedElement>(arena_->New<NamedValue>(
NamedValue{access.member_name(), &choice})));
access.set_static_type(&choice);
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
return Success();
}
@@ -3027,7 +3031,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
arena_->New<NamedElement>(arena_->New<NamedValue>(
NamedValue{access.member_name(), type})));
access.set_static_type(type);
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
return Success();
}
case Value::Kind::NominalClassType: {
@@ -3050,7 +3054,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
Substitute(class_type.bindings(),
&member->static_type()));
access.set_static_type(field_type);
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
return Success();
}
default:
@@ -3058,7 +3062,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
access.set_static_type(
arena_->New<TypeOfMemberName>(NamedElement(member)));
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
return Success();
} else {
return ProgramError(access.source_loc())
@@ -3077,7 +3081,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
access.set_found_in_interface(result.interface);
access.set_static_type(
arena_->New<TypeOfMemberName>(NamedElement(result.member)));
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
return Success();
}
default:
@@ -3206,7 +3210,8 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
case DeclarationKind::VariableDeclaration:
if (has_instance) {
CARBON_RETURN_IF_ERROR(set_static_type_as_member_type());
access.set_value_category(access.object().value_category());
access.set_expression_category(
access.object().expression_category());
return Success();
}
break;
@@ -3218,7 +3223,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
!member_name.base_type().has_value())
<< "vacuous compound member access";
CARBON_RETURN_IF_ERROR(set_static_type_as_member_type());
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
CARBON_RETURN_IF_ERROR(
CheckAddrMeAccess(&access, cast<FunctionDeclaration>(*decl),
bindings_for_member(), impl_scope));
@@ -3228,7 +3233,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
case DeclarationKind::AssociatedConstantDeclaration:
CARBON_RETURN_IF_ERROR(set_static_type_as_member_type());
access.set_value_category(access.object().value_category());
access.set_expression_category(access.object().expression_category());
return Success();
default:
CARBON_FATAL() << "member " << member_name
@@ -3238,7 +3243,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
access.set_static_type(
arena_->New<TypeOfMemberName>(member_name.member()));
access.set_value_category(ValueCategory::Let);
access.set_expression_category(ExpressionCategory::Value);
return Success();
}
case ExpressionKind::IdentifierExpression: {
@@ -3254,7 +3259,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
}
ident.set_static_type(&ident.value_node().static_type());
ident.set_value_category(ident.value_node().value_category());
ident.set_expression_category(ident.value_node().expression_category());
return Success();
}
case ExpressionKind::DotSelfExpression: {
@@ -3265,15 +3270,15 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
dot_self.set_static_type(arena_->New<TypeType>());
dot_self.self_binding().set_named_as_type_via_dot_self();
}
dot_self.set_value_category(ValueCategory::Let);
dot_self.set_expression_category(ExpressionCategory::Value);
return Success();
}
case ExpressionKind::IntLiteral:
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
e->set_static_type(arena_->New<IntType>());
return Success();
case ExpressionKind::BoolLiteral:
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
e->set_static_type(arena_->New<BoolType>());
return Success();
case ExpressionKind::OperatorExpression: {
@@ -3318,7 +3323,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
if (isa<IntType>(ts[0]) && isa<IntType>(ts[1]) &&
IsSameType(ts[0], ts[1], impl_scope)) {
op.set_static_type(ts[0]);
op.set_value_category(ValueCategory::Let);
op.set_expression_category(ExpressionCategory::Value);
return Success();
}
@@ -3348,7 +3353,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
// TODO: Replace this with an intrinsic.
if (isa<IntType>(ts[0])) {
op.set_static_type(arena_->New<IntType>());
op.set_value_category(ValueCategory::Let);
op.set_expression_category(ExpressionCategory::Value);
return Success();
}
// Now try an overloaded negation.
@@ -3388,7 +3393,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
{lhs_constraint, rhs_constraint}));
op.set_rewritten_form(arena_->New<ValueLiteral>(
op.source_loc(), result, arena_->New<TypeType>(),
ValueCategory::Let));
ExpressionCategory::Value));
return Success();
}
return handle_binary_operator(Builtin::BitAndWith);
@@ -3410,7 +3415,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
arena_->New<BoolType>(), ts[1],
impl_scope));
op.set_static_type(arena_->New<BoolType>());
op.set_value_category(ValueCategory::Let);
op.set_expression_category(ExpressionCategory::Value);
return Success();
case Operator::Or:
CARBON_RETURN_IF_ERROR(ExpectExactType(e->source_loc(), "||(1)",
@@ -3420,14 +3425,14 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
arena_->New<BoolType>(), ts[1],
impl_scope));
op.set_static_type(arena_->New<BoolType>());
op.set_value_category(ValueCategory::Let);
op.set_expression_category(ExpressionCategory::Value);
return Success();
case Operator::Not:
CARBON_RETURN_IF_ERROR(ExpectExactType(e->source_loc(), "!",
arena_->New<BoolType>(), ts[0],
impl_scope));
op.set_static_type(arena_->New<BoolType>());
op.set_value_category(ValueCategory::Let);
op.set_expression_category(ExpressionCategory::Value);
return Success();
case Operator::Eq:
return handle_compare(Builtin::EqWith, "Equal", "equality");
@@ -3446,7 +3451,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
CARBON_RETURN_IF_ERROR(
ExpectPointerType(e->source_loc(), "*", ts[0]));
op.set_static_type(&cast<PointerType>(*ts[0]).pointee_type());
op.set_value_category(ValueCategory::Var);
op.set_expression_category(ExpressionCategory::Reference);
return Success();
case Operator::Ptr: {
auto* type_type = arena_->New<TypeType>();
@@ -3456,17 +3461,18 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
type_type));
op.arguments()[0] = converted;
op.set_static_type(arena_->New<TypeType>());
op.set_value_category(ValueCategory::Let);
op.set_expression_category(ExpressionCategory::Value);
return Success();
}
case Operator::AddressOf:
if (op.arguments()[0]->value_category() != ValueCategory::Var) {
if (op.arguments()[0]->expression_category() !=
ExpressionCategory::Reference) {
return ProgramError(op.arguments()[0]->source_loc())
<< "Argument to " << OperatorToString(op.op())
<< " should be an lvalue.";
<< " should be a reference expression.";
}
op.set_static_type(arena_->New<PointerType>(ts[0]));
op.set_value_category(ValueCategory::Let);
op.set_expression_category(ExpressionCategory::Value);
return Success();
case Operator::As: {
CARBON_ASSIGN_OR_RETURN(
@@ -3511,7 +3517,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
Nonnull<const Value*> return_type,
Substitute(call.bindings(), &fun_t.return_type()));
call.set_static_type(return_type);
call.set_value_category(ValueCategory::Let);
call.set_expression_category(ExpressionCategory::Value);
return Success();
}
case Value::Kind::TypeOfParameterizedEntityName: {
@@ -3544,7 +3550,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
ChoiceDeclaration>(param_name.declaration()))
<< "unknown type of ParameterizedEntityName for " << param_name;
call.set_static_type(arena_->New<TypeType>());
call.set_value_category(ValueCategory::Let);
call.set_expression_category(ExpressionCategory::Value);
return Success();
}
case Value::Kind::ChoiceType: {
@@ -3581,13 +3587,13 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> ret,
TypeCheckTypeExp(&fn.return_type(), impl_scope));
fn.set_static_type(arena_->New<TypeType>());
fn.set_value_category(ValueCategory::Let);
fn.set_expression_category(ExpressionCategory::Value);
fn.set_constant_value(arena_->New<FunctionType>(param, ret));
return Success();
}
case ExpressionKind::StringLiteral:
e->set_static_type(arena_->New<StringType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
case ExpressionKind::IntrinsicExpression: {
auto& intrinsic_exp = cast<IntrinsicExpression>(*e);
@@ -3611,7 +3617,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
&args[1]->static_type(), impl_scope));
}
e->set_static_type(TupleType::Empty());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
case IntrinsicExpression::Intrinsic::Assert: {
if (args.size() != 2) {
@@ -3625,7 +3631,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
e->source_loc(), "__intrinsic_assert argument 1",
arena_->New<StringType>(), &args[1]->static_type(), impl_scope));
e->set_static_type(TupleType::Empty());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::Alloc: {
@@ -3635,7 +3641,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
const auto* arg_type = &args[0]->static_type();
e->set_static_type(arena_->New<PointerType>(arg_type));
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::Dealloc: {
@@ -3647,7 +3653,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
CARBON_RETURN_IF_ERROR(
ExpectPointerType(e->source_loc(), "*", arg_type));
e->set_static_type(TupleType::Empty());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::Rand: {
@@ -3664,7 +3670,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
&args[1]->static_type(), impl_scope));
e->set_static_type(arena_->New<IntType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::ImplicitAs: {
@@ -3674,7 +3680,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
}
CARBON_RETURN_IF_ERROR(TypeCheckTypeExp(args[0], impl_scope));
e->set_static_type(arena_->New<TypeType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::ImplicitAsConvert: {
@@ -3687,7 +3693,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
// TODO: Check that the type of args[0] implicitly converts to
// args[1].
e->set_static_type(result);
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::IntEq: {
@@ -3702,7 +3708,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
e->source_loc(), "__intrinsic_int_eq argument 2",
arena_->New<IntType>(), &args[1]->static_type(), impl_scope));
e->set_static_type(arena_->New<BoolType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::IntCompare: {
@@ -3717,7 +3723,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
e->source_loc(), "__intrinsic_int_compare argument 2",
arena_->New<IntType>(), &args[1]->static_type(), impl_scope));
e->set_static_type(arena_->New<IntType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::StrEq: {
@@ -3732,7 +3738,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
e->source_loc(), "__intrinsic_str_eq argument 2",
arena_->New<StringType>(), &args[1]->static_type(), impl_scope));
e->set_static_type(arena_->New<BoolType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::StrCompare: {
@@ -3747,7 +3753,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
e->source_loc(), "__intrinsic_str_compare argument 2",
arena_->New<StringType>(), &args[1]->static_type(), impl_scope));
e->set_static_type(arena_->New<IntType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case IntrinsicExpression::Intrinsic::IntBitComplement:
@@ -3759,7 +3765,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
e->source_loc(), "complement argument", arena_->New<IntType>(),
&args[0]->static_type(), impl_scope));
e->set_static_type(arena_->New<IntType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
case IntrinsicExpression::Intrinsic::IntBitAnd:
case IntrinsicExpression::Intrinsic::IntBitOr:
@@ -3777,7 +3783,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
e->source_loc(), "argument 2", arena_->New<IntType>(),
&args[1]->static_type(), impl_scope));
e->set_static_type(arena_->New<IntType>());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
}
@@ -3786,7 +3792,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
case ExpressionKind::StringTypeLiteral:
case ExpressionKind::TypeTypeLiteral:
case ExpressionKind::ContinuationTypeLiteral:
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
e->set_static_type(arena_->New<TypeType>());
return Success();
case ExpressionKind::IfExpression: {
@@ -3808,7 +3814,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
&if_expr.then_expression().static_type(),
&if_expr.else_expression().static_type(), impl_scope));
e->set_static_type(&if_expr.then_expression().static_type());
e->set_value_category(ValueCategory::Let);
e->set_expression_category(ExpressionCategory::Value);
return Success();
}
case ExpressionKind::WhereExpression: {
@@ -3938,7 +3944,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
auto* replacement_literal = arena_->New<ValueLiteral>(
rewrite_clause.source_loc(), replacement_value,
replacement_type, ValueCategory::Let);
replacement_type, ExpressionCategory::Value);
// Convert the replacement value to the type of the associated
// constant and find the converted value. This is the value that
@@ -3967,7 +3973,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
where.set_rewritten_form(arena_->New<ValueLiteral>(
where.source_loc(), std::move(builder).Build(),
arena_->New<TypeType>(), ValueCategory::Let));
arena_->New<TypeType>(), ExpressionCategory::Value));
return Success();
}
case ExpressionKind::UnimplementedExpression:
@@ -3992,7 +3998,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
<< "Array size cannot be negative";
}
array_literal.set_static_type(arena_->New<TypeType>());
array_literal.set_value_category(ValueCategory::Let);
array_literal.set_expression_category(ExpressionCategory::Value);
array_literal.set_constant_value(arena_->New<StaticArrayType>(
element_type, cast<IntValue>(size_value)->value()));
return Success();
@@ -4128,7 +4134,7 @@ auto TypeChecker::TypeCheckWhereClause(Nonnull<WhereClause*> clause,
auto TypeChecker::TypeCheckPattern(
Nonnull<Pattern*> p, std::optional<Nonnull<const Value*>> expected,
ImplScope& impl_scope, ValueCategory enclosing_value_category)
ImplScope& impl_scope, ExpressionCategory enclosing_expression_category)
-> ErrorOr<Success> {
if (trace_stream_->is_enabled()) {
*trace_stream_ << "checking " << p->kind() << " " << *p;
@@ -4151,8 +4157,9 @@ auto TypeChecker::TypeCheckPattern(
return ProgramError(binding.type().source_loc())
<< "the type of a binding pattern cannot contain bindings";
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&binding.type(), std::nullopt, impl_scope, enclosing_value_category));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&binding.type(), std::nullopt,
impl_scope,
enclosing_expression_category));
Nonnull<const Value*> type = &binding.type().value();
// Convert to a type.
// TODO: Convert the pattern before interpreting it rather than doing
@@ -4160,7 +4167,7 @@ auto TypeChecker::TypeCheckPattern(
if (!isa<TypeType>(binding.type().static_type())) {
auto* literal = arena_->New<ValueLiteral>(binding.source_loc(), type,
&binding.type().static_type(),
ValueCategory::Let);
ExpressionCategory::Value);
CARBON_ASSIGN_OR_RETURN(
auto* converted,
ImplicitlyConvert("type of name binding", impl_scope, literal,
@@ -4198,8 +4205,8 @@ auto TypeChecker::TypeCheckPattern(
? arena_->New<BindingPlaceholderValue>(&binding)
: arena_->New<BindingPlaceholderValue>());
if (!binding.has_value_category()) {
binding.set_value_category(enclosing_value_category);
if (!binding.has_expression_category()) {
binding.set_expression_category(enclosing_expression_category);
}
return Success();
}
@@ -4231,8 +4238,9 @@ auto TypeChecker::TypeCheckPattern(
if (expected) {
expected_field_type = cast<TupleType>(**expected).elements()[i];
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
field, expected_field_type, impl_scope, enclosing_value_category));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(field, expected_field_type,
impl_scope,
enclosing_expression_category));
if (trace_stream_->is_enabled()) {
*trace_stream_ << "finished checking tuple pattern field " << *field
<< "\n";
@@ -4277,7 +4285,7 @@ auto TypeChecker::TypeCheckPattern(
*(*signature)->parameters_static_type()));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&alternative.arguments(),
parameter_type, impl_scope,
enclosing_value_category));
enclosing_expression_category));
alternative.set_static_type(&choice_type);
alternative.set_value(arena_->New<AlternativeValue>(
&choice_type, *signature,
@@ -4297,9 +4305,9 @@ auto TypeChecker::TypeCheckPattern(
case PatternKind::VarPattern: {
auto& var_pattern = cast<VarPattern>(*p);
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&var_pattern.pattern(), expected,
impl_scope,
var_pattern.value_category()));
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(&var_pattern.pattern(), expected, impl_scope,
var_pattern.expression_category()));
var_pattern.set_static_type(&var_pattern.pattern().static_type());
var_pattern.set_value(&var_pattern.pattern().value());
return Success();
@@ -4312,7 +4320,7 @@ auto TypeChecker::TypeCheckPattern(
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&addr_pattern.binding(),
expected_ptr, impl_scope,
enclosing_value_category));
enclosing_expression_category));
if (const auto* inner_binding_type =
dyn_cast<PointerType>(&addr_pattern.binding().static_type())) {
@@ -4432,7 +4440,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
// statements? When would we run them? See #1283.
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&clause.pattern(), &match.expression().static_type(), clause_scope,
ValueCategory::Let));
ExpressionCategory::Value));
if (expected_type.has_value()) {
// TODO: For now, we require all patterns to have the same type. If
// that's not the same type as the scrutinee, we will convert the
@@ -4486,7 +4494,7 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
CARBON_RETURN_IF_ERROR(
TypeCheckPattern(&for_stmt.variable_declaration(),
&cast<StaticArrayType>(rhs).element_type(),
inner_impl_scope, ValueCategory::Var));
inner_impl_scope, ExpressionCategory::Reference));
CARBON_RETURN_IF_ERROR(ExpectExactType(
for_stmt.source_loc(), "`for` pattern",
&cast<StaticArrayType>(rhs).element_type(),
@@ -4530,8 +4538,8 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
var.init().source_loc(), &var.init().static_type()));
init_type = &var.init().static_type();
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&var.pattern(), init_type,
var_scope, var.value_category()));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&var.pattern(), init_type, var_scope, var.expression_category()));
CARBON_RETURN_IF_ERROR(ExpectCompleteType(
var.source_loc(), "type of variable", &var.pattern().static_type()));
@@ -4548,9 +4556,11 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
auto& assign = cast<Assign>(*s);
CARBON_RETURN_IF_ERROR(TypeCheckExp(&assign.rhs(), impl_scope));
CARBON_RETURN_IF_ERROR(TypeCheckExp(&assign.lhs(), impl_scope));
if (assign.lhs().value_category() != ValueCategory::Var) {
if (assign.lhs().expression_category() != ExpressionCategory::Reference) {
return ProgramError(assign.source_loc())
<< "Cannot assign to rvalue '" << assign.lhs() << "'";
<< "Only assign a reference expression can be assigned, but got "
"`'"
<< assign.lhs() << "`'";
}
if (assign.op() == AssignOperator::Plain &&
IsSameType(&assign.lhs().static_type(), &assign.rhs().static_type(),
@@ -4759,20 +4769,22 @@ auto TypeChecker::DeclareCallableDeclaration(Nonnull<CallableDeclaration*> f,
// Bring the deduced parameters into scope.
for (Nonnull<GenericBinding*> deduced : f->deduced_parameters()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
deduced, std::nullopt, function_scope, ValueCategory::Let));
deduced, std::nullopt, function_scope, ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(deduced, all_bindings);
CollectImplBindingsInPattern(deduced, impl_bindings);
}
// Type check the receiver pattern.
if (f->is_method()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
&f->self_pattern(), std::nullopt, function_scope, ValueCategory::Let));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&f->self_pattern(), std::nullopt,
function_scope,
ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(&f->self_pattern(), all_bindings);
CollectImplBindingsInPattern(&f->self_pattern(), impl_bindings);
}
// Type check the parameter pattern.
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&f->param_pattern(), std::nullopt,
function_scope, ValueCategory::Let));
function_scope,
ExpressionCategory::Value));
CollectImplBindingsInPattern(&f->param_pattern(), impl_bindings);
// All bindings we've seen so far in this scope are our deduced bindings.
@@ -4932,8 +4944,8 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
std::vector<Nonnull<const GenericBinding*>> bindings = scope_info.bindings;
if (class_decl->type_params().has_value()) {
Nonnull<TuplePattern*> type_params = *class_decl->type_params();
CARBON_RETURN_IF_ERROR(TypeCheckPattern(type_params, std::nullopt,
class_scope, ValueCategory::Let));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
type_params, std::nullopt, class_scope, ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(type_params, bindings);
if (trace_stream_->is_enabled()) {
*trace_stream_ << class_scope;
@@ -5102,7 +5114,8 @@ auto TypeChecker::DeclareMixinDeclaration(Nonnull<MixinDeclaration*> mixin_decl,
if (mixin_decl->params().has_value()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(*mixin_decl->params(), std::nullopt,
mixin_scope, ValueCategory::Let));
mixin_scope,
ExpressionCategory::Value));
if (trace_stream_->is_enabled()) {
*trace_stream_ << mixin_scope;
}
@@ -5121,7 +5134,8 @@ auto TypeChecker::DeclareMixinDeclaration(Nonnull<MixinDeclaration*> mixin_decl,
// Process the Self parameter.
CARBON_RETURN_IF_ERROR(TypeCheckPattern(mixin_decl->self(), std::nullopt,
mixin_scope, ValueCategory::Let));
mixin_scope,
ExpressionCategory::Value));
ScopeInfo mixin_scope_info = ScopeInfo::ForNonClassScope(&mixin_scope);
for (Nonnull<Declaration*> m : mixin_decl->members()) {
@@ -5231,7 +5245,7 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
if (constraint_decl->params().has_value()) {
CARBON_RETURN_IF_ERROR(TypeCheckPattern(*constraint_decl->params(),
std::nullopt, constraint_scope,
ValueCategory::Let));
ExpressionCategory::Value));
if (trace_stream_->is_enabled()) {
*trace_stream_ << constraint_scope;
}
@@ -5605,7 +5619,7 @@ auto TypeChecker::DeclareImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
for (Nonnull<GenericBinding*> deduced : impl_decl->deduced_parameters()) {
generic_bindings.push_back(deduced);
CARBON_RETURN_IF_ERROR(TypeCheckPattern(deduced, std::nullopt, impl_scope,
ValueCategory::Let));
ExpressionCategory::Value));
CollectImplBindingsInPattern(deduced, impl_bindings);
}
impl_decl->set_impl_bindings(impl_bindings);
@@ -5798,8 +5812,8 @@ auto TypeChecker::DeclareChoiceDeclaration(Nonnull<ChoiceDeclaration*> choice,
std::vector<Nonnull<const GenericBinding*>> bindings = scope_info.bindings;
if (choice->type_params().has_value()) {
Nonnull<TuplePattern*> type_params = *choice->type_params();
CARBON_RETURN_IF_ERROR(TypeCheckPattern(type_params, std::nullopt,
choice_scope, ValueCategory::Let));
CARBON_RETURN_IF_ERROR(TypeCheckPattern(
type_params, std::nullopt, choice_scope, ExpressionCategory::Value));
CollectAndNumberGenericBindingsInPattern(type_params, bindings);
if (trace_stream_->is_enabled()) {
*trace_stream_ << choice_scope;
@@ -5845,7 +5859,7 @@ static auto IsValidTypeForAliasTarget(Nonnull<const Value*> type) -> bool {
case Value::Kind::DestructorValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::LocationValue:
case Value::Kind::BoolValue:
case Value::Kind::StructValue:
case Value::Kind::NominalClassValue:
@@ -6118,7 +6132,7 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
}
CARBON_RETURN_IF_ERROR(TypeCheckPattern(&var.binding(), std::nullopt,
*scope_info.innermost_scope,
var.value_category()));
var.expression_category()));
CARBON_RETURN_IF_ERROR(ExpectCompleteType(
var.source_loc(), "type of variable", &var.binding().static_type()));
var.set_static_type(&var.binding().static_type());
+2 -2
View File
@@ -161,7 +161,7 @@ class TypeChecker {
// Checks a member access that might be accessing a function taking `addr
// self: Self*`. If it does, this function marks the member access accordingly
// and ensures the object argument is an lvalue.
// and ensures the object argument is a reference expression.
auto CheckAddrMeAccess(Nonnull<MemberAccessExpression*> access,
Nonnull<const FunctionDeclaration*> func_decl,
const Bindings& bindings, const ImplScope& impl_scope)
@@ -196,7 +196,7 @@ class TypeChecker {
auto TypeCheckPattern(Nonnull<Pattern*> p,
std::optional<Nonnull<const Value*>> expected,
ImplScope& impl_scope,
ValueCategory enclosing_value_category)
ExpressionCategory enclosing_expression_category)
-> ErrorOr<Success>;
// Type checks a generic binding. `symbolic_value` is the symbolic name by
+1 -1
View File
@@ -82,8 +82,8 @@ cc_library(
"//common:ostream",
"//common:string_helpers",
"//explorer/ast",
"//explorer/ast:expression_category",
"//explorer/ast:paren_contents",
"//explorer/ast:value_category",
"//explorer/common:arena",
"//explorer/common:error_builders",
"//explorer/common:nonnull",
+11 -10
View File
@@ -71,9 +71,9 @@
#include "explorer/ast/ast.h"
#include "explorer/ast/declaration.h"
#include "explorer/ast/expression.h"
#include "explorer/ast/expression_category.h"
#include "explorer/ast/paren_contents.h"
#include "explorer/ast/pattern.h"
#include "explorer/ast/value_category.h"
#include "explorer/common/arena.h"
#include "explorer/common/nonnull.h"
#include "explorer/syntax/bison_wrap.h"
@@ -941,7 +941,7 @@ clause:
$$ = Match::Clause(arena->New<BindingPattern>(
context.source_loc(), std::string(AnonymousName),
arena->New<AutoPattern>(context.source_loc()),
ValueCategory::Let),
ExpressionCategory::Value),
$3);
}
;
@@ -959,31 +959,31 @@ statement:
| VAR pattern SEMICOLON
{
$$ = arena->New<VariableDefinition>(
context.source_loc(), $2, std::nullopt, ValueCategory::Var,
context.source_loc(), $2, std::nullopt, ExpressionCategory::Reference,
VariableDefinition::DefinitionType::Var);
}
| VAR pattern EQUAL expression SEMICOLON
{
$$ = arena->New<VariableDefinition>(
context.source_loc(), $2, $4, ValueCategory::Var,
context.source_loc(), $2, $4, ExpressionCategory::Reference,
VariableDefinition::DefinitionType::Var);
}
| RETURNED VAR variable_declaration SEMICOLON
{
$$ = arena->New<VariableDefinition>(
context.source_loc(), $3, std::nullopt, ValueCategory::Var,
context.source_loc(), $3, std::nullopt, ExpressionCategory::Reference,
VariableDefinition::DefinitionType::Returned);
}
| RETURNED VAR variable_declaration EQUAL expression SEMICOLON
{
$$ = arena->New<VariableDefinition>(
context.source_loc(), $3, $5, ValueCategory::Var,
context.source_loc(), $3, $5, ExpressionCategory::Reference,
VariableDefinition::DefinitionType::Returned);
}
| LET pattern EQUAL expression SEMICOLON
{
$$ = arena->New<VariableDefinition>(
context.source_loc(), $2, $4, ValueCategory::Let,
context.source_loc(), $2, $4, ExpressionCategory::Value,
VariableDefinition::DefinitionType::Var);
}
| statement_expression SEMICOLON
@@ -1280,17 +1280,18 @@ declaration:
| VAR variable_declaration SEMICOLON
{
$$ = arena->New<VariableDeclaration>(context.source_loc(), $2,
std::nullopt, ValueCategory::Var);
std::nullopt,
ExpressionCategory::Reference);
}
| VAR variable_declaration EQUAL expression SEMICOLON
{
$$ = arena->New<VariableDeclaration>(context.source_loc(), $2, $4,
ValueCategory::Var);
ExpressionCategory::Reference);
}
| LET variable_declaration EQUAL expression SEMICOLON
{
$$ = arena->New<VariableDeclaration>(context.source_loc(), $2, $4,
ValueCategory::Let);
ExpressionCategory::Value);
}
| INTERFACE declared_name type_params LEFT_CURLY_BRACE interface_body RIGHT_CURLY_BRACE
{
+1 -1
View File
@@ -26,7 +26,7 @@ class Point {
fn Main() -> i32 {
let p: Point = Point.Origin();
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/addr/fail_method_let.carbon:[[@LINE+1]]: method p.GetSetX requires its receiver to be an lvalue
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/addr/fail_method_let.carbon:[[@LINE+1]]: method p.GetSetX requires its receiver to be a reference expression
var x: auto = p.GetSetX(42);
if (p.x == 42) {
return x;
@@ -12,7 +12,7 @@ fn F() {}
fn G() {}
fn Main() -> i32 {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_function.carbon:[[@LINE+1]]: Cannot assign to rvalue 'F'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_function.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'F`'
F = G;
return 0;
}
+1 -1
View File
@@ -9,7 +9,7 @@
package ExplorerTest api;
fn Main() -> i32 {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_rval.carbon:[[@LINE+1]]: Cannot assign to rvalue '1'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_assign_to_rval.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'1`'
1 = 0;
return 0;
}
+1 -1
View File
@@ -10,7 +10,7 @@ package ExplorerTest api;
fn f((var x: i32, y: i32)) -> i32 {
x = 0;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_function_args.carbon:[[@LINE+1]]: Cannot assign to rvalue 'y'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_function_args.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'y`'
y = 0;
return x - 1;
}
+1 -1
View File
@@ -11,7 +11,7 @@ package ExplorerTest api;
let x: i32 = 10;
fn Main() -> i32 {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_global_assign.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_global_assign.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'x`'
x = 0;
return 0;
}
+1 -1
View File
@@ -10,7 +10,7 @@ package ExplorerTest api;
fn Main() -> i32 {
let x: auto = 10;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_local_assign.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_local_assign.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'x`'
x = 0;
return 0;
}
+1 -1
View File
@@ -25,7 +25,7 @@ fn Main() -> i32 {
n = n - 1;
}
case Ints.Two(x: auto, y: auto) => {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_match_choice.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_match_choice.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'x`'
x = 0;
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ class Point {
}
fn SetX[self: Point](x: i32) {
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_method_args.carbon:[[@LINE+1]]: Cannot assign to rvalue 'x'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_method_args.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'x`'
x = 10;
}
@@ -12,7 +12,7 @@ fn Main() -> i32 {
let (var a: auto, b: auto, c: auto, d: auto) = (1, 2, 3, 4);
a = 0;
// should fail
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context.carbon:[[@LINE+1]]: Cannot assign to rvalue 'c'
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_tuple_pattern_let_context.carbon:[[@LINE+1]]: Only assign a reference expression can be assigned, but got `'c`'
c = 0;
return 0;
}
+1 -1
View File
@@ -10,7 +10,7 @@ package ExplorerTest api;
fn Main() -> i32 {
var x: i32 = 5;
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/pointer/fail_rvalue_addressof.carbon:[[@LINE+1]]: Argument to & should be an lvalue.
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/pointer/fail_rvalue_addressof.carbon:[[@LINE+1]]: Argument to & should be a reference expression.
var p: i32* = &5;
return 0;
}