mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Compound member access syntax. (#1233)
Implement initial support for `A.(B)` syntax, per #989. Specifically, this supports: * `object.(Type.member)` for instance members, * `object.(Interface.member)` for instance and non-instance members, * `object.(Type.(Interface.member))` for instance members, * `Type.(Interface.member)` for non-instance members. Three new AST nodes are introduced: * `CompoundFieldAccessExpression` represents the `A.(B)` syntax. * `MemberName` is a `Value` that represents the result of evaluating an expression such as `Type.member` or `Interface.member` or `Type.(Interface.member)`. * `TypeOfMemberName` is the type of a `MemberName` value. In order to handle members of classes and interfaces which have corresponding declarations and may need substitution into their types, and members of structs which don't have declarations but also don't need substitution, a class `Member` is introduced that can refer to either of these kinds of member. Co-authored-by: Geoff Romer <gromer@google.com> Co-authored-by: Jon Meow <jperkins@google.com>
This commit is contained in:
committed by
GitHub
co-authored by
Geoff Romer
Jon Meow
parent
20728dbd3a
commit
235cb88a8e
@@ -354,6 +354,25 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
out << *GetName(cast<ParameterizedEntityName>(*this).declaration());
|
||||
break;
|
||||
case Value::Kind::MemberName: {
|
||||
const auto& member_name = cast<MemberName>(*this);
|
||||
if (member_name.base_type().has_value()) {
|
||||
out << *member_name.base_type().value();
|
||||
}
|
||||
if (member_name.base_type().has_value() &&
|
||||
member_name.interface().has_value()) {
|
||||
out << "(";
|
||||
}
|
||||
if (member_name.interface().has_value()) {
|
||||
out << *member_name.interface().value();
|
||||
}
|
||||
out << "." << member_name.name();
|
||||
if (member_name.base_type().has_value() &&
|
||||
member_name.interface().has_value()) {
|
||||
out << ")";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Value::Kind::ChoiceType:
|
||||
out << "choice " << cast<ChoiceType>(*this).name();
|
||||
break;
|
||||
@@ -388,9 +407,13 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
<< ")";
|
||||
break;
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
out << "typeof(" << cast<TypeOfParameterizedEntityName>(*this).name()
|
||||
<< ")";
|
||||
out << "parameterized entity name "
|
||||
<< cast<TypeOfParameterizedEntityName>(*this).name();
|
||||
break;
|
||||
case Value::Kind::TypeOfMemberName: {
|
||||
out << "member name " << cast<TypeOfMemberName>(*this).member().name();
|
||||
break;
|
||||
}
|
||||
case Value::Kind::StaticArrayType: {
|
||||
const auto& array_type = cast<StaticArrayType>(*this);
|
||||
out << "[" << array_type.element_type() << "; " << array_type.size()
|
||||
@@ -522,10 +545,6 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
return TypeEqual(&cast<TypeOfChoiceType>(*t1).choice_type(),
|
||||
&cast<TypeOfChoiceType>(*t2).choice_type());
|
||||
case Value::Kind::TypeOfParameterizedEntityName: {
|
||||
return ValueEqual(&cast<TypeOfParameterizedEntityName>(*t1).name(),
|
||||
&cast<TypeOfParameterizedEntityName>(*t2).name());
|
||||
}
|
||||
case Value::Kind::StaticArrayType: {
|
||||
const auto& array1 = cast<StaticArrayType>(*t1);
|
||||
const auto& array2 = cast<StaticArrayType>(*t2);
|
||||
@@ -546,6 +565,9 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
|
||||
case Value::Kind::BindingPlaceholderValue:
|
||||
case Value::Kind::ContinuationValue:
|
||||
case Value::Kind::ParameterizedEntityName:
|
||||
case Value::Kind::MemberName:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
case Value::Kind::TypeOfMemberName:
|
||||
CARBON_FATAL() << "TypeEqual used to compare non-type values\n"
|
||||
<< *t1 << "\n"
|
||||
<< *t2;
|
||||
@@ -645,6 +667,7 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2) -> bool {
|
||||
case Value::Kind::TypeOfInterfaceType:
|
||||
case Value::Kind::TypeOfChoiceType:
|
||||
case Value::Kind::TypeOfParameterizedEntityName:
|
||||
case Value::Kind::TypeOfMemberName:
|
||||
case Value::Kind::StaticArrayType:
|
||||
return TypeEqual(v1, v2);
|
||||
case Value::Kind::NominalClassValue:
|
||||
@@ -654,6 +677,7 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2) -> bool {
|
||||
case Value::Kind::ContinuationValue:
|
||||
case Value::Kind::PointerValue:
|
||||
case Value::Kind::LValue:
|
||||
case Value::Kind::MemberName:
|
||||
// TODO: support pointer comparisons once we have a clearer distinction
|
||||
// between pointers and lvalues.
|
||||
CARBON_FATAL() << "ValueEqual does not support this kind of value: "
|
||||
@@ -703,6 +727,22 @@ 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_;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user