eval.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
  127. -> SemIR::ConstantId {
  128. // TODO: Ensure we have test coverage for each of these cases that can result
  129. // in a constant, once those situations are all reachable.
  130. // clang warns on unhandled enum values; clang-tidy is incorrect here.
  131. // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
  132. switch (inst.kind()) {
  133. // These cases are constants if their operands are.
  134. case SemIR::AddrOf::Kind:
  135. return RebuildIfFieldsAreConstant(context, inst,
  136. &SemIR::AddrOf::lvalue_id);
  137. case SemIR::ArrayType::Kind:
  138. return RebuildIfFieldsAreConstant(context, inst,
  139. &SemIR::ArrayType::bound_id);
  140. case SemIR::BoundMethod::Kind:
  141. return RebuildIfFieldsAreConstant(context, inst,
  142. &SemIR::BoundMethod::object_id,
  143. &SemIR::BoundMethod::function_id);
  144. case SemIR::StructType::Kind:
  145. return RebuildIfFieldsAreConstant(context, inst,
  146. &SemIR::StructType::fields_id);
  147. case SemIR::StructValue::Kind:
  148. return RebuildIfFieldsAreConstant(context, inst,
  149. &SemIR::StructValue::elements_id);
  150. case SemIR::Temporary::Kind:
  151. return RebuildIfFieldsAreConstant(context, inst,
  152. &SemIR::Temporary::init_id);
  153. case SemIR::TupleValue::Kind:
  154. return RebuildIfFieldsAreConstant(context, inst,
  155. &SemIR::TupleValue::elements_id);
  156. // These cases are always constants.
  157. case SemIR::Builtin::Kind:
  158. case SemIR::ClassType::Kind:
  159. case SemIR::PointerType::Kind:
  160. case SemIR::StructTypeField::Kind:
  161. case SemIR::TupleType::Kind:
  162. case SemIR::UnboundElementType::Kind:
  163. // TODO: Propagate symbolic / template nature from operands.
  164. return MakeConstantResult(context, inst, Phase::Template);
  165. // These cases are treated as being the unique canonical definition of the
  166. // corresponding constant value.
  167. // TODO: This doesn't properly handle redeclarations. Consider adding a
  168. // corresponding `Value` inst for each of these cases.
  169. case SemIR::BaseDecl::Kind:
  170. case SemIR::FieldDecl::Kind:
  171. case SemIR::FunctionDecl::Kind:
  172. case SemIR::Namespace::Kind:
  173. return SemIR::ConstantId::ForTemplateConstant(inst_id);
  174. case SemIR::BoolLiteral::Kind:
  175. case SemIR::IntLiteral::Kind:
  176. case SemIR::RealLiteral::Kind:
  177. case SemIR::StringLiteral::Kind:
  178. // Promote literals to the constant block.
  179. // TODO: Convert literals into a canonical form. Currently we can form two
  180. // different `i32` constants with the same value if they are represented
  181. // by `APInt`s with different bit widths.
  182. return MakeConstantResult(context, inst, Phase::Template);
  183. // TODO: These need special handling.
  184. case SemIR::ArrayIndex::Kind:
  185. case SemIR::ArrayInit::Kind:
  186. case SemIR::BindValue::Kind:
  187. case SemIR::Call::Kind:
  188. case SemIR::ClassElementAccess::Kind:
  189. case SemIR::ClassInit::Kind:
  190. case SemIR::CrossRef::Kind:
  191. case SemIR::Deref::Kind:
  192. case SemIR::InitializeFrom::Kind:
  193. case SemIR::SpliceBlock::Kind:
  194. case SemIR::StructAccess::Kind:
  195. case SemIR::StructInit::Kind:
  196. case SemIR::TemporaryStorage::Kind:
  197. case SemIR::TupleAccess::Kind:
  198. case SemIR::TupleIndex::Kind:
  199. case SemIR::TupleInit::Kind:
  200. case SemIR::ValueAsRef::Kind:
  201. case SemIR::ValueOfInitializer::Kind:
  202. break;
  203. case SemIR::BindSymbolicName::Kind:
  204. // TODO: Consider forming a constant value here using a de Bruijn index or
  205. // similar, so that corresponding symbolic parameters in redeclarations
  206. // are treated as the same value.
  207. return SemIR::ConstantId::ForSymbolicConstant(inst_id);
  208. case SemIR::BindName::Kind:
  209. // TODO: We need to look through `BindName`s for member accesses naming
  210. // fields, where the member name is a `BindName`. Should we really be
  211. // creating a `BindName` in that case?
  212. return context.constant_values().Get(inst.As<SemIR::BindName>().value_id);
  213. case SemIR::NameRef::Kind:
  214. return context.constant_values().Get(inst.As<SemIR::NameRef>().value_id);
  215. case SemIR::Converted::Kind:
  216. return context.constant_values().Get(
  217. inst.As<SemIR::Converted>().result_id);
  218. // `not true` -> `false`, `not false` -> `true`.
  219. // All other uses of unary `not` are non-constant.
  220. case SemIR::UnaryOperatorNot::Kind: {
  221. auto const_id = context.constant_values().Get(
  222. inst.As<SemIR::UnaryOperatorNot>().operand_id);
  223. auto phase = GetPhase(const_id);
  224. if (phase == Phase::Template) {
  225. auto value =
  226. context.insts().GetAs<SemIR::BoolLiteral>(const_id.inst_id());
  227. value.value =
  228. (value.value == SemIR::BoolValue::False ? SemIR::BoolValue::True
  229. : SemIR::BoolValue::False);
  230. return MakeConstantResult(context, value, Phase::Template);
  231. }
  232. if (phase == Phase::UnknownDueToError) {
  233. return SemIR::ConstantId::Error;
  234. }
  235. break;
  236. }
  237. // `const (const T)` evaluates to `const T`. Otherwise, `const T` evaluates
  238. // to itself.
  239. case SemIR::ConstType::Kind: {
  240. auto inner_id = context.constant_values().Get(
  241. context.types().GetInstId(inst.As<SemIR::ConstType>().inner_id));
  242. if (inner_id.is_constant() &&
  243. context.insts().Get(inner_id.inst_id()).Is<SemIR::ConstType>()) {
  244. return inner_id;
  245. }
  246. return MakeConstantResult(context, inst, GetPhase(inner_id));
  247. }
  248. // These cases are either not expressions or not constant.
  249. case SemIR::AddrPattern::Kind:
  250. case SemIR::Assign::Kind:
  251. case SemIR::BlockArg::Kind:
  252. case SemIR::Branch::Kind:
  253. case SemIR::BranchIf::Kind:
  254. case SemIR::BranchWithArg::Kind:
  255. case SemIR::ClassDecl::Kind:
  256. case SemIR::Import::Kind:
  257. case SemIR::InterfaceDecl::Kind:
  258. case SemIR::LazyImportRef::Kind:
  259. case SemIR::Param::Kind:
  260. case SemIR::ReturnExpr::Kind:
  261. case SemIR::Return::Kind:
  262. case SemIR::StructLiteral::Kind:
  263. case SemIR::TupleLiteral::Kind:
  264. case SemIR::VarStorage::Kind:
  265. break;
  266. }
  267. return SemIR::ConstantId::NotConstant;
  268. }
  269. } // namespace Carbon::Check