file.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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/file.h"
  5. #include "common/check.h"
  6. #include "llvm/ADT/STLExtras.h"
  7. #include "llvm/ADT/SmallVector.h"
  8. #include "toolchain/sem_ir/builtin_kind.h"
  9. #include "toolchain/sem_ir/node.h"
  10. #include "toolchain/sem_ir/node_kind.h"
  11. namespace Carbon::SemIR {
  12. auto ValueRepresentation::Print(llvm::raw_ostream& out) const -> void {
  13. out << "{kind: ";
  14. switch (kind) {
  15. case Unknown:
  16. out << "unknown";
  17. break;
  18. case None:
  19. out << "none";
  20. break;
  21. case Copy:
  22. out << "copy";
  23. break;
  24. case Pointer:
  25. out << "pointer";
  26. break;
  27. case Custom:
  28. out << "custom";
  29. break;
  30. }
  31. out << ", type: " << type_id << "}";
  32. }
  33. auto TypeInfo::Print(llvm::raw_ostream& out) const -> void {
  34. out << "{node: " << node_id << ", value_rep: " << value_representation << "}";
  35. }
  36. File::File()
  37. // Builtins are always the first IR, even when self-referential.
  38. : filename_("<builtins>"),
  39. cross_reference_irs_({this}),
  40. // Default entry for NodeBlockId::Empty.
  41. node_blocks_(1) {
  42. nodes_.reserve(BuiltinKind::ValidCount);
  43. // Error uses a self-referential type so that it's not accidentally treated as
  44. // a normal type. Every other builtin is a type, including the
  45. // self-referential TypeType.
  46. #define CARBON_SEM_IR_BUILTIN_KIND(Name, ...) \
  47. nodes_.push_back(Builtin(BuiltinKind::Name == BuiltinKind::Error \
  48. ? TypeId::Error \
  49. : TypeId::TypeType, \
  50. BuiltinKind::Name));
  51. #include "toolchain/sem_ir/builtin_kind.def"
  52. CARBON_CHECK(nodes_.size() == BuiltinKind::ValidCount)
  53. << "Builtins should produce " << BuiltinKind::ValidCount
  54. << " nodes, actual: " << nodes_.size();
  55. }
  56. File::File(std::string filename, const File* builtins)
  57. // Builtins are always the first IR.
  58. : filename_(std::move(filename)),
  59. cross_reference_irs_({builtins}),
  60. // Default entry for NodeBlockId::Empty.
  61. node_blocks_(1) {
  62. CARBON_CHECK(builtins != nullptr);
  63. CARBON_CHECK(builtins->cross_reference_irs_[0] == builtins)
  64. << "Not called with builtins!";
  65. // Copy builtins over.
  66. nodes_.reserve(BuiltinKind::ValidCount);
  67. static constexpr auto BuiltinIR = CrossReferenceIRId(0);
  68. for (auto [i, node] : llvm::enumerate(builtins->nodes_)) {
  69. // We can reuse builtin type IDs because they're special-cased values.
  70. nodes_.push_back(
  71. CrossReference(node.type_id(), BuiltinIR, SemIR::NodeId(i)));
  72. }
  73. }
  74. auto File::Verify() const -> ErrorOr<Success> {
  75. // Invariants don't necessarily hold for invalid IR.
  76. if (has_errors_) {
  77. return Success();
  78. }
  79. // Check that every code block has a terminator sequence that appears at the
  80. // end of the block.
  81. for (const Function& function : functions_) {
  82. for (NodeBlockId block_id : function.body_block_ids) {
  83. TerminatorKind prior_kind = TerminatorKind::NotTerminator;
  84. for (NodeId node_id : GetNodeBlock(block_id)) {
  85. TerminatorKind node_kind = GetNode(node_id).kind().terminator_kind();
  86. if (prior_kind == TerminatorKind::Terminator) {
  87. return Error(llvm::formatv("Node {0} in block {1} follows terminator",
  88. node_id, block_id));
  89. }
  90. if (prior_kind > node_kind) {
  91. return Error(
  92. llvm::formatv("Non-terminator node {0} in block {1} follows "
  93. "terminator sequence",
  94. node_id, block_id));
  95. }
  96. prior_kind = node_kind;
  97. }
  98. if (prior_kind != TerminatorKind::Terminator) {
  99. return Error(llvm::formatv("No terminator in block {0}", block_id));
  100. }
  101. }
  102. }
  103. // TODO: Check that a node only references other nodes that are either global
  104. // or that dominate it.
  105. return Success();
  106. }
  107. static constexpr int BaseIndent = 4;
  108. static constexpr int IndentStep = 2;
  109. // Define PrintList for ArrayRef.
  110. template <typename T, typename PrintT =
  111. std::function<void(llvm::raw_ostream&, const T& val)>>
  112. static auto PrintList(
  113. llvm::raw_ostream& out, llvm::StringLiteral name, llvm::ArrayRef<T> list,
  114. PrintT print = [](llvm::raw_ostream& out, const T& val) { out << val; }) {
  115. out.indent(BaseIndent);
  116. out << name << ": [\n";
  117. for (const auto& element : list) {
  118. out.indent(BaseIndent + IndentStep);
  119. print(out, element);
  120. out << ",\n";
  121. }
  122. out.indent(BaseIndent);
  123. out << "]\n";
  124. }
  125. // Adapt PrintList for a vector.
  126. template <typename T, typename PrintT =
  127. std::function<void(llvm::raw_ostream&, const T& val)>>
  128. static auto PrintList(
  129. llvm::raw_ostream& out, llvm::StringLiteral name,
  130. const llvm::SmallVector<T>& list,
  131. PrintT print = [](llvm::raw_ostream& out, const T& val) { out << val; }) {
  132. PrintList(out, name, llvm::ArrayRef(list), print);
  133. }
  134. // PrintBlock is only used for vectors.
  135. template <typename T>
  136. static auto PrintBlock(llvm::raw_ostream& out, llvm::StringLiteral block_name,
  137. const llvm::SmallVector<T>& blocks) {
  138. out.indent(BaseIndent);
  139. out << block_name << ": [\n";
  140. for (const auto& block : blocks) {
  141. out.indent(BaseIndent + IndentStep);
  142. out << "[\n";
  143. for (const auto& node : block) {
  144. out.indent(BaseIndent + 2 * IndentStep);
  145. out << node << ",\n";
  146. }
  147. out.indent(BaseIndent + IndentStep);
  148. out << "],\n";
  149. }
  150. out.indent(BaseIndent);
  151. out << "]\n";
  152. }
  153. auto File::Print(llvm::raw_ostream& out, bool include_builtins) const -> void {
  154. out << "- filename: " << filename_ << "\n"
  155. << " sem_ir:\n"
  156. << " - cross_reference_irs_size: " << cross_reference_irs_.size()
  157. << "\n";
  158. PrintList(out, "functions", functions_);
  159. PrintList(out, "classes", classes_);
  160. // Integer values are APInts, and default to a signed print, but we currently
  161. // treat them as unsigned.
  162. PrintList(out, "integers", integers_,
  163. [](llvm::raw_ostream& out, const llvm::APInt& val) {
  164. val.print(out, /*isSigned=*/false);
  165. });
  166. PrintList(out, "reals", reals_);
  167. PrintList(out, "strings", strings_);
  168. PrintList(out, "types", types_);
  169. PrintBlock(out, "type_blocks", type_blocks_);
  170. llvm::ArrayRef nodes = nodes_;
  171. if (!include_builtins) {
  172. nodes = nodes.drop_front(BuiltinKind::ValidCount);
  173. }
  174. PrintList(out, "nodes", nodes);
  175. PrintBlock(out, "node_blocks", node_blocks_);
  176. }
  177. // Map a node kind representing a type into an integer describing the
  178. // precedence of that type's syntax. Higher numbers correspond to higher
  179. // precedence.
  180. static auto GetTypePrecedence(NodeKind kind) -> int {
  181. // clang warns on unhandled enum values; clang-tidy is incorrect here.
  182. // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
  183. switch (kind) {
  184. case ArrayType::Kind:
  185. case Builtin::Kind:
  186. case ClassDeclaration::Kind:
  187. case StructType::Kind:
  188. case TupleType::Kind:
  189. return 0;
  190. case ConstType::Kind:
  191. return -1;
  192. case PointerType::Kind:
  193. return -2;
  194. case CrossReference::Kind:
  195. // TODO: Once we support stringification of cross-references, we'll need
  196. // to determine the precedence of the target of the cross-reference. For
  197. // now, all cross-references refer to builtin types from the prelude.
  198. return 0;
  199. case AddressOf::Kind:
  200. case ArrayIndex::Kind:
  201. case ArrayInit::Kind:
  202. case Assign::Kind:
  203. case BinaryOperatorAdd::Kind:
  204. case BindName::Kind:
  205. case BindValue::Kind:
  206. case BlockArg::Kind:
  207. case BoolLiteral::Kind:
  208. case Branch::Kind:
  209. case BranchIf::Kind:
  210. case BranchWithArg::Kind:
  211. case Call::Kind:
  212. case Dereference::Kind:
  213. case FunctionDeclaration::Kind:
  214. case InitializeFrom::Kind:
  215. case IntegerLiteral::Kind:
  216. case NameReference::Kind:
  217. case Namespace::Kind:
  218. case NoOp::Kind:
  219. case Parameter::Kind:
  220. case RealLiteral::Kind:
  221. case Return::Kind:
  222. case ReturnExpression::Kind:
  223. case SpliceBlock::Kind:
  224. case StringLiteral::Kind:
  225. case StructAccess::Kind:
  226. case StructTypeField::Kind:
  227. case StructLiteral::Kind:
  228. case StructInit::Kind:
  229. case StructValue::Kind:
  230. case Temporary::Kind:
  231. case TemporaryStorage::Kind:
  232. case TupleAccess::Kind:
  233. case TupleIndex::Kind:
  234. case TupleLiteral::Kind:
  235. case TupleInit::Kind:
  236. case TupleValue::Kind:
  237. case UnaryOperatorNot::Kind:
  238. case ValueAsReference::Kind:
  239. case VarStorage::Kind:
  240. CARBON_FATAL() << "GetTypePrecedence for non-type node kind " << kind;
  241. }
  242. }
  243. auto File::StringifyType(TypeId type_id, bool in_type_context) const
  244. -> std::string {
  245. std::string str;
  246. llvm::raw_string_ostream out(str);
  247. struct Step {
  248. // The node to print.
  249. NodeId node_id;
  250. // The index into node_id to print. Not used by all types.
  251. int index = 0;
  252. auto Next() const -> Step {
  253. return {.node_id = node_id, .index = index + 1};
  254. }
  255. };
  256. auto outer_node_id = GetTypeAllowBuiltinTypes(type_id);
  257. llvm::SmallVector<Step> steps = {{.node_id = outer_node_id}};
  258. while (!steps.empty()) {
  259. auto step = steps.pop_back_val();
  260. if (!step.node_id.is_valid()) {
  261. out << "<invalid type>";
  262. continue;
  263. }
  264. // Builtins have designated labels.
  265. if (step.node_id.index < BuiltinKind::ValidCount) {
  266. out << BuiltinKind::FromInt(step.node_id.index).label();
  267. continue;
  268. }
  269. auto node = GetNode(step.node_id);
  270. // clang warns on unhandled enum values; clang-tidy is incorrect here.
  271. // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
  272. switch (node.kind()) {
  273. case ArrayType::Kind: {
  274. auto array = node.As<ArrayType>();
  275. if (step.index == 0) {
  276. out << "[";
  277. steps.push_back(step.Next());
  278. steps.push_back(
  279. {.node_id = GetTypeAllowBuiltinTypes(array.element_type_id)});
  280. } else if (step.index == 1) {
  281. out << "; " << GetArrayBoundValue(array.bound_id) << "]";
  282. }
  283. break;
  284. }
  285. case ClassDeclaration::Kind: {
  286. auto class_name_id =
  287. GetClass(node.As<ClassDeclaration>().class_id).name_id;
  288. out << GetString(class_name_id);
  289. break;
  290. }
  291. case ConstType::Kind: {
  292. if (step.index == 0) {
  293. out << "const ";
  294. // Add parentheses if required.
  295. auto inner_type_node_id =
  296. GetTypeAllowBuiltinTypes(node.As<ConstType>().inner_id);
  297. if (GetTypePrecedence(GetNode(inner_type_node_id).kind()) <
  298. GetTypePrecedence(node.kind())) {
  299. out << "(";
  300. steps.push_back(step.Next());
  301. }
  302. steps.push_back({.node_id = inner_type_node_id});
  303. } else if (step.index == 1) {
  304. out << ")";
  305. }
  306. break;
  307. }
  308. case PointerType::Kind: {
  309. if (step.index == 0) {
  310. steps.push_back(step.Next());
  311. steps.push_back({.node_id = GetTypeAllowBuiltinTypes(
  312. node.As<PointerType>().pointee_id)});
  313. } else if (step.index == 1) {
  314. out << "*";
  315. }
  316. break;
  317. }
  318. case StructType::Kind: {
  319. auto refs = GetNodeBlock(node.As<StructType>().fields_id);
  320. if (refs.empty()) {
  321. out << "{}";
  322. break;
  323. } else if (step.index == 0) {
  324. out << "{";
  325. } else if (step.index < static_cast<int>(refs.size())) {
  326. out << ", ";
  327. } else {
  328. out << "}";
  329. break;
  330. }
  331. steps.push_back(step.Next());
  332. steps.push_back({.node_id = refs[step.index]});
  333. break;
  334. }
  335. case StructTypeField::Kind: {
  336. auto field = node.As<StructTypeField>();
  337. out << "." << GetString(field.name_id) << ": ";
  338. steps.push_back({.node_id = GetTypeAllowBuiltinTypes(field.type_id)});
  339. break;
  340. }
  341. case TupleType::Kind: {
  342. auto refs = GetTypeBlock(node.As<TupleType>().elements_id);
  343. if (refs.empty()) {
  344. out << "()";
  345. break;
  346. } else if (step.index == 0) {
  347. out << "(";
  348. } else if (step.index < static_cast<int>(refs.size())) {
  349. out << ", ";
  350. } else {
  351. // A tuple of one element has a comma to disambiguate from an
  352. // expression.
  353. if (step.index == 1) {
  354. out << ",";
  355. }
  356. out << ")";
  357. break;
  358. }
  359. steps.push_back(step.Next());
  360. steps.push_back(
  361. {.node_id = GetTypeAllowBuiltinTypes(refs[step.index])});
  362. break;
  363. }
  364. case AddressOf::Kind:
  365. case ArrayIndex::Kind:
  366. case ArrayInit::Kind:
  367. case Assign::Kind:
  368. case BinaryOperatorAdd::Kind:
  369. case BindName::Kind:
  370. case BindValue::Kind:
  371. case BlockArg::Kind:
  372. case BoolLiteral::Kind:
  373. case Branch::Kind:
  374. case BranchIf::Kind:
  375. case BranchWithArg::Kind:
  376. case Builtin::Kind:
  377. case Call::Kind:
  378. case CrossReference::Kind:
  379. case Dereference::Kind:
  380. case FunctionDeclaration::Kind:
  381. case InitializeFrom::Kind:
  382. case IntegerLiteral::Kind:
  383. case NameReference::Kind:
  384. case Namespace::Kind:
  385. case NoOp::Kind:
  386. case Parameter::Kind:
  387. case RealLiteral::Kind:
  388. case Return::Kind:
  389. case ReturnExpression::Kind:
  390. case SpliceBlock::Kind:
  391. case StringLiteral::Kind:
  392. case StructAccess::Kind:
  393. case StructLiteral::Kind:
  394. case StructInit::Kind:
  395. case StructValue::Kind:
  396. case Temporary::Kind:
  397. case TemporaryStorage::Kind:
  398. case TupleAccess::Kind:
  399. case TupleIndex::Kind:
  400. case TupleLiteral::Kind:
  401. case TupleInit::Kind:
  402. case TupleValue::Kind:
  403. case UnaryOperatorNot::Kind:
  404. case ValueAsReference::Kind:
  405. case VarStorage::Kind:
  406. // We don't need to handle stringification for nodes that don't show up
  407. // in errors, but make it clear what's going on so that it's clearer
  408. // when stringification is needed.
  409. out << "<cannot stringify " << step.node_id << ">";
  410. break;
  411. }
  412. }
  413. // For `{}` or any tuple type, we've printed a non-type expression, so add a
  414. // conversion to type `type` if it's not implied by the context.
  415. if (!in_type_context) {
  416. auto outer_node = GetNode(outer_node_id);
  417. if (outer_node.Is<TupleType>() ||
  418. (outer_node.Is<StructType>() &&
  419. GetNodeBlock(outer_node.As<StructType>().fields_id).empty())) {
  420. out << " as type";
  421. }
  422. }
  423. return str;
  424. }
  425. auto GetExpressionCategory(const File& file, NodeId node_id)
  426. -> ExpressionCategory {
  427. const File* ir = &file;
  428. while (true) {
  429. auto node = ir->GetNode(node_id);
  430. // clang warns on unhandled enum values; clang-tidy is incorrect here.
  431. // NOLINTNEXTLINE(bugprone-switch-missing-default-case)
  432. switch (node.kind()) {
  433. case Assign::Kind:
  434. case Branch::Kind:
  435. case BranchIf::Kind:
  436. case BranchWithArg::Kind:
  437. case FunctionDeclaration::Kind:
  438. case Namespace::Kind:
  439. case NoOp::Kind:
  440. case Return::Kind:
  441. case ReturnExpression::Kind:
  442. case StructTypeField::Kind:
  443. return ExpressionCategory::NotExpression;
  444. case CrossReference::Kind: {
  445. auto xref = node.As<CrossReference>();
  446. ir = &ir->GetCrossReferenceIR(xref.ir_id);
  447. node_id = xref.node_id;
  448. continue;
  449. }
  450. case NameReference::Kind: {
  451. node_id = node.As<NameReference>().value_id;
  452. continue;
  453. }
  454. case AddressOf::Kind:
  455. case ArrayType::Kind:
  456. case BinaryOperatorAdd::Kind:
  457. case BindValue::Kind:
  458. case BlockArg::Kind:
  459. case BoolLiteral::Kind:
  460. case ClassDeclaration::Kind:
  461. case ConstType::Kind:
  462. case IntegerLiteral::Kind:
  463. case Parameter::Kind:
  464. case PointerType::Kind:
  465. case RealLiteral::Kind:
  466. case StringLiteral::Kind:
  467. case StructValue::Kind:
  468. case StructType::Kind:
  469. case TupleValue::Kind:
  470. case TupleType::Kind:
  471. case UnaryOperatorNot::Kind:
  472. return ExpressionCategory::Value;
  473. case Builtin::Kind: {
  474. if (node.As<Builtin>().builtin_kind == BuiltinKind::Error) {
  475. return ExpressionCategory::Error;
  476. }
  477. return ExpressionCategory::Value;
  478. }
  479. case BindName::Kind: {
  480. node_id = node.As<BindName>().value_id;
  481. continue;
  482. }
  483. case ArrayIndex::Kind: {
  484. node_id = node.As<ArrayIndex>().array_id;
  485. continue;
  486. }
  487. case StructAccess::Kind: {
  488. node_id = node.As<StructAccess>().struct_id;
  489. continue;
  490. }
  491. case TupleAccess::Kind: {
  492. node_id = node.As<TupleAccess>().tuple_id;
  493. continue;
  494. }
  495. case TupleIndex::Kind: {
  496. node_id = node.As<TupleIndex>().tuple_id;
  497. continue;
  498. }
  499. case SpliceBlock::Kind: {
  500. node_id = node.As<SpliceBlock>().result_id;
  501. continue;
  502. }
  503. case StructLiteral::Kind:
  504. case TupleLiteral::Kind:
  505. return ExpressionCategory::Mixed;
  506. case ArrayInit::Kind:
  507. case Call::Kind:
  508. case InitializeFrom::Kind:
  509. case StructInit::Kind:
  510. case TupleInit::Kind:
  511. return ExpressionCategory::Initializing;
  512. case Dereference::Kind:
  513. case VarStorage::Kind:
  514. return ExpressionCategory::DurableReference;
  515. case Temporary::Kind:
  516. case TemporaryStorage::Kind:
  517. case ValueAsReference::Kind:
  518. return ExpressionCategory::EphemeralReference;
  519. }
  520. }
  521. }
  522. auto GetInitializingRepresentation(const File& file, TypeId type_id)
  523. -> InitializingRepresentation {
  524. auto value_rep = GetValueRepresentation(file, type_id);
  525. switch (value_rep.kind) {
  526. case ValueRepresentation::None:
  527. return {.kind = InitializingRepresentation::None};
  528. case ValueRepresentation::Copy:
  529. // TODO: Use in-place initialization for types that have non-trivial
  530. // destructive move.
  531. return {.kind = InitializingRepresentation::ByCopy};
  532. case ValueRepresentation::Pointer:
  533. case ValueRepresentation::Custom:
  534. return {.kind = InitializingRepresentation::InPlace};
  535. case ValueRepresentation::Unknown:
  536. CARBON_FATAL()
  537. << "Attempting to perform initialization of incomplete type";
  538. }
  539. }
  540. } // namespace Carbon::SemIR