Procházet zdrojové kódy

Remove some uses of ReturnTypeInfo (#6577)

As with #6572, this is a step toward supporting function calls that have
arbitrary numbers of initializing returns.
Geoff Romer před 3 měsíci
rodič
revize
4a47f1ebeb

+ 16 - 23
toolchain/check/call.cpp

@@ -211,21 +211,6 @@ static auto BuildCalleeSpecificFunction(
   return callee_id;
 }
 
-// Returns the return type, with a scoped annotation for any diagnostics.
-static auto CheckCalleeFunctionReturnType(Context& context, SemIR::LocId loc_id,
-                                          SemIR::FunctionId callee_function_id,
-                                          SemIR::SpecificId callee_specific_id)
-    -> SemIR::TypeId {
-  auto& function = context.functions().Get(callee_function_id);
-  Diagnostics::AnnotationScope annotate_diagnostics(
-      &context.emitter(), [&](auto& builder) {
-        CARBON_DIAGNOSTIC(IncompleteReturnTypeHere, Note,
-                          "return type declared here");
-        builder.Note(function.return_type_inst_id, IncompleteReturnTypeHere);
-      });
-  return CheckFunctionReturnType(context, loc_id, function, callee_specific_id);
-}
-
 auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
                            SemIR::InstId callee_id,
                            const SemIR::CalleeFunction& callee_function,
@@ -247,19 +232,27 @@ auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
                                             *callee_specific_id);
   }
 
-  auto return_type_id = CheckCalleeFunctionReturnType(
-      context, loc_id, callee_function.function_id, *callee_specific_id);
-
   auto& callee = context.functions().Get(callee_function.function_id);
+  auto return_type_id =
+      callee.GetDeclaredReturnType(context.sem_ir(), *callee_specific_id);
+  if (!return_type_id.has_value()) {
+    return_type_id = GetTupleType(context, {});
+  }
 
-  // Build storage for any output parameters.
   llvm::SmallVector<SemIR::InstId, 1> return_arg_ids;
   for (auto return_pattern_id :
        context.inst_blocks().GetOrEmpty(callee.return_patterns_id)) {
-    auto arg_type_id = SemIR::ExtractScrutineeType(
-        context.sem_ir(),
-        SemIR::GetTypeOfInstInSpecific(context.sem_ir(), *callee_specific_id,
-                                       return_pattern_id));
+    Diagnostics::AnnotationScope annotate_diagnostics(
+        &context.emitter(), [&](auto& builder) {
+          CARBON_DIAGNOSTIC(IncompleteReturnTypeHere, Note,
+                            "return type declared here");
+          builder.Note(return_pattern_id, IncompleteReturnTypeHere);
+        });
+    auto arg_type_id = CheckFunctionReturnPatternType(
+        context, loc_id, return_pattern_id, *callee_specific_id);
+    if (arg_type_id == SemIR::ErrorInst::TypeId) {
+      return_type_id = SemIR::ErrorInst::TypeId;
+    }
     switch (SemIR::InitRepr::ForType(context.sem_ir(), arg_type_id).kind) {
       case SemIR::InitRepr::InPlace:
       case SemIR::InitRepr::Dependent:

+ 20 - 28
toolchain/check/function.cpp

@@ -92,47 +92,38 @@ auto CheckFunctionTypeMatches(Context& context,
                                         prev_specific_id, diagnose);
 }
 
-auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
-                             const SemIR::Function& function,
-                             SemIR::SpecificId specific_id) -> SemIR::TypeId {
-  auto return_info = SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(),
-                                                        function, specific_id);
-
-  // If we couldn't determine the return information due to the return type
-  // being incomplete, try to complete it now.
-  if (return_info.init_repr.kind == SemIR::InitRepr::Incomplete ||
-      return_info.init_repr.kind == SemIR::InitRepr::Abstract) {
+auto CheckFunctionReturnPatternType(Context& context, SemIR::LocId loc_id,
+                                    SemIR::InstId return_pattern_id,
+                                    SemIR::SpecificId specific_id)
+    -> SemIR::TypeId {
+  auto arg_type_id = SemIR::ExtractScrutineeType(
+      context.sem_ir(), SemIR::GetTypeOfInstInSpecific(
+                            context.sem_ir(), specific_id, return_pattern_id));
+  auto init_repr = SemIR::InitRepr::ForType(context.sem_ir(), arg_type_id);
+  if (!init_repr.is_valid()) {
     auto diagnose_incomplete_return_type = [&] {
       CARBON_DIAGNOSTIC(IncompleteTypeInFunctionReturnType, Error,
                         "function returns incomplete type {0}", SemIR::TypeId);
       return context.emitter().Build(loc_id, IncompleteTypeInFunctionReturnType,
-                                     return_info.type_id);
+                                     arg_type_id);
     };
     auto diagnose_abstract_return_type = [&] {
       CARBON_DIAGNOSTIC(AbstractTypeInFunctionReturnType, Error,
                         "function returns abstract type {0}", SemIR::TypeId);
       return context.emitter().Build(loc_id, AbstractTypeInFunctionReturnType,
-                                     return_info.type_id);
+                                     arg_type_id);
     };
 
     // TODO: Consider suppressing the diagnostic if we've already diagnosed a
     // definition or call to this function.
-    if (RequireConcreteType(context, return_info.type_id, loc_id,
-                            diagnose_incomplete_return_type,
-                            diagnose_abstract_return_type)) {
-      return_info = SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(),
-                                                       function, specific_id);
+    if (!RequireConcreteType(
+            context, arg_type_id, SemIR::LocId(return_pattern_id),
+            diagnose_incomplete_return_type, diagnose_abstract_return_type)) {
+      return SemIR::ErrorInst::TypeId;
     }
   }
 
