operator.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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 =
  48. GetConstantInInstance(context, op_result.instance_id,
  49. context.constant_values().Get(op_result.inst_id));
  50. auto op_id = context.constant_values().GetInstId(op_const_id);
  51. // We expect it to be an associated function.
  52. if (context.insts().Is<SemIR::AssociatedEntity>(op_id)) {
  53. return op_id;
  54. }
  55. return SemIR::InstId::Invalid;
  56. }
  57. auto BuildUnaryOperator(Context& context, Parse::AnyExprId node_id, Operator op,
  58. SemIR::InstId operand_id) -> SemIR::InstId {
  59. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  60. if (!op_fn.is_valid()) {
  61. context.TODO(node_id,
  62. "missing or invalid operator interface, also avoid duplicate "
  63. "diagnostic if prelude is unavailable");
  64. return SemIR::InstId::BuiltinError;
  65. }
  66. // Form `operand.(Op)`.
  67. auto bound_op_id =
  68. PerformCompoundMemberAccess(context, node_id, operand_id, op_fn);
  69. if (bound_op_id == SemIR::InstId::BuiltinError) {
  70. return SemIR::InstId::BuiltinError;
  71. }
  72. // Form `bound_op()`.
  73. return PerformCall(context, node_id, bound_op_id, {});
  74. }
  75. auto BuildBinaryOperator(Context& context, Parse::AnyExprId node_id,
  76. Operator op, SemIR::InstId lhs_id,
  77. SemIR::InstId rhs_id) -> SemIR::InstId {
  78. auto op_fn = GetOperatorOpFunction(context, node_id, op);
  79. if (!op_fn.is_valid()) {
  80. context.TODO(node_id, "missing or invalid operator interface");
  81. return SemIR::InstId::BuiltinError;
  82. }
  83. // Form `lhs.(Op)`.
  84. auto bound_op_id =
  85. PerformCompoundMemberAccess(context, node_id, lhs_id, op_fn);
  86. if (bound_op_id == SemIR::InstId::BuiltinError) {
  87. return SemIR::InstId::BuiltinError;
  88. }
  89. // Form `bound_op(rhs)`.
  90. return PerformCall(context, node_id, bound_op_id, {rhs_id});
  91. }
  92. } // namespace Carbon::Check