eval.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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/check/eval.h"
  5. #include "toolchain/sem_ir/ids.h"
  6. #include "toolchain/sem_ir/typed_insts.h"
  7. #include "toolchain/sem_ir/value_stores.h"
  8. namespace Carbon::Check {
  9. namespace {
  10. // The evaluation phase for an expression, computed by evaluation. These are
  11. // ordered so that the phase of an expression is the numerically highest phase
  12. // of its constituent evaluations. Note that an expression with any runtime
  13. // component is known to have Runtime phase even if it involves an evaluation
  14. // with UnknownDueToError phase.
  15. enum class Phase : uint8_t {
  16. // Value could be entirely and concretely computed.
  17. Template,
  18. // Evaluation phase is symbolic because the expression involves a reference to
  19. // a symbolic binding.
  20. Symbolic,
  21. // The evaluation phase is unknown because evaluation encountered an
  22. // already-diagnosed semantic or syntax error. This is treated as being
  23. // potentially constant, but with an unknown phase.
  24. UnknownDueToError,
  25. // The expression has runtime phase because of a non-constant subexpression.
  26. Runtime,
  27. };
  28. } // namespace
  29. // Gets the phase in which the value of a constant will become available.
  30. static auto GetPhase(SemIR::ConstantId constant_id) -> Phase {
  31. if (!constant_id.is_constant()) {
  32. return Phase::Runtime;
  33. } else if (constant_id == SemIR::ConstantId::Error) {
  34. return Phase::UnknownDueToError;
  35. } else if (constant_id.is_template()) {
  36. return Phase::Template;
  37. } else {
  38. return Phase::Symbolic;
  39. }
  40. }
  41. // Returns the later of two phases.
  42. static auto LatestPhase(Phase a, Phase b) -> Phase {
  43. return static_cast<Phase>(
  44. std::max(static_cast<uint8_t>(a), static_cast<uint8_t>(b)));
  45. }
  46. // Forms a `constant_id` describing a given evaluation result.
  47. static auto MakeConstantResult(Context& context, SemIR::Inst inst, Phase phase)
  48. -> SemIR::ConstantId {
  49. switch (phase) {
  50. case Phase::Template:
  51. return context.AddConstant(inst, /*is_symbolic=*/false);
  52. case Phase::Symbolic:
  53. return context.AddConstant(inst, /*is_symbolic=*/true);
  54. case Phase::UnknownDueToError:
  55. return SemIR::ConstantId::Error;
  56. case Phase::Runtime:
  57. return SemIR::ConstantId::NotConstant;
  58. }
  59. }
  60. // `GetConstantValue` checks to see whether the provided ID describes a value
  61. // with constant phase, and if so, returns the corresponding constant value.
  62. // Overloads are provided for different kinds of ID.
  63. // If the given instruction is constant, returns its constant value.
  64. static auto GetConstantValue(Context& context, SemIR::InstId inst_id,
  65. Phase* phase) -> SemIR::InstId {
  66. auto const_id = context.constant_values().Get(inst_id);
  67. *phase = LatestPhase(*phase, GetPhase(const_id));
  68. return const_id.inst_id();
  69. }
  70. // If the given instruction block contains only constants, returns a
  71. // corresponding block of those values.
  72. static auto GetConstantValue(Context& context, SemIR::InstBlockId inst_block_id,
  73. Phase* phase) -> SemIR::InstBlockId {
  74. auto insts = context.inst_blocks().Get(inst_block_id);
  75. llvm::SmallVector<SemIR::InstId> const_insts;
  76. for (auto inst_id : insts) {
  77. auto const_inst_id = GetConstantValue(context, inst_id, phase);
  78. if (!const_inst_id.is_valid()) {
  79. return SemIR::InstBlockId::Invalid;
  80. }
  81. // Once we leave the small buffer, we know the first few elements are all
  82. // constant, so it's likely that the entire block is constant. Resize to the
  83. // target size given that we're going to allocate memory now anyway.
  84. if (const_insts.size() == const_insts.capacity()) {
  85. const_insts.reserve(insts.size());
  86. }
  87. const_insts.push_back(const_inst_id);
  88. }
  89. // TODO: If the new block is identical to the original block, return the
  90. // original ID.
  91. return context.inst_blocks().Add(const_insts);
  92. }
  93. // Replaces the specified field of the given typed instruction with its constant
  94. // value, if it has constant phase. Returns true on success, false if the value
  95. // has runtime phase.
  96. template <typename InstT, typename FieldIdT>
  97. static auto ReplaceFieldWithConstantValue(Context& context, InstT* inst,
  98. FieldIdT InstT::*field, Phase* phase)
  99. -> bool {
  100. auto unwrapped = GetConstantValue(context, inst->*field, phase);
  101. if (!unwrapped.is_valid()) {
  102. return false;
  103. }
  104. inst->*field = unwrapped;
  105. return true;
  106. }
  107. // If the specified fields of the given typed instruction have constant values,
  108. // replaces the fields with their constant values and builds a corresponding
  109. // constant value. Otherwise returns `SemIR::InstId::Invalid`.
  110. template <typename InstT, typename... EachFieldIdT>
  111. static auto RebuildIfFieldsAreConstant(Context& context, SemIR::Inst inst,
  112. EachFieldIdT InstT::*... each_field_id)
  113. -> SemIR::ConstantId {
  114. // Build a constant instruction by replacing each non-constant operand with
  115. // its constant value.
  116. auto typed_inst = inst.As<InstT>();
  117. Phase phase = Phase::Template;
  118. if ((ReplaceFieldWithConstantValue(context, &typed_inst, each_field_id,
  119. &phase) &&
  120. ...)) {
  121. return MakeConstantResult(context, typed_inst, phase);
  122. }
  123. return phase == Phase::UnknownDueToError ? SemIR::ConstantId::Error
  124. : SemIR::ConstantId::NotConstant;
  125. }
  126. // Rebuilds the given aggregate initialization instruction as a corresponding
  127. // constant aggregate value, if its elements are all constants.
  128. static auto RebuildInitAsValue(Context& context, SemIR::Inst inst,
  129. SemIR::InstKind value_kind)
  130. -> SemIR::ConstantId {
  131. auto init_inst = inst.As<SemIR::AnyAggregateInit>();
  132. Phase phase = Phase::Template;
  133. auto elements_id = GetConstantValue(context, init_inst.elements_id, &phase);
  134. return MakeConstantResult(
  135. context,
  136. SemIR::AnyAggregateValue{.kind = value_kind,
  137. .type_id = init_inst.type_id,
  138. .elements_id = elements_id},
  139. phase);
  140. }
  141. auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
  142. -> SemIR::ConstantId {
  143. // TODO: Ensure we have test coverage for each of these cases that can result
  144. // in a constant, once those situations are all reachable.
  145. // clang warns on unhandled enum values; clang-tidy is incorrect here.
  146. // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
  147. switch (inst.kind()) {
  148. // These cases are constants if their operands are.
  149. case SemIR::AddrOf::Kind:
  150. return RebuildIfFieldsAreConstant(context, inst,
  151. &SemIR::AddrOf::lvalue_id);
  152. case SemIR::ArrayType::Kind:
  153. return RebuildIfFieldsAreConstant(context, inst,
  154. &SemIR::ArrayType::bound_id);
  155. case SemIR::BoundMethod::Kind:
  156. return RebuildIfFieldsAreConstant(context, inst,
  157. &SemIR::BoundMethod::object_id,
  158. &SemIR::BoundMethod::function_id);
  159. case SemIR::StructType::Kind:
  160. return RebuildIfFieldsAreConstant(context, inst,
  161. &SemIR::StructType::fields_id);
  162. case SemIR::StructValue::Kind:
  163. return RebuildIfFieldsAreConstant(context, inst,
  164. &SemIR::StructValue::elements_id);
  165. case SemIR::TupleValue::Kind:
  166. return RebuildIfFieldsAreConstant(context, inst,
  167. &SemIR::TupleValue::elements_id);
  168. // Initializers evaluate to a value of the object representation.
  169. case SemIR::ArrayInit::Kind:
  170. // TODO: Add an `ArrayValue` to represent a constant array object
  171. // representation instead of using a `TupleValue`.
  172. return RebuildInitAsValue(context, inst, SemIR::TupleValue::Kind);
  173. case SemIR::ClassInit::Kind:
  174. // TODO: Add a `ClassValue` to represent a constant class object
  175. // representation instead of using a `StructValue`.
  176. return RebuildInitAsValue(context, inst, SemIR::StructValue::Kind);
  177. case SemIR::StructInit::Kind:
  178. return RebuildInitAsValue(context, inst, SemIR::StructValue::Kind);
  179. case SemIR::TupleInit::Kind:
  180. return RebuildInitAsValue(context, inst, SemIR::TupleValue::Kind);
  181. // These cases are always constants.
  182. case SemIR::Builtin::Kind:
  183. case SemIR::ClassType::Kind:
  184. case SemIR::PointerType::Kind:
  185. case SemIR::StructTypeField::Kind:
  186. case SemIR::TupleType::Kind:
  187. case SemIR::UnboundElementType::Kind:
  188. // TODO: Propagate symbolic / template nature from operands.
  189. return MakeConstantResult(context, inst, Phase::Template);
  190. // These cases are treated as being the unique canonical definition of the
  191. // corresponding constant value.
  192. // TODO: This doesn't properly handle redeclarations. Consider adding a
  193. // corresponding `Value` inst for each of these cases.
  194. case SemIR::BaseDecl::Kind:
  195. case SemIR::FieldDecl::Kind:
  196. case SemIR::FunctionDecl::Kind:
  197. case SemIR::Namespace::Kind:
  198. return SemIR::ConstantId::ForTemplateConstant(inst_id);
  199. case SemIR::BoolLiteral::Kind:
  200. case SemIR::IntLiteral::Kind:
  201. case SemIR::RealLiteral::Kind:
  202. case SemIR::StringLiteral::Kind:
  203. // Promote literals to the constant block.
  204. // TODO: Convert literals into a canonical form. Currently we can form two
  205. // different `i32` constants with the same value if they are represented
  206. // by `APInt`s with different bit widths.
  207. return MakeConstantResult(context, inst, Phase::Template);
  208. // TODO: Support subobject access.
  209. case SemIR::ArrayIndex::Kind:
  210. case SemIR::ClassElementAccess::Kind:
  211. case SemIR::StructAccess::Kind:
  212. case SemIR::TupleAccess::Kind:
  213. case SemIR::TupleIndex::Kind:
  214. break;
  215. // TODO: These need special handling.
  216. case SemIR::BindValue::Kind:
  217. case SemIR::Call::Kind:
  218. case SemIR::CrossRef::Kind:
  219. case SemIR::Deref::Kind:
  220. case SemIR::Temporary::Kind:
  221. case SemIR::TemporaryStorage::Kind:
  222. case SemIR::ValueAsRef::Kind:
  223. break;
  224. case SemIR::BindSymbolicName::Kind:
  225. // TODO: Consider forming a constant value here using a de Bruijn index or
  226. // similar, so that corresponding symbolic parameters in redeclarations
  227. // are treated as the same value.
  228. return SemIR::ConstantId::ForSymbolicConstant(inst_id);
  229. case SemIR::BindName::Kind:
  230. // TODO: We need to look through `BindName`s for member accesses naming
  231. // fields, where the member name is a `BindName`. Should we really be
  232. // creating a `BindName` in that case?
  233. return context.constant_values().Get(inst.As<SemIR::BindName>().value_id);
  234. // These semnatic wrappers don't change the constant value.
  235. case SemIR::NameRef::Kind:
  236. return context.constant_values().Get(inst.As<SemIR::NameRef>().value_id);
  237. case SemIR::Converted::Kind:
  238. return context.constant_values().Get(
  239. inst.As<SemIR::Converted>().result_id);
  240. case SemIR::InitializeFrom::Kind:
  241. return context.constant_values().Get(
  242. inst.As<SemIR::InitializeFrom>().src_id);
  243. case SemIR::SpliceBlock::Kind:
  244. return context.constant_values().Get(
  245. inst.As<SemIR::SpliceBlock>().result_id);
  246. case SemIR::ValueOfInitializer::Kind:
  247. return context.constant_values().Get(
  248. inst.As<SemIR::ValueOfInitializer>().init_id);
  249. // `not true` -> `false`, `not false` -> `true`.
  250. // All other uses of unary `not` are non-constant.
  251. case SemIR::UnaryOperatorNot::Kind: {
  252. auto const_id = context.constant_values().Get(
  253. inst.As<SemIR::UnaryOperatorNot>().operand_id);
  254. auto phase = GetPhase(const_id);
  255. if (phase == Phase::Template) {
  256. auto value =
  257. context.insts().GetAs<SemIR::BoolLiteral>(const_id.inst_id());
  258. value.value =
  259. (value.value == SemIR::BoolValue::False ? SemIR::BoolValue::True
  260. : SemIR::BoolValue::False);
  261. return MakeConstantResult(context, value, Phase::Template);
  262. }
  263. if (phase == Phase::UnknownDueToError) {
  264. return SemIR::ConstantId::Error;
  265. }
  266. break;
  267. }
  268. // `const (const T)` evaluates to `const T`. Otherwise, `const T` evaluates
  269. // to itself.
  270. case SemIR::ConstType::Kind: {
  271. auto inner_id = context.constant_values().Get(
  272. context.types().GetInstId(inst.As<SemIR::ConstType>().inner_id));
  273. if (inner_id.is_constant() &&
  274. context.insts().Get(inner_id.inst_id()).Is<SemIR::ConstType>()) {
  275. return inner_id;
  276. }
  277. return MakeConstantResult(context, inst, GetPhase(inner_id));
  278. }
  279. // These cases are either not expressions or not constant.
  280. case SemIR::AddrPattern::Kind:
  281. case SemIR::Assign::Kind:
  282. case SemIR::BlockArg::Kind:
  283. case SemIR::Branch::Kind:
  284. case SemIR::BranchIf::Kind:
  285. case SemIR::BranchWithArg::Kind:
  286. case SemIR::ClassDecl::Kind:
  287. case SemIR::Import::Kind:
  288. case SemIR::InterfaceDecl::Kind:
  289. case SemIR::LazyImportRef::Kind:
  290. case SemIR::Param::Kind:
  291. case SemIR::ReturnExpr::Kind:
  292. case SemIR::Return::Kind:
  293. case SemIR::StructLiteral::Kind:
  294. case SemIR::TupleLiteral::Kind:
  295. case SemIR::VarStorage::Kind:
  296. break;
  297. }
  298. return SemIR::ConstantId::NotConstant;
  299. }
  300. } // namespace Carbon::Check