operator.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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 generic
  35. // instance.
  36. LookupScope scope = {.name_scope_id = interface_scope_id,
  37. .instance_id = SemIR::GenericInstanceId::Invalid};
  38. // Lookup `Interface.Op`.
  39. auto op_ident_id = context.identifiers().Add(op.op_name);
  40. auto op_result = context.LookupQualifiedName(
  41. node_id, SemIR::NameId::ForIdentifier(op_ident_id), scope,
  42. /*required=*/false);
  43. if (!op_result.inst_id.is_valid()) {
  44. return SemIR::InstId::Invalid;
  45. }
  46. // Look through import_refs and aliases.
  47. auto op_const_id = GetConstantValueInInstance(
  48. context.sem_ir(), op_result.instance_id, op_result.inst_id);
  49. auto op_id = context.constant_values().GetInstId(op_const_id);
  50. // We expect it to be an associated function.
  51. if (context.insts().Is<SemIR::AssociatedEntity>(op_id)) {
  52. return op_id;
  53. }
  54. return SemIR::InstId::Invalid;
  55. }
  56. auto BuildUnaryOperator(Context& context, Parse::AnyExprId node_id, Operator op,
  57. SemIR::InstId operand_id) -> SemIR::InstId {
  58. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  59. if (!op_fn.is_valid()) {
  60. context.TODO(node_id,
  61. "missing or invalid operator interface, also avoid duplicate "
  62. "diagnostic if prelude is unavailable");
  63. return SemIR::InstId::BuiltinError;
  64. }
  65. // Form `operand.(Op)`.
  66. auto bound_op_id =
  67. PerformCompoundMemberAccess(context, node_id, operand_id, op_fn);
  68. if (bound_op_id == SemIR::InstId::BuiltinError) {
  69. return SemIR::InstId::BuiltinError;
  70. }
  71. // Form `bound_op()`.
  72. return PerformCall(context, node_id, bound_op_id, {});
  73. }
  74. auto BuildBinaryOperator(Context& context, Parse::AnyExprId node_id,
  75. Operator op, SemIR::InstId lhs_id,
  76. SemIR::InstId rhs_id) -> SemIR::InstId {
  77. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  78. if (!op_fn.is_valid()) {
  79. context.TODO(node_id, "missing or invalid operator interface");
  80. return SemIR::InstId::BuiltinError;
  81. }
  82. // Form `lhs.(Op)`.
  83. auto bound_op_id =
  84. PerformCompoundMemberAccess(context, node_id, lhs_id, op_fn);
  85. if (bound_op_id == SemIR::InstId::BuiltinError) {
  86. return SemIR::InstId::BuiltinError;
  87. }
  88. // Form `bound_op(rhs)`.
  89. return PerformCall(context, node_id, bound_op_id, {rhs_id});
  90. }
  91. } // namespace Carbon::Check