Explorer: Support class subtyping (#2460)

Features:
* Adds support for [subtyping](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/classes.md#subtyping) for local variables, and function parameters

Changes:
* Update function parameter `Deduce` to handle subtyping
* Update `InstantiateType` to support `PointerType`
* Update `Convert` to support convertion from child class to a base class

Relates to #1881 

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
Adrien Leravat
2022-12-19 11:32:32 -08:00
committed by GitHub
co-authored by Jon Ross-Perkins Geoff Romer
parent 8e6d48004b
commit 9299e51511
10 changed files with 245 additions and 10 deletions
+41 -1
View File
@@ -641,6 +641,13 @@ auto Interpreter::InstantiateType(Nonnull<const Value*> type,
EvalAssociatedConstant(cast<AssociatedConstant>(type), source_loc));
return type_value;
}
case Value::Kind::PointerType: {
const auto* ptr = cast<PointerType>(type);
CARBON_ASSIGN_OR_RETURN(
const auto* actual_type,
InstantiateType(&ptr->pointee_type(), source_loc));
return arena_->New<PointerType>(actual_type);
}
default:
return type;
}
@@ -712,7 +719,6 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
case Value::Kind::FunctionValue:
case Value::Kind::DestructorValue:
case Value::Kind::BoundMethodValue:
case Value::Kind::PointerValue:
case Value::Kind::LValue:
case Value::Kind::BoolValue:
case Value::Kind::NominalClassValue:
@@ -863,6 +869,40 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
}
return Convert(value, destination_type, source_loc);
}
case Value::Kind::PointerValue: {
if (destination_type->kind() != Value::Kind::PointerType ||
cast<PointerType>(destination_type)->pointee_type().kind() !=
Value::Kind::NominalClassType) {
// No conversion needed.
return value;
}
// Get pointee value.
const auto* src_ptr = cast<PointerValue>(value);
CARBON_ASSIGN_OR_RETURN(const auto* pointee,
heap_.Read(src_ptr->address(), source_loc))
CARBON_CHECK(pointee->kind() == Value::Kind::NominalClassValue)
<< "Unexpected pointer type";
const auto* dest_ptr = cast<PointerType>(destination_type);
std::optional<Nonnull<const NominalClassValue*>> class_subobj =
cast<NominalClassValue>(pointee);
auto new_addr = src_ptr->address();
while (class_subobj) {
if (TypeEqual(&(*class_subobj)->type(), &dest_ptr->pointee_type(),
std::nullopt)) {
return arena_->New<PointerValue>(new_addr);
}
class_subobj = (*class_subobj)->base();
new_addr = new_addr.ElementAddress(
arena_->New<BaseElement>(&dest_ptr->pointee_type()));
}
// Unable to resolve, return as-is.
// TODO: Produce error instead once we can properly substitute
// parameterized types for pointers in function call parameters.
return value;
}
}
}