mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Handle identifier value category properly. (#986)
This commit is contained in:
@@ -80,6 +80,7 @@ cc_library(
|
||||
":source_location",
|
||||
":statement",
|
||||
":static_scope",
|
||||
":value_category",
|
||||
"//common:ostream",
|
||||
"//executable_semantics/common:nonnull",
|
||||
"@llvm-project//llvm:Support",
|
||||
@@ -94,6 +95,7 @@ cc_library(
|
||||
":ast_node",
|
||||
":paren_contents",
|
||||
":static_scope",
|
||||
":value_category",
|
||||
"//common:indirect_value",
|
||||
"//common:ostream",
|
||||
"//executable_semantics/common:arena",
|
||||
@@ -146,6 +148,7 @@ cc_library(
|
||||
":expression",
|
||||
":source_location",
|
||||
":static_scope",
|
||||
":value_category",
|
||||
"//common:ostream",
|
||||
"//executable_semantics/common:arena",
|
||||
"//executable_semantics/common:error",
|
||||
@@ -171,6 +174,7 @@ cc_library(
|
||||
deps = [
|
||||
":ast_node",
|
||||
":source_location",
|
||||
":value_category",
|
||||
"//executable_semantics/common:arena",
|
||||
"//executable_semantics/common:error",
|
||||
],
|
||||
@@ -194,9 +198,15 @@ cc_library(
|
||||
":expression",
|
||||
":pattern",
|
||||
":source_location",
|
||||
":value_category",
|
||||
"//common:check",
|
||||
"//common:ostream",
|
||||
"//executable_semantics/common:arena",
|
||||
"@llvm-project//llvm:Support",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "value_category",
|
||||
hdrs = ["value_category.h"],
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/ast/statement.h"
|
||||
#include "executable_semantics/ast/static_scope.h"
|
||||
#include "executable_semantics/ast/value_category.h"
|
||||
#include "executable_semantics/common/nonnull.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
@@ -106,6 +107,8 @@ class GenericBinding : public AstNode {
|
||||
// and after typechecking it's guaranteed to be true.
|
||||
auto has_static_type() const -> bool { return static_type_.has_value(); }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
Nonnull<Expression*> type_;
|
||||
@@ -228,6 +231,8 @@ class FunctionDeclaration : public Declaration {
|
||||
auto body() const -> std::optional<Nonnull<const Block*>> { return body_; }
|
||||
auto body() -> std::optional<Nonnull<Block*>> { return body_; }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<Nonnull<GenericBinding*>> deduced_parameters_;
|
||||
@@ -253,6 +258,8 @@ class ClassDeclaration : public Declaration {
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto members() const -> llvm::ArrayRef<Nonnull<Member*>> { return members_; }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<Nonnull<Member*>> members_;
|
||||
@@ -304,6 +311,8 @@ class ChoiceDeclaration : public Declaration {
|
||||
return alternatives_;
|
||||
}
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<Nonnull<AlternativeSignature*>> alternatives_;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "executable_semantics/ast/paren_contents.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/ast/static_scope.h"
|
||||
#include "executable_semantics/ast/value_category.h"
|
||||
#include "executable_semantics/common/arena.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
@@ -25,16 +26,6 @@ class Value;
|
||||
|
||||
class Expression : public AstNode {
|
||||
public:
|
||||
// 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/C++ lvalue.
|
||||
Var,
|
||||
// A value. This roughly corresponds to a C/C++ rvalue.
|
||||
Let,
|
||||
};
|
||||
|
||||
~Expression() override = 0;
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
|
||||
@@ -118,6 +118,8 @@ class BindingPattern : public Pattern {
|
||||
auto type() const -> const Pattern& { return *type_; }
|
||||
auto type() -> Pattern& { return *type_; }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Var; }
|
||||
|
||||
private:
|
||||
std::optional<std::string> name_;
|
||||
Nonnull<Pattern*> type_;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/ast/static_scope.h"
|
||||
#include "executable_semantics/ast/value_category.h"
|
||||
#include "executable_semantics/common/arena.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
@@ -344,6 +345,8 @@ class Continuation : public Statement {
|
||||
// and after typechecking it's guaranteed to be true.
|
||||
auto has_static_type() const -> bool { return static_type_.has_value(); }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Var; }
|
||||
|
||||
private:
|
||||
std::string continuation_variable_;
|
||||
Nonnull<Block*> body_;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/ast/value_category.h"
|
||||
#include "executable_semantics/common/nonnull.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -20,12 +21,19 @@ namespace Carbon {
|
||||
class Value;
|
||||
|
||||
// True if NodeType::ImplementsCarbonNamedEntity is valid and names a type,
|
||||
// indicating that NodeType implements the NamedEntity interface. This imposes
|
||||
// the following requirements on NodeType, where `node` is a const instance of
|
||||
// NodeType:
|
||||
// indicating that NodeType implements the NamedEntity interface, which means
|
||||
// it must define the following methods, with contracts as documented.
|
||||
#if 0
|
||||
// Returns the static type of an IdentifierExpression that names *this.
|
||||
auto static_type() const -> const Value&;
|
||||
|
||||
// Returns the value category of an IdentifierExpression that names *this.
|
||||
auto value_category() const -> ValueCategory;
|
||||
#endif
|
||||
// NodeType must be derived from AstNode.
|
||||
//
|
||||
// - NodeType is derived from AstNode.
|
||||
// - node.static_type() is well-formed and has type const Value&.
|
||||
// TODO: consider turning the above documentation into real code, as sketched
|
||||
// at https://godbolt.org/z/186oEozhc
|
||||
template <typename T, typename = void>
|
||||
static constexpr bool ImplementsNamedEntity = false;
|
||||
|
||||
@@ -43,9 +51,13 @@ class NamedEntityView {
|
||||
NamedEntityView(Nonnull<const NodeType*> node)
|
||||
// Type-erase NodeType, retaining a pointer to the base class AstNode
|
||||
// and using std::function to encapsulate the ability to call
|
||||
// the derived class's static_type.
|
||||
: base_(node), static_type_([](const AstNode& base) -> const Value& {
|
||||
// the derived class's methods.
|
||||
: base_(node),
|
||||
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();
|
||||
}) {}
|
||||
|
||||
NamedEntityView(const NamedEntityView&) = default;
|
||||
@@ -59,6 +71,11 @@ class NamedEntityView {
|
||||
// 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_);
|
||||
}
|
||||
|
||||
friend auto operator==(const NamedEntityView& lhs,
|
||||
const NamedEntityView& rhs) {
|
||||
return lhs.base_ == rhs.base_;
|
||||
@@ -72,6 +89,7 @@ class NamedEntityView {
|
||||
private:
|
||||
Nonnull<const AstNode*> base_;
|
||||
std::function<const Value&(const AstNode&)> static_type_;
|
||||
std::function<ValueCategory(const AstNode&)> value_category_;
|
||||
};
|
||||
|
||||
// Maps the names visible in a given scope to the entities they name.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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 EXECUTABLE_SEMANTICS_AST_VALUE_CATEGORY_H_
|
||||
#define EXECUTABLE_SEMANTICS_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/C++ lvalue.
|
||||
Var,
|
||||
// A value. This roughly corresponds to a C/C++ rvalue.
|
||||
Let,
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // EXECUTABLE_SEMANTICS_AST_VALUE_CATEGORY_H_
|
||||
Reference in New Issue
Block a user