mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Track a resolved Member on each member access expression. (#1333)
Type checking now stores information on a member access identifying the member that was accessed, not only its name. This parallels what we do for other similar constructs whose meaning is resolved by name lookup or type-checking, and will allow us to avoid redoing lookups in some cases during interpretation.
This commit is contained in:
@@ -9,6 +9,7 @@ cc_library(
|
||||
hdrs = ["ast.h"],
|
||||
deps = [
|
||||
":declaration",
|
||||
":member_impl",
|
||||
":library_name",
|
||||
"//explorer/common:nonnull",
|
||||
],
|
||||
@@ -109,6 +110,30 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "member",
|
||||
hdrs = [
|
||||
"member.h",
|
||||
],
|
||||
deps = [
|
||||
"//explorer/common:nonnull",
|
||||
"@llvm-project//llvm:Support",
|
||||
],
|
||||
)
|
||||
|
||||
# TODO: This is split out to resolve a cyclic implementation dependency between
|
||||
# this and :declaration. Consider folding all of the "ast" target together.
|
||||
cc_library(
|
||||
name = "member_impl",
|
||||
srcs = ["member.cpp"],
|
||||
deps = [
|
||||
":declaration",
|
||||
":member",
|
||||
"//explorer/common:nonnull",
|
||||
"@llvm-project//llvm:Support",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "return_term",
|
||||
hdrs = ["return_term.h"],
|
||||
@@ -128,6 +153,7 @@ cc_library(
|
||||
hdrs = ["expression.h", "pattern.h"],
|
||||
deps = [
|
||||
":ast_node",
|
||||
":member",
|
||||
":paren_contents",
|
||||
":static_scope",
|
||||
":value_category",
|
||||
|
||||
@@ -143,7 +143,8 @@ void Declaration::PrintID(llvm::raw_ostream& out) const {
|
||||
}
|
||||
}
|
||||
|
||||
auto GetName(const Declaration& declaration) -> std::optional<std::string> {
|
||||
auto GetName(const Declaration& declaration)
|
||||
-> std::optional<std::string_view> {
|
||||
switch (declaration.kind()) {
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
return cast<FunctionDeclaration>(declaration).name();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define CARBON_EXPLORER_AST_DECLARATION_H_
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -174,7 +175,7 @@ class SelfDeclaration : public Declaration {
|
||||
return InheritsFromSelfDeclaration(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string { return "Self"; }
|
||||
static auto name() -> std::string_view { return "Self"; }
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
};
|
||||
|
||||
@@ -437,7 +438,7 @@ class AliasDeclaration : public Declaration {
|
||||
return InheritsFromAliasDeclaration(node->kind());
|
||||
}
|
||||
|
||||
auto name() const -> const std::string { return name_; }
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto target() const -> const Expression& { return *target_; }
|
||||
auto target() -> Expression& { return *target_; }
|
||||
auto value_category() const -> ValueCategory { return ValueCategory::Let; }
|
||||
@@ -448,7 +449,7 @@ class AliasDeclaration : public Declaration {
|
||||
};
|
||||
|
||||
// Return the name of a declaration, if it has one.
|
||||
auto GetName(const Declaration&) -> std::optional<std::string>;
|
||||
auto GetName(const Declaration&) -> std::optional<std::string_view>;
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ void Expression::Print(llvm::raw_ostream& out) const {
|
||||
}
|
||||
case ExpressionKind::SimpleMemberAccessExpression: {
|
||||
const auto& access = cast<SimpleMemberAccessExpression>(*this);
|
||||
out << access.object() << "." << access.member();
|
||||
out << access.object() << "." << access.member_name();
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::CompoundMemberAccessExpression: {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "explorer/ast/ast_node.h"
|
||||
#include "explorer/ast/member.h"
|
||||
#include "explorer/ast/paren_contents.h"
|
||||
#include "explorer/ast/static_scope.h"
|
||||
#include "explorer/ast/value_category.h"
|
||||
@@ -193,10 +194,10 @@ class SimpleMemberAccessExpression : public Expression {
|
||||
public:
|
||||
explicit SimpleMemberAccessExpression(SourceLocation source_loc,
|
||||
Nonnull<Expression*> object,
|
||||
std::string member)
|
||||
std::string member_name)
|
||||
: Expression(AstNodeKind::SimpleMemberAccessExpression, source_loc),
|
||||
object_(object),
|
||||
member_(std::move(member)) {}
|
||||
member_name_(std::move(member_name)) {}
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromSimpleMemberAccessExpression(node->kind());
|
||||
@@ -204,7 +205,20 @@ class SimpleMemberAccessExpression : public Expression {
|
||||
|
||||
auto object() const -> const Expression& { return *object_; }
|
||||
auto object() -> Expression& { return *object_; }
|
||||
auto member() const -> const std::string& { return member_; }
|
||||
auto member_name() const -> const std::string& { return member_name_; }
|
||||
|
||||
// Returns the `Member` that the member name resolved to.
|
||||
// Should not be called before typechecking.
|
||||
auto member() const -> const Member& {
|
||||
CARBON_CHECK(member_.has_value());
|
||||
return *member_;
|
||||
}
|
||||
|
||||
// Can only be called once, during typechecking.
|
||||
void set_member(Member member) {
|
||||
CARBON_CHECK(!member_.has_value());
|
||||
member_ = member;
|
||||
}
|
||||
|
||||
// Returns true if the field is a method that has a "me" declaration in an
|
||||
// AddrPattern.
|
||||
@@ -244,7 +258,8 @@ class SimpleMemberAccessExpression : public Expression {
|
||||
|
||||
private:
|
||||
Nonnull<Expression*> object_;
|
||||
std::string member_;
|
||||
std::string member_name_;
|
||||
std::optional<Member> member_;
|
||||
bool is_field_addr_me_method_ = false;
|
||||
std::optional<Nonnull<const Expression*>> impl_;
|
||||
std::optional<Nonnull<const InterfaceType*>> found_in_interface_;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "explorer/ast/member.h"
|
||||
|
||||
#include "explorer/ast/declaration.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
Member::Member(Nonnull<const Declaration*> declaration)
|
||||
: member_(declaration) {}
|
||||
|
||||
Member::Member(Nonnull<const NamedValue*> struct_member)
|
||||
: member_(struct_member) {}
|
||||
|
||||
auto Member::name() const -> std::string_view {
|
||||
if (const Declaration* decl = member_.dyn_cast<const Declaration*>()) {
|
||||
return GetName(*decl).value();
|
||||
} else {
|
||||
return member_.get<const NamedValue*>()->name;
|
||||
}
|
||||
}
|
||||
|
||||
auto Member::type() const -> const Value& {
|
||||
if (const Declaration* decl = member_.dyn_cast<const Declaration*>()) {
|
||||
return decl->static_type();
|
||||
} else {
|
||||
return *member_.get<const NamedValue*>()->value;
|
||||
}
|
||||
}
|
||||
|
||||
auto Member::declaration() const -> std::optional<Nonnull<const Declaration*>> {
|
||||
if (const Declaration* decl = member_.dyn_cast<const Declaration*>()) {
|
||||
return decl;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
@@ -0,0 +1,51 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef CARBON_EXPLORER_AST_MEMBER_H_
|
||||
#define CARBON_EXPLORER_AST_MEMBER_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "explorer/common/nonnull.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
class Declaration;
|
||||
class Value;
|
||||
|
||||
// A NamedValue represents a value with a name, such as a single struct field.
|
||||
struct NamedValue {
|
||||
// The field name.
|
||||
std::string name;
|
||||
|
||||
// The field's value.
|
||||
Nonnull<const Value*> value;
|
||||
};
|
||||
|
||||
// A member of a type.
|
||||
//
|
||||
// This is either a declared member of a class, interface, or similar, or a
|
||||
// member of a struct with no declaration.
|
||||
class Member {
|
||||
public:
|
||||
explicit Member(Nonnull<const Declaration*> declaration);
|
||||
explicit Member(Nonnull<const NamedValue*> struct_member);
|
||||
|
||||
// The name of the member.
|
||||
auto name() const -> std::string_view;
|
||||
// The declared type of the member, which might include type variables.
|
||||
auto type() const -> const Value&;
|
||||
// A declaration of the member, if any exists.
|
||||
auto declaration() const -> std::optional<Nonnull<const Declaration*>>;
|
||||
|
||||
private:
|
||||
llvm::PointerUnion<Nonnull<const Declaration*>, Nonnull<const NamedValue*>>
|
||||
member_;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // CARBON_EXPLORER_AST_MEMBER_H_
|
||||
@@ -334,7 +334,8 @@ class AlternativePattern : public Pattern {
|
||||
Nonnull<SimpleMemberAccessExpression*> member_access,
|
||||
RequireSimpleMemberAccess(alternative));
|
||||
return arena->New<AlternativePattern>(source_loc, &member_access->object(),
|
||||
member_access->member(), arguments);
|
||||
member_access->member_name(),
|
||||
arguments);
|
||||
}
|
||||
|
||||
// Constructs an AlternativePattern that matches a value of the type
|
||||
|
||||
@@ -113,12 +113,12 @@ static auto ExpressionToProto(const Expression& expression)
|
||||
// The parser rewrites `.Foo` into `.Self.Foo`. Undo this
|
||||
// transformation.
|
||||
auto* designator_proto = expression_proto.mutable_designator();
|
||||
designator_proto->set_name(simple_member_access.member());
|
||||
designator_proto->set_name(simple_member_access.member_name());
|
||||
break;
|
||||
}
|
||||
auto* simple_member_access_proto =
|
||||
expression_proto.mutable_simple_member_access();
|
||||
simple_member_access_proto->set_field(simple_member_access.member());
|
||||
simple_member_access_proto->set_field(simple_member_access.member_name());
|
||||
*simple_member_access_proto->mutable_object() =
|
||||
ExpressionToProto(simple_member_access.object());
|
||||
break;
|
||||
|
||||
@@ -26,6 +26,7 @@ cc_library(
|
||||
"//common:ostream",
|
||||
"//explorer/ast:declaration",
|
||||
"//explorer/ast:expression",
|
||||
"//explorer/ast:member",
|
||||
"//explorer/ast:statement",
|
||||
"//explorer/common:arena",
|
||||
"//explorer/common:error_builders",
|
||||
@@ -90,6 +91,7 @@ cc_library(
|
||||
deps = [
|
||||
"//common:ostream",
|
||||
"//explorer/ast",
|
||||
"//explorer/ast:member",
|
||||
"//explorer/ast:static_scope",
|
||||
"@llvm-project//llvm:Support",
|
||||
],
|
||||
|
||||
@@ -66,9 +66,9 @@ class Address {
|
||||
|
||||
// If *this represents the address of an object with a field named
|
||||
// `field_name`, this method returns the address of that field.
|
||||
auto SubobjectAddress(std::string field_name) const -> Address {
|
||||
auto SubobjectAddress(Member member) const -> Address {
|
||||
Address result = *this;
|
||||
result.field_path_.Append(std::move(field_name));
|
||||
result.field_path_.Append(member);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "explorer/ast/member.h"
|
||||
#include "explorer/ast/static_scope.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
@@ -38,26 +39,27 @@ class FieldPath {
|
||||
// need `witness`, a pointer to the witness table containing that field.
|
||||
class Component {
|
||||
public:
|
||||
explicit Component(std::string name) : name_(std::move(name)) {}
|
||||
Component(std::string name, std::optional<Nonnull<const Witness*>> witness)
|
||||
: name_(std::move(name)), witness_(witness) {}
|
||||
explicit Component(Member member) : member_(member) {}
|
||||
Component(Member member, std::optional<Nonnull<const Witness*>> witness)
|
||||
: member_(member), witness_(witness) {}
|
||||
|
||||
auto name() const -> const std::string& { return name_; }
|
||||
auto member() const -> Member { return member_; }
|
||||
|
||||
auto name() const -> std::string_view { return member_.name(); }
|
||||
|
||||
auto witness() const -> std::optional<Nonnull<const Witness*>> {
|
||||
return witness_;
|
||||
}
|
||||
|
||||
void Print(llvm::raw_ostream& out) const { out << name_; }
|
||||
void Print(llvm::raw_ostream& out) const { out << name(); }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
Member member_;
|
||||
std::optional<Nonnull<const Witness*>> witness_;
|
||||
};
|
||||
|
||||
// Constructs a FieldPath consisting of a single step.
|
||||
explicit FieldPath(std::string name)
|
||||
: components_({Component(std::move(name))}) {}
|
||||
explicit FieldPath(Member member) : components_({Component(member)}) {}
|
||||
explicit FieldPath(const Component& f) : components_({f}) {}
|
||||
|
||||
FieldPath(const FieldPath&) = default;
|
||||
@@ -68,9 +70,9 @@ class FieldPath {
|
||||
// Returns whether *this is empty.
|
||||
auto IsEmpty() const -> bool { return components_.empty(); }
|
||||
|
||||
// Appends `name` to the end of *this.
|
||||
auto Append(std::string name) -> void {
|
||||
components_.push_back(Component(std::move(name)));
|
||||
// Appends `member` to the end of *this.
|
||||
auto Append(Member member) -> void {
|
||||
components_.push_back(Component(member));
|
||||
}
|
||||
|
||||
void Print(llvm::raw_ostream& out) const {
|
||||
|
||||
@@ -352,7 +352,7 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
|
||||
Convert(act.results()[0], *access.member().base_type(),
|
||||
exp.source_loc()));
|
||||
Address object = cast<LValue>(*val).address();
|
||||
Address field = object.SubobjectAddress(access.member().name());
|
||||
Address field = object.SubobjectAddress(access.member().member());
|
||||
return todo_.FinishAction(arena_->New<LValue>(field));
|
||||
}
|
||||
}
|
||||
@@ -370,9 +370,14 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
|
||||
// { v :: [][i] :: C, E, F} :: S, H}
|
||||
// -> { { &v[i] :: C, E, F} :: S, H }
|
||||
Address object = cast<LValue>(*act.results()[0]).address();
|
||||
// TODO: Add support to `Member` for naming tuple fields rather than
|
||||
// pretending we have struct fields with numerical names.
|
||||
std::string f =
|
||||
std::to_string(cast<IntValue>(*act.results()[1]).value());
|
||||
Address field = object.SubobjectAddress(f);
|
||||
auto* tuple_field_as_struct_field =
|
||||
arena_->New<NamedValue>(NamedValue{f, &exp.static_type()});
|
||||
Address field =
|
||||
object.SubobjectAddress(Member(tuple_field_as_struct_field));
|
||||
return todo_.FinishAction(arena_->New<LValue>(field));
|
||||
}
|
||||
}
|
||||
@@ -907,7 +912,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
object, Convert(object, *access.member().base_type(),
|
||||
exp.source_loc()));
|
||||
}
|
||||
FieldPath::Component field(access.member().name(), witness);
|
||||
FieldPath::Component field(access.member().member(), witness);
|
||||
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> member,
|
||||
object->GetMember(arena_, FieldPath(field),
|
||||
exp.source_loc(), object));
|
||||
|
||||
@@ -1434,16 +1434,17 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
switch (object_type.kind()) {
|
||||
case Value::Kind::StructType: {
|
||||
const auto& struct_type = cast<StructType>(object_type);
|
||||
for (const auto& [field_name, field_type] : struct_type.fields()) {
|
||||
if (access.member() == field_name) {
|
||||
access.set_static_type(field_type);
|
||||
for (const auto& field : struct_type.fields()) {
|
||||
if (access.member_name() == field.name) {
|
||||
access.set_member(Member(&field));
|
||||
access.set_static_type(field.value);
|
||||
access.set_value_category(access.object().value_category());
|
||||
return Success();
|
||||
}
|
||||
}
|
||||
return CompilationError(access.source_loc())
|
||||
<< "struct " << struct_type << " does not have a field named "
|
||||
<< access.member();
|
||||
<< access.member_name();
|
||||
}
|
||||
case Value::Kind::TypeType: {
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
@@ -1451,7 +1452,8 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
InterpExp(&access.object(), arena_, trace_stream_));
|
||||
if (const auto* struct_type = dyn_cast<StructType>(type)) {
|
||||
for (const auto& field : struct_type->fields()) {
|
||||
if (access.member() == field.name) {
|
||||
if (access.member_name() == field.name) {
|
||||
access.set_member(Member(&field));
|
||||
access.set_static_type(
|
||||
arena_->New<TypeOfMemberName>(Member(&field)));
|
||||
access.set_value_category(ValueCategory::Let);
|
||||
@@ -1460,7 +1462,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
}
|
||||
return CompilationError(access.source_loc())
|
||||
<< "struct " << *struct_type
|
||||
<< " does not have a field named " << access.member();
|
||||
<< " does not have a field named " << access.member_name();
|
||||
}
|
||||
// TODO: We should handle all types here, not only structs. For
|
||||
// example:
|
||||
@@ -1476,11 +1478,12 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
}
|
||||
case Value::Kind::NominalClassType: {
|
||||
const auto& t_class = cast<NominalClassType>(object_type);
|
||||
if (std::optional<Nonnull<const Declaration*>> member =
|
||||
FindMember(access.member(), t_class.declaration().members());
|
||||
if (std::optional<Nonnull<const Declaration*>> member = FindMember(
|
||||
access.member_name(), t_class.declaration().members());
|
||||
member.has_value()) {
|
||||
Nonnull<const Value*> field_type =
|
||||
Substitute(t_class.type_args(), &(*member)->static_type());
|
||||
access.set_member(Member(member.value()));
|
||||
access.set_static_type(field_type);
|
||||
switch ((*member)->kind()) {
|
||||
case DeclarationKind::VariableDeclaration:
|
||||
@@ -1499,7 +1502,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
&access.object().static_type(), &impl_scope));
|
||||
if (access.object().value_category() != ValueCategory::Var) {
|
||||
return CompilationError(e->source_loc())
|
||||
<< "method " << access.member()
|
||||
<< "method " << access.member_name()
|
||||
<< " requires its receiver to be an lvalue";
|
||||
}
|
||||
}
|
||||
@@ -1507,7 +1510,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CARBON_FATAL() << "member " << access.member()
|
||||
CARBON_FATAL() << "member " << access.member_name()
|
||||
<< " is not a field or method";
|
||||
break;
|
||||
}
|
||||
@@ -1515,21 +1518,27 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
} else {
|
||||
return CompilationError(e->source_loc())
|
||||
<< "class " << t_class.declaration().name()
|
||||
<< " does not have a field named " << access.member();
|
||||
<< " does not have a field named " << access.member_name();
|
||||
}
|
||||
}
|
||||
case Value::Kind::TypeOfChoiceType: {
|
||||
const ChoiceType& choice =
|
||||
cast<TypeOfChoiceType>(object_type).choice_type();
|
||||
std::optional<Nonnull<const Value*>> parameter_types =
|
||||
choice.FindAlternative(access.member());
|
||||
choice.FindAlternative(access.member_name());
|
||||
if (!parameter_types.has_value()) {
|
||||
return CompilationError(e->source_loc())
|
||||
<< "choice " << choice.name()
|
||||
<< " does not have an alternative named " << access.member();
|
||||
<< " does not have an alternative named "
|
||||
<< access.member_name();
|
||||
}
|
||||
access.set_static_type(arena_->New<FunctionType>(
|
||||
*parameter_types, llvm::None, &choice, llvm::None, llvm::None));
|
||||
Nonnull<const Value*> type = arena_->New<FunctionType>(
|
||||
*parameter_types, llvm::None, &choice, llvm::None, llvm::None);
|
||||
// TODO: Should there be a Declaration corresponding to each choice
|
||||
// type alternative?
|
||||
access.set_member(Member(
|
||||
arena_->New<NamedValue>(NamedValue{access.member_name(), type})));
|
||||
access.set_static_type(type);
|
||||
access.set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
@@ -1537,8 +1546,9 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
const NominalClassType& class_type =
|
||||
cast<TypeOfClassType>(object_type).class_type();
|
||||
if (std::optional<Nonnull<const Declaration*>> member = FindMember(
|
||||
access.member(), class_type.declaration().members());
|
||||
access.member_name(), class_type.declaration().members());
|
||||
member.has_value()) {
|
||||
access.set_member(Member(member.value()));
|
||||
switch ((*member)->kind()) {
|
||||
case DeclarationKind::FunctionDeclaration: {
|
||||
const auto& func = cast<FunctionDeclaration>(*member);
|
||||
@@ -1561,7 +1571,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
} else {
|
||||
return CompilationError(access.source_loc())
|
||||
<< class_type << " does not have a member named "
|
||||
<< access.member();
|
||||
<< access.member_name();
|
||||
}
|
||||
}
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
@@ -1574,7 +1584,8 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
}
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
ConstraintLookupResult result,
|
||||
LookupInConstraint(e->source_loc(), type, access.member()));
|
||||
LookupInConstraint(e->source_loc(), type, access.member_name()));
|
||||
access.set_member(Member(result.member));
|
||||
access.set_found_in_interface(result.interface);
|
||||
access.set_static_type(
|
||||
arena_->New<TypeOfMemberName>(Member(result.member)));
|
||||
@@ -1591,13 +1602,14 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
ConstraintLookupResult result,
|
||||
LookupInConstraint(e->source_loc(), &typeof_var,
|
||||
access.member()));
|
||||
access.member_name()));
|
||||
|
||||
const Value& member_type = result.member->static_type();
|
||||
BindingMap binding_map = result.interface->args();
|
||||
binding_map[result.interface->declaration().self()] = &object_type;
|
||||
Nonnull<const Value*> inst_member_type =
|
||||
Substitute(binding_map, &member_type);
|
||||
access.set_member(Member(result.member));
|
||||
access.set_found_in_interface(result.interface);
|
||||
access.set_static_type(inst_member_type);
|
||||
|
||||
@@ -1620,10 +1632,11 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
ConstraintLookupResult result,
|
||||
LookupInConstraint(e->source_loc(), &object_type,
|
||||
access.member()));
|
||||
access.member_name()));
|
||||
CARBON_ASSIGN_OR_RETURN(Nonnull<Expression*> impl,
|
||||
impl_scope.Resolve(result.interface, type,
|
||||
e->source_loc(), *this));
|
||||
access.set_member(Member(result.member));
|
||||
access.set_impl(impl);
|
||||
access.set_found_in_interface(result.interface);
|
||||
|
||||
@@ -3035,7 +3048,7 @@ auto TypeChecker::CheckImplIsComplete(Nonnull<const InterfaceType*> iface_type,
|
||||
-> ErrorOr<Success> {
|
||||
const auto& iface_decl = iface_type->declaration();
|
||||
for (Nonnull<Declaration*> m : iface_decl.members()) {
|
||||
std::optional<std::string> mem_name = GetName(*m);
|
||||
std::optional<std::string_view> mem_name = GetName(*m);
|
||||
CARBON_CHECK(mem_name.has_value()) << "unnamed interface member " << *m;
|
||||
|
||||
std::optional<Nonnull<const Declaration*>> mem =
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Carbon {
|
||||
using llvm::cast;
|
||||
using llvm::dyn_cast;
|
||||
|
||||
auto StructValue::FindField(const std::string& name) const
|
||||
auto StructValue::FindField(std::string_view name) const
|
||||
-> std::optional<Nonnull<const Value*>> {
|
||||
for (const NamedValue& element : elements_) {
|
||||
if (element.name == name) {
|
||||
@@ -33,7 +33,7 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
|
||||
const FieldPath::Component& field,
|
||||
SourceLocation source_loc, Nonnull<const Value*> me_value)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
const std::string& f = field.name();
|
||||
std::string_view f = field.name();
|
||||
|
||||
if (field.witness().has_value()) {
|
||||
Nonnull<const Witness*> witness = cast<Witness>(*field.witness());
|
||||
@@ -185,7 +185,7 @@ static auto SetFieldImpl(
|
||||
std::vector<Nonnull<const Value*>> elements =
|
||||
cast<TupleValue>(*value).elements();
|
||||
// TODO(geoffromer): update FieldPath to hold integers as well as strings.
|
||||
int index = std::stoi((*path_begin).name());
|
||||
int index = std::stoi(std::string((*path_begin).name()));
|
||||
if (index < 0 || static_cast<size_t>(index) >= elements.size()) {
|
||||
return RuntimeError(source_loc) << "index " << (*path_begin).name()
|
||||
<< " out of range in " << *value;
|
||||
@@ -770,9 +770,9 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2) -> bool {
|
||||
case Value::Kind::StringValue:
|
||||
return cast<StringValue>(*v1).value() == cast<StringValue>(*v2).value();
|
||||
case Value::Kind::ParameterizedEntityName: {
|
||||
std::optional<std::string> name1 =
|
||||
std::optional<std::string_view> name1 =
|
||||
GetName(cast<ParameterizedEntityName>(v1)->declaration());
|
||||
std::optional<std::string> name2 =
|
||||
std::optional<std::string_view> name2 =
|
||||
GetName(cast<ParameterizedEntityName>(v2)->declaration());
|
||||
CARBON_CHECK(name1.has_value() && name2.has_value())
|
||||
<< "parameterized name refers to unnamed declaration";
|
||||
@@ -828,7 +828,7 @@ auto ChoiceType::FindAlternative(std::string_view name) const
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto NominalClassType::FindFunction(const std::string& name) const
|
||||
auto NominalClassType::FindFunction(std::string_view name) const
|
||||
-> std::optional<Nonnull<const FunctionValue*>> {
|
||||
for (const auto& member : declaration().members()) {
|
||||
switch (member->kind()) {
|
||||
@@ -846,11 +846,11 @@ auto NominalClassType::FindFunction(const std::string& name) const
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto FindMember(const std::string& name,
|
||||
auto FindMember(std::string_view name,
|
||||
llvm::ArrayRef<Nonnull<Declaration*>> members)
|
||||
-> std::optional<Nonnull<const Declaration*>> {
|
||||
for (Nonnull<const Declaration*> member : members) {
|
||||
if (std::optional<std::string> mem_name = GetName(*member);
|
||||
if (std::optional<std::string_view> mem_name = GetName(*member);
|
||||
mem_name.has_value()) {
|
||||
if (*mem_name == name) {
|
||||
return member;
|
||||
@@ -860,22 +860,6 @@ auto FindMember(const std::string& name,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto Member::name() const -> std::string {
|
||||
if (const Declaration* decl = member_.dyn_cast<const Declaration*>()) {
|
||||
return GetName(*decl).value();
|
||||
} else {
|
||||
return member_.get<const NamedValue*>()->name;
|
||||
}
|
||||
}
|
||||
|
||||
auto Member::type() const -> const Value& {
|
||||
if (const Declaration* decl = member_.dyn_cast<const Declaration*>()) {
|
||||
return decl->static_type();
|
||||
} else {
|
||||
return *member_.get<const NamedValue*>()->value;
|
||||
}
|
||||
}
|
||||
|
||||
void ImplBinding::Print(llvm::raw_ostream& out) const {
|
||||
out << "impl binding " << *type_var_ << " as " << *iface_;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
|
||||
#include "common/ostream.h"
|
||||
#include "explorer/ast/declaration.h"
|
||||
#include "explorer/ast/member.h"
|
||||
#include "explorer/ast/statement.h"
|
||||
#include "explorer/common/nonnull.h"
|
||||
#include "explorer/interpreter/address.h"
|
||||
#include "explorer/interpreter/field_path.h"
|
||||
#include "explorer/interpreter/stack.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace Carbon {
|
||||
@@ -112,15 +112,6 @@ class Value {
|
||||
const Kind kind_;
|
||||
};
|
||||
|
||||
// A NamedValue represents a value with a name, such as a single struct field.
|
||||
struct NamedValue {
|
||||
// The field name.
|
||||
std::string name;
|
||||
|
||||
// The field's value.
|
||||
Nonnull<const Value*> value;
|
||||
};
|
||||
|
||||
// An integer value.
|
||||
class IntValue : public Value {
|
||||
public:
|
||||
@@ -281,7 +272,7 @@ class StructValue : public Value {
|
||||
|
||||
// Returns the value of the field named `name` in this struct, or
|
||||
// nullopt if there is no such field.
|
||||
auto FindField(const std::string& name) const
|
||||
auto FindField(std::string_view name) const
|
||||
-> std::optional<Nonnull<const Value*>>;
|
||||
|
||||
private:
|
||||
@@ -309,7 +300,8 @@ class NominalClassValue : public Value {
|
||||
// An alternative constructor value.
|
||||
class AlternativeConstructorValue : public Value {
|
||||
public:
|
||||
AlternativeConstructorValue(std::string alt_name, std::string choice_name)
|
||||
AlternativeConstructorValue(std::string_view alt_name,
|
||||
std::string_view choice_name)
|
||||
: Value(Kind::AlternativeConstructorValue),
|
||||
alt_name_(std::move(alt_name)),
|
||||
choice_name_(std::move(choice_name)) {}
|
||||
@@ -329,7 +321,7 @@ class AlternativeConstructorValue : public Value {
|
||||
// An alternative value.
|
||||
class AlternativeValue : public Value {
|
||||
public:
|
||||
AlternativeValue(std::string alt_name, std::string choice_name,
|
||||
AlternativeValue(std::string_view alt_name, std::string_view choice_name,
|
||||
Nonnull<const Value*> argument)
|
||||
: Value(Kind::AlternativeValue),
|
||||
alt_name_(std::move(alt_name)),
|
||||
@@ -595,7 +587,7 @@ class NominalClassType : public Value {
|
||||
|
||||
// Returns the value of the function named `name` in this class, or
|
||||
// nullopt if there is no such function.
|
||||
auto FindFunction(const std::string& name) const
|
||||
auto FindFunction(std::string_view name) const
|
||||
-> std::optional<Nonnull<const FunctionValue*>>;
|
||||
|
||||
private:
|
||||
@@ -605,7 +597,7 @@ class NominalClassType : public Value {
|
||||
};
|
||||
|
||||
// Return the declaration of the member with the given name.
|
||||
auto FindMember(const std::string& name,
|
||||
auto FindMember(std::string_view name,
|
||||
llvm::ArrayRef<Nonnull<Declaration*>> members)
|
||||
-> std::optional<Nonnull<const Declaration*>>;
|
||||
|
||||
@@ -855,32 +847,6 @@ class ParameterizedEntityName : public Value {
|
||||
Nonnull<const TuplePattern*> params_;
|
||||
};
|
||||
|
||||
// A member of a type.
|
||||
//
|
||||
// This is either a declared member of a class, interface, or similar, or a
|
||||
// member of a struct with no declaration.
|
||||
class Member {
|
||||
public:
|
||||
explicit Member(const Declaration* declaration) : member_(declaration) {}
|
||||
explicit Member(const NamedValue* struct_member) : member_(struct_member) {}
|
||||
|
||||
// The name of the member.
|
||||
auto name() const -> std::string;
|
||||
// The declared type of the member, which might include type variables.
|
||||
auto type() const -> const Value&;
|
||||
// A declaration of the member, if any exists.
|
||||
auto declaration() const -> std::optional<Nonnull<const Declaration*>> {
|
||||
if (const Declaration* decl = member_.dyn_cast<const Declaration*>()) {
|
||||
return decl;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::PointerUnion<Nonnull<const Declaration*>, Nonnull<const NamedValue*>>
|
||||
member_;
|
||||
};
|
||||
|
||||
// The name of a member of a class or interface.
|
||||
//
|
||||
// These values are used to represent the second operand of a compound member
|
||||
@@ -914,7 +880,7 @@ class MemberName : public Value {
|
||||
// The member.
|
||||
auto member() const -> Member { return member_; }
|
||||
// The name of the member.
|
||||
auto name() const -> std::string { return member().name(); }
|
||||
auto name() const -> std::string_view { return member().name(); }
|
||||
|
||||
private:
|
||||
std::optional<Nonnull<const Value*>> base_type_;
|
||||
|
||||
Reference in New Issue
Block a user