operator.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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/operator.h"
  5. #include "toolchain/check/call.h"
  6. #include "toolchain/check/context.h"
  7. #include "toolchain/check/member_access.h"
  8. #include "toolchain/sem_ir/ids.h"
  9. #include "toolchain/sem_ir/typed_insts.h"
  10. namespace Carbon::Check {
  11. // Returns the scope of the Core package, or Invalid if it's not found.
  12. //
  13. // TODO: Consider tracking the Core package in SemIR so we don't need to use
  14. // name lookup to find it.
  15. static auto GetCorePackage(Context& context, Parse::AnyExprId node_id)
  16. -> SemIR::NameScopeId {
  17. // TODO: If the current package is the `Core` package, return
  18. // `SemIR::InstId::Package`.
  19. auto ident_id = context.identifiers().Lookup("Core");
  20. if (!ident_id.is_valid()) {
  21. return SemIR::NameScopeId::Invalid;
  22. }
  23. auto name_id = SemIR::NameId::ForIdentifier(ident_id);
  24. // Look up `package.Core`.
  25. auto package_id = context.LookupQualifiedName(
  26. node_id, name_id, SemIR::NameScopeId::Package, /*required=*/false);
  27. if (!package_id.is_valid()) {
  28. return SemIR::NameScopeId::Invalid;
  29. }
  30. // Look through import_refs and aliases.
  31. package_id = context.constant_values().Get(package_id).inst_id();
  32. // We expect it to be a package, and fail if not.
  33. if (auto package_inst =
  34. context.insts().TryGetAs<SemIR::Namespace>(package_id)) {
  35. auto& name_scope = context.name_scopes().Get(package_inst->name_scope_id);
  36. // Check that this is really the `Core` package and not an alias.
  37. if (name_scope.is_closed_import && name_scope.name_id == name_id &&
  38. name_scope.enclosing_scope_id == SemIR::NameScopeId::Package) {
  39. return package_inst->name_scope_id;
  40. }
  41. }
  42. return SemIR::NameScopeId::Invalid;
  43. }
  44. // Returns the name scope of the operator interface for the specified operator
  45. // from the Core package.
  46. static auto GetOperatorInterface(Context& context, Parse::AnyExprId node_id,
  47. Operator op) -> SemIR::NameScopeId {
  48. auto carbon_package_id = GetCorePackage(context, node_id);
  49. if (!carbon_package_id.is_valid()) {
  50. return SemIR::NameScopeId::Invalid;
  51. }
  52. // Lookup `Core.InterfaceName`.
  53. auto interface_ident_id = context.identifiers().Add(op.interface_name);
  54. auto interface_id = context.LookupQualifiedName(
  55. node_id, SemIR::NameId::ForIdentifier(interface_ident_id),
  56. carbon_package_id, /*required=*/false);
  57. if (!interface_id.is_valid()) {
  58. return SemIR::NameScopeId::Invalid;
  59. }
  60. // Look through import_refs and aliases.
  61. interface_id = context.constant_values().Get(interface_id).inst_id();
  62. // We expect it to be an interface.
  63. if (auto interface_inst =
  64. context.insts().TryGetAs<SemIR::InterfaceType>(interface_id)) {
  65. return context.interfaces().Get(interface_inst->interface_id).scope_id;
  66. }
  67. return SemIR::NameScopeId::Invalid;
  68. }
  69. // Returns the `Op` function for the specified operator.
  70. static auto GetOperatorOpFunction(Context& context, Parse::AnyExprId node_id,
  71. Operator op) -> SemIR::InstId {
  72. auto interface_scope_id = GetOperatorInterface(context, node_id, op);
  73. if (!interface_scope_id.is_valid()) {
  74. return SemIR::InstId::Invalid;
  75. }
  76. // Lookup `Interface.Op`.
  77. auto op_ident_id = context.identifiers().Add(op.op_name);
  78. auto op_id = context.LookupQualifiedName(
  79. node_id, SemIR::NameId::ForIdentifier(op_ident_id), interface_scope_id,
  80. /*required=*/false);
  81. if (!op_id.is_valid()) {
  82. return SemIR::InstId::Invalid;
  83. }
  84. // Look through import_refs and aliases.
  85. op_id = context.constant_values().Get(op_id).inst_id();
  86. // We expect it to be an associated function.
  87. if (context.insts().Is<SemIR::AssociatedEntity>(op_id)) {
  88. return op_id;
  89. }
  90. return SemIR::InstId::Invalid;
  91. }
  92. auto BuildUnaryOperator(Context& context, Parse::AnyExprId node_id, Operator op,
  93. SemIR::InstId operand_id) -> SemIR::InstId {
  94. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  95. if (!op_fn.is_valid()) {
  96. context.TODO(node_id, "missing or invalid operator interface");
  97. return SemIR::InstId::BuiltinError;
  98. }
  99. // Form `operand.(Op)`.
  100. auto bound_op_id =
  101. PerformCompoundMemberAccess(context, node_id, operand_id, op_fn);
  102. if (bound_op_id == SemIR::InstId::BuiltinError) {
  103. return SemIR::InstId::BuiltinError;
  104. }
  105. // Form `bound_op()`.
  106. return PerformCall(context, node_id, bound_op_id, {});
  107. }
  108. auto BuildBinaryOperator(Context& context, Parse::AnyExprId node_id,
  109. Operator op, SemIR::InstId lhs_id,
  110. SemIR::InstId rhs_id) -> SemIR::InstId {
  111. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  112. if (!op_fn.is_valid()) {
  113. context.TODO(node_id, "missing or invalid operator interface");
  114. return SemIR::InstId::BuiltinError;
  115. }
  116. // Form `lhs.(Op)`.
  117. auto bound_op_id =
  118. PerformCompoundMemberAccess(context, node_id, lhs_id, op_fn);
  119. if (bound_op_id == SemIR::InstId::BuiltinError) {
  120. return SemIR::InstId::BuiltinError;
  121. }
  122. // Form `bound_op(rhs)`.
  123. return PerformCall(context, node_id, bound_op_id, {rhs_id});
  124. }
  125. } // namespace Carbon::Check