|
|
@@ -74,6 +74,7 @@ static auto IsConcreteType(Nonnull<const Value*> value) -> bool {
|
|
|
switch (value->kind()) {
|
|
|
case Value::Kind::IntValue:
|
|
|
case Value::Kind::FunctionValue:
|
|
|
+ case Value::Kind::BoundMethodValue:
|
|
|
case Value::Kind::PointerValue:
|
|
|
case Value::Kind::LValue:
|
|
|
case Value::Kind::BoolValue:
|
|
|
@@ -165,7 +166,7 @@ static auto IsImplicitlyConvertible(Nonnull<const Value*> source,
|
|
|
case Value::Kind::NominalClassType:
|
|
|
return FieldTypesImplicitlyConvertible(
|
|
|
cast<StructType>(*source).fields(),
|
|
|
- cast<NominalClassType>(*destination).fields());
|
|
|
+ FieldTypes(cast<NominalClassType>(*destination)));
|
|
|
default:
|
|
|
return false;
|
|
|
}
|
|
|
@@ -314,6 +315,7 @@ void TypeChecker::ArgumentDeduction(
|
|
|
case Value::Kind::IntValue:
|
|
|
case Value::Kind::BoolValue:
|
|
|
case Value::Kind::FunctionValue:
|
|
|
+ case Value::Kind::BoundMethodValue:
|
|
|
case Value::Kind::PointerValue:
|
|
|
case Value::Kind::LValue:
|
|
|
case Value::Kind::StructValue:
|
|
|
@@ -380,6 +382,7 @@ auto TypeChecker::Substitute(
|
|
|
case Value::Kind::IntValue:
|
|
|
case Value::Kind::BoolValue:
|
|
|
case Value::Kind::FunctionValue:
|
|
|
+ case Value::Kind::BoundMethodValue:
|
|
|
case Value::Kind::PointerValue:
|
|
|
case Value::Kind::LValue:
|
|
|
case Value::Kind::StructValue:
|
|
|
@@ -480,25 +483,28 @@ void TypeChecker::TypeCheckExp(Nonnull<Expression*> e) {
|
|
|
}
|
|
|
case Value::Kind::NominalClassType: {
|
|
|
const auto& t_class = cast<NominalClassType>(aggregate_type);
|
|
|
- // Search for a field
|
|
|
- for (auto& field : t_class.fields()) {
|
|
|
- if (access.field() == field.name) {
|
|
|
- SetStaticType(&access, field.value);
|
|
|
- access.set_value_category(access.aggregate().value_category());
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- // Search for a method
|
|
|
- for (auto& method : t_class.methods()) {
|
|
|
- if (access.field() == method.name) {
|
|
|
- SetStaticType(&access, method.value);
|
|
|
- access.set_value_category(ValueCategory::Let);
|
|
|
- return;
|
|
|
+ if (std::optional<Nonnull<const Declaration*>> member =
|
|
|
+ t_class.FindMember(access.field());
|
|
|
+ member.has_value()) {
|
|
|
+ SetStaticType(&access, &(*member)->static_type());
|
|
|
+ switch ((*member)->kind()) {
|
|
|
+ case DeclarationKind::VariableDeclaration:
|
|
|
+ access.set_value_category(access.aggregate().value_category());
|
|
|
+ break;
|
|
|
+ case DeclarationKind::FunctionDeclaration:
|
|
|
+ access.set_value_category(ValueCategory::Let);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ FATAL() << "member " << access.field()
|
|
|
+ << " is not a field or method";
|
|
|
+ break;
|
|
|
}
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ FATAL_COMPILATION_ERROR(e->source_loc())
|
|
|
+ << "class " << t_class.declaration().name()
|
|
|
+ << " does not have a field named " << access.field();
|
|
|
}
|
|
|
- FATAL_COMPILATION_ERROR(e->source_loc())
|
|
|
- << "class " << t_class.name() << " does not have a field named "
|
|
|
- << access.field();
|
|
|
}
|
|
|
case Value::Kind::TypeOfChoiceType: {
|
|
|
const ChoiceType& choice =
|
|
|
@@ -517,10 +523,36 @@ void TypeChecker::TypeCheckExp(Nonnull<Expression*> e) {
|
|
|
access.set_value_category(ValueCategory::Let);
|
|
|
return;
|
|
|
}
|
|
|
+ case Value::Kind::TypeOfClassType: {
|
|
|
+ const NominalClassType& class_type =
|
|
|
+ cast<TypeOfClassType>(aggregate_type).class_type();
|
|
|
+ if (std::optional<Nonnull<const Declaration*>> member =
|
|
|
+ class_type.FindMember(access.field());
|
|
|
+ member.has_value()) {
|
|
|
+ switch ((*member)->kind()) {
|
|
|
+ case DeclarationKind::FunctionDeclaration: {
|
|
|
+ const auto& func = cast<FunctionDeclaration>(*member);
|
|
|
+ if (func->is_method()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ SetStaticType(&access, &(*member)->static_type());
|
|
|
+ access.set_value_category(ValueCategory::Let);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ FATAL_COMPILATION_ERROR(access.source_loc())
|
|
|
+ << access.field() << " is not a class function";
|
|
|
+ } else {
|
|
|
+ FATAL_COMPILATION_ERROR(access.source_loc())
|
|
|
+ << class_type << " does not have a class function named "
|
|
|
+ << access.field();
|
|
|
+ }
|
|
|
+ }
|
|
|
default:
|
|
|
FATAL_COMPILATION_ERROR(e->source_loc())
|
|
|
- << "field access, expected a struct\n"
|
|
|
- << *e;
|
|
|
+ << "field access, unexpected " << aggregate_type << " in " << *e;
|
|
|
}
|
|
|
}
|
|
|
case ExpressionKind::IdentifierExpression: {
|
|
|
@@ -623,8 +655,9 @@ void TypeChecker::TypeCheckExp(Nonnull<Expression*> e) {
|
|
|
return;
|
|
|
case Operator::AddressOf:
|
|
|
if (op.arguments()[0]->value_category() != ValueCategory::Var) {
|
|
|
- FATAL_COMPILATION_ERROR(op.arguments()[0]->source_loc()) <<
|
|
|
- "Argument to " << ToString(op.op()) << " should be an lvalue.";
|
|
|
+ FATAL_COMPILATION_ERROR(op.arguments()[0]->source_loc())
|
|
|
+ << "Argument to " << ToString(op.op())
|
|
|
+ << " should be an lvalue.";
|
|
|
}
|
|
|
SetStaticType(&op, arena_->New<PointerType>(ts[0]));
|
|
|
op.set_value_category(ValueCategory::Let);
|
|
|
@@ -1001,6 +1034,11 @@ void TypeChecker::TypeCheckFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
|
|
SetStaticType(deduced, arena_->New<VariableType>(deduced));
|
|
|
SetConstantValue(deduced, &deduced->static_type());
|
|
|
}
|
|
|
+ if (f->is_method()) {
|
|
|
+ // Type check the receiver patter
|
|
|
+ TypeCheckPattern(&f->me_pattern(), std::nullopt);
|
|
|
+ }
|
|
|
+
|
|
|
// Type check the parameter pattern
|
|
|
TypeCheckPattern(&f->param_pattern(), std::nullopt);
|
|
|
|
|
|
@@ -1044,32 +1082,32 @@ void TypeChecker::TypeCheckFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
|
|
arena_->New<IntType>(), &f->return_term().static_type());
|
|
|
// TODO: Check that main doesn't have any parameters.
|
|
|
}
|
|
|
+ SetConstantValue(f, arena_->New<FunctionValue>(f));
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
void TypeChecker::TypeCheckClassDeclaration(
|
|
|
Nonnull<ClassDeclaration*> class_decl) {
|
|
|
- std::vector<NamedValue> fields;
|
|
|
- std::vector<NamedValue> methods;
|
|
|
- for (Nonnull<Member*> m : class_decl->members()) {
|
|
|
- switch (m->kind()) {
|
|
|
- case MemberKind::FieldMember: {
|
|
|
- BindingPattern& binding = cast<FieldMember>(*m).binding();
|
|
|
- if (binding.name() == AnonymousName) {
|
|
|
- FATAL_COMPILATION_ERROR(binding.source_loc())
|
|
|
- << "Struct members must have names";
|
|
|
- }
|
|
|
- TypeCheckPattern(&binding, std::nullopt);
|
|
|
- fields.push_back(
|
|
|
- {.name = binding.name(), .value = &binding.static_type()});
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ // The declarations of the members may refer to the class, so we
|
|
|
+ // must set the constant value of the class and its static type
|
|
|
+ // before we start processing the members.
|
|
|
+ Nonnull<NominalClassType*> class_type =
|
|
|
+ arena_->New<NominalClassType>(class_decl);
|
|
|
+ SetConstantValue(class_decl, class_type);
|
|
|
+ SetStaticType(class_decl, arena_->New<TypeOfClassType>(class_type));
|
|
|
+
|
|
|
+ // First pass: process the field, class function, and method
|
|
|
+ // declarations but not the bodies of class functions or method
|
|
|
+ // declarations.
|
|
|
+ for (Nonnull<Declaration*> m : class_decl->members()) {
|
|
|
+ DeclareDeclaration(m);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Second pass: type check the bodies of the class functions and
|
|
|
+ // methods.
|
|
|
+ for (Nonnull<Declaration*> m : class_decl->members()) {
|
|
|
+ TypeCheckDeclaration(m);
|
|
|
}
|
|
|
- SetStaticType(
|
|
|
- class_decl,
|
|
|
- arena_->New<TypeOfClassType>(arena_->New<NominalClassType>(
|
|
|
- class_decl->name(), std::move(fields), std::move(methods))));
|
|
|
}
|
|
|
|
|
|
void TypeChecker::TypeCheckChoiceDeclaration(
|
|
|
@@ -1081,12 +1119,13 @@ void TypeChecker::TypeCheckChoiceDeclaration(
|
|
|
alternatives.push_back({.name = alternative->name(), .value = signature});
|
|
|
}
|
|
|
auto ct = arena_->New<ChoiceType>(choice->name(), std::move(alternatives));
|
|
|
+ SetConstantValue(choice, ct);
|
|
|
SetStaticType(choice, arena_->New<TypeOfChoiceType>(ct));
|
|
|
}
|
|
|
|
|
|
void TypeChecker::TypeCheck(AST& ast) {
|
|
|
for (Nonnull<Declaration*> declaration : ast.declarations) {
|
|
|
- TopLevel(declaration);
|
|
|
+ DeclareDeclaration(declaration);
|
|
|
}
|
|
|
for (Nonnull<Declaration*> decl : ast.declarations) {
|
|
|
TypeCheckDeclaration(decl);
|
|
|
@@ -1111,7 +1150,9 @@ void TypeChecker::TypeCheckDeclaration(Nonnull<Declaration*> d) {
|
|
|
// Signals a type error if the initializing expression does not have
|
|
|
// the declared type of the variable, otherwise returns this
|
|
|
// declaration with annotated types.
|
|
|
- TypeCheckExp(&var.initializer());
|
|
|
+ if (var.has_initializer()) {
|
|
|
+ TypeCheckExp(&var.initializer());
|
|
|
+ }
|
|
|
const auto* binding_type =
|
|
|
dyn_cast<ExpressionPattern>(&var.binding().type());
|
|
|
if (binding_type == nullptr) {
|
|
|
@@ -1122,35 +1163,32 @@ void TypeChecker::TypeCheckDeclaration(Nonnull<Declaration*> d) {
|
|
|
Nonnull<const Value*> declared_type =
|
|
|
InterpExp(&binding_type->expression(), arena_, trace_);
|
|
|
SetStaticType(&var, declared_type);
|
|
|
- ExpectType(var.source_loc(), "initializer of variable", declared_type,
|
|
|
- &var.initializer().static_type());
|
|
|
+ if (var.has_initializer()) {
|
|
|
+ ExpectType(var.source_loc(), "initializer of variable", declared_type,
|
|
|
+ &var.initializer().static_type());
|
|
|
+ }
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void TypeChecker::TopLevel(Nonnull<Declaration*> d) {
|
|
|
+void TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d) {
|
|
|
switch (d->kind()) {
|
|
|
case DeclarationKind::FunctionDeclaration: {
|
|
|
auto& func_def = cast<FunctionDeclaration>(*d);
|
|
|
TypeCheckFunctionDeclaration(&func_def, /*check_body=*/false);
|
|
|
- SetConstantValue(&func_def, arena_->New<FunctionValue>(&func_def));
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case DeclarationKind::ClassDeclaration: {
|
|
|
auto& class_decl = cast<ClassDeclaration>(*d);
|
|
|
TypeCheckClassDeclaration(&class_decl);
|
|
|
- const auto& type = cast<TypeOfClassType>(class_decl.static_type());
|
|
|
- SetConstantValue(&class_decl, &type.class_type());
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case DeclarationKind::ChoiceDeclaration: {
|
|
|
auto& choice = cast<ChoiceDeclaration>(*d);
|
|
|
TypeCheckChoiceDeclaration(&choice);
|
|
|
- const auto& type = cast<TypeOfChoiceType>(choice.static_type());
|
|
|
- SetConstantValue(&choice, &type.choice_type());
|
|
|
break;
|
|
|
}
|
|
|
|