Adds basic support for class functions and methods. (#1057)

* adding methods to the ast

* pre commit stuff?

* implementation of class functions

* implemented methods

* some cleanup

* more cleanup

* add newlines in test programs

* pre-commit fixups

* added include of return_term.h

* a test of a method calling another method

* replacing Member with Declaration

* removing the member.h etc files

* clarify a type annotation

* update uses of FunctionDeclaration

* remove ReturnTarget, no longer needed

* more cleanup

* more cleanup

* yet more cleanup, playing with pre-commit

* did a pre-commit run --all-files

* fixed const issue

* remove comment

* checking dependencies in BUILD files and headers

* pre-commit working now

* refactor NominalClassType to just hold a pointer to the class declaration

* remove Member from rtti

* responding to Geoffreys review

* change field_types to a non-member function
This commit is contained in:
Jeremy G. Siek
2022-02-05 12:30:13 -05:00
committed by GitHub
parent 4479c55305
commit ac0b810bf3
27 changed files with 739 additions and 351 deletions
+111 -8
View File
@@ -40,10 +40,27 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
return *field;
}
case Value::Kind::NominalClassValue: {
const NominalClassValue& object = cast<NominalClassValue>(*v);
// Look for a field
std::optional<Nonnull<const Value*>> field =
cast<StructValue>(cast<NominalClassValue>(*v).inits()).FindField(f);
cast<StructValue>(object.inits()).FindField(f);
if (field == std::nullopt) {
FATAL_RUNTIME_ERROR(source_loc) << "member " << f << " not in " << *v;
// Look for a method in the object's class
const NominalClassType& class_type =
cast<NominalClassType>(object.type());
std::optional<Nonnull<const FunctionValue*>> func =
class_type.FindFunction(f);
if (func == std::nullopt) {
FATAL_RUNTIME_ERROR(source_loc) << "member " << f << " not in " << *v
<< " or its class " << class_type;
} else if ((*func)->declaration().is_method()) {
// Found a method. Turn it into a bound method.
const FunctionValue& m = cast<FunctionValue>(**func);
return arena->New<BoundMethodValue>(&m.declaration(), &object);
} else {
// Found a class function
return *func;
}
}
return *field;
}
@@ -55,6 +72,16 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
}
return arena->New<AlternativeConstructorValue>(f, choice.name());
}
case Value::Kind::NominalClassType: {
const NominalClassType& class_type = cast<NominalClassType>(*v);
std::optional<Nonnull<const FunctionValue*>> fun =
class_type.FindFunction(f);
if (fun == std::nullopt) {
FATAL_RUNTIME_ERROR(source_loc)
<< "class function " << f << " not in " << *v;
}
return *fun;
}
default:
FATAL() << "field access not allowed for value " << *v;
}
@@ -158,7 +185,7 @@ void Value::Print(llvm::raw_ostream& out) const {
}
case Value::Kind::NominalClassValue: {
const auto& s = cast<NominalClassValue>(*this);
out << cast<NominalClassType>(s.type()).name() << s.inits();
out << cast<NominalClassType>(s.type()).declaration().name() << s.inits();
break;
}
case Value::Kind::TupleValue: {
@@ -179,6 +206,10 @@ void Value::Print(llvm::raw_ostream& out) const {
case Value::Kind::FunctionValue:
out << "fun<" << cast<FunctionValue>(*this).declaration().name() << ">";
break;
case Value::Kind::BoundMethodValue:
out << "bound_method<"
<< cast<BoundMethodValue>(*this).declaration().name() << ">";
break;
case Value::Kind::PointerValue:
out << "ptr<" << cast<PointerValue>(*this).address() << ">";
break;
@@ -230,9 +261,11 @@ void Value::Print(llvm::raw_ostream& out) const {
out << "}";
break;
}
case Value::Kind::NominalClassType:
out << "class " << cast<NominalClassType>(*this).name();
case Value::Kind::NominalClassType: {
const NominalClassType& class_type = cast<NominalClassType>(*this);
out << "class " << class_type.declaration().name();
break;
}
case Value::Kind::ChoiceType:
out << "choice " << cast<ChoiceType>(*this).name();
break;
@@ -252,7 +285,8 @@ void Value::Print(llvm::raw_ostream& out) const {
out << "\"";
break;
case Value::Kind::TypeOfClassType:
out << "typeof(" << cast<TypeOfClassType>(*this).class_type().name()
out << "typeof("
<< cast<TypeOfClassType>(*this).class_type().declaration().name()
<< ")";
break;
case Value::Kind::TypeOfChoiceType:
@@ -328,8 +362,8 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2) -> bool {
return true;
}
case Value::Kind::NominalClassType:
return cast<NominalClassType>(*t1).name() ==
cast<NominalClassType>(*t2).name();
return cast<NominalClassType>(*t1).declaration().name() ==
cast<NominalClassType>(*t2).declaration().name();
case Value::Kind::ChoiceType:
return cast<ChoiceType>(*t1).name() == cast<ChoiceType>(*t2).name();
case Value::Kind::TupleValue: {
@@ -387,6 +421,15 @@ auto ValueEqual(Nonnull<const Value*> v1, Nonnull<const Value*> v2) -> bool {
return body1.has_value() == body2.has_value() &&
(!body1.has_value() || *body1 == *body2);
}
case Value::Kind::BoundMethodValue: {
const BoundMethodValue& m1 = cast<BoundMethodValue>(*v1);
const BoundMethodValue& m2 = cast<BoundMethodValue>(*v2);
std::optional<Nonnull<const Statement*>> body1 = m1.declaration().body();
std::optional<Nonnull<const Statement*>> body2 = m2.declaration().body();
return ValueEqual(m1.receiver(), m2.receiver()) &&
body1.has_value() == body2.has_value() &&
(!body1.has_value() || *body1 == *body2);
}
case Value::Kind::TupleValue: {
const std::vector<Nonnull<const Value*>>& elements1 =
cast<TupleValue>(*v1).elements();
@@ -455,4 +498,64 @@ auto ChoiceType::FindAlternative(std::string_view name) const
return std::nullopt;
}
auto NominalClassType::FindFunction(const std::string& name) const
-> std::optional<Nonnull<const FunctionValue*>> {
for (const auto& member : declaration().members()) {
switch (member->kind()) {
case DeclarationKind::FunctionDeclaration: {
const auto& fun = cast<FunctionDeclaration>(*member);
if (fun.name() == name) {
return &cast<FunctionValue>(**fun.constant_value());
}
break;
}
default:
break;
}
}
return std::nullopt;
}
auto FieldTypes(const NominalClassType& class_type) -> std::vector<NamedValue> {
std::vector<NamedValue> field_types;
for (Nonnull<Declaration*> m : class_type.declaration().members()) {
switch (m->kind()) {
case DeclarationKind::VariableDeclaration: {
const auto& var = cast<VariableDeclaration>(*m);
field_types.push_back({.name = var.binding().name(),
.value = &var.binding().static_type()});
break;
}
default:
break;
}
}
return field_types;
}
auto NominalClassType::FindMember(const std::string& name) const
-> std::optional<Nonnull<const Declaration*>> {
for (const auto& member : declaration().members()) {
switch (member->kind()) {
case DeclarationKind::FunctionDeclaration: {
const auto& fun = cast<FunctionDeclaration>(*member);
if (fun.name() == name) {
return &fun;
}
break;
}
case DeclarationKind::VariableDeclaration: {
const auto& var = cast<VariableDeclaration>(*member);
if (var.binding().name() == name) {
return &var;
}
break;
}
default:
break;
}
}
return std::nullopt;
}
} // namespace Carbon