convert.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_CHECK_CONVERT_H_
  5. #define CARBON_TOOLCHAIN_CHECK_CONVERT_H_
  6. #include "toolchain/check/context.h"
  7. #include "toolchain/check/pending_block.h"
  8. #include "toolchain/sem_ir/entity_with_params_base.h"
  9. #include "toolchain/sem_ir/ids.h"
  10. namespace Carbon::Check {
  11. // Description of the target of a conversion.
  12. struct ConversionTarget {
  13. enum Kind : int8_t {
  14. // Convert to a value of type `type_id`.
  15. Value,
  16. // Convert to either a value or a reference of type `type_id`.
  17. ValueOrRef,
  18. // Convert to a durable reference of type `type_id`.
  19. DurableRef,
  20. // Convert to a reference, suitable for binding to a reference parameter.
  21. // This allows both durable and ephemeral references. The restriction that
  22. // only a `ref self` parameter can bind to an ephemeral reference is
  23. // enforced separately when handling `ref` tags on call arguments.
  24. RefParam,
  25. // Equivalent to RefParam, except that the source expression is not required
  26. // to be marked with a `ref` tag, such as an argument to a `ref self`
  27. // parameter or an operator operand.
  28. UnmarkedRefParam,
  29. // Convert to a reference of type `type_id`, for use as the argument to a
  30. // C++ thunk.
  31. CppThunkRef,
  32. // Convert for an explicit `as` cast. This allows any expression category
  33. // as the result, and uses the `As` interface instead of the `ImplicitAs`
  34. // interface.
  35. ExplicitAs,
  36. // Convert for an explicit `unsafe as` cast. This allows any expression
  37. // category as the result, and uses the `UnsafeAs` interface instead of the
  38. // `As` or `ImplicitAs` interface.
  39. ExplicitUnsafeAs,
  40. // The result of the conversion is discarded. It can't be an initializing
  41. // expression, but can be anything else.
  42. Discarded,
  43. // Convert to an initializing expression that uses `type_id`'s initializing
  44. // representation. The resulting expression will usually be a
  45. // repr-initializing expression, but may be an in-place initializing
  46. // expression if the source expression was. If `storage_id` is present, it
  47. // is used as the storage argument for the converted expression, and it must
  48. // be present if the initializing representation might be in-place.
  49. Initializing,
  50. // Convert to an in-place initializing expression whose storage is
  51. // designated by `storage_id` (which must not be `None`)
  52. InPlaceInitializing,
  53. Last = InPlaceInitializing
  54. };
  55. // The kind of the target for this conversion.
  56. Kind kind;
  57. // The target type for the conversion.
  58. SemIR::TypeId type_id;
  59. // The storage being initialized, if any.
  60. SemIR::InstId storage_id = SemIR::InstId::None;
  61. // For an initializer, a block of pending instructions that `storage_id`
  62. // depends on, and that can be discarded if `storage_id` is not accessed.
  63. PendingBlock* storage_access_block = nullptr;
  64. // Whether failure of conversion is an error and is diagnosed to the user.
  65. // When looking for a possible conversion but with graceful fallback, diagnose
  66. // should be false.
  67. bool diagnose = true;
  68. // Are we converting this value into an initializer for an object?
  69. auto is_initializer() const -> bool {
  70. return kind == Initializing || kind == InPlaceInitializing;
  71. }
  72. // Is this some kind of explicit `as` conversion?
  73. auto is_explicit_as() const -> bool {
  74. return kind == ExplicitAs || kind == ExplicitUnsafeAs;
  75. }
  76. };
  77. // Convert a value to another type and expression category.
  78. // TODO: The `vtable_id` parameter is too much of a special case here, and
  79. // should be removed - once partial classes are implemented, the vtable pointer
  80. // initialization will be done not in this conversion, but during initialization
  81. // of the object of non-partial class type from the object of partial class
  82. // type.
  83. auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
  84. ConversionTarget target,
  85. SemIR::ClassType* vtable_class_type = nullptr) -> SemIR::InstId;
  86. // Converts `value_id` to an initializing expression of the type of
  87. // `storage_id`, and returns the possibly-converted initializing expression.
  88. // `storage_id` is used as the storage argument of the resulting expression
  89. // except as noted below. The caller is responsible for passing the result to an
  90. // inst that is documented as consuming it, such as `Assign`.
  91. //
  92. // `for_return` indicates that this conversion is initializing the operand of a
  93. // `return` statement. This means that `storage_id` will be the return slot
  94. // parameter, which isn't valid to access if the type's initializing
  95. // representation is not in-place, so in that case `storage_id` will be used
  96. // solely for its type.
  97. //
  98. // TODO: Consider making the target type a separate parameter, and making
  99. // storage_id optional.
  100. auto Initialize(Context& context, SemIR::LocId loc_id, SemIR::InstId storage_id,
  101. SemIR::InstId value_id, bool for_return = false)
  102. -> SemIR::InstId;
  103. // Convert the given expression to a value expression of the same type.
  104. auto ConvertToValueExpr(Context& context, SemIR::InstId expr_id)
  105. -> SemIR::InstId;
  106. // Convert the given expression to a value or reference expression of the same
  107. // type.
  108. auto ConvertToValueOrRefExpr(Context& context, SemIR::InstId expr_id)
  109. -> SemIR::InstId;
  110. // Converts `expr_id` to a value expression of type `type_id`.
  111. auto ConvertToValueOfType(Context& context, SemIR::LocId loc_id,
  112. SemIR::InstId expr_id, SemIR::TypeId type_id)
  113. -> SemIR::InstId;
  114. // Convert the given expression to a value or reference expression of the given
  115. // type.
  116. auto ConvertToValueOrRefOfType(Context& context, SemIR::LocId loc_id,
  117. SemIR::InstId expr_id, SemIR::TypeId type_id)
  118. -> SemIR::InstId;
  119. // Attempted to convert `expr_id` to a value expression of type `type_id`, with
  120. // graceful failure, which does not result in diagnostics. An ErrorInst
  121. // instruction is still returned on failure.
  122. auto TryConvertToValueOfType(Context& context, SemIR::LocId loc_id,
  123. SemIR::InstId expr_id, SemIR::TypeId type_id)
  124. -> SemIR::InstId;
  125. // Converts `value_id` to a value expression of type `bool`.
  126. auto ConvertToBoolValue(Context& context, SemIR::LocId loc_id,
  127. SemIR::InstId value_id) -> SemIR::InstId;
  128. // Converts `value_id` to type `type_id` for an `as` expression.
  129. auto ConvertForExplicitAs(Context& context, Parse::NodeId as_node,
  130. SemIR::InstId value_id, SemIR::TypeId type_id,
  131. bool unsafe) -> SemIR::InstId;
  132. // Implicitly converts a set of arguments to match the parameter types in a
  133. // function call. Returns a block containing the converted implicit and explicit
  134. // argument values for runtime parameters. `is_operator_syntax` indicates that
  135. // this call was generated from an operator rather than from function call
  136. // syntax, so arguments to `ref` parameters aren't required to have `ref` tags.
  137. auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id,
  138. SemIR::InstId self_id,
  139. llvm::ArrayRef<SemIR::InstId> arg_refs,
  140. llvm::ArrayRef<SemIR::InstId> return_arg_ids,
  141. const SemIR::Function& callee,
  142. SemIR::SpecificId callee_specific_id,
  143. bool is_operator_syntax) -> SemIR::InstBlockId;
  144. // A type that has been converted for use as a type expression.
  145. struct TypeExpr {
  146. static const TypeExpr None;
  147. // Returns a TypeExpr describing a type with no associated spelling or type
  148. // sugar.
  149. static auto ForUnsugared(Context& context, SemIR::TypeId type_id) -> TypeExpr;
  150. // The converted expression of type `type`, or `ErrorInst::InstId`.
  151. SemIR::TypeInstId inst_id;
  152. // The corresponding type, or `ErrorInst::TypeId`.
  153. SemIR::TypeId type_id;
  154. };
  155. inline constexpr TypeExpr TypeExpr::None = {.inst_id = SemIR::TypeInstId::None,
  156. .type_id = SemIR::TypeId::None};
  157. // Converts an expression for use as a type.
  158. //
  159. // If `diagnose` is true, errors are diagnosed to the user. Set it to false when
  160. // looking to see if a conversion is possible but with graceful fallback.
  161. //
  162. // TODO: Most of the callers of this function discard the `inst_id` and lose
  163. // track of the conversion. In most cases we should be retaining that as the
  164. // operand of some downstream instruction.
  165. auto ExprAsType(Context& context, SemIR::LocId loc_id, SemIR::InstId value_id,
  166. bool diagnose = true) -> TypeExpr;
  167. // Converts an expression for use as a form. If the expression is a type
  168. // expression, it is interpreted as an initializing form.
  169. auto ExprAsReturnForm(Context& context, SemIR::LocId loc_id,
  170. SemIR::InstId value_id) -> Context::FormExpr;
  171. // Handles an expression whose result value is unused.
  172. auto DiscardExpr(Context& context, SemIR::InstId expr_id) -> void;
  173. } // namespace Carbon::Check
  174. #endif // CARBON_TOOLCHAIN_CHECK_CONVERT_H_