Use resolved names in typechecker (#974)

As a byproduct, replace NamedEntity with a type-erasing wrapper NamedEntityView, eliminate virtual inheritance from the AST, and eliminate interfaces from gen_rtti.
This commit is contained in:
Geoff Romer
2021-12-13 16:35:30 -08:00
committed by GitHub
parent fd45b089e9
commit 8e6c209a28
14 changed files with 208 additions and 240 deletions
+1
View File
@@ -93,6 +93,7 @@ cc_library(
deps = [
":ast_node",
":paren_contents",
":static_scope",
"//common:indirect_value",
"//common:ostream",
"//executable_semantics/common:arena",
-38
View File
@@ -35,8 +35,6 @@ namespace Carbon {
// The definitions of `InheritsFromFoo` and `FooKind` are generated from
// ast_rtti.txt, and are implicitly provided by this header.
//
// When inheriting from this class, the inheritance must me marked `virtual`.
//
// TODO: To support generic traversal, add children() method, and ensure that
// all AstNodes are reachable from a root AstNode.
class AstNode {
@@ -75,40 +73,4 @@ class AstNode {
} // namespace Carbon
// Ensure that LLVM casts from AstNode use dynamic_cast, because static_cast
// doesn't work with a virtual base class.
namespace llvm {
template <typename To>
struct cast_convert_val<To, const Carbon::AstNode*, const Carbon::AstNode*> {
using ResultType = typename cast_retty<To, const Carbon::AstNode*>::ret_type;
static auto doit(const Carbon::AstNode* node) -> ResultType {
return dynamic_cast<ResultType>(node);
}
};
template <typename To>
struct cast_convert_val<To, Carbon::AstNode*, Carbon::AstNode*> {
using ResultType = typename cast_retty<To, Carbon::AstNode*>::ret_type;
static auto doit(Carbon::AstNode* node) -> ResultType {
return dynamic_cast<ResultType>(node);
}
};
template <typename To>
struct cast_convert_val<To, const Carbon::AstNode, const Carbon::AstNode> {
using ResultType = typename cast_retty<To, const Carbon::AstNode>::ret_type;
static auto doit(const Carbon::AstNode& node) -> ResultType {
return dynamic_cast<ResultType>(node);
}
};
template <typename To>
struct cast_convert_val<To, Carbon::AstNode, Carbon::AstNode> {
using ResultType = typename cast_retty<To, Carbon::AstNode>::ret_type;
static auto doit(Carbon::AstNode& node) -> ResultType {
return dynamic_cast<ResultType>(node);
}
};
} // namespace llvm
#endif // EXECUTABLE_SEMANTICS_AST_AST_NODE_H_
+6 -7
View File
@@ -3,19 +3,18 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
root class AstNode;
interface class NamedEntity : AstNode;
abstract class Pattern : AstNode;
class AutoPattern : Pattern;
class BindingPattern : Pattern, NamedEntity;
class BindingPattern : Pattern;
class TuplePattern : Pattern;
class AlternativePattern : Pattern;
class ExpressionPattern : Pattern;
abstract class Declaration : AstNode;
class FunctionDeclaration : Declaration, NamedEntity;
class ClassDeclaration : Declaration, NamedEntity;
class ChoiceDeclaration : Declaration, NamedEntity;
class FunctionDeclaration : Declaration;
class ClassDeclaration : Declaration;
class ChoiceDeclaration : Declaration;
class VariableDeclaration : Declaration;
class GenericBinding : AstNode, NamedEntity;
class GenericBinding : AstNode;
class AlternativeSignature : AstNode;
abstract class Statement : AstNode;
class ExpressionStatement : Statement;
@@ -28,7 +27,7 @@ abstract class Statement : AstNode;
class Break : Statement;
class Continue : Statement;
class Match : Statement;
class Continuation : Statement, NamedEntity;
class Continuation : Statement;
class Run : Statement;
class Await : Statement;
abstract class Expression : AstNode;
+20 -11
View File
@@ -29,7 +29,7 @@ namespace Carbon {
// every concrete derived class must have a corresponding enumerator
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
// details.
class Declaration : public virtual AstNode {
class Declaration : public AstNode {
public:
~Declaration() override = 0;
@@ -65,7 +65,8 @@ class Declaration : public virtual AstNode {
// Constructs a Declaration representing syntax at the given line number.
// `kind` must be the enumerator corresponding to the most-derived type being
// constructed.
Declaration() = default;
Declaration(AstNodeKind kind, SourceLocation source_loc)
: AstNode(kind, source_loc) {}
private:
std::optional<Nonnull<const Value*>> static_type_;
@@ -73,8 +74,10 @@ class Declaration : public virtual AstNode {
// TODO: expand the kinds of things that can be deduced parameters.
// For now, only generic parameters are supported.
struct GenericBinding : public virtual AstNode, public NamedEntity {
class GenericBinding : public AstNode {
public:
using ImplementsCarbonNamedEntity = void;
GenericBinding(SourceLocation source_loc, std::string name,
Nonnull<Expression*> type)
: AstNode(AstNodeKind::GenericBinding, source_loc),
@@ -188,14 +191,16 @@ class ReturnTerm {
SourceLocation source_loc_;
};
class FunctionDeclaration : public Declaration, public NamedEntity {
class FunctionDeclaration : public Declaration {
public:
using ImplementsCarbonNamedEntity = void;
FunctionDeclaration(SourceLocation source_loc, std::string name,
std::vector<Nonnull<GenericBinding*>> deduced_params,
Nonnull<TuplePattern*> param_pattern,
ReturnTerm return_term,
std::optional<Nonnull<Block*>> body)
: AstNode(AstNodeKind::FunctionDeclaration, source_loc),
: Declaration(AstNodeKind::FunctionDeclaration, source_loc),
name_(std::move(name)),
deduced_parameters_(std::move(deduced_params)),
param_pattern_(param_pattern),
@@ -231,11 +236,13 @@ class FunctionDeclaration : public Declaration, public NamedEntity {
std::optional<Nonnull<Block*>> body_;
};
class ClassDeclaration : public Declaration, public NamedEntity {
class ClassDeclaration : public Declaration {
public:
using ImplementsCarbonNamedEntity = void;
ClassDeclaration(SourceLocation source_loc, std::string name,
std::vector<Nonnull<Member*>> members)
: AstNode(AstNodeKind::ClassDeclaration, source_loc),
: Declaration(AstNodeKind::ClassDeclaration, source_loc),
name_(std::move(name)),
members_(std::move(members)) {}
@@ -251,7 +258,7 @@ class ClassDeclaration : public Declaration, public NamedEntity {
std::vector<Nonnull<Member*>> members_;
};
class AlternativeSignature : public virtual AstNode {
class AlternativeSignature : public AstNode {
public:
AlternativeSignature(SourceLocation source_loc, std::string name,
Nonnull<Expression*> signature)
@@ -274,11 +281,13 @@ class AlternativeSignature : public virtual AstNode {
Nonnull<Expression*> signature_;
};
class ChoiceDeclaration : public Declaration, public NamedEntity {
class ChoiceDeclaration : public Declaration {
public:
using ImplementsCarbonNamedEntity = void;
ChoiceDeclaration(SourceLocation source_loc, std::string name,
std::vector<Nonnull<AlternativeSignature*>> alternatives)
: AstNode(AstNodeKind::ChoiceDeclaration, source_loc),
: Declaration(AstNodeKind::ChoiceDeclaration, source_loc),
name_(std::move(name)),
alternatives_(std::move(alternatives)) {}
@@ -306,7 +315,7 @@ class VariableDeclaration : public Declaration {
VariableDeclaration(SourceLocation source_loc,
Nonnull<BindingPattern*> binding,
Nonnull<Expression*> initializer)
: AstNode(AstNodeKind::VariableDeclaration, source_loc),
: Declaration(AstNodeKind::VariableDeclaration, source_loc),
binding_(binding),
initializer_(initializer) {}
+30 -28
View File
@@ -14,6 +14,7 @@
#include "executable_semantics/ast/ast_node.h"
#include "executable_semantics/ast/paren_contents.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/ast/static_scope.h"
#include "executable_semantics/common/arena.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
@@ -21,9 +22,8 @@
namespace Carbon {
class Value;
class NamedEntity;
class Expression : public virtual AstNode {
class Expression : public AstNode {
public:
// The value category of a Carbon expression indicates whether it evaluates
// to a variable or a value. A variable can be mutated, and can have its
@@ -76,7 +76,8 @@ class Expression : public virtual AstNode {
// Constructs an Expression representing syntax at the given line number.
// `kind` must be the enumerator corresponding to the most-derived type being
// constructed.
Expression() = default;
Expression(AstNodeKind kind, SourceLocation source_loc)
: AstNode(kind, source_loc) {}
private:
std::optional<Nonnull<const Value*>> static_type_;
@@ -121,7 +122,7 @@ auto ToString(Operator op) -> std::string_view;
class IdentifierExpression : public Expression {
public:
explicit IdentifierExpression(SourceLocation source_loc, std::string name)
: AstNode(AstNodeKind::IdentifierExpression, source_loc),
: Expression(AstNodeKind::IdentifierExpression, source_loc),
name_(std::move(name)) {}
static auto classof(const AstNode* node) -> bool {
@@ -130,15 +131,15 @@ class IdentifierExpression : public Expression {
auto name() const -> const std::string& { return name_; }
// Returns the NamedEntity this identifier refers to. Cannot be called before
// name resolution.
auto named_entity() const -> const NamedEntity& { return **named_entity_; }
// Returns the NamedEntityView this identifier refers to. Cannot be called
// before name resolution.
auto named_entity() const -> const NamedEntityView& { return *named_entity_; }
// Sets the value returned by named_entity. Can be called only once,
// during name resolution.
void set_named_entity(Nonnull<const NamedEntity*> named_entity) {
void set_named_entity(NamedEntityView named_entity) {
CHECK(!named_entity_.has_value());
named_entity_ = named_entity;
named_entity_ = std::move(named_entity);
}
// Returns true if set_named_entity has been called. Should be used only
@@ -148,7 +149,7 @@ class IdentifierExpression : public Expression {
private:
std::string name_;
std::optional<Nonnull<const NamedEntity*>> named_entity_;
std::optional<NamedEntityView> named_entity_;
};
class FieldAccessExpression : public Expression {
@@ -156,7 +157,7 @@ class FieldAccessExpression : public Expression {
explicit FieldAccessExpression(SourceLocation source_loc,
Nonnull<Expression*> aggregate,
std::string field)
: AstNode(AstNodeKind::FieldAccessExpression, source_loc),
: Expression(AstNodeKind::FieldAccessExpression, source_loc),
aggregate_(aggregate),
field_(std::move(field)) {}
@@ -178,7 +179,7 @@ class IndexExpression : public Expression {
explicit IndexExpression(SourceLocation source_loc,
Nonnull<Expression*> aggregate,
Nonnull<Expression*> offset)
: AstNode(AstNodeKind::IndexExpression, source_loc),
: Expression(AstNodeKind::IndexExpression, source_loc),
aggregate_(aggregate),
offset_(offset) {}
@@ -199,7 +200,7 @@ class IndexExpression : public Expression {
class IntLiteral : public Expression {
public:
explicit IntLiteral(SourceLocation source_loc, int value)
: AstNode(AstNodeKind::IntLiteral, source_loc), value_(value) {}
: Expression(AstNodeKind::IntLiteral, source_loc), value_(value) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromIntLiteral(node->kind());
@@ -214,7 +215,7 @@ class IntLiteral : public Expression {
class BoolLiteral : public Expression {
public:
explicit BoolLiteral(SourceLocation source_loc, bool value)
: AstNode(AstNodeKind::BoolLiteral, source_loc), value_(value) {}
: Expression(AstNodeKind::BoolLiteral, source_loc), value_(value) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromBoolLiteral(node->kind());
@@ -229,7 +230,7 @@ class BoolLiteral : public Expression {
class StringLiteral : public Expression {
public:
explicit StringLiteral(SourceLocation source_loc, std::string value)
: AstNode(AstNodeKind::StringLiteral, source_loc),
: Expression(AstNodeKind::StringLiteral, source_loc),
value_(std::move(value)) {}
static auto classof(const AstNode* node) -> bool {
@@ -245,7 +246,7 @@ class StringLiteral : public Expression {
class StringTypeLiteral : public Expression {
public:
explicit StringTypeLiteral(SourceLocation source_loc)
: AstNode(AstNodeKind::StringTypeLiteral, source_loc) {}
: Expression(AstNodeKind::StringTypeLiteral, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromStringTypeLiteral(node->kind());
@@ -259,7 +260,7 @@ class TupleLiteral : public Expression {
explicit TupleLiteral(SourceLocation source_loc,
std::vector<Nonnull<Expression*>> fields)
: AstNode(AstNodeKind::TupleLiteral, source_loc),
: Expression(AstNodeKind::TupleLiteral, source_loc),
fields_(std::move(fields)) {}
static auto classof(const AstNode* node) -> bool {
@@ -285,7 +286,8 @@ class StructLiteral : public Expression {
public:
explicit StructLiteral(SourceLocation loc,
std::vector<FieldInitializer> fields)
: AstNode(AstNodeKind::StructLiteral, loc), fields_(std::move(fields)) {
: Expression(AstNodeKind::StructLiteral, loc),
fields_(std::move(fields)) {
CHECK(!fields_.empty())
<< "`{}` is represented as a StructTypeLiteral, not a StructLiteral.";
}
@@ -311,7 +313,7 @@ class StructTypeLiteral : public Expression {
explicit StructTypeLiteral(SourceLocation loc,
std::vector<FieldInitializer> fields)
: AstNode(AstNodeKind::StructTypeLiteral, loc),
: Expression(AstNodeKind::StructTypeLiteral, loc),
fields_(std::move(fields)) {}
static auto classof(const AstNode* node) -> bool {
@@ -330,7 +332,7 @@ class PrimitiveOperatorExpression : public Expression {
explicit PrimitiveOperatorExpression(
SourceLocation source_loc, Operator op,
std::vector<Nonnull<Expression*>> arguments)
: AstNode(AstNodeKind::PrimitiveOperatorExpression, source_loc),
: Expression(AstNodeKind::PrimitiveOperatorExpression, source_loc),
op_(op),
arguments_(std::move(arguments)) {}
@@ -356,7 +358,7 @@ class CallExpression : public Expression {
explicit CallExpression(SourceLocation source_loc,
Nonnull<Expression*> function,
Nonnull<Expression*> argument)
: AstNode(AstNodeKind::CallExpression, source_loc),
: Expression(AstNodeKind::CallExpression, source_loc),
function_(function),
argument_(argument) {}
@@ -379,7 +381,7 @@ class FunctionTypeLiteral : public Expression {
explicit FunctionTypeLiteral(SourceLocation source_loc,
Nonnull<Expression*> parameter,
Nonnull<Expression*> return_type)
: AstNode(AstNodeKind::FunctionTypeLiteral, source_loc),
: Expression(AstNodeKind::FunctionTypeLiteral, source_loc),
parameter_(parameter),
return_type_(return_type) {}
@@ -400,7 +402,7 @@ class FunctionTypeLiteral : public Expression {
class BoolTypeLiteral : public Expression {
public:
explicit BoolTypeLiteral(SourceLocation source_loc)
: AstNode(AstNodeKind::BoolTypeLiteral, source_loc) {}
: Expression(AstNodeKind::BoolTypeLiteral, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromBoolTypeLiteral(node->kind());
@@ -410,7 +412,7 @@ class BoolTypeLiteral : public Expression {
class IntTypeLiteral : public Expression {
public:
explicit IntTypeLiteral(SourceLocation source_loc)
: AstNode(AstNodeKind::IntTypeLiteral, source_loc) {}
: Expression(AstNodeKind::IntTypeLiteral, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromIntTypeLiteral(node->kind());
@@ -420,7 +422,7 @@ class IntTypeLiteral : public Expression {
class ContinuationTypeLiteral : public Expression {
public:
explicit ContinuationTypeLiteral(SourceLocation source_loc)
: AstNode(AstNodeKind::ContinuationTypeLiteral, source_loc) {}
: Expression(AstNodeKind::ContinuationTypeLiteral, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromContinuationTypeLiteral(node->kind());
@@ -430,7 +432,7 @@ class ContinuationTypeLiteral : public Expression {
class TypeTypeLiteral : public Expression {
public:
explicit TypeTypeLiteral(SourceLocation source_loc)
: AstNode(AstNodeKind::TypeTypeLiteral, source_loc) {}
: Expression(AstNodeKind::TypeTypeLiteral, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromTypeTypeLiteral(node->kind());
@@ -446,7 +448,7 @@ class IntrinsicExpression : public Expression {
explicit IntrinsicExpression(std::string_view intrinsic_name,
Nonnull<TupleLiteral*> args,
SourceLocation source_loc)
: AstNode(AstNodeKind::IntrinsicExpression, source_loc),
: Expression(AstNodeKind::IntrinsicExpression, source_loc),
intrinsic_(FindIntrinsic(intrinsic_name, source_loc)),
args_(args) {}
@@ -480,7 +482,7 @@ class UnimplementedExpression : public Expression {
template <typename... Children>
UnimplementedExpression(SourceLocation source_loc, std::string label,
Children... children)
: AstNode(AstNodeKind::UnimplementedExpression, source_loc),
: Expression(AstNodeKind::UnimplementedExpression, source_loc),
label_(std::move(label)) {
AddChildren(children...);
}
+4 -3
View File
@@ -23,7 +23,7 @@ namespace Carbon {
// every concrete derived class must have a corresponding enumerator
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
// details.
class Member : public virtual AstNode {
class Member : public AstNode {
public:
~Member() override = 0;
@@ -43,13 +43,14 @@ class Member : public virtual AstNode {
}
protected:
Member() = default;
Member(AstNodeKind kind, SourceLocation source_loc)
: AstNode(kind, source_loc) {}
};
class FieldMember : public Member {
public:
FieldMember(SourceLocation source_loc, Nonnull<BindingPattern*> binding)
: AstNode(AstNodeKind::FieldMember, source_loc), binding_(binding) {}
: Member(AstNodeKind::FieldMember, source_loc), binding_(binding) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromFieldMember(node->kind());
+1 -1
View File
@@ -89,7 +89,7 @@ static auto RequireFieldAccess(Nonnull<Expression*> alternative)
AlternativePattern::AlternativePattern(SourceLocation source_loc,
Nonnull<Expression*> alternative,
Nonnull<TuplePattern*> arguments)
: AstNode(AstNodeKind::AlternativePattern, source_loc),
: Pattern(AstNodeKind::AlternativePattern, source_loc),
choice_type_(&RequireFieldAccess(alternative).aggregate()),
alternative_name_(RequireFieldAccess(alternative).field()),
arguments_(arguments) {}
+11 -8
View File
@@ -29,7 +29,7 @@ class Value;
// every concrete derived class must have a corresponding enumerator
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
// details.
class Pattern : public virtual AstNode {
class Pattern : public AstNode {
public:
Pattern(const Pattern&) = delete;
auto operator=(const Pattern&) -> Pattern& = delete;
@@ -76,7 +76,8 @@ class Pattern : public virtual AstNode {
// Constructs a Pattern representing syntax at the given line number.
// `kind` must be the enumerator corresponding to the most-derived type being
// constructed.
Pattern() = default;
Pattern(AstNodeKind kind, SourceLocation source_loc)
: AstNode(kind, source_loc) {}
private:
std::optional<Nonnull<const Value*>> static_type_;
@@ -87,7 +88,7 @@ class Pattern : public virtual AstNode {
class AutoPattern : public Pattern {
public:
explicit AutoPattern(SourceLocation source_loc)
: AstNode(AstNodeKind::AutoPattern, source_loc) {}
: Pattern(AstNodeKind::AutoPattern, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromAutoPattern(node->kind());
@@ -96,11 +97,13 @@ class AutoPattern : public Pattern {
// A pattern that matches a value of a specified type, and optionally binds
// a name to it.
class BindingPattern : public Pattern, public NamedEntity {
class BindingPattern : public Pattern {
public:
using ImplementsCarbonNamedEntity = void;
BindingPattern(SourceLocation source_loc, std::optional<std::string> name,
Nonnull<Pattern*> type)
: AstNode(AstNodeKind::BindingPattern, source_loc),
: Pattern(AstNodeKind::BindingPattern, source_loc),
name_(std::move(name)),
type_(type) {}
@@ -124,7 +127,7 @@ class BindingPattern : public Pattern, public NamedEntity {
class TuplePattern : public Pattern {
public:
TuplePattern(SourceLocation source_loc, std::vector<Nonnull<Pattern*>> fields)
: AstNode(AstNodeKind::TuplePattern, source_loc),
: Pattern(AstNodeKind::TuplePattern, source_loc),
fields_(std::move(fields)) {}
static auto classof(const AstNode* node) -> bool {
@@ -170,7 +173,7 @@ class AlternativePattern : public Pattern {
Nonnull<Expression*> choice_type,
std::string alternative_name,
Nonnull<TuplePattern*> arguments)
: AstNode(AstNodeKind::AlternativePattern, source_loc),
: Pattern(AstNodeKind::AlternativePattern, source_loc),
choice_type_(choice_type),
alternative_name_(std::move(alternative_name)),
arguments_(arguments) {}
@@ -204,7 +207,7 @@ class AlternativePattern : public Pattern {
class ExpressionPattern : public Pattern {
public:
explicit ExpressionPattern(Nonnull<Expression*> expression)
: AstNode(AstNodeKind::ExpressionPattern, expression->source_loc()),
: Pattern(AstNodeKind::ExpressionPattern, expression->source_loc()),
expression_(expression) {}
static auto classof(const AstNode* node) -> bool {
+19 -16
View File
@@ -21,7 +21,7 @@ namespace Carbon {
class FunctionDeclaration;
class Statement : public virtual AstNode {
class Statement : public AstNode {
public:
~Statement() override = 0;
@@ -39,13 +39,14 @@ class Statement : public virtual AstNode {
}
protected:
Statement() = default;
Statement(AstNodeKind kind, SourceLocation source_loc)
: AstNode(kind, source_loc) {}
};
class Block : public Statement {
public:
Block(SourceLocation source_loc, std::vector<Nonnull<Statement*>> statements)
: AstNode(AstNodeKind::Block, source_loc),
: Statement(AstNodeKind::Block, source_loc),
statements_(std::move(statements)) {}
static auto classof(const AstNode* node) -> bool {
@@ -67,7 +68,7 @@ class ExpressionStatement : public Statement {
public:
ExpressionStatement(SourceLocation source_loc,
Nonnull<Expression*> expression)
: AstNode(AstNodeKind::ExpressionStatement, source_loc),
: Statement(AstNodeKind::ExpressionStatement, source_loc),
expression_(expression) {}
static auto classof(const AstNode* node) -> bool {
@@ -85,7 +86,7 @@ class Assign : public Statement {
public:
Assign(SourceLocation source_loc, Nonnull<Expression*> lhs,
Nonnull<Expression*> rhs)
: AstNode(AstNodeKind::Assign, source_loc), lhs_(lhs), rhs_(rhs) {}
: Statement(AstNodeKind::Assign, source_loc), lhs_(lhs), rhs_(rhs) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromAssign(node->kind());
@@ -105,7 +106,7 @@ class VariableDefinition : public Statement {
public:
VariableDefinition(SourceLocation source_loc, Nonnull<Pattern*> pattern,
Nonnull<Expression*> init)
: AstNode(AstNodeKind::VariableDefinition, source_loc),
: Statement(AstNodeKind::VariableDefinition, source_loc),
pattern_(pattern),
init_(init) {}
@@ -127,7 +128,7 @@ class If : public Statement {
public:
If(SourceLocation source_loc, Nonnull<Expression*> condition,
Nonnull<Block*> then_block, std::optional<Nonnull<Block*>> else_block)
: AstNode(AstNodeKind::If, source_loc),
: Statement(AstNodeKind::If, source_loc),
condition_(condition),
then_block_(then_block),
else_block_(else_block) {}
@@ -157,7 +158,7 @@ class Return : public Statement {
: Return(source_loc, arena->New<TupleLiteral>(source_loc), true) {}
Return(SourceLocation source_loc, Nonnull<Expression*> expression,
bool is_omitted_expression)
: AstNode(AstNodeKind::Return, source_loc),
: Statement(AstNodeKind::Return, source_loc),
expression_(expression),
is_omitted_expression_(is_omitted_expression) {}
@@ -194,7 +195,7 @@ class While : public Statement {
public:
While(SourceLocation source_loc, Nonnull<Expression*> condition,
Nonnull<Block*> body)
: AstNode(AstNodeKind::While, source_loc),
: Statement(AstNodeKind::While, source_loc),
condition_(condition),
body_(body) {}
@@ -215,7 +216,7 @@ class While : public Statement {
class Break : public Statement {
public:
explicit Break(SourceLocation source_loc)
: AstNode(AstNodeKind::Break, source_loc) {}
: Statement(AstNodeKind::Break, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromBreak(node->kind());
@@ -242,7 +243,7 @@ class Break : public Statement {
class Continue : public Statement {
public:
explicit Continue(SourceLocation source_loc)
: AstNode(AstNodeKind::Continue, source_loc) {}
: Statement(AstNodeKind::Continue, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromContinue(node->kind());
@@ -285,7 +286,7 @@ class Match : public Statement {
Match(SourceLocation source_loc, Nonnull<Expression*> expression,
std::vector<Clause> clauses)
: AstNode(AstNodeKind::Match, source_loc),
: Statement(AstNodeKind::Match, source_loc),
expression_(expression),
clauses_(std::move(clauses)) {}
@@ -308,11 +309,13 @@ class Match : public Statement {
// __continuation <continuation_variable> {
// <body>
// }
class Continuation : public Statement, public NamedEntity {
class Continuation : public Statement {
public:
using ImplementsCarbonNamedEntity = void;
Continuation(SourceLocation source_loc, std::string continuation_variable,
Nonnull<Block*> body)
: AstNode(AstNodeKind::Continuation, source_loc),
: Statement(AstNodeKind::Continuation, source_loc),
continuation_variable_(std::move(continuation_variable)),
body_(body) {}
@@ -353,7 +356,7 @@ class Continuation : public Statement, public NamedEntity {
class Run : public Statement {
public:
Run(SourceLocation source_loc, Nonnull<Expression*> argument)
: AstNode(AstNodeKind::Run, source_loc), argument_(argument) {}
: Statement(AstNodeKind::Run, source_loc), argument_(argument) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromRun(node->kind());
@@ -372,7 +375,7 @@ class Run : public Statement {
class Await : public Statement {
public:
explicit Await(SourceLocation source_loc)
: AstNode(AstNodeKind::Await, source_loc) {}
: Statement(AstNodeKind::Await, source_loc) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromAwait(node->kind());
+10 -13
View File
@@ -8,22 +8,18 @@
namespace Carbon {
NamedEntity::~NamedEntity() = default;
void StaticScope::Add(std::string name, Nonnull<const NamedEntity*> entity) {
void StaticScope::Add(std::string name, NamedEntityView entity) {
auto [it, success] = declared_names_.insert({name, entity});
if (!success && it->second != entity) {
FATAL_COMPILATION_ERROR(entity->source_loc())
FATAL_COMPILATION_ERROR(entity.base().source_loc())
<< "Duplicate name `" << name << "` also found at "
<< it->second->source_loc();
<< it->second.base().source_loc();
}
}
auto StaticScope::Resolve(const std::string& name,
SourceLocation source_loc) const
-> Nonnull<const NamedEntity*> {
std::optional<Nonnull<const NamedEntity*>> result =
TryResolve(name, source_loc);
SourceLocation source_loc) const -> NamedEntityView {
std::optional<NamedEntityView> result = TryResolve(name, source_loc);
if (!result.has_value()) {
FATAL_COMPILATION_ERROR(source_loc) << "could not resolve '" << name << "'";
}
@@ -32,19 +28,20 @@ auto StaticScope::Resolve(const std::string& name,
auto StaticScope::TryResolve(const std::string& name,
SourceLocation source_loc) const
-> std::optional<Nonnull<const NamedEntity*>> {
-> std::optional<NamedEntityView> {
auto it = declared_names_.find(name);
if (it != declared_names_.end()) {
return it->second;
}
std::optional<Nonnull<const NamedEntity*>> result;
std::optional<NamedEntityView> result;
for (Nonnull<const StaticScope*> parent : parent_scopes_) {
auto parent_result = parent->TryResolve(name, source_loc);
if (parent_result.has_value() && result.has_value() &&
*parent_result != *result) {
FATAL_COMPILATION_ERROR(source_loc)
<< "'" << name << "' is ambiguous between " << (*result)->source_loc()
<< " and " << (*parent_result)->source_loc();
<< "'" << name << "' is ambiguous between "
<< result->base().source_loc() << " and "
<< parent_result->base().source_loc();
}
result = parent_result;
}
+56 -10
View File
@@ -5,6 +5,7 @@
#ifndef EXECUTABLE_SEMANTICS_AST_STATIC_SCOPE_H_
#define EXECUTABLE_SEMANTICS_AST_STATIC_SCOPE_H_
#include <functional>
#include <string>
#include <unordered_map>
#include <variant>
@@ -16,16 +17,61 @@
namespace Carbon {
class NamedEntity : public virtual AstNode {
class Value;
// True if NodeType::ImplementsCarbonNamedEntity is valid and names a type,
// indicating that NodeType implements the NamedEntity interface. This imposes
// the following requirements on NodeType, where `node` is a const instance of
// NodeType:
//
// - NodeType is derived from AstNode.
// - node.static_type() is well-formed and has type const Value&.
template <typename T, typename = void>
static constexpr bool ImplementsNamedEntity = false;
template <typename T>
static constexpr bool
ImplementsNamedEntity<T, typename T::ImplementsCarbonNamedEntity> = true;
// Non-owning type-erased wrapper around a const NodeType* `node`, where
// NodeType implements the NamedEntity interface.
class NamedEntityView {
public:
~NamedEntity() override = 0;
template <typename NodeType,
typename = std::enable_if_t<ImplementsNamedEntity<NodeType>>>
// NOLINTNEXTLINE(google-explicit-constructor)
NamedEntityView(Nonnull<const NodeType*> node)
// Type-erase NodeType, retaining a pointer to the base class AstNode
// and using std::function to encapsulate the ability to call
// the derived class's static_type.
: base_(node), static_type_([](const AstNode& base) -> const Value& {
return llvm::cast<NodeType>(base).static_type();
}) {}
NamedEntity() = default;
NamedEntityView(const NamedEntityView&) = default;
NamedEntityView(NamedEntityView&&) = default;
auto operator=(const NamedEntityView&) -> NamedEntityView& = default;
auto operator=(NamedEntityView&&) -> NamedEntityView& = default;
// TODO: This is unused, but is intended for casts after lookup.
auto kind() const -> NamedEntityKind {
return static_cast<NamedEntityKind>(root_kind());
// Returns `node` as an instance of the base class AstNode.
auto base() const -> const AstNode& { return *base_; }
// Returns node->static_type()
auto static_type() const -> const Value& { return static_type_(*base_); }
friend auto operator==(const NamedEntityView& lhs,
const NamedEntityView& rhs) {
return lhs.base_ == rhs.base_;
}
friend auto operator!=(const NamedEntityView& lhs,
const NamedEntityView& rhs) {
return lhs.base_ != rhs.base_;
}
private:
Nonnull<const AstNode*> base_;
std::function<const Value&(const AstNode&)> static_type_;
};
// Maps the names visible in a given scope to the entities they name.
@@ -35,7 +81,7 @@ class StaticScope {
public:
// Defines `name` to be `entity` in this scope, or reports a compilation error
// if `name` is already defined to be a different entity in this scope.
void Add(std::string name, Nonnull<const NamedEntity*> entity);
void Add(std::string name, NamedEntityView entity);
// Make `parent` a parent of this scope.
// REQUIRES: `parent` is not already a parent of this scope.
@@ -47,17 +93,17 @@ class StaticScope {
// scope, or reports a compilation error at `source_loc` there isn't exactly
// one such definition.
auto Resolve(const std::string& name, SourceLocation source_loc) const
-> Nonnull<const NamedEntity*>;
-> NamedEntityView;
private:
// Equivalent to Resolve, but returns `nullopt` instead of raising an error
// if no definition can be found. Still raises a compilation error if more
// than one definition is found.
auto TryResolve(const std::string& name, SourceLocation source_loc) const
-> std::optional<Nonnull<const NamedEntity*>>;
-> std::optional<NamedEntityView>;
// Maps locally declared names to their entities.
std::unordered_map<std::string, Nonnull<const NamedEntity*>> declared_names_;
std::unordered_map<std::string, NamedEntityView> declared_names_;
// A list of scopes used for name lookup within this scope.
std::vector<Nonnull<StaticScope*>> parent_scopes_;