expr_info.cpp 8.3 KB

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