mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:20:11 +01:00
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:
+3
-3
@@ -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
@@ -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_;
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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_
|
||||
@@ -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
@@ -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,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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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_
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() << " ";
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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*>>;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user