44
55#include " toolchain/sem_ir/expr_info.h"
66
7+ #include < concepts>
8+
79#include " common/check.h"
810#include " toolchain/base/kind_switch.h"
11+ #include " toolchain/sem_ir/ids.h"
12+ #include " toolchain/sem_ir/inst_kind.h"
913#include " toolchain/sem_ir/typed_insts.h"
1014
1115namespace Carbon ::SemIR {
1216
17+ // Returns the InstId represented by an instruction operand.
18+ static auto AsAnyInstId (Inst::ArgAndKind arg) -> InstId {
19+ if (auto inst_id = arg.TryAs <SemIR::InstId>()) {
20+ return *inst_id;
21+ }
22+ return arg.As <SemIR::AbsoluteInstId>();
23+ }
24+
1325auto GetExprCategory (const File& file, InstId inst_id) -> ExprCategory {
1426 const File* ir = &file;
1527
@@ -19,228 +31,64 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
1931
2032 while (true ) {
2133 auto untyped_inst = ir->insts ().Get (inst_id);
22- CARBON_KIND_SWITCH (untyped_inst) {
23- case AdaptDecl::Kind:
24- case Assign::Kind:
25- case BaseDecl::Kind:
26- case Branch::Kind:
27- case BranchIf::Kind:
28- case BranchWithArg::Kind:
29- case FieldDecl::Kind:
30- case FunctionDecl::Kind:
31- case ImplDecl::Kind:
32- case NameBindingDecl::Kind:
33- case Namespace::Kind:
34- case OutParamPattern::Kind:
35- case RefBindingPattern::Kind:
36- case RefParamPattern::Kind:
37- case RequireImplsDecl::Kind:
38- case RequirementBaseFacetType::Kind:
39- case RequirementEquivalent::Kind:
40- case RequirementImpls::Kind:
41- case RequirementRewrite::Kind:
42- case Return::Kind:
43- case ReturnSlotPattern::Kind:
44- case ReturnExpr::Kind:
45- case SymbolicBindingPattern::Kind:
46- case TuplePattern::Kind:
47- case ValueBindingPattern::Kind:
48- case ValueParamPattern::Kind:
49- case VarParamPattern::Kind:
50- case VarPattern::Kind:
51- return ExprCategory::NotExpr;
52-
53- case ImportRefUnloaded::Kind:
54- case ImportRefLoaded::Kind: {
55- auto import_ir_inst = ir->import_ir_insts ().Get (
56- untyped_inst.As <AnyImportRef>().import_ir_inst_id );
57- ir = ir->import_irs ().Get (import_ir_inst.ir_id ()).sem_ir ;
58- inst_id = import_ir_inst.inst_id ();
59- continue ;
60- }
61-
62- case CARBON_KIND (AsCompatible inst): {
63- inst_id = inst.source_id ;
64- continue ;
65- }
34+ auto category_from_kind = untyped_inst.kind ().expr_category ();
6635
67- case CARBON_KIND (AliasBinding inst): {
68- inst_id = inst.value_id ;
69- continue ;
70- }
71- case CARBON_KIND (ExportDecl inst): {
72- inst_id = inst.value_id ;
73- continue ;
74- }
75- case CARBON_KIND (NameRef inst): {
76- inst_id = inst.value_id ;
77- continue ;
78- }
79-
80- case CARBON_KIND (Converted inst): {
81- inst_id = inst.result_id ;
82- continue ;
83- }
84-
85- case CARBON_KIND (ImplWitnessAssociatedConstant inst): {
86- inst_id = inst.inst_id ;
87- continue ;
88- }
89-
90- case CARBON_KIND (SpecificConstant inst): {
91- inst_id = inst.inst_id ;
92- continue ;
93- }
94-
95- case AccessMemberAction::Kind:
96- case AccessOptionalMemberAction::Kind:
97- case AddrOf::Kind:
98- case ArrayType::Kind:
99- case AssociatedConstantDecl::Kind:
100- case AssociatedEntity::Kind:
101- case AssociatedEntityType::Kind:
102- case AutoType::Kind:
103- case SymbolicBinding::Kind:
104- case AcquireValue::Kind:
105- case ValueBinding::Kind:
106- case BlockArg::Kind:
107- case BoolLiteral::Kind:
108- case BoolType::Kind:
109- case BoundMethod::Kind:
110- case BoundMethodType::Kind:
111- case CharLiteralType::Kind:
112- case CharLiteralValue::Kind:
113- case ClassDecl::Kind:
114- case ClassType::Kind:
115- case CompleteTypeWitness::Kind:
116- case ConstType::Kind:
117- case ConvertToValueAction::Kind:
118- case CppOverloadSetType::Kind:
119- case CppOverloadSetValue::Kind:
120- case CustomLayoutType::Kind:
121- case FacetAccessType::Kind:
122- case FacetType::Kind:
123- case FacetValue::Kind:
124- case FloatLiteralType::Kind:
125- case FloatLiteralValue::Kind:
126- case FloatType::Kind:
127- case FloatValue::Kind:
128- case FunctionType::Kind:
129- case FunctionTypeWithSelfType::Kind:
130- case GenericClassType::Kind:
131- case GenericInterfaceType::Kind:
132- case GenericNamedConstraintType::Kind:
133- case LookupImplWitness::Kind:
134- case ImplWitness::Kind:
135- case ImplWitnessAccess::Kind:
136- case ImplWitnessAccessSubstituted::Kind:
137- case ImplWitnessTable::Kind:
138- case ImportCppDecl::Kind:
139- case ImportDecl::Kind:
140- case InstType::Kind:
141- case InstValue::Kind:
142- case IntLiteralType::Kind:
143- case IntType::Kind:
144- case IntValue::Kind:
145- case InterfaceDecl::Kind:
146- case MaybeUnformedType::Kind:
147- case NamedConstraintDecl::Kind:
148- case NamespaceType::Kind:
149- case PartialType::Kind:
150- case PatternType::Kind:
151- case PointerType::Kind:
152- case RefineTypeAction::Kind:
153- case RequireCompleteType::Kind:
154- case SpecificFunction::Kind:
155- case SpecificFunctionType::Kind:
156- case SpecificImplFunction::Kind:
157- case StringLiteral::Kind:
158- case StructType::Kind:
159- case StructValue::Kind:
160- case SymbolicBindingType::Kind:
161- case TupleType::Kind:
162- case TupleValue::Kind:
163- case TypeOfInst::Kind:
164- case TypeType::Kind:
165- case UnaryOperatorNot::Kind:
166- case UnboundElementType::Kind:
167- case UninitializedValue::Kind:
168- case ValueOfInitializer::Kind:
169- case ValueParam::Kind:
170- case VtableType::Kind:
171- case WhereExpr::Kind:
172- case WitnessType::Kind:
173- return value_category;
174-
175- case ErrorInst::Kind:
176- return ExprCategory::Error;
177-
178- case CARBON_KIND (ArrayIndex inst): {
179- inst_id = inst.array_id ;
180- continue ;
181- }
182-
183- case VtablePtr::Kind:
184- case VtableDecl::Kind:
185- return ExprCategory::EphemeralRef;
36+ // If this instruction kind has a fixed category, return it.
37+ if (auto fixed_category = category_from_kind.TryAsFixedCategory ()) {
38+ return *fixed_category == ExprCategory::Value ? value_category
39+ : *fixed_category;
40+ }
18641
187- case CARBON_KIND (ClassElementAccess inst): {
42+ // Handle any special cases that use
43+ // ComputedExprCategory::DependsOnOperands.
44+ auto handle_special_case = [&]<typename TypedInstT>(TypedInstT inst) {
45+ if constexpr (std::same_as<TypedInstT, ClassElementAccess>) {
18846 inst_id = inst.base_id ;
18947 // A value of class type is a pointer to an object representation.
19048 // Therefore, if the base is a value, the result is an ephemeral
19149 // reference.
19250 value_category = ExprCategory::EphemeralRef;
193- continue ;
51+ } else if constexpr (std::same_as<TypedInstT, ImportRefLoaded> ||
52+ std::same_as<TypedInstT, ImportRefUnloaded>) {
53+ auto import_ir_inst = ir->import_ir_insts ().Get (inst.import_ir_inst_id );
54+ ir = ir->import_irs ().Get (import_ir_inst.ir_id ()).sem_ir ;
55+ inst_id = import_ir_inst.inst_id ();
56+ } else {
57+ static_assert (
58+ TypedInstT::Kind.expr_category ().TryAsComputedCategory () !=
59+ ComputedExprCategory::DependsOnOperands,
60+ " Missing expression category computation for type" );
19461 }
62+ };
19563
196- case CARBON_KIND (StructAccess inst): {
197- inst_id = inst.struct_id ;
198- continue ;
64+ // If the category depends on the operands of the instruction, determine it.
65+ // Usually this means the category is the same as the category of an
66+ // operand.
67+ switch (*category_from_kind.TryAsComputedCategory ()) {
68+ case ComputedExprCategory::ValueIfHasType: {
69+ return untyped_inst.kind ().has_type () ? value_category
70+ : ExprCategory::NotExpr;
19971 }
20072
201- case CARBON_KIND (TupleAccess inst) : {
202- inst_id = inst. tuple_id ;
203- continue ;
73+ case ComputedExprCategory::SameAsFirstOperand : {
74+ inst_id = AsAnyInstId (untyped_inst. arg0_and_kind ()) ;
75+ break ;
20476 }
20577
206- case CARBON_KIND (SpliceBlock inst) : {
207- inst_id = inst. result_id ;
208- continue ;
78+ case ComputedExprCategory::SameAsSecondOperand : {
79+ inst_id = AsAnyInstId (untyped_inst. arg1_and_kind ()) ;
80+ break ;
20981 }
21082
211- case SpliceInst::Kind:
212- // TODO: Add ExprCategory::Dependent.
213- return value_category;
214-
215- case StructLiteral::Kind:
216- case TupleLiteral::Kind:
217- return ExprCategory::Mixed;
218-
219- case ArrayInit::Kind:
220- case Call::Kind:
221- case InitializeFrom::Kind:
222- case InPlaceInit::Kind:
223- case ClassInit::Kind:
224- case StructInit::Kind:
225- case TupleInit::Kind:
226- return ExprCategory::Initializing;
227-
228- case RefBinding::Kind:
229- case Deref::Kind:
230- case VarStorage::Kind:
231- case ReturnSlot::Kind:
232- return ExprCategory::DurableRef;
233-
234- case Temporary::Kind:
235- case TemporaryStorage::Kind:
236- case ValueAsRef::Kind:
237- return ExprCategory::EphemeralRef;
238-
239- case OutParam::Kind:
240- case RefParam::Kind:
241- // TODO: Consider introducing a separate category for OutParam:
242- // unlike other DurableRefs, it permits initialization.
243- return ExprCategory::DurableRef;
83+ case ComputedExprCategory::DependsOnOperands: {
84+ switch (untyped_inst.kind ()) {
85+ #define CARBON_SEM_IR_INST_KIND (TypedInstT ) \
86+ case TypedInstT::Kind: \
87+ handle_special_case (untyped_inst.As <TypedInstT>()); \
88+ break ;
89+ #include " toolchain/sem_ir/inst_kind.def"
90+ }
91+ }
24492 }
24593 }
24694}
0 commit comments