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:
Jeremy G. Siek
2022-03-29 13:09:41 -04:00
committed by GitHub
co-authored by Jon Meow Geoff Romer
parent 37a0e35b31
commit 210856dd57
41 changed files with 1597 additions and 401 deletions
+4 -4
View File
@@ -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",
+3
View File
@@ -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.
+1 -1
View File
@@ -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;
+62 -13
View File
@@ -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
+31 -54
View File
@@ -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.
+58 -29
View File
@@ -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;
}
}
+18 -3
View File
@@ -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 {
@@ -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_; }
+40
View File
@@ -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);
+60 -1
View File
@@ -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.
+4
View File
@@ -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_;
+22 -4
View File
@@ -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_;