|
@@ -12,6 +12,7 @@
|
|
|
#include <set>
|
|
#include <set>
|
|
|
#include <string>
|
|
#include <string>
|
|
|
#include <string_view>
|
|
#include <string_view>
|
|
|
|
|
+#include <tuple>
|
|
|
#include <unordered_set>
|
|
#include <unordered_set>
|
|
|
#include <vector>
|
|
#include <vector>
|
|
|
|
|
|
|
@@ -426,40 +427,37 @@ auto TypeChecker::FieldTypesImplicitlyConvertible(
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Returns all class members from class and its parent classes.
|
|
|
|
|
-static auto GetClassHierarchy(const NominalClassType& class_type)
|
|
|
|
|
- -> std::vector<Nonnull<const NominalClassType*>> {
|
|
|
|
|
- Nonnull<const NominalClassType*> curr_class_type = &class_type;
|
|
|
|
|
- std::vector<Nonnull<const NominalClassType*>> all_classes{curr_class_type};
|
|
|
|
|
- while (curr_class_type->base().has_value()) {
|
|
|
|
|
- curr_class_type = curr_class_type->base().value();
|
|
|
|
|
- all_classes.push_back(curr_class_type);
|
|
|
|
|
- }
|
|
|
|
|
- return all_classes;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
auto TypeChecker::FieldTypes(const NominalClassType& class_type) const
|
|
auto TypeChecker::FieldTypes(const NominalClassType& class_type) const
|
|
|
-> std::vector<NamedValue> {
|
|
-> std::vector<NamedValue> {
|
|
|
std::vector<NamedValue> field_types;
|
|
std::vector<NamedValue> field_types;
|
|
|
- for (const auto class_type : GetClassHierarchy(class_type)) {
|
|
|
|
|
- for (Nonnull<Declaration*> m : class_type->declaration().members()) {
|
|
|
|
|
- switch (m->kind()) {
|
|
|
|
|
- case DeclarationKind::VariableDeclaration: {
|
|
|
|
|
- const auto& var = cast<VariableDeclaration>(*m);
|
|
|
|
|
- Nonnull<const Value*> field_type =
|
|
|
|
|
- Substitute(class_type->bindings(), &var.binding().static_type());
|
|
|
|
|
- field_types.push_back(
|
|
|
|
|
- {.name = var.binding().name(), .value = field_type});
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- default:
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ for (Nonnull<Declaration*> m : class_type.declaration().members()) {
|
|
|
|
|
+ switch (m->kind()) {
|
|
|
|
|
+ case DeclarationKind::VariableDeclaration: {
|
|
|
|
|
+ const auto& var = cast<VariableDeclaration>(*m);
|
|
|
|
|
+ Nonnull<const Value*> field_type =
|
|
|
|
|
+ Substitute(class_type.bindings(), &var.binding().static_type());
|
|
|
|
|
+ field_types.push_back(
|
|
|
|
|
+ {.name = var.binding().name(), .value = field_type});
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
return field_types;
|
|
return field_types;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+auto TypeChecker::FieldTypesWithBase(const NominalClassType& class_type) const
|
|
|
|
|
+ -> std::vector<NamedValue> {
|
|
|
|
|
+ auto fields = FieldTypes(class_type);
|
|
|
|
|
+ if (const auto base_type = class_type.base()) {
|
|
|
|
|
+ auto base_fields = FieldTypesWithBase(*base_type.value());
|
|
|
|
|
+ fields.emplace_back(NamedValue{std::string(NominalClassValue::BaseField),
|
|
|
|
|
+ base_type.value()});
|
|
|
|
|
+ }
|
|
|
|
|
+ return fields;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
auto TypeChecker::IsImplicitlyConvertible(
|
|
auto TypeChecker::IsImplicitlyConvertible(
|
|
|
Nonnull<const Value*> source, Nonnull<const Value*> destination,
|
|
Nonnull<const Value*> source, Nonnull<const Value*> destination,
|
|
|
const ImplScope& impl_scope, bool allow_user_defined_conversions) const
|
|
const ImplScope& impl_scope, bool allow_user_defined_conversions) const
|
|
@@ -484,10 +482,11 @@ auto TypeChecker::IsImplicitlyConvertible(
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
case Value::Kind::NominalClassType:
|
|
case Value::Kind::NominalClassType:
|
|
|
- if (FieldTypesImplicitlyConvertible(
|
|
|
|
|
- cast<StructType>(*source).fields(),
|
|
|
|
|
- FieldTypes(cast<NominalClassType>(*destination)),
|
|
|
|
|
- impl_scope)) {
|
|
|
|
|
|
|
+ if (IsImplicitlyConvertible(
|
|
|
|
|
+ source,
|
|
|
|
|
+ arena_->New<StructType>(
|
|
|
|
|
+ FieldTypesWithBase(cast<NominalClassType>(*destination))),
|
|
|
|
|
+ impl_scope, allow_user_defined_conversions)) {
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
@@ -1897,10 +1896,15 @@ auto TypeChecker::SubstituteImpl(const Bindings& bindings,
|
|
|
}
|
|
}
|
|
|
case Value::Kind::NominalClassType: {
|
|
case Value::Kind::NominalClassType: {
|
|
|
const auto& class_type = cast<NominalClassType>(*type);
|
|
const auto& class_type = cast<NominalClassType>(*type);
|
|
|
|
|
+ auto base_type = class_type.base();
|
|
|
|
|
+ if (base_type.has_value()) {
|
|
|
|
|
+ base_type = cast<NominalClassType>(
|
|
|
|
|
+ SubstituteImpl(base_type.value()->bindings(), base_type.value()));
|
|
|
|
|
+ }
|
|
|
Nonnull<const NominalClassType*> new_class_type =
|
|
Nonnull<const NominalClassType*> new_class_type =
|
|
|
arena_->New<NominalClassType>(
|
|
arena_->New<NominalClassType>(
|
|
|
&class_type.declaration(),
|
|
&class_type.declaration(),
|
|
|
- substitute_into_bindings(&class_type.bindings()));
|
|
|
|
|
|
|
+ substitute_into_bindings(&class_type.bindings()), base_type);
|
|
|
return new_class_type;
|
|
return new_class_type;
|
|
|
}
|
|
}
|
|
|
case Value::Kind::InterfaceType: {
|
|
case Value::Kind::InterfaceType: {
|
|
@@ -2567,9 +2571,9 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
|
|
const auto res,
|
|
const auto res,
|
|
|
FindMemberWithParents(access.member_name(), &t_class));
|
|
FindMemberWithParents(access.member_name(), &t_class));
|
|
|
if (res.has_value()) {
|
|
if (res.has_value()) {
|
|
|
- auto [member_type, member] = res.value();
|
|
|
|
|
|
|
+ auto [member_type, member, member_t_class] = res.value();
|
|
|
Nonnull<const Value*> field_type =
|
|
Nonnull<const Value*> field_type =
|
|
|
- Substitute(t_class.bindings(), member_type);
|
|
|
|
|
|
|
+ Substitute(member_t_class->bindings(), member_type);
|
|
|
access.set_member(Member(member));
|
|
access.set_member(Member(member));
|
|
|
access.set_static_type(field_type);
|
|
access.set_static_type(field_type);
|
|
|
access.set_is_type_access(!IsInstanceMember(access.member()));
|
|
access.set_is_type_access(!IsInstanceMember(access.member()));
|
|
@@ -4510,27 +4514,24 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
|
|
|
Nonnull<Expression*> base_class_expr = *class_decl->base_expr();
|
|
Nonnull<Expression*> base_class_expr = *class_decl->base_expr();
|
|
|
CARBON_ASSIGN_OR_RETURN(const auto base_type,
|
|
CARBON_ASSIGN_OR_RETURN(const auto base_type,
|
|
|
TypeCheckTypeExp(base_class_expr, class_scope));
|
|
TypeCheckTypeExp(base_class_expr, class_scope));
|
|
|
- switch (base_type->kind()) {
|
|
|
|
|
- case Value::Kind::NominalClassType:
|
|
|
|
|
- base_class = cast<NominalClassType>(base_type);
|
|
|
|
|
- if (base_class.value()->declaration().extensibility() ==
|
|
|
|
|
- ClassExtensibility::None) {
|
|
|
|
|
- return ProgramError(class_decl->source_loc())
|
|
|
|
|
- << "Base class `" << base_class.value()->declaration().name()
|
|
|
|
|
- << "` is `final` and cannot inherited. Add the `base` or "
|
|
|
|
|
- "`abstract` class prefix to `"
|
|
|
|
|
- << base_class.value()->declaration().name()
|
|
|
|
|
- << "` to allow it to be inherited";
|
|
|
|
|
- }
|
|
|
|
|
- class_decl->set_base(&base_class.value()->declaration());
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- return ProgramError(class_decl->source_loc())
|
|
|
|
|
- << "Unsupported base class type for class `"
|
|
|
|
|
- << class_decl->name()
|
|
|
|
|
- << "`. Only simple classes are currently supported as base "
|
|
|
|
|
- "class.";
|
|
|
|
|
|
|
+ if (base_type->kind() != Value::Kind::NominalClassType) {
|
|
|
|
|
+ return ProgramError(class_decl->source_loc())
|
|
|
|
|
+ << "Unsupported base class type for class `" << class_decl->name()
|
|
|
|
|
+ << "`. Only simple classes are currently supported as base "
|
|
|
|
|
+ "class.";
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ base_class = cast<NominalClassType>(base_type);
|
|
|
|
|
+ if (base_class.value()->declaration().extensibility() ==
|
|
|
|
|
+ ClassExtensibility::None) {
|
|
|
|
|
+ return ProgramError(class_decl->source_loc())
|
|
|
|
|
+ << "Base class `" << base_class.value()->declaration().name()
|
|
|
|
|
+ << "` is `final` and cannot inherited. Add the `base` or "
|
|
|
|
|
+ "`abstract` class prefix to `"
|
|
|
|
|
+ << base_class.value()->declaration().name()
|
|
|
|
|
+ << "` to allow it to be inherited";
|
|
|
|
|
+ }
|
|
|
|
|
+ class_decl->set_base_type(base_class);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
std::vector<Nonnull<const GenericBinding*>> bindings = scope_info.bindings;
|
|
std::vector<Nonnull<const GenericBinding*>> bindings = scope_info.bindings;
|
|
@@ -5599,17 +5600,18 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
auto TypeChecker::FindMemberWithParents(
|
|
auto TypeChecker::FindMemberWithParents(
|
|
|
- std::string_view name, Nonnull<const NominalClassType*> class_type)
|
|
|
|
|
|
|
+ std::string_view name, Nonnull<const NominalClassType*> enclosing_class)
|
|
|
-> ErrorOr<std::optional<
|
|
-> ErrorOr<std::optional<
|
|
|
- std::pair<Nonnull<const Value*>, Nonnull<const Declaration*>>>> {
|
|
|
|
|
|
|
+ std::tuple<Nonnull<const Value*>, Nonnull<const Declaration*>,
|
|
|
|
|
+ Nonnull<const NominalClassType*>>>> {
|
|
|
CARBON_ASSIGN_OR_RETURN(
|
|
CARBON_ASSIGN_OR_RETURN(
|
|
|
const auto res,
|
|
const auto res,
|
|
|
- FindMixedMemberAndType(name, class_type->declaration().members(),
|
|
|
|
|
- class_type));
|
|
|
|
|
|
|
+ FindMixedMemberAndType(name, enclosing_class->declaration().members(),
|
|
|
|
|
+ enclosing_class));
|
|
|
if (res.has_value()) {
|
|
if (res.has_value()) {
|
|
|
- return res;
|
|
|
|
|
|
|
+ return {std::make_tuple(res->first, res->second, enclosing_class)};
|
|
|
}
|
|
}
|
|
|
- if (const auto base = class_type->base(); base.has_value()) {
|
|
|
|
|
|
|
+ if (const auto base = enclosing_class->base(); base.has_value()) {
|
|
|
return FindMemberWithParents(name, base.value());
|
|
return FindMemberWithParents(name, base.value());
|
|
|
}
|
|
}
|
|
|
return {std::nullopt};
|
|
return {std::nullopt};
|