Explorer: Include self pattern in method type (#2935)

This fixes a bug where Explorer would not detect when:

- an implementation used a method to implement a class function in an interface
- an implementation used a class function to implement a method in an interface
- an implementation method used `addr self` when the interface method did not
- an interface method used `addr self` when the implementation method did not

at type checking time. This would then cause a crash at runtime.

Closes #2857

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
josh11b
2023-06-28 09:07:01 -07:00
committed by GitHub
co-authored by Richard Smith
parent 594ebff23b
commit 318eb793eb
10 changed files with 213 additions and 19 deletions
+22 -1
View File
@@ -585,13 +585,21 @@ void Value::Print(llvm::raw_ostream& out) const {
case Value::Kind::FunctionType: {
const auto& fn_type = cast<FunctionType>(*this);
out << "fn ";
if (!fn_type.deduced_bindings().empty()) {
auto self = fn_type.method_self();
if (!fn_type.deduced_bindings().empty() || self.has_value()) {
out << "[";
llvm::ListSeparator sep;
for (Nonnull<const GenericBinding*> deduced :
fn_type.deduced_bindings()) {
out << sep << *deduced;
}
if (self.has_value()) {
if (self->addr_self) {
out << sep << "addr self: " << *self->self_type << "*";
} else {
out << sep << "self: " << *self->self_type;
}
}
out << "]";
}
out << fn_type.parameters() << " -> " << fn_type.return_type();
@@ -844,6 +852,19 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2,
case Value::Kind::FunctionType: {
const auto& fn1 = cast<FunctionType>(*t1);
const auto& fn2 = cast<FunctionType>(*t2);
// Verify `self` parameters match
auto self1 = fn1.method_self();
auto self2 = fn2.method_self();
if (self1.has_value() != self2.has_value()) {
return false;
}
if (self1) {
if (self1->addr_self != self2->addr_self ||
!TypeEqual(self1->self_type, self2->self_type, equality_ctx)) {
return false;
}
}
// Verify parameters and return types match
return TypeEqual(&fn1.parameters(), &fn2.parameters(), equality_ctx) &&
TypeEqual(&fn1.return_type(), &fn2.return_type(), equality_ctx);
}