-  if (return_info.init_repr.kind == SemIR::InitRepr::Incomplete ||
-      return_info.init_repr.kind == SemIR::InitRepr::Abstract) {
-    return SemIR::ErrorInst::TypeId;
-  }
-  if (!return_info.type_id.has_value()) {
-    return GetTupleType(context, {});
-  }
-  return return_info.type_id;
+  return arg_type_id;
 }
 
 auto CheckFunctionDefinitionSignature(Context& context,
@@ -143,9 +134,10 @@ auto CheckFunctionDefinitionSignature(Context& context,
       context.inst_blocks().GetOrEmpty(function.call_params_id);
 
   // Check the return type is complete.
-  if (function.return_type_inst_id.has_value()) {
-    CheckFunctionReturnType(context, SemIR::LocId(function.return_type_inst_id),
-                            function, SemIR::SpecificId::None);
+  for (auto return_pattern_id :
+       context.inst_blocks().GetOrEmpty(function.return_patterns_id)) {
+    CheckFunctionReturnPatternType(context, SemIR::LocId(return_pattern_id),
+                                   return_pattern_id, SemIR::SpecificId::None);
   }
 
   // Check the parameter types are complete.

+ 8 - 6
toolchain/check/function.h

@@ -53,12 +53,14 @@ inline auto CheckFunctionTypeMatches(Context& context,
                                   /*check_syntax=*/true, /*check_self=*/true);
 }
 
-// Checks that the return type of the specified function is complete, issuing an
-// error if not. This computes the return slot usage for the function if
-// necessary, and returns the function's return type.
-auto CheckFunctionReturnType(Context& context, SemIR::LocId loc_id,
-                             const SemIR::Function& function,
-                             SemIR::SpecificId specific_id) -> SemIR::TypeId;
+// Checks that the scrutinee type of `return_pattern_id` in `specific_id` is
+// concrete. If so, it returns that type; if not, it issues an error and returns
+// SemIR::ErrorInst::TypeId. `return_pattern_id` must be part of a function's
+// return form, or the error message will be nonsensical.
+auto CheckFunctionReturnPatternType(Context& context, SemIR::LocId loc_id,
+                                    SemIR::InstId return_pattern_id,
+                                    SemIR::SpecificId specific_id)
+    -> SemIR::TypeId;
 
 // Checks that a function declaration's signature is suitable to support a
 // function definition. This requires the parameter types to be complete and the

+ 14 - 8
toolchain/check/return.cpp

@@ -75,15 +75,10 @@ auto RegisterReturnedVar(Context& context, Parse::NodeId returned_node,
                          Parse::NodeId type_node, SemIR::TypeId type_id,
                          SemIR::InstId bind_id) -> void {
   auto& function = GetCurrentFunctionForReturn(context);
-  auto return_info =
-      SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function);
-  if (!return_info.is_valid()) {
-    // We already diagnosed this when we started defining the function.
-    return;
-  }
+  auto return_type_id = function.GetDeclaredReturnType(context.sem_ir());
 
   // A `returned var` requires an explicit return type.
-  if (!return_info.type_id.has_value()) {
+  if (!return_type_id.has_value()) {
     CARBON_DIAGNOSTIC(ReturnedVarWithNoReturnType, Error,
                       "cannot declare a `returned var` in this function");
     auto diag =
@@ -94,7 +89,7 @@ auto RegisterReturnedVar(Context& context, Parse::NodeId returned_node,
   }
 
   // The declared type of the var must match the return type of the function.
-  if (return_info.type_id != type_id) {
+  if (return_type_id != type_id) {
     CARBON_DIAGNOSTIC(ReturnedVarWrongType, Error,
                       "type {0} of `returned var` does not match "
                       "return type of enclosing function",
@@ -105,6 +100,17 @@ auto RegisterReturnedVar(Context& context, Parse::NodeId returned_node,
     diag.Emit();
   }
 
+  auto form_inst_id = function.GetDeclaredReturnForm(context.sem_ir());
+  if (!context.insts().Is<SemIR::InitForm>(form_inst_id)) {
+    CARBON_DIAGNOSTIC(ReturnedVarNotInit, Error,
+                      "`returned var` declaration in function with "
+                      "non-initializing return form");
+    auto diag = context.emitter().Build(returned_node, ReturnedVarNotInit);
+    CARBON_DIAGNOSTIC(ReturnFormHereNote, Note, "return form declared here");
+    diag.Note(function.return_form_inst_id, ReturnFormHereNote);
+    diag.Emit();
+  }
+
   auto existing_id = context.scope_stack().SetReturnedVarOrGetExisting(bind_id);
   if (existing_id.has_value()) {
     CARBON_DIAGNOSTIC(ReturnedVarShadowed, Error,

+ 3 - 3
toolchain/check/testdata/interop/cpp/function/class.carbon

@@ -452,9 +452,9 @@ fn F() {
   // CHECK:STDERR: class C;
   // CHECK:STDERR:       ^
   // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-14]]:10: in file included here [InCppInclude]
-  // CHECK:STDERR: ./decl_value_return_type.h:2:7: note: return type declared here [IncompleteReturnTypeHere]
-  // CHECK:STDERR: class C;
-  // CHECK:STDERR:       ^
+  // CHECK:STDERR: ./decl_value_return_type.h:4:1: note: return type declared here [IncompleteReturnTypeHere]
+  // CHECK:STDERR: auto foo() -> C;
+  // CHECK:STDERR: ^
   // CHECK:STDERR:
   Cpp.foo();
 }

+ 3 - 3
toolchain/check/testdata/interop/cpp/function/struct.carbon

@@ -451,9 +451,9 @@ fn F() {
   // CHECK:STDERR: struct S;
   // CHECK:STDERR:        ^
   // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-14]]:10: in file included here [InCppInclude]
-  // CHECK:STDERR: ./decl_value_return_type.h:2:8: note: return type declared here [IncompleteReturnTypeHere]
-  // CHECK:STDERR: struct S;
-  // CHECK:STDERR:        ^
+  // CHECK:STDERR: ./decl_value_return_type.h:4:1: note: return type declared here [IncompleteReturnTypeHere]
+  // CHECK:STDERR: auto foo() -> S;
+  // CHECK:STDERR: ^
   // CHECK:STDERR:
   Cpp.foo();
 }

+ 3 - 3
toolchain/check/testdata/interop/cpp/function/union.carbon

@@ -413,9 +413,9 @@ fn F() {
   // CHECK:STDERR: union U;
   // CHECK:STDERR:       ^
   // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-14]]:10: in file included here [InCppInclude]
-  // CHECK:STDERR: ./decl_value_return_type.h:2:7: note: return type declared here [IncompleteReturnTypeHere]
-  // CHECK:STDERR: union U;
-  // CHECK:STDERR:       ^
+  // CHECK:STDERR: ./decl_value_return_type.h:4:1: note: return type declared here [IncompleteReturnTypeHere]
+  // CHECK:STDERR: auto foo() -> U;
+  // CHECK:STDERR: ^
   // CHECK:STDERR:
   Cpp.foo();
 }

+ 24 - 0
toolchain/check/testdata/return/fail_returned_var_form.carbon

@@ -0,0 +1,24 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon
+// EXTRA-ARGS: --dump-sem-ir-ranges=only
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/return/fail_returned_var_form.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/return/fail_returned_var_form.carbon
+
+fn Mismatch() -> ref () {
+  // CHECK:STDERR: fail_returned_var_form.carbon:[[@LINE+7]]:3: error: `returned var` declaration in function with non-initializing return form [ReturnedVarNotInit]
+  // CHECK:STDERR:   returned var v: () = ();
+  // CHECK:STDERR:   ^~~~~~~~
+  // CHECK:STDERR: fail_returned_var_form.carbon:[[@LINE-4]]:18: note: return form declared here [ReturnFormHereNote]
+  // CHECK:STDERR: fn Mismatch() -> ref () {
+  // CHECK:STDERR:                  ^~~~~~
+  // CHECK:STDERR:
+  returned var v: () = ();
+  return var;
+}

+ 2 - 0
toolchain/diagnostics/diagnostic_kind.def

@@ -469,10 +469,12 @@ CARBON_DIAGNOSTIC_KIND(TupleIndexOutOfBounds)
 CARBON_DIAGNOSTIC_KIND(TupleInitElementCountMismatch)
 CARBON_DIAGNOSTIC_KIND(PartialOnFinal)
 CARBON_DIAGNOSTIC_KIND(ReturnedVarHere)
+CARBON_DIAGNOSTIC_KIND(ReturnedVarNotInit)
 CARBON_DIAGNOSTIC_KIND(ReturnedVarShadowed)
 CARBON_DIAGNOSTIC_KIND(ReturnedVarWithNoReturnType)
 CARBON_DIAGNOSTIC_KIND(ReturnedVarWrongType)
 CARBON_DIAGNOSTIC_KIND(ReturnExprWithReturnedVar)
+CARBON_DIAGNOSTIC_KIND(ReturnFormHereNote)
 CARBON_DIAGNOSTIC_KIND(ReturnVarWithNoReturnedVar)
 CARBON_DIAGNOSTIC_KIND(ReturnStatementDisallowExpr)
 CARBON_DIAGNOSTIC_KIND(ReturnTypeHereNote)

+ 30 - 6
toolchain/sem_ir/expr_info.cpp

@@ -174,15 +174,39 @@ auto FindReturnSlotArgForInitializer(const File& sem_ir, InstId init_id)
         return init.dest_id;
       }
       case CARBON_KIND(Call call): {
-        if (!ReturnTypeInfo::ForCallee(sem_ir, call.callee_id)
-                 .has_return_slot()) {
+        auto callee_function = GetCalleeAsFunction(sem_ir, call.callee_id);
+        const auto& function =
+            sem_ir.functions().Get(callee_function.function_id);
+        if (!function.return_form_inst_id.has_value()) {
           return InstId::None;
         }
-        if (!call.args_id.has_value()) {
-          // Argument initialization failed, so we have no return slot.
-          return InstId::None;
+        auto return_form_constant_id = GetConstantValueInSpecific(
+            sem_ir, callee_function.resolved_specific_id,
+            function.return_form_inst_id);
+        auto return_form = sem_ir.insts().Get(
+            sem_ir.constant_values().GetInstId(return_form_constant_id));
+        CARBON_KIND_SWITCH(return_form) {
+          case CARBON_KIND(InitForm init_form): {
+            auto type_id = sem_ir.types().GetTypeIdForTypeInstId(
+                init_form.type_component_inst_id);
+            if (!InitRepr::ForType(sem_ir, type_id).MightBeInPlace()) {
+              return InstId::None;
+            }
+
+            if (!call.args_id.has_value()) {
+              // Argument initialization failed, so we have no return slot.
+              return InstId::None;
+            }
+
+            return sem_ir.inst_blocks().Get(
+                call.args_id)[init_form.index.index];
+          }
+          case CARBON_KIND(RefForm _): {
+            return InstId::None;
+          }
+          default:
+            CARBON_FATAL("Unexpected inst kind: {0}", return_form);
         }
-        return sem_ir.inst_blocks().Get(call.args_id).back();
       }
       case CARBON_KIND(ErrorInst _): {
         return InstId::None;