Files
carbon-lang/toolchain/sem_ir/expr_info.cpp
T

293 lines
8.4 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/sem_ir/expr_info.h"
#include "common/check.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::SemIR {
auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
const File* ir = &file;
// The overall expression category if the current instruction is a value
// expression.
ExprCategory value_category = ExprCategory::Value;
while (true) {
auto untyped_inst = ir->insts().Get(inst_id);
CARBON_KIND_SWITCH(untyped_inst) {
case AdaptDecl::Kind:
case AddrPattern::Kind:
case Assign::Kind:
case BaseDecl::Kind:
case BindingPattern::Kind:
case Branch::Kind:
case BranchIf::Kind:
case BranchWithArg::Kind:
case FieldDecl::Kind:
case FunctionDecl::Kind:
case ImplDecl::Kind:
case NameBindingDecl::Kind:
case Namespace::Kind:
case OutParamPattern::Kind:
case RefParamPattern::Kind:
case RequirementBaseFacetType::Kind:
case RequirementEquivalent::Kind:
case RequirementImpls::Kind:
case RequirementRewrite::Kind:
case Return::Kind:
case ReturnSlotPattern::Kind:
case ReturnExpr::Kind:
case SymbolicBindingPattern::Kind:
case TuplePattern::Kind:
case ValueParamPattern::Kind:
case VarPattern::Kind:
return ExprCategory::NotExpr;
case ImportRefUnloaded::Kind:
case ImportRefLoaded::Kind: {
auto import_ir_inst = ir->import_ir_insts().Get(
untyped_inst.As<AnyImportRef>().import_ir_inst_id);
ir = ir->import_irs().Get(import_ir_inst.ir_id()).sem_ir;
inst_id = import_ir_inst.inst_id();
continue;
}
case CARBON_KIND(AsCompatible inst): {
inst_id = inst.source_id;
continue;
}
case CARBON_KIND(BindAlias inst): {
inst_id = inst.value_id;
continue;
}
case CARBON_KIND(ExportDecl inst): {
inst_id = inst.value_id;
continue;
}
case CARBON_KIND(NameRef inst): {
inst_id = inst.value_id;
continue;
}
case CARBON_KIND(Converted inst): {
inst_id = inst.result_id;
continue;
}
case CARBON_KIND(ImplWitnessAssociatedConstant inst): {
inst_id = inst.inst_id;
continue;
}
case CARBON_KIND(SpecificConstant inst): {
inst_id = inst.inst_id;
continue;
}
case AccessMemberAction::Kind:
case AccessOptionalMemberAction::Kind:
case AddrOf::Kind:
case ArrayType::Kind:
case AssociatedConstantDecl::Kind:
case AssociatedEntity::Kind:
case AssociatedEntityType::Kind:
case AutoType::Kind:
case BindSymbolicName::Kind:
case BindValue::Kind:
case BlockArg::Kind:
case BoolLiteral::Kind:
case BoolType::Kind:
case BoundMethod::Kind:
case BoundMethodType::Kind:
case CharLiteralType::Kind:
case CharLiteralValue::Kind:
case ClassDecl::Kind:
case ClassType::Kind:
case CompleteTypeWitness::Kind:
case ConstType::Kind:
case ConvertToValueAction::Kind:
case CustomLayoutType::Kind:
case FacetAccessType::Kind:
case FacetType::Kind:
case FacetValue::Kind:
case FloatLiteralType::Kind:
case FloatLiteralValue::Kind:
case FloatType::Kind:
case FloatValue::Kind:
case FunctionType::Kind:
case FunctionTypeWithSelfType::Kind:
case GenericClassType::Kind:
case GenericInterfaceType::Kind:
case LookupImplWitness::Kind:
case ImplWitness::Kind:
case ImplWitnessAccess::Kind:
case ImplWitnessAccessSubstituted::Kind:
case ImplWitnessTable::Kind:
case ImplWitnessTablePlaceholder::Kind:
case ImportCppDecl::Kind:
case ImportDecl::Kind:
case InstType::Kind:
case InstValue::Kind:
case IntLiteralType::Kind:
case IntType::Kind:
case IntValue::Kind:
case InterfaceDecl::Kind:
case NamespaceType::Kind:
case PartialType::Kind:
case PatternType::Kind:
case PointerType::Kind:
case RefineTypeAction::Kind:
case RequireCompleteType::Kind:
case SpecificFunction::Kind:
case SpecificFunctionType::Kind:
case SpecificImplFunction::Kind:
case StringLiteral::Kind:
case StructType::Kind:
case StructValue::Kind:
case TupleType::Kind:
case TupleValue::Kind:
case TypeOfInst::Kind:
case TypeType::Kind:
case UnaryOperatorNot::Kind:
case UnboundElementType::Kind:
case ValueOfInitializer::Kind:
case ValueParam::Kind:
case VtableType::Kind:
case WhereExpr::Kind:
case WitnessType::Kind:
return value_category;
case ErrorInst::Kind:
return ExprCategory::Error;
case CARBON_KIND(BindName inst): {
// TODO: Don't rely on value_id for expression category, since it may
// not be valid yet. This workaround only works because we don't support
// `var` in function signatures yet.
if (!inst.value_id.has_value()) {
return value_category;
}
inst_id = inst.value_id;
continue;
}
case CARBON_KIND(ArrayIndex inst): {
inst_id = inst.array_id;
continue;
}
case VtablePtr::Kind:
case VtableDecl::Kind:
return ExprCategory::EphemeralRef;
case CARBON_KIND(ClassElementAccess inst): {
inst_id = inst.base_id;
// A value of class type is a pointer to an object representation.
// Therefore, if the base is a value, the result is an ephemeral
// reference.
value_category = ExprCategory::EphemeralRef;
continue;
}
case CARBON_KIND(StructAccess inst): {
inst_id = inst.struct_id;
continue;
}
case CARBON_KIND(TupleAccess inst): {
inst_id = inst.tuple_id;
continue;
}
case CARBON_KIND(SpliceBlock inst): {
inst_id = inst.result_id;
continue;
}
case SpliceInst::Kind:
// TODO: Add ExprCategory::Dependent.
return value_category;
case StructLiteral::Kind:
case TupleLiteral::Kind:
return ExprCategory::Mixed;
case ArrayInit::Kind:
case Call::Kind:
case InitializeFrom::Kind:
case ClassInit::Kind:
case StructInit::Kind:
case TupleInit::Kind:
return ExprCategory::Initializing;
case Deref::Kind:
case VarStorage::Kind:
case ReturnSlot::Kind:
return ExprCategory::DurableRef;
case Temporary::Kind:
case TemporaryStorage::Kind:
case ValueAsRef::Kind:
return ExprCategory::EphemeralRef;
case OutParam::Kind:
case RefParam::Kind:
// TODO: Consider introducing a separate category for OutParam:
// unlike other DurableRefs, it permits initialization.
return ExprCategory::DurableRef;
}
}
}
auto FindReturnSlotArgForInitializer(const File& sem_ir, InstId init_id)
-> InstId {
while (true) {
Inst init_untyped = sem_ir.insts().Get(init_id);
CARBON_KIND_SWITCH(init_untyped) {
case CARBON_KIND(AsCompatible init): {
init_id = init.source_id;
continue;
}
case CARBON_KIND(Converted init): {
init_id = init.result_id;
continue;
}
case CARBON_KIND(ArrayInit init): {
return init.dest_id;
}
case CARBON_KIND(ClassInit init): {
return init.dest_id;
}
case CARBON_KIND(StructInit init): {
return init.dest_id;
}
case CARBON_KIND(TupleInit init): {
return init.dest_id;
}
case CARBON_KIND(InitializeFrom init): {
return init.dest_id;
}
case CARBON_KIND(Call call): {
if (!ReturnTypeInfo::ForType(sem_ir, call.type_id).has_return_slot()) {
return InstId::None;
}
if (!call.args_id.has_value()) {
// Argument initialization failed, so we have no return slot.
return InstId::None;
}
return sem_ir.inst_blocks().Get(call.args_id).back();
}
default:
CARBON_FATAL("Initialization from unexpected inst {0}", init_untyped);
}
}
}
} // namespace Carbon::SemIR