expr_info.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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. #include "toolchain/sem_ir/expr_info.h"
  5. #include "common/check.h"
  6. #include "toolchain/base/kind_switch.h"
  7. #include "toolchain/sem_ir/typed_insts.h"
  8. namespace Carbon::SemIR {
  9. auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
  10. const File* ir = &file;
  11. // The overall expression category if the current instruction is a value
  12. // expression.
  13. ExprCategory value_category = ExprCategory::Value;
  14. while (true) {
  15. auto untyped_inst = ir->insts().Get(inst_id);
  16. CARBON_KIND_SWITCH(untyped_inst) {
  17. case AdaptDecl::Kind:
  18. case AddrPattern::Kind:
  19. case Assign::Kind:
  20. case BaseDecl::Kind:
  21. case BindingPattern::Kind:
  22. case Branch::Kind:
  23. case BranchIf::Kind:
  24. case BranchWithArg::Kind:
  25. case FieldDecl::Kind:
  26. case FunctionDecl::Kind:
  27. case ImplDecl::Kind:
  28. case NameBindingDecl::Kind:
  29. case Namespace::Kind:
  30. case OutParamPattern::Kind:
  31. case RefParamPattern::Kind:
  32. case RequirementEquivalent::Kind:
  33. case RequirementImpls::Kind:
  34. case RequirementRewrite::Kind:
  35. case Return::Kind:
  36. case ReturnSlotPattern::Kind:
  37. case ReturnExpr::Kind:
  38. case SymbolicBindingPattern::Kind:
  39. case TuplePattern::Kind:
  40. case ValueParamPattern::Kind:
  41. case VarPattern::Kind:
  42. return ExprCategory::NotExpr;
  43. case ImportRefUnloaded::Kind:
  44. case ImportRefLoaded::Kind: {
  45. auto import_ir_inst = ir->import_ir_insts().Get(
  46. untyped_inst.As<AnyImportRef>().import_ir_inst_id);
  47. ir = ir->import_irs().Get(import_ir_inst.ir_id()).sem_ir;
  48. inst_id = import_ir_inst.inst_id();
  49. continue;
  50. }
  51. case CARBON_KIND(AsCompatible inst): {
  52. inst_id = inst.source_id;
  53. continue;
  54. }
  55. case CARBON_KIND(BindAlias inst): {
  56. inst_id = inst.value_id;
  57. continue;
  58. }
  59. case CARBON_KIND(ExportDecl inst): {
  60. inst_id = inst.value_id;
  61. continue;
  62. }
  63. case CARBON_KIND(NameRef inst): {
  64. inst_id = inst.value_id;
  65. continue;
  66. }
  67. case CARBON_KIND(Converted inst): {
  68. inst_id = inst.result_id;
  69. continue;
  70. }
  71. case CARBON_KIND(ImplWitnessAssociatedConstant inst): {
  72. inst_id = inst.inst_id;
  73. continue;
  74. }
  75. case CARBON_KIND(SpecificConstant inst): {
  76. inst_id = inst.inst_id;
  77. continue;
  78. }
  79. case AccessMemberAction::Kind:
  80. case AccessOptionalMemberAction::Kind:
  81. case AddrOf::Kind:
  82. case ArrayType::Kind:
  83. case AssociatedConstantDecl::Kind:
  84. case AssociatedEntity::Kind:
  85. case AssociatedEntityType::Kind:
  86. case AutoType::Kind:
  87. case BindSymbolicName::Kind:
  88. case BindValue::Kind:
  89. case BlockArg::Kind:
  90. case BoolLiteral::Kind:
  91. case BoolType::Kind:
  92. case BoundMethod::Kind:
  93. case BoundMethodType::Kind:
  94. case CharLiteralType::Kind:
  95. case CharLiteralValue::Kind:
  96. case ClassDecl::Kind:
  97. case ClassType::Kind:
  98. case CompleteTypeWitness::Kind:
  99. case ConstType::Kind:
  100. case ConvertToValueAction::Kind:
  101. case CustomLayoutType::Kind:
  102. case FacetAccessType::Kind:
  103. case FacetType::Kind:
  104. case FacetValue::Kind:
  105. case FloatType::Kind:
  106. case FloatValue::Kind:
  107. case FunctionType::Kind:
  108. case FunctionTypeWithSelfType::Kind:
  109. case GenericClassType::Kind:
  110. case GenericInterfaceType::Kind:
  111. case LookupImplWitness::Kind:
  112. case ImplWitness::Kind:
  113. case ImplWitnessAccess::Kind:
  114. case ImplWitnessTable::Kind:
  115. case ImplWitnessTablePlaceholder::Kind:
  116. case ImportCppDecl::Kind:
  117. case ImportDecl::Kind:
  118. case InstType::Kind:
  119. case InstValue::Kind:
  120. case IntLiteralType::Kind:
  121. case IntType::Kind:
  122. case IntValue::Kind:
  123. case InterfaceDecl::Kind:
  124. case LegacyFloatType::Kind:
  125. case NamespaceType::Kind:
  126. case PartialType::Kind:
  127. case PatternType::Kind:
  128. case PointerType::Kind:
  129. case RefineTypeAction::Kind:
  130. case RequireCompleteType::Kind:
  131. case SpecificFunction::Kind:
  132. case SpecificFunctionType::Kind:
  133. case SpecificImplFunction::Kind:
  134. case StringLiteral::Kind:
  135. case StringType::Kind:
  136. case StructType::Kind:
  137. case StructValue::Kind:
  138. case TupleType::Kind:
  139. case TupleValue::Kind:
  140. case TypeOfInst::Kind:
  141. case TypeType::Kind:
  142. case UnaryOperatorNot::Kind:
  143. case UnboundElementType::Kind:
  144. case ValueOfInitializer::Kind:
  145. case ValueParam::Kind:
  146. case VtableType::Kind:
  147. case WhereExpr::Kind:
  148. case WitnessType::Kind:
  149. return value_category;
  150. case ErrorInst::Kind:
  151. return ExprCategory::Error;
  152. case CARBON_KIND(BindName inst): {
  153. // TODO: Don't rely on value_id for expression category, since it may
  154. // not be valid yet. This workaround only works because we don't support
  155. // `var` in function signatures yet.
  156. if (!inst.value_id.has_value()) {
  157. return value_category;
  158. }
  159. inst_id = inst.value_id;
  160. continue;
  161. }
  162. case CARBON_KIND(ArrayIndex inst): {
  163. inst_id = inst.array_id;
  164. continue;
  165. }
  166. case VtablePtr::Kind:
  167. return ExprCategory::EphemeralRef;
  168. case CARBON_KIND(ClassElementAccess inst): {
  169. inst_id = inst.base_id;
  170. // A value of class type is a pointer to an object representation.
  171. // Therefore, if the base is a value, the result is an ephemeral
  172. // reference.
  173. value_category = ExprCategory::EphemeralRef;
  174. continue;
  175. }
  176. case CARBON_KIND(StructAccess inst): {
  177. inst_id = inst.struct_id;
  178. continue;
  179. }
  180. case CARBON_KIND(TupleAccess inst): {
  181. inst_id = inst.tuple_id;
  182. continue;
  183. }
  184. case CARBON_KIND(SpliceBlock inst): {
  185. inst_id = inst.result_id;
  186. continue;
  187. }
  188. case SpliceInst::Kind:
  189. // TODO: Add ExprCategory::Dependent.
  190. return value_category;
  191. case StructLiteral::Kind:
  192. case TupleLiteral::Kind:
  193. return ExprCategory::Mixed;
  194. case ArrayInit::Kind:
  195. case Call::Kind:
  196. case InitializeFrom::Kind:
  197. case ClassInit::Kind:
  198. case StructInit::Kind:
  199. case TupleInit::Kind:
  200. return ExprCategory::Initializing;
  201. case Deref::Kind:
  202. case VarStorage::Kind:
  203. case ReturnSlot::Kind:
  204. return ExprCategory::DurableRef;
  205. case Temporary::Kind:
  206. case TemporaryStorage::Kind:
  207. case ValueAsRef::Kind:
  208. return ExprCategory::EphemeralRef;
  209. case OutParam::Kind:
  210. case RefParam::Kind:
  211. // TODO: Consider introducing a separate category for OutParam:
  212. // unlike other DurableRefs, it permits initialization.
  213. return ExprCategory::DurableRef;
  214. }
  215. }
  216. }
  217. auto FindReturnSlotArgForInitializer(const File& sem_ir, InstId init_id)
  218. -> InstId {
  219. while (true) {
  220. Inst init_untyped = sem_ir.insts().Get(init_id);
  221. CARBON_KIND_SWITCH(init_untyped) {
  222. case CARBON_KIND(AsCompatible init): {
  223. init_id = init.source_id;
  224. continue;
  225. }
  226. case CARBON_KIND(Converted init): {
  227. init_id = init.result_id;
  228. continue;
  229. }
  230. case CARBON_KIND(ArrayInit init): {
  231. return init.dest_id;
  232. }
  233. case CARBON_KIND(ClassInit init): {
  234. return init.dest_id;
  235. }
  236. case CARBON_KIND(StructInit init): {
  237. return init.dest_id;
  238. }
  239. case CARBON_KIND(TupleInit init): {
  240. return init.dest_id;
  241. }
  242. case CARBON_KIND(InitializeFrom init): {
  243. return init.dest_id;
  244. }
  245. case CARBON_KIND(Call call): {
  246. if (!ReturnTypeInfo::ForType(sem_ir, call.type_id).has_return_slot()) {
  247. return InstId::None;
  248. }
  249. if (!call.args_id.has_value()) {
  250. // Argument initialization failed, so we have no return slot.
  251. return InstId::None;
  252. }
  253. return sem_ir.inst_blocks().Get(call.args_id).back();
  254. }
  255. default:
  256. CARBON_FATAL("Initialization from unexpected inst {0}", init_untyped);
  257. }
  258. }
  259. }
  260. } // namespace Carbon::SemIR