Files
carbon-lang/executable_semantics/interpreter/value.h
T
Geoff RomerandJon Meow 17e0a1afb9 Implement static name resolution (#958)
This doesn't actually use the results of name resolution, but it does verify that they are present.
Also ensures that name resolution and type checking are applied to deduced function parameters and the implicit call to `Main()`.

Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
2021-11-30 13:33:54 -08:00

570 lines
16 KiB
C++

// 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_INTERPRETER_VALUE_H_
#define EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_
#include <optional>
#include <string>
#include <variant>
#include <vector>
#include "common/ostream.h"
#include "executable_semantics/ast/declaration.h"
#include "executable_semantics/ast/statement.h"
#include "executable_semantics/common/nonnull.h"
#include "executable_semantics/interpreter/address.h"
#include "executable_semantics/interpreter/field_path.h"
#include "executable_semantics/interpreter/stack.h"
#include "llvm/Support/Compiler.h"
namespace Carbon {
class Action;
// Abstract base class of all AST nodes representing values.
//
// Value and its derived classes support LLVM-style RTTI, including
// llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every
// class derived from Value must provide a `classof` operation, and
// every concrete derived class must have a corresponding enumerator
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
// details.
class Value {
public:
enum class Kind {
IntValue,
FunctionValue,
LValue,
BoolValue,
StructValue,
NominalClassValue,
AlternativeValue,
TupleValue,
IntType,
BoolType,
TypeType,
FunctionType,
PointerType,
AutoType,
StructType,
NominalClassType,
ChoiceType,
ContinuationType, // The type of a continuation.
VariableType, // e.g., generic type parameters.
BindingPlaceholderValue,
AlternativeConstructorValue,
ContinuationValue, // A first-class continuation value.
StringType,
StringValue,
};
Value(const Value&) = delete;
auto operator=(const Value&) -> Value& = delete;
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
// Returns the sub-Value specified by `path`, which must be a valid field
// path for *this.
auto GetField(Nonnull<Arena*> arena, const FieldPath& path,
SourceLocation source_loc) const -> Nonnull<const Value*>;
// Returns a copy of *this, but with the sub-Value specified by `path`
// set to `field_value`. `path` must be a valid field path for *this.
auto SetField(Nonnull<Arena*> arena, const FieldPath& path,
Nonnull<const Value*> field_value,
SourceLocation source_loc) const -> Nonnull<const Value*>;
// Returns the enumerator corresponding to the most-derived type of this
// object.
auto kind() const -> Kind { return kind_; }
protected:
// Constructs a Value. `kind` must be the enumerator corresponding to the
// most-derived type being constructed.
explicit Value(Kind kind) : kind_(kind) {}
private:
const Kind kind_;
};
// A NamedValue represents a value with a name, such as a single struct field.
struct NamedValue {
// The field name.
std::string name;
// The field's value.
Nonnull<const Value*> value;
};
// An integer value.
class IntValue : public Value {
public:
explicit IntValue(int value) : Value(Kind::IntValue), value_(value) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::IntValue;
}
auto value() const -> int { return value_; }
private:
int value_;
};
// A function value.
class FunctionValue : public Value {
public:
FunctionValue(Nonnull<const FunctionDeclaration*> declaration)
: Value(Kind::FunctionValue), declaration_(declaration) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::FunctionValue;
}
auto declaration() const -> const FunctionDeclaration& {
return *declaration_;
}
private:
Nonnull<const FunctionDeclaration*> declaration_;
};
// The value of a location in memory.
class LValue : public Value {
public:
explicit LValue(Address value)
: Value(Kind::LValue), value_(std::move(value)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::LValue;
}
auto address() const -> const Address& { return value_; }
private:
Address value_;
};
// A bool value.
class BoolValue : public Value {
public:
explicit BoolValue(bool value) : Value(Kind::BoolValue), value_(value) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::BoolValue;
}
auto value() const -> bool { return value_; }
private:
bool value_;
};
// A non-empty value of a struct type.
//
// It can't be empty because `{}` is a struct type as well as a value of that
// type, so for consistency we always represent it as a StructType rather than
// let it oscillate unpredictably between the two. However, this means code
// that handles StructValue instances may also need to be able to handle
// StructType instances.
class StructValue : public Value {
public:
explicit StructValue(std::vector<NamedValue> elements)
: Value(Kind::StructValue), elements_(std::move(elements)) {
CHECK(!elements_.empty())
<< "`{}` is represented as a StructType, not a StructValue.";
}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::StructValue;
}
auto elements() const -> llvm::ArrayRef<NamedValue> { return elements_; }
// Returns the value of the field named `name` in this struct, or
// nullopt if there is no such field.
auto FindField(const std::string& name) const
-> std::optional<Nonnull<const Value*>>;
private:
std::vector<NamedValue> elements_;
};
// A value of a nominal class type.
class NominalClassValue : public Value {
public:
NominalClassValue(Nonnull<const Value*> type, Nonnull<const Value*> inits)
: Value(Kind::NominalClassValue), type_(type), inits_(inits) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::NominalClassValue;
}
auto type() const -> const Value& { return *type_; }
auto inits() const -> const Value& { return *inits_; }
private:
Nonnull<const Value*> type_;
Nonnull<const Value*> inits_;
};
// An alternative constructor value.
class AlternativeConstructorValue : public Value {
public:
AlternativeConstructorValue(std::string alt_name, std::string choice_name)
: Value(Kind::AlternativeConstructorValue),
alt_name_(std::move(alt_name)),
choice_name_(std::move(choice_name)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::AlternativeConstructorValue;
}
auto alt_name() const -> const std::string& { return alt_name_; }
auto choice_name() const -> const std::string& { return choice_name_; }
private:
std::string alt_name_;
std::string choice_name_;
};
// An alternative value.
class AlternativeValue : public Value {
public:
AlternativeValue(std::string alt_name, std::string choice_name,
Nonnull<const Value*> argument)
: Value(Kind::AlternativeValue),
alt_name_(std::move(alt_name)),
choice_name_(std::move(choice_name)),
argument_(argument) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::AlternativeValue;
}
auto alt_name() const -> const std::string& { return alt_name_; }
auto choice_name() const -> const std::string& { return choice_name_; }
auto argument() const -> const Value& { return *argument_; }
private:
std::string alt_name_;
std::string choice_name_;
Nonnull<const Value*> argument_;
};
// A function value.
class TupleValue : public Value {
public:
// An empty tuple, also known as the unit type.
static auto Empty() -> Nonnull<const TupleValue*> {
static const TupleValue empty =
TupleValue(std::vector<Nonnull<const Value*>>());
return Nonnull<const TupleValue*>(&empty);
}
explicit TupleValue(std::vector<Nonnull<const Value*>> elements)
: Value(Kind::TupleValue), elements_(std::move(elements)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::TupleValue;
}
auto elements() const -> llvm::ArrayRef<Nonnull<const Value*>> {
return elements_;
}
private:
std::vector<Nonnull<const Value*>> elements_;
};
// A binding placeholder value.
class BindingPlaceholderValue : public Value {
public:
// nullopt represents the `_` placeholder.
BindingPlaceholderValue(std::optional<std::string> name,
Nonnull<const Value*> type)
: Value(Kind::BindingPlaceholderValue),
name_(std::move(name)),
type_(type) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::BindingPlaceholderValue;
}
auto name() const -> const std::optional<std::string>& { return name_; }
auto type() const -> const Value& { return *type_; }
private:
std::optional<std::string> name_;
Nonnull<const Value*> type_;
};
// The int type.
class IntType : public Value {
public:
IntType() : Value(Kind::IntType) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::IntType;
}
};
// The bool type.
class BoolType : public Value {
public:
BoolType() : Value(Kind::BoolType) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::BoolType;
}
};
// A type type.
class TypeType : public Value {
public:
TypeType() : Value(Kind::TypeType) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::TypeType;
}
};
// A function type.
class FunctionType : public Value {
public:
FunctionType(llvm::ArrayRef<Nonnull<const GenericBinding*>> deduced,
Nonnull<const Value*> parameters,
Nonnull<const Value*> return_type)
: Value(Kind::FunctionType),
deduced_(deduced),
parameters_(parameters),
return_type_(return_type) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::FunctionType;
}
auto deduced() const -> llvm::ArrayRef<Nonnull<const GenericBinding*>> {
return deduced_;
}
auto parameters() const -> const Value& { return *parameters_; }
auto return_type() const -> const Value& { return *return_type_; }
private:
std::vector<Nonnull<const GenericBinding*>> deduced_;
Nonnull<const Value*> parameters_;
Nonnull<const Value*> return_type_;
};
// A pointer type.
class PointerType : public Value {
public:
explicit PointerType(Nonnull<const Value*> type)
: Value(Kind::PointerType), type_(type) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::PointerType;
}
auto type() const -> const Value& { return *type_; }
private:
Nonnull<const Value*> type_;
};
// The `auto` type.
class AutoType : public Value {
public:
AutoType() : Value(Kind::AutoType) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::AutoType;
}
};
// A struct type.
//
// Code that handles this type may sometimes need to have special-case handling
// for `{}`, which is a struct value in addition to being a struct type.
class StructType : public Value {
public:
StructType() : StructType(std::vector<NamedValue>{}) {}
explicit StructType(std::vector<NamedValue> fields)
: Value(Kind::StructType), fields_(std::move(fields)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::StructType;
}
auto fields() const -> llvm::ArrayRef<NamedValue> { return fields_; }
private:
std::vector<NamedValue> fields_;
};
// A class type.
class NominalClassType : public Value {
public:
NominalClassType(std::string name, std::vector<NamedValue> fields,
std::vector<NamedValue> methods)
: Value(Kind::NominalClassType),
name_(std::move(name)),
fields_(std::move(fields)),
methods_(std::move(methods)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::NominalClassType;
}
auto name() const -> const std::string& { return name_; }
auto fields() const -> llvm::ArrayRef<NamedValue> { return fields_; }
auto methods() const -> llvm::ArrayRef<NamedValue> { return methods_; }
private:
std::string name_;
std::vector<NamedValue> fields_;
std::vector<NamedValue> methods_;
};
// A choice type.
class ChoiceType : public Value {
public:
ChoiceType(std::string name, std::vector<NamedValue> alternatives)
: Value(Kind::ChoiceType),
name_(std::move(name)),
alternatives_(std::move(alternatives)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::ChoiceType;
}
auto name() const -> const std::string& { return name_; }
// Returns the parameter types of the alternative with the given name,
// or nullopt if no such alternative is present.
auto FindAlternative(std::string_view name) const
-> std::optional<Nonnull<const Value*>>;
private:
std::string name_;
std::vector<NamedValue> alternatives_;
};
// A continuation type.
class ContinuationType : public Value {
public:
ContinuationType() : Value(Kind::ContinuationType) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::ContinuationType;
}
};
// A variable type.
class VariableType : public Value {
public:
explicit VariableType(std::string name)
: Value(Kind::VariableType), name_(std::move(name)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::VariableType;
}
auto name() const -> const std::string& { return name_; }
private:
std::string name_;
};
// A first-class continuation representation of a fragment of the stack.
// A continuation value behaves like a pointer to the underlying stack
// fragment, which is exposed by `Stack()`.
class ContinuationValue : public Value {
public:
class StackFragment {
public:
// Constructs an empty StackFragment.
StackFragment() = default;
// Requires *this to be empty, because by the time we're tearing down the
// Arena, it's no longer safe to invoke ~Action.
~StackFragment();
StackFragment(StackFragment&&) = delete;
StackFragment& operator=(StackFragment&&) = delete;
// Store the given partial todo stack in *this, which must currently be
// empty. The stack is represented with the top of the stack at the
// beginning of the vector, the reverse of the usual order.
void StoreReversed(std::vector<std::unique_ptr<Action>> reversed_todo);
// Restore the currently stored stack fragment to the top of `todo`,
// leaving *this empty.
void RestoreTo(Stack<std::unique_ptr<Action>>& todo);
// Destroy the currently stored stack fragment.
void Clear();
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
private:
// The todo stack of a suspended continuation, starting with the top
// Action.
std::vector<std::unique_ptr<Action>> reversed_todo_;
};
explicit ContinuationValue(Nonnull<StackFragment*> stack)
: Value(Kind::ContinuationValue), stack_(stack) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::ContinuationValue;
}
// The todo stack of the suspended continuation. Note that this provides
// mutable access, even when *this is const, because of the reference-like
// semantics of ContinuationValue.
auto stack() const -> StackFragment& { return *stack_; }
private:
Nonnull<StackFragment*> stack_;
};
// The String type.
class StringType : public Value {
public:
StringType() : Value(Kind::StringType) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::StringType;
}
};
// A string value.
class StringValue : public Value {
public:
explicit StringValue(std::string value)
: Value(Kind::StringValue), value_(std::move(value)) {}
static auto classof(const Value* value) -> bool {
return value->kind() == Kind::StringValue;
}
auto value() const -> const std::string& { return value_; }
private:
std::string value_;
};
auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool;
auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2,
SourceLocation source_loc) -> bool;
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_