From 17ee3ed9b7cfdf94b00e53197a77cd393d1fd531 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 16 Jun 2022 17:22:31 -0700 Subject: [PATCH] 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. --- explorer/ast/BUILD | 26 +++++++++++++ explorer/ast/declaration.cpp | 3 +- explorer/ast/declaration.h | 7 ++-- explorer/ast/expression.cpp | 2 +- explorer/ast/expression.h | 23 +++++++++-- explorer/ast/member.cpp | 40 +++++++++++++++++++ explorer/ast/member.h | 51 +++++++++++++++++++++++++ explorer/ast/pattern.h | 3 +- explorer/fuzzing/ast_to_proto.cpp | 4 +- explorer/interpreter/BUILD | 2 + explorer/interpreter/address.h | 4 +- explorer/interpreter/field_path.h | 24 ++++++------ explorer/interpreter/interpreter.cpp | 11 ++++-- explorer/interpreter/type_checker.cpp | 55 +++++++++++++++++---------- explorer/interpreter/value.cpp | 32 ++++------------ explorer/interpreter/value.h | 50 ++++-------------------- 16 files changed, 222 insertions(+), 115 deletions(-) create mode 100644 explorer/ast/member.cpp create mode 100644 explorer/ast/member.h diff --git a/explorer/ast/BUILD b/explorer/ast/BUILD index e993178a7535..6d5651fe2d6e 100644 --- a/explorer/ast/BUILD +++ b/explorer/ast/BUILD @@ -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", diff --git a/explorer/ast/declaration.cpp b/explorer/ast/declaration.cpp index f44a25dd5e0f..a52dccaaa077 100644 --- a/explorer/ast/declaration.cpp +++ b/explorer/ast/declaration.cpp @@ -143,7 +143,8 @@ void Declaration::PrintID(llvm::raw_ostream& out) const { } } -auto GetName(const Declaration& declaration) -> std::optional { +auto GetName(const Declaration& declaration) + -> std::optional { switch (declaration.kind()) { case DeclarationKind::FunctionDeclaration: return cast(declaration).name(); diff --git a/explorer/ast/declaration.h b/explorer/ast/declaration.h index d9d1fe923696..3daebee2c505 100644 --- a/explorer/ast/declaration.h +++ b/explorer/ast/declaration.h @@ -6,6 +6,7 @@ #define CARBON_EXPLORER_AST_DECLARATION_H_ #include +#include #include #include @@ -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; +auto GetName(const Declaration&) -> std::optional; } // namespace Carbon diff --git a/explorer/ast/expression.cpp b/explorer/ast/expression.cpp index bf05a9167294..3274855b41ad 100644 --- a/explorer/ast/expression.cpp +++ b/explorer/ast/expression.cpp @@ -96,7 +96,7 @@ void Expression::Print(llvm::raw_ostream& out) const { } case ExpressionKind::SimpleMemberAccessExpression: { const auto& access = cast(*this); - out << access.object() << "." << access.member(); + out << access.object() << "." << access.member_name(); break; } case ExpressionKind::CompoundMemberAccessExpression: { diff --git a/explorer/ast/expression.h b/explorer/ast/expression.h index 615a19d1305a..e7f83131f688 100644 --- a/explorer/ast/expression.h +++ b/explorer/ast/expression.h @@ -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 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 object_; - std::string member_; + std::string member_name_; + std::optional member_; bool is_field_addr_me_method_ = false; std::optional> impl_; std::optional> found_in_interface_; diff --git a/explorer/ast/member.cpp b/explorer/ast/member.cpp new file mode 100644 index 000000000000..c6b4ef413ec0 --- /dev/null +++ b/explorer/ast/member.cpp @@ -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 declaration) + : member_(declaration) {} + +Member::Member(Nonnull struct_member) + : member_(struct_member) {} + +auto Member::name() const -> std::string_view { + if (const Declaration* decl = member_.dyn_cast()) { + return GetName(*decl).value(); + } else { + return member_.get()->name; + } +} + +auto Member::type() const -> const Value& { + if (const Declaration* decl = member_.dyn_cast()) { + return decl->static_type(); + } else { + return *member_.get()->value; + } +} + +auto Member::declaration() const -> std::optional> { + if (const Declaration* decl = member_.dyn_cast()) { + return decl; + } + return std::nullopt; +} + +} // namespace Carbon diff --git a/explorer/ast/member.h b/explorer/ast/member.h new file mode 100644 index 000000000000..470339fc9675 --- /dev/null +++ b/explorer/ast/member.h @@ -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 +#include + +#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 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 declaration); + explicit Member(Nonnull 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>; + + private: + llvm::PointerUnion, Nonnull> + member_; +}; + +} // namespace Carbon + +#endif // CARBON_EXPLORER_AST_MEMBER_H_ diff --git a/explorer/ast/pattern.h b/explorer/ast/pattern.h index 414f5a1f1a45..d7849bc8ad8c 100644 --- a/explorer/ast/pattern.h +++ b/explorer/ast/pattern.h @@ -334,7 +334,8 @@ class AlternativePattern : public Pattern { Nonnull member_access, RequireSimpleMemberAccess(alternative)); return arena->New(source_loc, &member_access->object(), - member_access->member(), arguments); + member_access->member_name(), + arguments); } // Constructs an AlternativePattern that matches a value of the type diff --git a/explorer/fuzzing/ast_to_proto.cpp b/explorer/fuzzing/ast_to_proto.cpp index 5c250c266351..9fc59fccbdc1 100644 --- a/explorer/fuzzing/ast_to_proto.cpp +++ b/explorer/fuzzing/ast_to_proto.cpp @@ -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; diff --git a/explorer/interpreter/BUILD b/explorer/interpreter/BUILD index 1b58053dc1b3..f7f285ac1f14 100644 --- a/explorer/interpreter/BUILD +++ b/explorer/interpreter/BUILD @@ -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", ], diff --git a/explorer/interpreter/address.h b/explorer/interpreter/address.h index 328088a9f4e6..b42116ce4311 100644 --- a/explorer/interpreter/address.h +++ b/explorer/interpreter/address.h @@ -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; } diff --git a/explorer/interpreter/field_path.h b/explorer/interpreter/field_path.h index 05d4c3927137..1c30592cf358 100644 --- a/explorer/interpreter/field_path.h +++ b/explorer/interpreter/field_path.h @@ -9,6 +9,7 @@ #include #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> witness) - : name_(std::move(name)), witness_(witness) {} + explicit Component(Member member) : member_(member) {} + Component(Member member, std::optional> 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> { 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> 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 { diff --git a/explorer/interpreter/interpreter.cpp b/explorer/interpreter/interpreter.cpp index e9b1fbce3df4..0b39af034154 100644 --- a/explorer/interpreter/interpreter.cpp +++ b/explorer/interpreter/interpreter.cpp @@ -352,7 +352,7 @@ auto Interpreter::StepLvalue() -> ErrorOr { Convert(act.results()[0], *access.member().base_type(), exp.source_loc())); Address object = cast(*val).address(); - Address field = object.SubobjectAddress(access.member().name()); + Address field = object.SubobjectAddress(access.member().member()); return todo_.FinishAction(arena_->New(field)); } } @@ -370,9 +370,14 @@ auto Interpreter::StepLvalue() -> ErrorOr { // { v :: [][i] :: C, E, F} :: S, H} // -> { { &v[i] :: C, E, F} :: S, H } Address object = cast(*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(*act.results()[1]).value()); - Address field = object.SubobjectAddress(f); + auto* tuple_field_as_struct_field = + arena_->New(NamedValue{f, &exp.static_type()}); + Address field = + object.SubobjectAddress(Member(tuple_field_as_struct_field)); return todo_.FinishAction(arena_->New(field)); } } @@ -907,7 +912,7 @@ auto Interpreter::StepExp() -> ErrorOr { 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 member, object->GetMember(arena_, FieldPath(field), exp.source_loc(), object)); diff --git a/explorer/interpreter/type_checker.cpp b/explorer/interpreter/type_checker.cpp index 8ec0b5869925..704ebd398877 100644 --- a/explorer/interpreter/type_checker.cpp +++ b/explorer/interpreter/type_checker.cpp @@ -1434,16 +1434,17 @@ auto TypeChecker::TypeCheckExp(Nonnull e, switch (object_type.kind()) { case Value::Kind::StructType: { const auto& struct_type = cast(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 e, InterpExp(&access.object(), arena_, trace_stream_)); if (const auto* struct_type = dyn_cast(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(Member(&field))); access.set_value_category(ValueCategory::Let); @@ -1460,7 +1462,7 @@ auto TypeChecker::TypeCheckExp(Nonnull 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 e, } case Value::Kind::NominalClassType: { const auto& t_class = cast(object_type); - if (std::optional> member = - FindMember(access.member(), t_class.declaration().members()); + if (std::optional> member = FindMember( + access.member_name(), t_class.declaration().members()); member.has_value()) { Nonnull 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 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 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 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(object_type).choice_type(); std::optional> 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( - *parameter_types, llvm::None, &choice, llvm::None, llvm::None)); + Nonnull type = arena_->New( + *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{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 e, const NominalClassType& class_type = cast(object_type).class_type(); if (std::optional> 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(*member); @@ -1561,7 +1571,7 @@ auto TypeChecker::TypeCheckExp(Nonnull 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 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(Member(result.member))); @@ -1591,13 +1602,14 @@ auto TypeChecker::TypeCheckExp(Nonnull 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 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 e, CARBON_ASSIGN_OR_RETURN( ConstraintLookupResult result, LookupInConstraint(e->source_loc(), &object_type, - access.member())); + access.member_name())); CARBON_ASSIGN_OR_RETURN(Nonnull 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 iface_type, -> ErrorOr { const auto& iface_decl = iface_type->declaration(); for (Nonnull m : iface_decl.members()) { - std::optional mem_name = GetName(*m); + std::optional mem_name = GetName(*m); CARBON_CHECK(mem_name.has_value()) << "unnamed interface member " << *m; std::optional> mem = diff --git a/explorer/interpreter/value.cpp b/explorer/interpreter/value.cpp index c5a06f7c407f..c1f1c33d8d32 100644 --- a/explorer/interpreter/value.cpp +++ b/explorer/interpreter/value.cpp @@ -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> { for (const NamedValue& element : elements_) { if (element.name == name) { @@ -33,7 +33,7 @@ static auto GetMember(Nonnull arena, Nonnull v, const FieldPath::Component& field, SourceLocation source_loc, Nonnull me_value) -> ErrorOr> { - const std::string& f = field.name(); + std::string_view f = field.name(); if (field.witness().has_value()) { Nonnull witness = cast(*field.witness()); @@ -185,7 +185,7 @@ static auto SetFieldImpl( std::vector> elements = cast(*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(index) >= elements.size()) { return RuntimeError(source_loc) << "index " << (*path_begin).name() << " out of range in " << *value; @@ -770,9 +770,9 @@ auto ValueEqual(Nonnull v1, Nonnull v2) -> bool { case Value::Kind::StringValue: return cast(*v1).value() == cast(*v2).value(); case Value::Kind::ParameterizedEntityName: { - std::optional name1 = + std::optional name1 = GetName(cast(v1)->declaration()); - std::optional name2 = + std::optional name2 = GetName(cast(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> { 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> members) -> std::optional> { for (Nonnull member : members) { - if (std::optional mem_name = GetName(*member); + if (std::optional 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()) { - return GetName(*decl).value(); - } else { - return member_.get()->name; - } -} - -auto Member::type() const -> const Value& { - if (const Declaration* decl = member_.dyn_cast()) { - return decl->static_type(); - } else { - return *member_.get()->value; - } -} - void ImplBinding::Print(llvm::raw_ostream& out) const { out << "impl binding " << *type_var_ << " as " << *iface_; } diff --git a/explorer/interpreter/value.h b/explorer/interpreter/value.h index 6cad900e1109..d3f822cacefc 100644 --- a/explorer/interpreter/value.h +++ b/explorer/interpreter/value.h @@ -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 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>; 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 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>; 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> members) -> std::optional>; @@ -855,32 +847,6 @@ class ParameterizedEntityName : public Value { Nonnull 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> { - if (const Declaration* decl = member_.dyn_cast()) { - return decl; - } - return std::nullopt; - } - - private: - llvm::PointerUnion, Nonnull> - 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> base_type_;