operator.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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 name scope of the operator interface for the specified operator
  12. // from the Core package.
  13. static auto GetOperatorInterface(Context& context, Parse::AnyExprId node_id,
  14. Operator op) -> SemIR::NameScopeId {
  15. auto interface_id = context.LookupNameInCore(node_id, op.interface_name);
  16. if (interface_id == SemIR::InstId::BuiltinError) {
  17. return SemIR::NameScopeId::Invalid;
  18. }
  19. // We expect it to be an interface.
  20. if (auto interface_inst =
  21. context.insts().TryGetAs<SemIR::InterfaceType>(interface_id)) {
  22. return context.interfaces().Get(interface_inst->interface_id).scope_id;
  23. }
  24. return SemIR::NameScopeId::Invalid;
  25. }
  26. // Returns the `Op` function for the specified operator.
  27. static auto GetOperatorOpFunction(Context& context, Parse::AnyExprId node_id,
  28. Operator op) -> SemIR::InstId {
  29. auto interface_scope_id = GetOperatorInterface(context, node_id, op);
  30. if (!interface_scope_id.is_valid()) {
  31. return SemIR::InstId::Invalid;
  32. }
  33. // Lookup `Interface.Op`.
  34. auto op_ident_id = context.identifiers().Add(op.op_name);
  35. auto op_id = context.LookupQualifiedName(
  36. node_id, SemIR::NameId::ForIdentifier(op_ident_id), interface_scope_id,
  37. /*required=*/false);
  38. if (!op_id.is_valid()) {
  39. return SemIR::InstId::Invalid;
  40. }
  41. // Look through import_refs and aliases.
  42. op_id = context.constant_values().GetConstantInstId(op_id);
  43. // We expect it to be an associated function.
  44. if (context.insts().Is<SemIR::AssociatedEntity>(op_id)) {
  45. return op_id;
  46. }
  47. return SemIR::InstId::Invalid;
  48. }
  49. auto BuildUnaryOperator(Context& context, Parse::AnyExprId node_id, Operator op,
  50. SemIR::InstId operand_id) -> SemIR::InstId {
  51. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  52. if (!op_fn.is_valid()) {
  53. context.TODO(node_id,
  54. "missing or invalid operator interface, also avoid duplicate "
  55. "diagnostic if prelude is unavailable");
  56. return SemIR::InstId::BuiltinError;
  57. }
  58. // Form `operand.(Op)`.
  59. auto bound_op_id =
  60. PerformCompoundMemberAccess(context, node_id, operand_id, op_fn);
  61. if (bound_op_id == SemIR::InstId::BuiltinError) {
  62. return SemIR::InstId::BuiltinError;
  63. }
  64. // Form `bound_op()`.
  65. return PerformCall(context, node_id, bound_op_id, {});
  66. }
  67. auto BuildBinaryOperator(Context& context, Parse::AnyExprId node_id,
  68. Operator op, SemIR::InstId lhs_id,
  69. SemIR::InstId rhs_id) -> SemIR::InstId {
  70. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  71. if (!op_fn.is_valid()) {
  72. context.TODO(node_id, "missing or invalid operator interface");
  73. return SemIR::InstId::BuiltinError;
  74. }
  75. // Form `lhs.(Op)`.
  76. auto bound_op_id =
  77. PerformCompoundMemberAccess(context, node_id, lhs_id, op_fn);
  78. if (bound_op_id == SemIR::InstId::BuiltinError) {
  79. return SemIR::InstId::BuiltinError;
  80. }
  81. // Form `bound_op(rhs)`.
  82. return PerformCall(context, node_id, bound_op_id, {rhs_id});
  83. }
  84. } // namespace Carbon::Check