Diagnose uses of declarations that are too early. (#2288)

There are lots of ways a declaration can be used before we have the information necessary to handle that use. Issue diagnostics for these.

Interleave declaration and type-checking of global declarations so that declaring a later declaration can depend on the results of type-checking an earlier one.

Incorporates tests added in #2266.

Fixes #1394, fixes #1395, fixes #1396.

Co-authored-by: pmqtt <51272730+pmqtt@users.noreply.github.com>
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2022-10-13 15:30:29 -07:00
committed by GitHub
co-authored by pmqtt Jon Ross-Perkins
parent e111418b32
commit a3329cf004
22 changed files with 481 additions and 68 deletions
+17 -2
View File
@@ -592,6 +592,13 @@ auto Interpreter::InstantiateType(Nonnull<const Value*> type,
InstantiateBindings(&class_type.bindings(), source_loc));
return arena_->New<NominalClassType>(&class_type.declaration(), bindings);
}
case Value::Kind::ChoiceType: {
const auto& choice_type = cast<ChoiceType>(*type);
CARBON_ASSIGN_OR_RETURN(
Nonnull<const Bindings*> bindings,
InstantiateBindings(&choice_type.bindings(), source_loc));
return arena_->New<ChoiceType>(&choice_type.declaration(), bindings);
}
case Value::Kind::AssociatedConstant: {
CARBON_ASSIGN_OR_RETURN(
Nonnull<const Value*> type_value,
@@ -801,6 +808,16 @@ auto Interpreter::CallFunction(const CallExpression& call,
case Value::Kind::FunctionValue: {
const FunctionValue& fun_val = cast<FunctionValue>(*fun);
const FunctionDeclaration& function = fun_val.declaration();
if (!function.body().has_value()) {
return ProgramError(call.source_loc())
<< "attempt to call function `" << function.name()
<< "` that has not been defined";
}
if (!function.is_type_checked()) {
return ProgramError(call.source_loc())
<< "attempt to call function `" << function.name()
<< "` that has not been fully type-checked";
}
RuntimeScope binding_scope(&heap_);
// Bring the class type arguments into scope.
for (const auto& [bind, val] : fun_val.type_args()) {
@@ -830,8 +847,6 @@ auto Interpreter::CallFunction(const CallExpression& call,
CARBON_CHECK(PatternMatch(
&function.param_pattern().value(), converted_args, call.source_loc(),
&function_scope, generic_args, trace_stream_, this->arena_));
CARBON_CHECK(function.body().has_value())
<< "Calling a function that's missing a body";
return todo_.Spawn(std::make_unique<StatementAction>(*function.body()),
std::move(function_scope));
}