Skip to content

Commit

Permalink
interfaces, impls, and constrained generics (basics) (#1073)
Browse files Browse the repository at this point in the history
* interfaces, impls, and constrained generics (basics)

* separate type checking into declare vs. type check, removing redundancy

* external impls

* added impl scopes to handle generics calling generics

* cleanup

* more cleanup

* Update executable_semantics/testdata/interface/external_impl_point_vector.carbon

Co-authored-by: josh11b <[email protected]>

* Update executable_semantics/testdata/interface/generic_call_generic.carbon

Co-authored-by: josh11b <[email protected]>

* Update executable_semantics/testdata/interface/tuple_vector_add_scale.carbon

Co-authored-by: josh11b <[email protected]>

* Update executable_semantics/testdata/interface/vector_point_add_scale.carbon

Co-authored-by: josh11b <[email protected]>

* change ImplementationDeclaration to ImplDeclaration

* remove impl_type_value

* split NamedEntity into two

* changed GetName to be a free function

* adding comments

* more edits to respond to review

* introduce ImplBinding, remove punning on GenericBinding

* new test case and some minor edits

* refactor GetMember and GetField to move impl logic to interpreter

* remove commennt

* change EntityView to ImplBinding in FieldAccess...

* move ImplBinding

* review response

* added example to impl_scope.h

* minor edits

* Update executable_semantics/interpreter/field_path.h

Co-authored-by: Geoff Romer <[email protected]>

* Update executable_semantics/interpreter/value.cpp

Co-authored-by: Geoff Romer <[email protected]>

* Update executable_semantics/interpreter/interpreter.cpp

Co-authored-by: Geoff Romer <[email protected]>

* Update executable_semantics/ast/expression.h

Co-authored-by: Geoff Romer <[email protected]>

* Update executable_semantics/ast/expression.h

Co-authored-by: Geoff Romer <[email protected]>

* Update executable_semantics/ast/generic_binding.h

Co-authored-by: Geoff Romer <[email protected]>

* more edits from review

* review response

* Update executable_semantics/ast/static_scope.h

Co-authored-by: Geoff Romer <[email protected]>

* remove ImplType, renamed node_view to value_node

Co-authored-by: josh11b <[email protected]>
Co-authored-by: Geoff Romer <[email protected]>
  • Loading branch information
3 people authored Mar 2, 2022
1 parent 8f6e42d commit 7cce1bd
Show file tree
Hide file tree
Showing 43 changed files with 1,719 additions and 438 deletions.
18 changes: 18 additions & 0 deletions executable_semantics/ast/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ cc_test(
],
)

cc_library(
name = "generic_binding",
hdrs = [
"generic_binding.h",
],
deps = [
":ast_node",
":source_location",
":value_category",
"//common:check",
"//common:ostream",
"//executable_semantics/common:nonnull",
"@llvm-project//llvm:Support",
],
)

