mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-29 22:02:42 +01:00
The SymbolicBindingType refers to the type value that will be substituted in for the BindSymbolicName, but holds onto the EntityNameId from the BindSymbolicName instead of (or in addition to, for now) the instruction. The EntityNameId will be used to look in the ScopeStack to find the witnesses either from the BindSymbolicName instruction, or other instructions that specify `impls` constraints against the EntityName. This will allow us to have the `T` in `I(T)` resolve to a `.Self` reference in the type so that we get type equality with the binding's type: `T:! I(.Self)`.
307 lines
8.8 KiB
C++
307 lines
8.8 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 CppOverloadSetType::Kind:
|
|
case CppOverloadSetValue::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 MaybeUnformedType::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 SymbolicBindingType::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 InPlaceInit::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(InPlaceInit init): {
|
|
if (!ReturnTypeInfo::ForType(sem_ir, init.type_id).has_return_slot()) {
|
|
return InstId::None;
|
|
}
|
|
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();
|
|
}
|
|
case CARBON_KIND(ErrorInst _): {
|
|
return InstId::None;
|
|
}
|
|
default:
|
|
CARBON_FATAL("Initialization from unexpected inst {0}", init_untyped);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Carbon::SemIR
|