operator.cpp 3.8 KB

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