cc_library(
name = "declaration",
srcs = ["declaration.cpp"],
Expand All @@ -77,6 +93,7 @@ cc_library(
],
deps = [
":ast_node",
":generic_binding",
":pattern",
":return_term",
":source_location",
Expand Down Expand Up @@ -108,6 +125,7 @@ cc_library(
hdrs = ["expression.h"],
deps = [
":ast_node",
":generic_binding",
":paren_contents",
":source_location",
":static_scope",
Expand Down
2 changes: 1 addition & 1 deletion executable_semantics/ast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ inheritance, we handle these cases using a form of type erasure: we specify a
notional interface that those types conform to, and then define a "view" class
that behaves like a pointer to an instance of that interface. Types declare that
they model an interface `Foo` by defining a public static member named
`ImplementsCarbonFoo`. See [NamedEntityView](static_scope.h) for an example of
`ImplementsCarbonFoo`. See [ValueNodeView](static_scope.h) for an example of
this pattern.
3 changes: 3 additions & 0 deletions executable_semantics/ast/ast_rtti.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ abstract class Declaration : AstNode;
class ClassDeclaration : Declaration;
class ChoiceDeclaration : Declaration;
class VariableDeclaration : Declaration;
class InterfaceDeclaration : Declaration;
class ImplDeclaration : Declaration;
class GenericBinding : AstNode;
class ImplBinding : AstNode;
class AlternativeSignature : AstNode;
abstract class Statement : AstNode;
class ExpressionStatement : Statement;
Expand Down
44 changes: 44 additions & 0 deletions executable_semantics/ast/declaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,32 @@ Declaration::~Declaration() = default;

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";
for (Nonnull<Declaration*> m : iface_decl.members()) {
out << *m;
}
out << "}\n";
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() << " {\n";
for (Nonnull<Declaration*> m : impl_decl.members()) {
out << *m;
}
out << "}\n";
break;
}
case DeclarationKind::FunctionDeclaration:
cast<FunctionDeclaration>(*this).PrintDepth(-1, out);
break;
Expand Down Expand Up @@ -51,6 +77,23 @@ void Declaration::Print(llvm::raw_ostream& out) const {
}
}

auto GetName(const Declaration& declaration) -> std::optional<std::string> {
switch (declaration.kind()) {
case DeclarationKind::FunctionDeclaration:
return cast<FunctionDeclaration>(declaration).name();
case DeclarationKind::ClassDeclaration:
return cast<ClassDeclaration>(declaration).name();
case DeclarationKind::ChoiceDeclaration:
return cast<ChoiceDeclaration>(declaration).name();
case DeclarationKind::InterfaceDeclaration:
return cast<InterfaceDeclaration>(declaration).name();
case DeclarationKind::VariableDeclaration:
return cast<VariableDeclaration>(declaration).binding().name();
case DeclarationKind::ImplDeclaration:
return std::nullopt;
}
}

void GenericBinding::Print(llvm::raw_ostream& out) const {
out << name() << ":! " << type();
}
Expand All @@ -63,6 +106,7 @@ void ReturnTerm::Print(llvm::raw_ostream& out) const {
out << "-> auto";
return;
case ReturnKind::Expression:
CHECK(type_expression_.has_value());
out << "-> " << **type_expression_;
return;
}
Expand Down
164 changes: 107 additions & 57 deletions executable_semantics/ast/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "common/ostream.h"
#include "executable_semantics/ast/ast_node.h"
#include "executable_semantics/ast/generic_binding.h"
#include "executable_semantics/ast/pattern.h"
#include "executable_semantics/ast/return_term.h"
#include "executable_semantics/ast/source_location.h"
Expand Down Expand Up @@ -56,7 +57,10 @@ class Declaration : public AstNode {

// Sets the static type of the declared entity. Can only be called once,
// during typechecking.
void set_static_type(Nonnull<const Value*> type) { static_type_ = type; }
void set_static_type(Nonnull<const Value*> type) {
CHECK(!static_type_.has_value());
static_type_ = type;
}

// Returns whether the static type has been set. Should only be called
// during typechecking: before typechecking it's guaranteed to be false,
Expand All @@ -74,62 +78,9 @@ class Declaration : public AstNode {
std::optional<Nonnull<const Value*>> static_type_;
};

// TODO: expand the kinds of things that can be deduced parameters.
// For now, only generic parameters are supported.
class GenericBinding : public AstNode {
public:
using ImplementsCarbonNamedEntity = 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) { static_type_ = type; }

// Returns whether the static type has been set. Should only be called
// during typechecking: before typechecking it's guaranteed to be false,
// 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; }
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_;
Nonnull<Expression*> type_;
std::optional<Nonnull<const Value*>> static_type_;
std::optional<Nonnull<const Value*>> constant_value_;
};

class FunctionDeclaration : public Declaration {
public:
using ImplementsCarbonNamedEntity = void;
using ImplementsCarbonValueNode = void;

FunctionDeclaration(SourceLocation source_loc, std::string name,
std::vector<Nonnull<AstNode*>> deduced_params,
Expand Down Expand Up @@ -196,7 +147,7 @@ class FunctionDeclaration : public Declaration {

class ClassDeclaration : public Declaration {
public:
using ImplementsCarbonNamedEntity = void;
using ImplementsCarbonValueNode = void;

ClassDeclaration(SourceLocation source_loc, std::string name,
std::vector<Nonnull<Declaration*>> members)
Expand Down Expand Up @@ -256,7 +207,7 @@ class AlternativeSignature : public AstNode {

class ChoiceDeclaration : public Declaration {
public:
using ImplementsCarbonNamedEntity = void;
using ImplementsCarbonValueNode = void;

ChoiceDeclaration(SourceLocation source_loc, std::string name,
std::vector<Nonnull<AlternativeSignature*>> alternatives)
Expand Down Expand Up @@ -324,6 +275,105 @@ class VariableDeclaration : public Declaration {
std::optional<Nonnull<Expression*>> initializer_;
};

class InterfaceDeclaration : public Declaration {
public:
using ImplementsCarbonValueNode = void;

InterfaceDeclaration(SourceLocation source_loc, std::string name,
Nonnull<GenericBinding*> self,
std::vector<Nonnull<Declaration*>> members)
: Declaration(AstNodeKind::InterfaceDeclaration, source_loc),
name_(std::move(name)),
members_(std::move(members)),
self_(self) {}

static auto classof(const AstNode* node) -> bool {
return InheritsFromInterfaceDeclaration(node->kind());
}

auto name() const -> const std::string& { return name_; }
auto members() const -> llvm::ArrayRef<Nonnull<Declaration*>> {
return members_;
}
auto self() const -> Nonnull<const GenericBinding*> { return self_; }
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_;
};

enum class ImplKind { InternalImpl, ExternalImpl };

class ImplDeclaration : public Declaration {
public:
using ImplementsCarbonValueNode = void;

ImplDeclaration(SourceLocation source_loc, ImplKind kind,
Nonnull<Expression*> impl_type,
Nonnull<Expression*> interface,
std::vector<Nonnull<Declaration*>> members)
: Declaration(AstNodeKind::ImplDeclaration, source_loc),
kind_(kind),
impl_type_(impl_type),
interface_(interface),
members_(members) {}

static auto classof(const AstNode* node) -> bool {
return InheritsFromImplDeclaration(node->kind());
}
// Return whether this is an external or internal impl.
auto kind() const -> ImplKind { return kind_; }
// Return the type that is doing the implementing.
auto impl_type() const -> Nonnull<Expression*> { return impl_type_; }
// Return the interface that is being implemented.
auto interface() const -> const Expression& { return *interface_; }
auto interface() -> Expression& { return *interface_; }
void set_interface_type(Nonnull<const Value*> iface_type) {
interface_type_ = iface_type;
}
auto interface_type() const -> Nonnull<const Value*> {
return *interface_type_;
}
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:
ImplKind kind_;
Nonnull<Expression*> impl_type_; // TODO: make this optional
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.
auto GetName(const Declaration&) -> std::optional<std::string>;

} // namespace Carbon

#endif // EXECUTABLE_SEMANTICS_AST_DECLARATION_H_
Loading

0 comments on commit 7cce1bd

Please sign in to comment.