mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Generic classes (#1124)
* start of generic classes * fix regressions * class functions in interfaces * access to class function on interface from class parameter * more stuff working for generic classes * fixing bugs * update TypeEqual for generic classes * fixing bugs and finding new ones * disable unqualified access to members from other members for now * minor edits * bug fixes * introduce compile_time_value to use in type checker instead of constant_value * cleanup * put a CHECK back in * failure test cases for the new FATAL_COMPILATION_ERROR * change a runtime FATAL into a FATAL_COMPILATION_ERROR * Update executable_semantics/ast/declaration.h Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/action_stack.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/interpreter.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/value.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/value.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/interpreter.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/value.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/value.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/resolve_names.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * responses to reviews * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * rename compile_time_value to symbolic_identity * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/type_checker.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/value.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/value.cpp Co-authored-by: Jon Meow <jperkins@google.com> * Update executable_semantics/interpreter/value.cpp Co-authored-by: Jon Meow <jperkins@google.com> * more edits from review * Apply suggestions from code review Co-authored-by: Geoff Romer <gromer@google.com> * review responses * Update executable_semantics/interpreter/interpreter.cpp Co-authored-by: Geoff Romer <gromer@google.com> * const impl_scope for TypeCheckChoiceDeclaration * add some const Co-authored-by: Jon Meow <jperkins@google.com> Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
committed by
GitHub
co-authored by
Jon Meow
Geoff Romer
parent
37a0e35b31
commit
210856dd57
@@ -70,12 +70,13 @@ cc_test(
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "generic_binding",
|
||||
name = "impl_binding",
|
||||
hdrs = [
|
||||
"generic_binding.h",
|
||||
"impl_binding.h",
|
||||
],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":pattern",
|
||||
":source_location",
|
||||
":value_category",
|
||||
"//common:check",
|
||||
@@ -93,7 +94,7 @@ cc_library(
|
||||
],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":generic_binding",
|
||||
":impl_binding",
|
||||
":pattern",
|
||||
":return_term",
|
||||
":source_location",
|
||||
@@ -125,7 +126,6 @@ cc_library(
|
||||
hdrs = ["expression.h"],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":generic_binding",
|
||||
":paren_contents",
|
||||
":source_location",
|
||||
":static_scope",
|
||||
|
||||
@@ -43,7 +43,10 @@ class AstNode {
|
||||
auto operator=(AstNode&&) -> AstNode& = delete;
|
||||
virtual ~AstNode() = 0;
|
||||
|
||||
// Print the AST rooted at the node.
|
||||
virtual void Print(llvm::raw_ostream& out) const = 0;
|
||||
// Print identifying information about the node, such as it's name.
|
||||
virtual void PrintID(llvm::raw_ostream& out) const = 0;
|
||||
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
|
||||
|
||||
// Returns an enumerator specifying the concrete type of this node.
|
||||
|
||||
@@ -7,6 +7,7 @@ abstract class Pattern : AstNode;
|
||||
class AutoPattern : Pattern;
|
||||
class VarPattern : Pattern;
|
||||
class BindingPattern : Pattern;
|
||||
class GenericBinding : Pattern;
|
||||
class TuplePattern : Pattern;
|
||||
class AlternativePattern : Pattern;
|
||||
class ExpressionPattern : Pattern;
|
||||
@@ -17,7 +18,6 @@ abstract class Declaration : AstNode;
|
||||
class VariableDeclaration : Declaration;
|
||||
class InterfaceDeclaration : Declaration;
|
||||
class ImplDeclaration : Declaration;
|
||||
class GenericBinding : AstNode;
|
||||
class ImplBinding : AstNode;
|
||||
class AlternativeSignature : AstNode;
|
||||
abstract class Statement : AstNode;
|
||||
|
||||
@@ -17,7 +17,8 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case DeclarationKind::InterfaceDeclaration: {
|
||||
const auto& iface_decl = cast<InterfaceDeclaration>(*this);
|
||||
out << "interface " << iface_decl.name() << " {\n";
|
||||
PrintID(out);
|
||||
out << " {\n";
|
||||
for (Nonnull<Declaration*> m : iface_decl.members()) {
|
||||
out << *m;
|
||||
}
|
||||
@@ -26,15 +27,8 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
case DeclarationKind::ImplDeclaration: {
|
||||
const auto& impl_decl = cast<ImplDeclaration>(*this);
|
||||
switch (impl_decl.kind()) {
|
||||
case ImplKind::InternalImpl:
|
||||
break;
|
||||
case ImplKind::ExternalImpl:
|
||||
out << "external ";
|
||||
break;
|
||||
}
|
||||
out << "impl " << *impl_decl.impl_type() << " as "
|
||||
<< impl_decl.interface() << " {\n";
|
||||
PrintID(out);
|
||||
out << " {\n";
|
||||
for (Nonnull<Declaration*> m : impl_decl.members()) {
|
||||
out << *m;
|
||||
}
|
||||
@@ -47,7 +41,11 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
|
||||
case DeclarationKind::ClassDeclaration: {
|
||||
const auto& class_decl = cast<ClassDeclaration>(*this);
|
||||
out << "class " << class_decl.name() << " {\n";
|
||||
PrintID(out);
|
||||
if (class_decl.type_params().has_value()) {
|
||||
out << **class_decl.type_params();
|
||||
}
|
||||
out << " {\n";
|
||||
for (Nonnull<Declaration*> m : class_decl.members()) {
|
||||
out << *m;
|
||||
}
|
||||
@@ -57,7 +55,8 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
const auto& choice = cast<ChoiceDeclaration>(*this);
|
||||
out << "choice " << choice.name() << " {\n";
|
||||
PrintID(out);
|
||||
out << " {\n";
|
||||
for (Nonnull<const AlternativeSignature*> alt : choice.alternatives()) {
|
||||
out << *alt << ";\n";
|
||||
}
|
||||
@@ -67,7 +66,7 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = cast<VariableDeclaration>(*this);
|
||||
out << "var " << var.binding();
|
||||
PrintID(out);
|
||||
if (var.has_initializer()) {
|
||||
out << " = " << var.initializer();
|
||||
}
|
||||
@@ -77,6 +76,50 @@ void Declaration::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Declaration::PrintID(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case DeclarationKind::InterfaceDeclaration: {
|
||||
const auto& iface_decl = cast<InterfaceDeclaration>(*this);
|
||||
out << "interface" << iface_decl.name();
|
||||
break;
|
||||
}
|
||||
case DeclarationKind::ImplDeclaration: {
|
||||
const auto& impl_decl = cast<ImplDeclaration>(*this);
|
||||
switch (impl_decl.kind()) {
|
||||
case ImplKind::InternalImpl:
|
||||
break;
|
||||
case ImplKind::ExternalImpl:
|
||||
out << "external ";
|
||||
break;
|
||||
}
|
||||
out << "impl " << *impl_decl.impl_type() << " as "
|
||||
<< impl_decl.interface();
|
||||
break;
|
||||
}
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
out << "fn " << cast<FunctionDeclaration>(*this).name();
|
||||
break;
|
||||
|
||||
case DeclarationKind::ClassDeclaration: {
|
||||
const auto& class_decl = cast<ClassDeclaration>(*this);
|
||||
out << "class " << class_decl.name();
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
const auto& choice = cast<ChoiceDeclaration>(*this);
|
||||
out << "choice " << choice.name();
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
const auto& var = cast<VariableDeclaration>(*this);
|
||||
out << "var " << var.binding();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto GetName(const Declaration& declaration) -> std::optional<std::string> {
|
||||
switch (declaration.kind()) {
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
@@ -98,6 +141,8 @@ void GenericBinding::Print(llvm::raw_ostream& out) const {
|
||||
out << name() << ":! " << type();
|
||||
}
|
||||
|
||||
void GenericBinding::PrintID(llvm::raw_ostream& out) const { out << name(); }
|
||||
|
||||
void ReturnTerm::Print(llvm::raw_ostream& out) const {
|
||||
switch (kind_) {
|
||||
case ReturnKind::Omitted:
|
||||
@@ -170,4 +215,8 @@ void AlternativeSignature::Print(llvm::raw_ostream& out) const {
|
||||
out << "alt " << name() << " " << signature();
|
||||
}
|
||||
|
||||
void AlternativeSignature::PrintID(llvm::raw_ostream& out) const {
|
||||
out << name();
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
#include "executable_semantics/ast/generic_binding.h"
|
||||
#include "executable_semantics/ast/impl_binding.h"
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/ast/return_term.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
@@ -40,6 +40,7 @@ class Declaration : public AstNode {
|
||||
auto operator=(const Declaration&) -> Declaration& = delete;
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
void PrintID(llvm::raw_ostream& out) const override;
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromDeclaration(node->kind());
|
||||
@@ -67,6 +68,23 @@ class Declaration : public AstNode {
|
||||
// and after typechecking it's guaranteed to be true.
|
||||
auto has_static_type() const -> bool { return static_type_.has_value(); }
|
||||
|
||||
// Sets the value returned by constant_value(). Can only be called once,
|
||||
// during typechecking.
|
||||
void set_constant_value(Nonnull<const Value*> value) {
|
||||
CHECK(!constant_value_.has_value());
|
||||
constant_value_ = value;
|
||||
}
|
||||
|
||||
// See static_scope.h for API.
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
|
||||
// See static_scope.h for API.
|
||||
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Constructs a Declaration representing syntax at the given line number.
|
||||
// `kind` must be the enumerator corresponding to the most-derived type being
|
||||
@@ -76,6 +94,7 @@ class Declaration : public AstNode {
|
||||
|
||||
private:
|
||||
std::optional<Nonnull<const Value*>> static_type_;
|
||||
std::optional<Nonnull<const Value*>> constant_value_;
|
||||
};
|
||||
|
||||
class FunctionDeclaration : public Declaration {
|
||||
@@ -130,16 +149,6 @@ class FunctionDeclaration : public Declaration {
|
||||
auto body() -> std::optional<Nonnull<Block*>> { return body_; }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
|
||||
// Sets the value returned by constant_value(). Can only be called once,
|
||||
// during typechecking.
|
||||
void set_constant_value(Nonnull<const Value*> value) {
|
||||
CHECK(!constant_value_.has_value());
|
||||
constant_value_ = value;
|
||||
}
|
||||
|
||||
auto is_method() const -> bool { return me_pattern_.has_value(); }
|
||||
|
||||
@@ -150,7 +159,6 @@ class FunctionDeclaration : public Declaration {
|
||||
Nonnull<TuplePattern*> param_pattern_;
|
||||
ReturnTerm return_term_;
|
||||
std::optional<Nonnull<Block*>> body_;
|
||||
std::optional<Nonnull<const Value*>> constant_value_;
|
||||
};
|
||||
|
||||
class ClassDeclaration : public Declaration {
|
||||
@@ -158,9 +166,11 @@ class ClassDeclaration : public Declaration {
|
||||
using ImplementsCarbonValueNode = void;
|
||||
|
||||
ClassDeclaration(SourceLocation source_loc, std::string name,
|
||||
std::optional<Nonnull<TuplePattern*>> type_params,
|
||||
std::vector<Nonnull<Declaration*>> members)
|
||||
: Declaration(AstNodeKind::ClassDeclaration, source_loc),
|
||||
name_(std::move(name)),
|
||||
type_params_(type_params),
|
||||
members_(std::move(members)) {}
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
@@ -168,26 +178,23 @@ class ClassDeclaration : public Declaration {
|
||||
}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto type_params() const -> std::optional<Nonnull<const TuplePattern*>> {
|
||||
return type_params_;
|
||||
}
|
||||
auto type_params() -> std::optional<Nonnull<TuplePattern*>> {
|
||||
return type_params_;
|
||||
}
|
||||
|
||||
auto members() const -> llvm::ArrayRef<Nonnull<Declaration*>> {
|
||||
return members_;
|
||||
}
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
|
||||
// Sets the value returned by constant_value(). Can only be called once,
|
||||
// during typechecking.
|
||||
void set_constant_value(Nonnull<const Value*> value) {
|
||||
CHECK(!constant_value_.has_value());
|
||||
constant_value_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::optional<Nonnull<TuplePattern*>> type_params_;
|
||||
std::vector<Nonnull<Declaration*>> members_;
|
||||
std::optional<Nonnull<const Value*>> constant_value_;
|
||||
};
|
||||
|
||||
class AlternativeSignature : public AstNode {
|
||||
@@ -199,6 +206,7 @@ class AlternativeSignature : public AstNode {
|
||||
signature_(signature) {}
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
void PrintID(llvm::raw_ostream& out) const override;
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromAlternativeSignature(node->kind());
|
||||
@@ -237,21 +245,10 @@ class ChoiceDeclaration : public Declaration {
|
||||
}
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
|
||||
// Sets the value returned by constant_value(). Can only be called once,
|
||||
// during typechecking.
|
||||
void set_constant_value(Nonnull<const Value*> value) {
|
||||
CHECK(!constant_value_.has_value());
|
||||
constant_value_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<Nonnull<AlternativeSignature*>> alternatives_;
|
||||
std::optional<Nonnull<const Value*>> constant_value_;
|
||||
};
|
||||
|
||||
// Global variable definition implements the Declaration concept.
|
||||
@@ -311,21 +308,10 @@ class InterfaceDeclaration : public Declaration {
|
||||
auto self() -> Nonnull<GenericBinding*> { return self_; }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
|
||||
// Sets the value returned by constant_value(). Can only be called once,
|
||||
// during typechecking.
|
||||
void set_constant_value(Nonnull<const Value*> value) {
|
||||
CHECK(!constant_value_.has_value());
|
||||
constant_value_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<Nonnull<Declaration*>> members_;
|
||||
std::optional<Nonnull<const Value*>> constant_value_;
|
||||
Nonnull<GenericBinding*> self_;
|
||||
};
|
||||
|
||||
@@ -364,14 +350,6 @@ class ImplDeclaration : public Declaration {
|
||||
auto members() const -> llvm::ArrayRef<Nonnull<Declaration*>> {
|
||||
return members_;
|
||||
}
|
||||
// Return the witness table for this impl.
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
void set_constant_value(Nonnull<const Value*> value) {
|
||||
CHECK(!constant_value_.has_value());
|
||||
constant_value_ = value;
|
||||
}
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
|
||||
private:
|
||||
@@ -380,7 +358,6 @@ class ImplDeclaration : public Declaration {
|
||||
Nonnull<Expression*> interface_;
|
||||
std::optional<Nonnull<const Value*>> interface_type_;
|
||||
std::vector<Nonnull<Declaration*>> members_;
|
||||
std::optional<Nonnull<const Value*>> constant_value_;
|
||||
};
|
||||
|
||||
// Return the name of a declaration, if it has one.
|
||||
|
||||
@@ -116,12 +116,6 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
PrintFields(out, cast<StructTypeLiteral>(*this).fields(), ": ");
|
||||
out << "}";
|
||||
break;
|
||||
case ExpressionKind::IntLiteral:
|
||||
out << cast<IntLiteral>(*this).value();
|
||||
break;
|
||||
case ExpressionKind::BoolLiteral:
|
||||
out << (cast<BoolLiteral>(*this).value() ? "true" : "false");
|
||||
break;
|
||||
case ExpressionKind::PrimitiveOperatorExpression: {
|
||||
out << "(";
|
||||
const auto& op = cast<PrimitiveOperatorExpression>(*this);
|
||||
@@ -142,9 +136,6 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
out << ")";
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::IdentifierExpression:
|
||||
out << cast<IdentifierExpression>(*this).name();
|
||||
break;
|
||||
case ExpressionKind::CallExpression: {
|
||||
const auto& call = cast<CallExpression>(*this);
|
||||
out << call.function();
|
||||
@@ -155,26 +146,6 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::BoolTypeLiteral:
|
||||
out << "Bool";
|
||||
break;
|
||||
case ExpressionKind::IntTypeLiteral:
|
||||
out << "i32";
|
||||
break;
|
||||
case ExpressionKind::StringLiteral:
|
||||
out << "\"";
|
||||
out.write_escaped(cast<StringLiteral>(*this).value());
|
||||
out << "\"";
|
||||
break;
|
||||
case ExpressionKind::StringTypeLiteral:
|
||||
out << "String";
|
||||
break;
|
||||
case ExpressionKind::TypeTypeLiteral:
|
||||
out << "Type";
|
||||
break;
|
||||
case ExpressionKind::ContinuationTypeLiteral:
|
||||
out << "Continuation";
|
||||
break;
|
||||
case ExpressionKind::FunctionTypeLiteral: {
|
||||
const auto& fn = cast<FunctionTypeLiteral>(*this);
|
||||
out << "fn " << fn.parameter() << " -> " << fn.return_type();
|
||||
@@ -205,6 +176,64 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
out << ")";
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::IdentifierExpression:
|
||||
case ExpressionKind::IntLiteral:
|
||||
case ExpressionKind::BoolLiteral:
|
||||
case ExpressionKind::BoolTypeLiteral:
|
||||
case ExpressionKind::IntTypeLiteral:
|
||||
case ExpressionKind::StringLiteral:
|
||||
case ExpressionKind::StringTypeLiteral:
|
||||
case ExpressionKind::TypeTypeLiteral:
|
||||
case ExpressionKind::ContinuationTypeLiteral:
|
||||
PrintID(out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Expression::PrintID(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case ExpressionKind::IdentifierExpression:
|
||||
out << cast<IdentifierExpression>(*this).name();
|
||||
break;
|
||||
case ExpressionKind::IntLiteral:
|
||||
out << cast<IntLiteral>(*this).value();
|
||||
break;
|
||||
case ExpressionKind::BoolLiteral:
|
||||
out << (cast<BoolLiteral>(*this).value() ? "true" : "false");
|
||||
break;
|
||||
case ExpressionKind::BoolTypeLiteral:
|
||||
out << "Bool";
|
||||
break;
|
||||
case ExpressionKind::IntTypeLiteral:
|
||||
out << "i32";
|
||||
break;
|
||||
case ExpressionKind::StringLiteral:
|
||||
out << "\"";
|
||||
out.write_escaped(cast<StringLiteral>(*this).value());
|
||||
out << "\"";
|
||||
break;
|
||||
case ExpressionKind::StringTypeLiteral:
|
||||
out << "String";
|
||||
break;
|
||||
case ExpressionKind::TypeTypeLiteral:
|
||||
out << "Type";
|
||||
break;
|
||||
case ExpressionKind::ContinuationTypeLiteral:
|
||||
out << "Continuation";
|
||||
break;
|
||||
case ExpressionKind::IndexExpression:
|
||||
case ExpressionKind::FieldAccessExpression:
|
||||
case ExpressionKind::IfExpression:
|
||||
case ExpressionKind::TupleLiteral:
|
||||
case ExpressionKind::StructLiteral:
|
||||
case ExpressionKind::StructTypeLiteral:
|
||||
case ExpressionKind::CallExpression:
|
||||
case ExpressionKind::PrimitiveOperatorExpression:
|
||||
case ExpressionKind::IntrinsicExpression:
|
||||
case ExpressionKind::UnimplementedExpression:
|
||||
case ExpressionKind::FunctionTypeLiteral:
|
||||
out << "...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_
|
||||
#define EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
@@ -12,7 +13,6 @@
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
#include "executable_semantics/ast/generic_binding.h"
|
||||
#include "executable_semantics/ast/paren_contents.h"
|
||||
#include "executable_semantics/ast/source_location.h"
|
||||
#include "executable_semantics/ast/static_scope.h"
|
||||
@@ -25,12 +25,14 @@ namespace Carbon {
|
||||
|
||||
class Value;
|
||||
class VariableType;
|
||||
class ImplBinding;
|
||||
|
||||
class Expression : public AstNode {
|
||||
public:
|
||||
~Expression() override = 0;
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
void PrintID(llvm::raw_ostream& out) const override;
|
||||
|
||||
static auto classof(const AstNode* node) {
|
||||
return InheritsFromExpression(node->kind());
|
||||
@@ -43,7 +45,10 @@ class Expression : public AstNode {
|
||||
}
|
||||
|
||||
// The static type of this expression. Cannot be called before typechecking.
|
||||
auto static_type() const -> const Value& { return **static_type_; }
|
||||
auto static_type() const -> const Value& {
|
||||
CHECK(static_type_.has_value());
|
||||
return **static_type_;
|
||||
}
|
||||
|
||||
// Sets the static type of this expression. Can only be called once, during
|
||||
// typechecking.
|
||||
@@ -354,7 +359,10 @@ class PrimitiveOperatorExpression : public Expression {
|
||||
std::vector<Nonnull<Expression*>> arguments_;
|
||||
};
|
||||
|
||||
class ImplBinding;
|
||||
class GenericBinding;
|
||||
|
||||
using BindingMap =
|
||||
std::map<Nonnull<const GenericBinding*>, Nonnull<const Value*>>;
|
||||
|
||||
class CallExpression : public Expression {
|
||||
public:
|
||||
@@ -390,10 +398,17 @@ class CallExpression : public Expression {
|
||||
impls_ = impls;
|
||||
}
|
||||
|
||||
auto deduced_args() const -> const BindingMap& { return deduced_args_; }
|
||||
|
||||
void set_deduced_args(const BindingMap& deduced_args) {
|
||||
deduced_args_ = deduced_args;
|
||||
}
|
||||
|
||||
private:
|
||||
Nonnull<Expression*> function_;
|
||||
Nonnull<Expression*> argument_;
|
||||
std::map<Nonnull<const ImplBinding*>, ValueNodeView> impls_;
|
||||
BindingMap deduced_args_;
|
||||
};
|
||||
|
||||
class FunctionTypeLiteral : public Expression {
|
||||
|
||||
+5
-65
@@ -10,6 +10,7 @@
|
||||
#include "common/check.h"
|
||||
#include "common/ostream.h"
|
||||
#include "executable_semantics/ast/ast_node.h"
|
||||
#include "executable_semantics/ast/pattern.h"
|
||||
#include "executable_semantics/ast/value_category.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -18,71 +19,6 @@ class Value;
|
||||
class Expression;
|
||||
class ImplBinding;
|
||||
|
||||
// TODO: expand the kinds of things that can be deduced parameters.
|
||||
// For now, only generic parameters are supported.
|
||||
class GenericBinding : public AstNode {
|
||||
public:
|
||||
using ImplementsCarbonValueNode = void;
|
||||
|
||||
GenericBinding(SourceLocation source_loc, std::string name,
|
||||
Nonnull<Expression*> type)
|
||||
: AstNode(AstNodeKind::GenericBinding, source_loc),
|
||||
name_(std::move(name)),
|
||||
type_(type) {}
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromGenericBinding(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto type() const -> const Expression& { return *type_; }
|
||||
auto type() -> Expression& { return *type_; }
|
||||
|
||||
// The static type of the binding. Cannot be called before typechecking.
|
||||
auto static_type() const -> const Value& { return **static_type_; }
|
||||
|
||||
// Sets the static type of the binding. Can only be called once, during
|
||||
// typechecking.
|
||||
void set_static_type(Nonnull<const Value*> type) {
|
||||
CHECK(!static_type_.has_value());
|
||||
static_type_ = type;
|
||||
}
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return constant_value_;
|
||||
}
|
||||
|
||||
// Sets the value returned by constant_value(). Can only be called once,
|
||||
// during typechecking.
|
||||
void set_constant_value(Nonnull<const Value*> value) {
|
||||
CHECK(!constant_value_.has_value());
|
||||
constant_value_ = value;
|
||||
}
|
||||
|
||||
// The impl binding associated with this type variable.
|
||||
auto impl_binding() const -> std::optional<Nonnull<const ImplBinding*>> {
|
||||
return impl_binding_;
|
||||
}
|
||||
// Set the impl binding.
|
||||
void set_impl_binding(Nonnull<const ImplBinding*> binding) {
|
||||
CHECK(!impl_binding_.has_value());
|
||||
impl_binding_ = binding;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
Nonnull<Expression*> type_;
|
||||
std::optional<Nonnull<const Value*>> static_type_;
|
||||
std::optional<Nonnull<const Value*>> constant_value_;
|
||||
std::optional<Nonnull<const ImplBinding*>> impl_binding_;
|
||||
};
|
||||
|
||||
using BindingMap =
|
||||
std::map<Nonnull<const GenericBinding*>, Nonnull<const Value*>>;
|
||||
|
||||
// The run-time counterpart of a `GenericBinding`.
|
||||
//
|
||||
// Once a generic binding has been declared, it can be used
|
||||
@@ -106,6 +42,7 @@ class ImplBinding : public AstNode {
|
||||
return InheritsFromImplBinding(node->kind());
|
||||
}
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
void PrintID(llvm::raw_ostream& out) const override;
|
||||
|
||||
// The binding for the type variable.
|
||||
auto type_var() const -> Nonnull<const GenericBinding*> { return type_var_; }
|
||||
@@ -116,6 +53,9 @@ class ImplBinding : public AstNode {
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// The static type of the impl. Cannot be called before typechecking.
|
||||
auto static_type() const -> const Value& { return **static_type_; }
|
||||
@@ -29,6 +29,11 @@ void Pattern::Print(llvm::raw_ostream& out) const {
|
||||
out << binding.name() << ": " << binding.type();
|
||||
break;
|
||||
}
|
||||
case PatternKind::GenericBinding: {
|
||||
const auto& binding = cast<GenericBinding>(*this);
|
||||
out << binding.name() << ":! " << binding.type();
|
||||
break;
|
||||
}
|
||||
case PatternKind::TuplePattern: {
|
||||
const auto& tuple = cast<TuplePattern>(*this);
|
||||
out << "(";
|
||||
@@ -54,6 +59,40 @@ void Pattern::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Pattern::PrintID(llvm::raw_ostream& out) const {
|
||||
switch (kind()) {
|
||||
case PatternKind::AutoPattern:
|
||||
out << "auto";
|
||||
break;
|
||||
case PatternKind::BindingPattern: {
|
||||
const auto& binding = cast<BindingPattern>(*this);
|
||||
out << binding.name();
|
||||
break;
|
||||
}
|
||||
case PatternKind::GenericBinding: {
|
||||
const auto& binding = cast<GenericBinding>(*this);
|
||||
out << binding.name();
|
||||
break;
|
||||
}
|
||||
case PatternKind::TuplePattern: {
|
||||
out << "(...)";
|
||||
break;
|
||||
}
|
||||
case PatternKind::AlternativePattern: {
|
||||
const auto& alternative = cast<AlternativePattern>(*this);
|
||||
out << alternative.choice_type() << "." << alternative.alternative_name()
|
||||
<< "(...)";
|
||||
break;
|
||||
}
|
||||
case PatternKind::VarPattern:
|
||||
out << "var ...";
|
||||
break;
|
||||
case PatternKind::ExpressionPattern:
|
||||
out << "...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent to `GetBindings`, but stores its output in `bindings` instead of
|
||||
// returning it.
|
||||
static void GetBindingsImpl(
|
||||
@@ -73,6 +112,7 @@ static void GetBindingsImpl(
|
||||
return;
|
||||
case PatternKind::AutoPattern:
|
||||
case PatternKind::ExpressionPattern:
|
||||
case PatternKind::GenericBinding:
|
||||
return;
|
||||
case PatternKind::VarPattern:
|
||||
GetBindingsImpl(cast<VarPattern>(pattern).pattern(), bindings);
|
||||
|
||||
@@ -38,6 +38,7 @@ class Pattern : public AstNode {
|
||||
~Pattern() override = 0;
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
void PrintID(llvm::raw_ostream& out) const override;
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromPattern(node->kind());
|
||||
@@ -50,7 +51,10 @@ class Pattern : public AstNode {
|
||||
}
|
||||
|
||||
// The static type of this pattern. Cannot be called before typechecking.
|
||||
auto static_type() const -> const Value& { return **static_type_; }
|
||||
auto static_type() const -> const Value& {
|
||||
CHECK(static_type_.has_value());
|
||||
return **static_type_;
|
||||
}
|
||||
|
||||
// Sets the static type of this expression. Can only be called once, during
|
||||
// typechecking.
|
||||
@@ -168,6 +172,9 @@ class BindingPattern : public Pattern {
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
@@ -195,6 +202,58 @@ class TuplePattern : public Pattern {
|
||||
std::vector<Nonnull<Pattern*>> fields_;
|
||||
};
|
||||
|
||||
class GenericBinding : public Pattern {
|
||||
public:
|
||||
using ImplementsCarbonValueNode = void;
|
||||
|
||||
GenericBinding(SourceLocation source_loc, std::string name,
|
||||
Nonnull<Expression*> type)
|
||||
: Pattern(AstNodeKind::GenericBinding, source_loc),
|
||||
name_(std::move(name)),
|
||||
type_(type) {}
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override;
|
||||
void PrintID(llvm::raw_ostream& out) const override;
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromGenericBinding(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto type() const -> const Expression& { return *type_; }
|
||||
auto type() -> Expression& { return *type_; }
|
||||
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
|
||||
return symbolic_identity_;
|
||||
}
|
||||
void set_symbolic_identity(Nonnull<const Value*> value) {
|
||||
CHECK(!symbolic_identity_.has_value());
|
||||
symbolic_identity_ = value;
|
||||
}
|
||||
|
||||
// The impl binding associated with this type variable.
|
||||
auto impl_binding() const -> std::optional<Nonnull<const ImplBinding*>> {
|
||||
return impl_binding_;
|
||||
}
|
||||
// Set the impl binding.
|
||||
void set_impl_binding(Nonnull<const ImplBinding*> binding) {
|
||||
CHECK(!impl_binding_.has_value());
|
||||
impl_binding_ = binding;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
Nonnull<Expression*> type_;
|
||||
std::optional<Nonnull<const Value*>> symbolic_identity_;
|
||||
std::optional<Nonnull<const ImplBinding*>> impl_binding_;
|
||||
};
|
||||
|
||||
// Converts paren_contents to a Pattern, interpreting the parentheses as
|
||||
// grouping if their contents permit that interpretation, or as forming a
|
||||
// tuple otherwise.
|
||||
|
||||
@@ -29,6 +29,7 @@ class Statement : public AstNode {
|
||||
~Statement() override = 0;
|
||||
|
||||
void Print(llvm::raw_ostream& out) const override { PrintDepth(-1, out); }
|
||||
void PrintID(llvm::raw_ostream& out) const override { PrintDepth(1, out); }
|
||||
void PrintDepth(int depth, llvm::raw_ostream& out) const;
|
||||
|
||||
static auto classof(const AstNode* node) {
|
||||
@@ -350,6 +351,9 @@ class Continuation : public Statement {
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
|
||||
@@ -38,15 +38,22 @@ static constexpr bool ImplementsValueNode = false;
|
||||
with a value, such as declarations and bindings. The interface consists of
|
||||
the following methods:
|
||||
|
||||
// Returns the constant associated with the node.
|
||||
// This is called by the interpreter, not the type checker.
|
||||
auto constant_value() const -> std::optional<Nonnull<const Value*>>;
|
||||
|
||||
// Returns the symbolic compile-time identity of the node.
|
||||
// This is called by the type checker, not the interpreter.
|
||||
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>>;
|
||||
|
||||
// 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;
|
||||
|
||||
// Print the node for diagnostic or tracing purposes.
|
||||
void Print(llvm::raw_ostream& out) const;
|
||||
|
||||
// Print the node's identity (e.g. its name).
|
||||
void PrintID(llvm::raw_ostream& out) const;
|
||||
|
||||
*/
|
||||
// TODO: consider turning the above documentation into real code, as sketched
|
||||
@@ -70,9 +77,13 @@ class ValueNodeView {
|
||||
[](const AstNode& base) -> std::optional<Nonnull<const Value*>> {
|
||||
return llvm::cast<NodeType>(base).constant_value();
|
||||
}),
|
||||
symbolic_identity_(
|
||||
[](const AstNode& base) -> std::optional<Nonnull<const Value*>> {
|
||||
return llvm::cast<NodeType>(base).symbolic_identity();
|
||||
}),
|
||||
print_([](const AstNode& base, llvm::raw_ostream& out) -> void {
|
||||
// TODO: change this to print a summary of the node
|
||||
return llvm::cast<NodeType>(base).Print(out);
|
||||
return llvm::cast<NodeType>(base).PrintID(out);
|
||||
}),
|
||||
static_type_([](const AstNode& base) -> const Value& {
|
||||
return llvm::cast<NodeType>(base).static_type();
|
||||
@@ -94,6 +105,11 @@ class ValueNodeView {
|
||||
return constant_value_(*base_);
|
||||
}
|
||||
|
||||
// Returns node->symbolic_identity()
|
||||
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
|
||||
return symbolic_identity_(*base_);
|
||||
}
|
||||
|
||||
void Print(llvm::raw_ostream& out) const { print_(*base_, out); }
|
||||
|
||||
// Returns node->static_type()
|
||||
@@ -123,6 +139,8 @@ class ValueNodeView {
|
||||
Nonnull<const AstNode*> base_;
|
||||
std::function<std::optional<Nonnull<const Value*>>(const AstNode&)>
|
||||
constant_value_;
|
||||
std::function<std::optional<Nonnull<const Value*>>(const AstNode&)>
|
||||
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_;
|
||||
|
||||
Reference in New Issue
Block a user