diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 4978ed0f19e5..3e3644d26c2e 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -1744,13 +1744,16 @@ static auto TryEvalTypedInst(EvalContext& eval_context, SemIR::InstId inst_id, // Couldn't perform the action because it's still dependent. return MakeConstantResult(eval_context.context(), inst, Phase::TemplateSymbolic); + } else if constexpr (InstT::Kind.constant_needs_inst_id()) { + CARBON_CHECK(inst_id.has_value()); + return ConvertEvalResultToConstantId( + eval_context.context(), + EvalConstantInst(eval_context.context(), inst_id, inst.As()), + phase); } else { return ConvertEvalResultToConstantId( eval_context.context(), - EvalConstantInst(eval_context.context(), - eval_context.GetDiagnosticLoc({inst_id}), - inst.As()), - phase); + EvalConstantInst(eval_context.context(), inst.As()), phase); } } } @@ -1947,14 +1950,8 @@ static auto TryEvalInstInContext(EvalContext& eval_context, inst_id, inst); } -auto TryEvalInst(Context& context, SemIR::LocId loc_id, SemIR::InstId inst_id, - SemIR::Inst inst) -> SemIR::ConstantId { - EvalContext eval_context(&context, loc_id); - return TryEvalInstInContext(eval_context, inst_id, inst); -} - -auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) - -> SemIR::ConstantId { +auto TryEvalInstUnsafe(Context& context, SemIR::InstId inst_id, + SemIR::Inst inst) -> SemIR::ConstantId { EvalContext eval_context(&context, inst_id); return TryEvalInstInContext(eval_context, inst_id, inst); } diff --git a/toolchain/check/eval.h b/toolchain/check/eval.h index e1be408e763d..1998d2b09062 100644 --- a/toolchain/check/eval.h +++ b/toolchain/check/eval.h @@ -18,15 +18,31 @@ namespace Carbon::Check { auto AddImportedConstant(Context& context, SemIR::Inst inst) -> SemIR::ConstantId; -// Determines the phase of the instruction `inst`, and returns its constant +// Evaluates the instruction `inst`. If `inst_id` is specified, it is the ID of +// the instruction; otherwise, evaluation of the instruction must not require an +// `InstId` to be provided. +auto TryEvalInstUnsafe(Context& context, SemIR::InstId inst_id, + SemIR::Inst inst) -> SemIR::ConstantId; + +// Determines the phase of the instruction `inst_id`, and returns its constant // value if it has constant phase. If it has runtime phase, returns // `SemIR::ConstantId::NotConstant`. -auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) - -> SemIR::ConstantId; -// Like the above but specific a LocId instead of deriving it from the -// `inst_id`. This is most useful when passing `None` as the `inst_id`. -auto TryEvalInst(Context& context, SemIR::LocId loc_id, SemIR::InstId inst_id, - SemIR::Inst inst) -> SemIR::ConstantId; +inline auto TryEvalInst(Context& context, SemIR::InstId inst_id) + -> SemIR::ConstantId { + return TryEvalInstUnsafe(context, inst_id, context.insts().Get(inst_id)); +} + +// Same, but for a typed instruction that doesn't have an InstId assigned yet, +// in the case where evaluation doesn't need an InstId. This can be used to +// avoid allocating an instruction in the case where you just want a constant +// value and the instruction is known to not matter. However, even then care +// should be taken: if the produced constant is symbolic, you may still need an +// instruction to associate the constant with the enclosing generic. +template + requires(!InstT::Kind.constant_needs_inst_id()) +auto TryEvalInst(Context& context, InstT inst) -> SemIR::ConstantId { + return TryEvalInstUnsafe(context, SemIR::InstId::None, inst); +} // Evaluates the eval block for a region of a specific. Produces a block // containing the evaluated constant values of the instructions in the eval diff --git a/toolchain/check/eval_inst.cpp b/toolchain/check/eval_inst.cpp index 6e3a8fb0e09d..8061217423c7 100644 --- a/toolchain/check/eval_inst.cpp +++ b/toolchain/check/eval_inst.cpp @@ -14,32 +14,12 @@ #include "toolchain/check/inst.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" +#include "toolchain/diagnostics/diagnostic.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { -// When calling from eval to various Check functions, we need the actual LocId. -// This allows us to unwrap the SemIRLoc to do so. -// -// TODO: Decide whether to refactor calls everywhere to accept `SemIRLoc`, or -// fold `SemIRLoc` into `LocId`. Either way, we would like eval to call other -// code without unwrapping `SemIRLoc`. -class UnwrapSemIRLoc { - public: - auto operator()(Context& context, SemIRLoc loc) -> SemIR::LocId { - if (loc.is_inst_id_) { - if (loc.inst_id_.has_value()) { - return context.insts().GetLocId(loc.inst_id_); - } else { - return SemIR::LocId::None; - } - } else { - return loc.loc_id_; - } - } -}; - // Performs an access into an aggregate, retrieving the specified element. static auto PerformAggregateAccess(Context& context, SemIR::Inst inst) -> ConstantEvalResult { @@ -59,16 +39,16 @@ static auto PerformAggregateAccess(Context& context, SemIR::Inst inst) return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::ArrayInit inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::ArrayInit inst) + -> ConstantEvalResult { // TODO: Add an `ArrayValue` to represent a constant array object // representation instead of using a `TupleValue`. return ConstantEvalResult::NewSamePhase( SemIR::TupleValue{.type_id = inst.type_id, .elements_id = inst.inits_id}); } -auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::ArrayType inst) - -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, + SemIR::ArrayType inst) -> ConstantEvalResult { auto bound_inst = context.insts().Get(inst.bound_id); auto int_bound = bound_inst.TryAs(); if (!int_bound) { @@ -84,22 +64,24 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::ArrayType inst) bound_val.isNegative()) { CARBON_DIAGNOSTIC(ArrayBoundNegative, Error, "array bound of {0} is negative", TypedInt); - context.emitter().Emit(loc, ArrayBoundNegative, - {.type = int_bound->type_id, .value = bound_val}); + context.emitter().Emit( + context.insts().GetAs(inst_id).bound_id, + ArrayBoundNegative, {.type = int_bound->type_id, .value = bound_val}); return ConstantEvalResult::Error; } if (bound_val.getActiveBits() > 64) { CARBON_DIAGNOSTIC(ArrayBoundTooLarge, Error, "array bound of {0} is too large", TypedInt); - context.emitter().Emit(loc, ArrayBoundTooLarge, - {.type = int_bound->type_id, .value = bound_val}); + context.emitter().Emit( + context.insts().GetAs(inst_id).bound_id, + ArrayBoundTooLarge, {.type = int_bound->type_id, .value = bound_val}); return ConstantEvalResult::Error; } return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::AsCompatible inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::AsCompatible inst) + -> ConstantEvalResult { // AsCompatible changes the type of the source instruction; its constant // value, if there is one, needs to be modified to be of the same type. auto value_id = context.constant_values().Get(inst.source_id); @@ -111,26 +93,26 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, return ConstantEvalResult::NewAnyPhase(value_inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::BindAlias inst) +auto EvalConstantInst(Context& context, SemIR::BindAlias inst) -> ConstantEvalResult { // An alias evaluates to the value it's bound to. return ConstantEvalResult::Existing( context.constant_values().Get(inst.value_id)); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::BindValue /*inst*/) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::BindValue /*inst*/) + -> ConstantEvalResult { // TODO: Handle this once we've decided how to represent constant values of // reference expressions. return ConstantEvalResult::TODO; } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::ClassElementAccess inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::ClassElementAccess inst) + -> ConstantEvalResult { return PerformAggregateAccess(context, inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ClassDecl inst) +auto EvalConstantInst(Context& context, SemIR::ClassDecl inst) -> ConstantEvalResult { // If the class has generic parameters, we don't produce a class type, but a // callable whose return value is a class type. @@ -146,15 +128,15 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ClassDecl inst) .specific_id = SemIR::SpecificId::None}); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::ClassInit inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::ClassInit inst) + -> ConstantEvalResult { // TODO: Add a `ClassValue` to represent a constant class object // representation instead of using a `StructValue`. return ConstantEvalResult::NewSamePhase(SemIR::StructValue{ .type_id = inst.type_id, .elements_id = inst.elements_id}); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ConstType inst) +auto EvalConstantInst(Context& context, SemIR::ConstType inst) -> ConstantEvalResult { // `const (const T)` evaluates to `const T`. if (context.insts().Is(inst.inner_id)) { @@ -165,28 +147,28 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::ConstType inst) return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::Converted inst) +auto EvalConstantInst(Context& context, SemIR::Converted inst) -> ConstantEvalResult { // A conversion evaluates to the result of the conversion. return ConstantEvalResult::Existing( context.constant_values().Get(inst.result_id)); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::Deref /*inst*/) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::Deref /*inst*/) + -> ConstantEvalResult { // TODO: Handle this. return ConstantEvalResult::TODO; } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::ExportDecl inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::ExportDecl inst) + -> ConstantEvalResult { // An export instruction evaluates to the exported declaration. return ConstantEvalResult::Existing( context.constant_values().Get(inst.value_id)); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::FacetAccessType inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::FacetAccessType inst) + -> ConstantEvalResult { if (auto facet_value = context.insts().TryGetAs( inst.facet_value_inst_id)) { return ConstantEvalResult::Existing( @@ -195,8 +177,13 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::FacetAccessWitness inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::FacetAccessWitness inst) + -> ConstantEvalResult { + // TODO: The `index` we are given is an index into the required_interfaces of + // the original facet type, but we're using it to index into the witnesses of + // the substituted facet type. There is no reason to expect those witnesses to + // be in the same order, or even for there to be the same number of witnesses. + if (auto facet_value = context.insts().TryGetAs( inst.facet_value_inst_id)) { auto impl_witness_inst_id = context.inst_blocks().Get( @@ -207,15 +194,15 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::FloatType inst) - -> ConstantEvalResult { - return ValidateFloatType(context, loc, inst) +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, + SemIR::FloatType inst) -> ConstantEvalResult { + return ValidateFloatType(context, inst_id, inst) ? ConstantEvalResult::NewSamePhase(inst) : ConstantEvalResult::Error; } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::FunctionDecl inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::FunctionDecl inst) + -> ConstantEvalResult { // A function declaration evaluates to a function object, which is an empty // object of function type. // TODO: Eventually we may need to handle captures here. @@ -223,10 +210,10 @@ auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, .type_id = inst.type_id, .elements_id = SemIR::InstBlockId::Empty}); } -auto EvalConstantInst(Context& context, SemIRLoc loc, +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, SemIR::LookupImplWitness inst) -> ConstantEvalResult { auto result = EvalLookupSingleImplWitness( - context, UnwrapSemIRLoc()(context, loc), inst); + context, context.insts().GetLocId(inst_id), inst); if (!result.has_value()) { // We use NotConstant to communicate back to impl lookup that the lookup // failed. This can not happen for a deferred symbolic lookup in a generic @@ -241,7 +228,7 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, context.constant_values().Get(result.concrete_witness())); } -auto EvalConstantInst(Context& context, SemIRLoc loc, +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, SemIR::ImplWitnessAccess inst) -> ConstantEvalResult { // This is PerformAggregateAccess followed by GetConstantValueInSpecific. if (auto witness = @@ -263,36 +250,36 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, ImplAccessMemberBeforeSet, Error, "accessing member from impl before it has a defined value"); // TODO: Add note pointing to the impl declaration. - context.emitter().Emit(loc, ImplAccessMemberBeforeSet); + context.emitter().Emit(inst_id, ImplAccessMemberBeforeSet); return ConstantEvalResult::Error; } return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::ImportRefUnloaded inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::ImportRefUnloaded inst) + -> ConstantEvalResult { CARBON_FATAL("ImportRefUnloaded should be loaded before TryEvalInst: {0}", inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::InitializeFrom inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::InitializeFrom inst) + -> ConstantEvalResult { // Initialization is not performed in-place during constant evaluation, so // just return the value of the initializer. return ConstantEvalResult::Existing( context.constant_values().Get(inst.src_id)); } -auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::IntType inst) - -> ConstantEvalResult { - return ValidateIntType(context, loc, inst) +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, + SemIR::IntType inst) -> ConstantEvalResult { + return ValidateIntType(context, inst_id, inst) ? ConstantEvalResult::NewSamePhase(inst) : ConstantEvalResult::Error; } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::InterfaceDecl inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::InterfaceDecl inst) + -> ConstantEvalResult { // If the interface has generic parameters, we don't produce an interface // type, but a callable whose return value is an interface type. if (context.interfaces().Get(inst.interface_id).has_parameters()) { @@ -305,14 +292,14 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, context, inst.interface_id, SemIR::SpecificId::None)); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, SemIR::NameRef inst) +auto EvalConstantInst(Context& context, SemIR::NameRef inst) -> ConstantEvalResult { // A name reference evaluates to the value the name resolves to. return ConstantEvalResult::Existing( context.constant_values().Get(inst.value_id)); } -auto EvalConstantInst(Context& context, SemIRLoc loc, +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, SemIR::RequireCompleteType inst) -> ConstantEvalResult { auto witness_type_id = GetSingletonType(context, SemIR::WitnessType::SingletonInstId); @@ -320,13 +307,16 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, // If the type is a concrete constant, require it to be complete now. auto complete_type_id = inst.complete_type_id; if (context.types().GetConstantId(complete_type_id).is_concrete()) { - if (!TryToCompleteType(context, complete_type_id, loc, [&] { - // TODO: It'd be nice to report the original type prior to - // evaluation here. + if (!TryToCompleteType(context, complete_type_id, inst_id, [&] { CARBON_DIAGNOSTIC(IncompleteTypeInMonomorphization, Error, - "type {0} is incomplete", SemIR::TypeId); - return context.emitter().Build(loc, IncompleteTypeInMonomorphization, - complete_type_id); + "{0} evaluates to incomplete type {1}", + SemIR::TypeId, SemIR::TypeId); + return context.emitter().Build( + inst_id, IncompleteTypeInMonomorphization, + context.insts() + .GetAs(inst_id) + .complete_type_id, + complete_type_id); })) { return ConstantEvalResult::Error; } @@ -340,14 +330,14 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::SpecificConstant inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::SpecificConstant inst) + -> ConstantEvalResult { // Pull the constant value out of the specific. return ConstantEvalResult::Existing(SemIR::GetConstantValueInSpecific( context.sem_ir(), inst.specific_id, inst.inst_id)); } -auto EvalConstantInst(Context& context, SemIRLoc loc, +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, SemIR::SpecificImplFunction inst) -> ConstantEvalResult { auto callee_inst = context.insts().Get(inst.callee_id); // If the callee is not a function value, we're not ready to evaluate this @@ -393,8 +383,8 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, CARBON_CHECK(static_cast(interface_fn_args.size()) >= remaining_params); args.append(interface_fn_args.end() - remaining_params, interface_fn_args.end()); - auto specific_id = MakeSpecific(context, loc, generic_id, args); - context.definitions_required_by_use().push_back({loc, specific_id}); + auto specific_id = MakeSpecific(context, inst_id, generic_id, args); + context.definitions_required_by_use().push_back({inst_id, specific_id}); return ConstantEvalResult::NewSamePhase( SemIR::SpecificFunction{.type_id = inst.type_id, @@ -402,20 +392,21 @@ auto EvalConstantInst(Context& context, SemIRLoc loc, .specific_id = specific_id}); } -auto EvalConstantInst(Context& context, SemIRLoc loc, +auto EvalConstantInst(Context& context, SemIR::InstId inst_id, SemIR::SpecificFunction inst) -> ConstantEvalResult { if (!SemIR::GetCalleeFunction(context.sem_ir(), inst.callee_id) .self_type_id.has_value()) { // This is not an associated function. Those will be required to be defined // as part of checking that the impl is complete. - context.definitions_required_by_use().push_back({loc, inst.specific_id}); + context.definitions_required_by_use().push_back( + {inst_id, inst.specific_id}); } // Create new constant for a specific function. return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::SpliceBlock inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::SpliceBlock inst) + -> ConstantEvalResult { // SpliceBlock evaluates to the result value that is (typically) within the // block. This can be constant even if the block contains other non-constant // instructions. @@ -423,8 +414,8 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, context.constant_values().Get(inst.result_id)); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::SpliceInst inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::SpliceInst inst) + -> ConstantEvalResult { // The constant value of a SpliceInst is the constant value of the instruction // being spliced. Note that `inst.inst_id` is the instruction being spliced, // so we need to go through another round of obtaining the constant value in @@ -440,36 +431,36 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, return ConstantEvalResult::NotConstant; } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::StructAccess inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::StructAccess inst) + -> ConstantEvalResult { return PerformAggregateAccess(context, inst); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::StructInit inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::StructInit inst) + -> ConstantEvalResult { return ConstantEvalResult::NewSamePhase(SemIR::StructValue{ .type_id = inst.type_id, .elements_id = inst.elements_id}); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::Temporary /*inst*/) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::Temporary /*inst*/) + -> ConstantEvalResult { // TODO: Handle this. Can we just return the value of `init_id`? return ConstantEvalResult::TODO; } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::TupleAccess inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::TupleAccess inst) + -> ConstantEvalResult { return PerformAggregateAccess(context, inst); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::TupleInit inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& /*context*/, SemIR::TupleInit inst) + -> ConstantEvalResult { return ConstantEvalResult::NewSamePhase(SemIR::TupleValue{ .type_id = inst.type_id, .elements_id = inst.elements_id}); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::TypeOfInst inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::TypeOfInst inst) + -> ConstantEvalResult { // Grab the type from the instruction produced as our operand. if (auto inst_value = context.insts().TryGetAs(inst.inst_id)) { @@ -479,8 +470,8 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, return ConstantEvalResult::NewSamePhase(inst); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::UnaryOperatorNot inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::UnaryOperatorNot inst) + -> ConstantEvalResult { // `not true` -> `false`, `not false` -> `true`. // All other uses of unary `not` are non-constant. auto const_id = context.constant_values().Get(inst.operand_id); @@ -493,8 +484,8 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, return ConstantEvalResult::NotConstant; } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::ValueOfInitializer inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::ValueOfInitializer inst) + -> ConstantEvalResult { // Values of value expressions and initializing expressions are represented in // the same way during constant evaluation, so just return the value of the // operand. @@ -502,18 +493,12 @@ auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, context.constant_values().Get(inst.init_id)); } -auto EvalConstantInst(Context& context, SemIRLoc /*loc*/, - SemIR::ValueParamPattern inst) -> ConstantEvalResult { +auto EvalConstantInst(Context& context, SemIR::ValueParamPattern inst) + -> ConstantEvalResult { // TODO: Treat this as a non-expression (here and in GetExprCategory) // once generic deduction doesn't need patterns to have constant values. return ConstantEvalResult::Existing( context.constant_values().Get(inst.subpattern_id)); } -auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, - SemIR::VtablePtr /*inst*/) -> ConstantEvalResult { - // TODO: Handle this. - return ConstantEvalResult::TODO; -} - } // namespace Carbon::Check diff --git a/toolchain/check/eval_inst.h b/toolchain/check/eval_inst.h index 7a2c427cd42b..818682c10170 100644 --- a/toolchain/check/eval_inst.h +++ b/toolchain/check/eval_inst.h @@ -6,6 +6,7 @@ #define CARBON_TOOLCHAIN_CHECK_EVAL_INST_H_ #include "toolchain/check/eval.h" +#include "toolchain/sem_ir/inst_kind.h" namespace Carbon::Check { @@ -93,6 +94,60 @@ constexpr ConstantEvalResult ConstantEvalResult::NotConstant = constexpr ConstantEvalResult ConstantEvalResult::TODO = NotConstant; +// Implementation details to compute the type of the `EvalConstantInst` +// functions. +namespace Internal { + +// Returns whether an `EvalConstantInst` overload is expected to exist for this +// instruction constant kind. +constexpr auto ConstantKindHasEvalConstantInst(SemIR::InstConstantKind kind) + -> bool { + switch (kind) { + case SemIR::InstConstantKind::Never: + case SemIR::InstConstantKind::InstAction: + case SemIR::InstConstantKind::WheneverPossible: + case SemIR::InstConstantKind::Always: + case SemIR::InstConstantKind::Unique: + return false; + + case SemIR::InstConstantKind::Indirect: + case SemIR::InstConstantKind::SymbolicOnly: + case SemIR::InstConstantKind::Conditional: + return true; + } +} + +// Given an instruction kind, determines the type that should be used to declare +// `EvalConstantInst` for that instruction. +template +struct FunctionTypeForEvalConstantInstImpl { + // By default, we want no `EvalConstantInst` function at all. But we can't + // express that, so use the type `auto () -> voic` as a placaeholder. + using Type = auto() -> void; +}; +template +struct FunctionTypeForEvalConstantInstImpl { + // Can be evaluated, evaluation doesn't need InstId. + using Type = auto(Context& context, InstT inst) -> ConstantEvalResult; +}; +template +struct FunctionTypeForEvalConstantInstImpl { + // Can be evaluated, evaluation needs InstId. + using Type = auto(Context& context, SemIR::InstId inst_id, InstT inst) + -> ConstantEvalResult; +}; +template +using FunctionTypeForEvalConstantInst = + typename FunctionTypeForEvalConstantInstImpl< + InstT, ConstantKindHasEvalConstantInst(InstT::Kind.constant_kind()), + InstT::Kind.constant_needs_inst_id()>::Type; + +} // namespace Internal + +// Explicitly delete the overload generated for non-evaluatable instructions. +// These all produce the same signature, so we only need to delete it once. +auto EvalConstantInst() -> void = delete; + // `EvalConstantInst` evaluates an instruction whose operands are all constant, // in a context unrelated to the enclosing evaluation. The function is given the // instruction after its operands, including its type, are replaced by their @@ -110,12 +165,23 @@ constexpr ConstantEvalResult ConstantEvalResult::TODO = NotConstant; // context itself. Those cases are handled by explicit specialization of // `TryEvalTypedInst` in `eval.cpp` instead. // +// The signature of an overload is +// +// auto EvalConstantInst(Context& context, SemIR::InstId inst_id, InstT inst) +// -> ConstantEvalResult; +// +// if `InstT::Kind.constant_needs_inst_id()` is true, and +// +// auto EvalConstantInst(Context& context, InstT inst) -> ConstantEvalResult; +// +// otherwise. +// // Overloads are *declared* for all types, because there isn't a good way to // declare only the overloads we want here without duplicating the list of -// types. Missing overloads will be diagnosed when linking. -#define CARBON_SEM_IR_INST_KIND(Kind) \ - auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::Kind inst) \ - -> ConstantEvalResult; +// types. Missing overloads will be diagnosed when linking. Excess overloads +// map to a deleted signature to prevent accidental calls. +#define CARBON_SEM_IR_INST_KIND(Kind) \ + Internal::FunctionTypeForEvalConstantInst EvalConstantInst; #include "toolchain/sem_ir/inst_kind.def" } // namespace Carbon::Check diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index 311344ac6098..29d812fe694c 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -344,8 +344,8 @@ static auto FindWitnessInImpls(Context& context, SemIR::LocId loc_id, SemIR::ConstantId query_self_const_id, SemIR::SpecificInterface interface) -> SemIR::InstId { - auto witness_const_id = TryEvalInst( - context, loc_id, SemIR::InstId::None, + auto witness_id = AddInstInNoBlock( + context, loc_id, SemIR::LookupImplWitness{ .type_id = GetSingletonType(context, SemIR::WitnessType::SingletonInstId), @@ -356,6 +356,7 @@ static auto FindWitnessInImpls(Context& context, SemIR::LocId loc_id, }); // We use a NotConstant result from eval to communicate back an impl // lookup failure. See `EvalConstantInst()` for `LookupImplWitness`. + auto witness_const_id = context.constant_values().Get(witness_id); if (!witness_const_id.is_constant()) { return SemIR::InstId::None; } diff --git a/toolchain/check/inst.cpp b/toolchain/check/inst.cpp index 4272e9a6ea68..8649fa26fe80 100644 --- a/toolchain/check/inst.cpp +++ b/toolchain/check/inst.cpp @@ -28,7 +28,7 @@ static auto FinishInst(Context& context, SemIR::InstId inst_id, } // If the instruction has a constant value, compute it. - auto const_id = TryEvalInst(context, inst_id, inst); + auto const_id = TryEvalInstUnsafe(context, inst_id, inst); context.constant_values().Set(inst_id, const_id); if (const_id.is_constant()) { CARBON_VLOG_TO(context.vlog_stream(), "Constant: {0} -> {1}\n", inst, @@ -100,9 +100,10 @@ auto AddPatternInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst) auto GetOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst) -> SemIR::InstId { - if (loc_id_and_inst.loc_id.is_implicit()) { + if (loc_id_and_inst.loc_id.is_implicit() && + !loc_id_and_inst.inst.kind().constant_needs_inst_id()) { auto const_id = - TryEvalInst(context, SemIR::InstId::None, loc_id_and_inst.inst); + TryEvalInstUnsafe(context, SemIR::InstId::None, loc_id_and_inst.inst); if (const_id.has_value()) { CARBON_VLOG_TO(context.vlog_stream(), "GetOrAddInst: constant: {0}\n", loc_id_and_inst.inst); @@ -154,7 +155,7 @@ auto ReplaceInstPreservingConstantValue(Context& context, SemIR::InstId inst_id, context.sem_ir().insts().Set(inst_id, inst); CARBON_VLOG_TO(context.vlog_stream(), "ReplaceInst: {0} -> {1}\n", inst_id, inst); - auto new_const_id = TryEvalInst(context, inst_id, inst); + auto new_const_id = TryEvalInstUnsafe(context, inst_id, inst); CARBON_CHECK(old_const_id == new_const_id); } diff --git a/toolchain/check/interface.cpp b/toolchain/check/interface.cpp index 5014c1c6e90b..4902c306cda2 100644 --- a/toolchain/check/interface.cpp +++ b/toolchain/check/interface.cpp @@ -91,11 +91,10 @@ static auto GetSelfFacet(Context& context, auto type_inst_id = context.types().GetInstId(self_type_id); auto witnesses_block_id = context.inst_blocks().AddCanonical({self_witness_id}); - auto self_value_const_id = - TryEvalInst(context, SemIR::InstId::None, - SemIR::FacetValue{.type_id = self_facet_type_id, - .type_inst_id = type_inst_id, - .witnesses_block_id = witnesses_block_id}); + auto self_value_const_id = TryEvalInst( + context, SemIR::FacetValue{.type_id = self_facet_type_id, + .type_inst_id = type_inst_id, + .witnesses_block_id = witnesses_block_id}); return context.constant_values().GetInstId(self_value_const_id); } @@ -164,8 +163,8 @@ auto GetSelfSpecificForInterfaceMemberWithSelfType( CARBON_CHECK(entity_name.bind_index_value >= 0); bind_name.entity_name_id = context.entity_names().AddCanonical(entity_name); - new_arg_id = context.constant_values().GetInstId( - TryEvalInst(context, arg_id, bind_name)); + new_arg_id = + context.constant_values().GetInstId(TryEvalInst(context, bind_name)); } arg_ids.push_back(new_arg_id); } diff --git a/toolchain/check/member_access.cpp b/toolchain/check/member_access.cpp index 3fabb5fcf193..f6661ef2f066 100644 --- a/toolchain/check/member_access.cpp +++ b/toolchain/check/member_access.cpp @@ -583,7 +583,7 @@ static auto GetAssociatedValueImpl(Context& context, SemIR::LocId loc_id, // That facet value has both the self type we need below and the witness // we are going to use to look up the value of the associated member. auto self_type_const_id = TryEvalInst( - context, SemIR::InstId::None, + context, SemIR::FacetAccessType{.type_id = SemIR::TypeType::SingletonTypeId, .facet_value_inst_id = facet_inst_id}); // TODO: We should be able to lookup constant associated values from runtime diff --git a/toolchain/check/subst.cpp b/toolchain/check/subst.cpp index de4c43205cec..86f533e6c6b3 100644 --- a/toolchain/check/subst.cpp +++ b/toolchain/check/subst.cpp @@ -7,6 +7,7 @@ #include "toolchain/base/kind_switch.h" #include "toolchain/check/eval.h" #include "toolchain/check/generic.h" +#include "toolchain/check/inst.h" #include "toolchain/sem_ir/copy_on_write_block.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" @@ -402,12 +403,17 @@ class SubstConstantCallbacks final : public SubstInstCallbacks { } // Rebuilds an instruction by building a new constant. - auto Rebuild(SemIR::InstId /*old_inst_id*/, SemIR::Inst new_inst) const + auto Rebuild(SemIR::InstId old_inst_id, SemIR::Inst new_inst) const -> SemIR::InstId override { - auto result_id = TryEvalInst(*context_, SemIR::InstId::None, new_inst); - CARBON_CHECK(result_id.is_constant(), + auto result_id = GetOrAddInst( + *context_, + SemIR::LocIdAndInst::UncheckedLoc( + context_->insts().GetLocId(old_inst_id).ToImplicit(), new_inst)); + auto const_inst_id = + context_->constant_values().GetConstantInstId(result_id); + CARBON_CHECK(const_inst_id.has_value(), "Substitution into constant produced non-constant"); - return context_->constant_values().GetInstId(result_id); + return const_inst_id; } private: diff --git a/toolchain/check/testdata/array/fail_bound_negative.carbon b/toolchain/check/testdata/array/fail_bound_negative.carbon index 37e932ae1b79..e6a591a4c01d 100644 --- a/toolchain/check/testdata/array/fail_bound_negative.carbon +++ b/toolchain/check/testdata/array/fail_bound_negative.carbon @@ -10,9 +10,9 @@ fn Negate(n: i32) -> i32 = "int.snegate"; -// CHECK:STDERR: fail_bound_negative.carbon:[[@LINE+4]]:8: error: array bound of -1 is negative [ArrayBoundNegative] +// CHECK:STDERR: fail_bound_negative.carbon:[[@LINE+4]]:19: error: array bound of -1 is negative [ArrayBoundNegative] // CHECK:STDERR: var a: array(i32, Negate(1)); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: ^~~~~~~~~ // CHECK:STDERR: var a: array(i32, Negate(1)); diff --git a/toolchain/check/testdata/array/fail_bound_overflow.carbon b/toolchain/check/testdata/array/fail_bound_overflow.carbon index d61622f801e8..8ebd37a740e0 100644 --- a/toolchain/check/testdata/array/fail_bound_overflow.carbon +++ b/toolchain/check/testdata/array/fail_bound_overflow.carbon @@ -8,9 +8,9 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/array/fail_bound_overflow.carbon -// CHECK:STDERR: fail_bound_overflow.carbon:[[@LINE+4]]:8: error: array bound of 39999999999999999993 is too large [ArrayBoundTooLarge] +// CHECK:STDERR: fail_bound_overflow.carbon:[[@LINE+4]]:19: error: array bound of 39999999999999999993 is too large [ArrayBoundTooLarge] // CHECK:STDERR: var a: array(i32, 39999999999999999993); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: var a: array(i32, 39999999999999999993); diff --git a/toolchain/check/testdata/class/import.carbon b/toolchain/check/testdata/class/import.carbon index 1d0566171b6d..59ba98034ac0 100644 --- a/toolchain/check/testdata/class/import.carbon +++ b/toolchain/check/testdata/class/import.carbon @@ -364,5 +364,5 @@ fn Run() { // CHECK:STDOUT: // CHECK:STDOUT: fn @F[%self.param_patt: %ForwardDeclared.7b34f2.1]() [from "a.carbon"]; // CHECK:STDOUT: -// CHECK:STDOUT: fn @G[addr .inst1141: %ptr.6cf]() [from "a.carbon"]; +// CHECK:STDOUT: fn @G[addr .inst1143: %ptr.6cf]() [from "a.carbon"]; // CHECK:STDOUT: diff --git a/toolchain/check/testdata/facet/min_prelude/convert_class_type_to_generic_facet_value.carbon b/toolchain/check/testdata/facet/min_prelude/convert_class_type_to_generic_facet_value.carbon index fc603ef1686e..3f6a2dbd986c 100644 --- a/toolchain/check/testdata/facet/min_prelude/convert_class_type_to_generic_facet_value.carbon +++ b/toolchain/check/testdata/facet/min_prelude/convert_class_type_to_generic_facet_value.carbon @@ -245,6 +245,7 @@ fn G() { // CHECK:STDOUT: %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod] // CHECK:STDOUT: %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam] // CHECK:STDOUT: %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric] +// CHECK:STDOUT: %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769] // CHECK:STDOUT: %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet] // CHECK:STDOUT: %.loc18: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet] // CHECK:STDOUT: %CallGenericMethod.specific_fn: = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%CallGenericMethod.specific_fn.934] @@ -278,6 +279,7 @@ fn G() { // CHECK:STDOUT: %PassThroughToGenericMethod.ref: %PassThroughToGenericMethod.type = name_ref PassThroughToGenericMethod, file.%PassThroughToGenericMethod.decl [concrete = constants.%PassThroughToGenericMethod] // CHECK:STDOUT: %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam] // CHECK:STDOUT: %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric] +// CHECK:STDOUT: %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769] // CHECK:STDOUT: %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet] // CHECK:STDOUT: %.loc26: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet] // CHECK:STDOUT: %PassThroughToGenericMethod.specific_fn: = specific_function %PassThroughToGenericMethod.ref, @PassThroughToGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%PassThroughToGenericMethod.specific_fn] @@ -535,6 +537,7 @@ fn G() { // CHECK:STDOUT: %.loc18_36.3: init %GenericParam = class_init (), %.loc18_36.2 [concrete = constants.%GenericParam.val] // CHECK:STDOUT: %.loc18_36.4: ref %GenericParam = temporary %.loc18_36.2, %.loc18_36.3 // CHECK:STDOUT: %.loc18_38.1: ref %GenericParam = converted %.loc18_36.1, %.loc18_36.4 +// CHECK:STDOUT: %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769] // CHECK:STDOUT: %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet] // CHECK:STDOUT: %.loc18_53: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet] // CHECK:STDOUT: %CallGenericMethod.specific_fn: = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet) [concrete = constants.%CallGenericMethod.specific_fn] diff --git a/toolchain/check/testdata/facet/min_prelude/convert_class_value_to_generic_facet_value_value.carbon b/toolchain/check/testdata/facet/min_prelude/convert_class_value_to_generic_facet_value_value.carbon index 15471cc881fd..51bcb6f7147e 100644 --- a/toolchain/check/testdata/facet/min_prelude/convert_class_value_to_generic_facet_value_value.carbon +++ b/toolchain/check/testdata/facet/min_prelude/convert_class_value_to_generic_facet_value_value.carbon @@ -319,6 +319,7 @@ fn B() { // CHECK:STDOUT: %.loc20_42.3: init %GenericParam = class_init (), %.loc20_42.2 [concrete = constants.%GenericParam.val] // CHECK:STDOUT: %.loc20_42.4: ref %GenericParam = temporary %.loc20_42.2, %.loc20_42.3 // CHECK:STDOUT: %.loc20_44.1: ref %GenericParam = converted %.loc20_42.1, %.loc20_42.4 +// CHECK:STDOUT: %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769] // CHECK:STDOUT: %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness) [concrete = constants.%Generic.facet.8bd] // CHECK:STDOUT: %.loc20_59: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet.8bd] // CHECK:STDOUT: %CallGenericMethod.specific_fn: = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet.8bd) [concrete = constants.%CallGenericMethod.specific_fn] diff --git a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon index f6326118e7f4..8a9f75780989 100644 --- a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon +++ b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon @@ -921,8 +921,8 @@ fn CallsWithTypeExplicit(U:! type) { // CHECK:STDOUT: %require_complete: = require_complete_type @HandleTameAnimal2.%W.as_type.loc11_44.2 (%W.as_type) [symbolic = %require_complete (constants.%require_complete.ba9)] // CHECK:STDOUT: %W.as_wit.iface0.loc12_14.3: = facet_access_witness %W.loc11_22.2, element0 [symbolic = %W.as_wit.iface0.loc12_14.3 (constants.%W.as_wit.iface0)] // CHECK:STDOUT: %Animal.facet.loc12_14.3: %Animal.type = facet_value %W.as_type.loc11_44.2, (%W.as_wit.iface0.loc12_14.3) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)] -// CHECK:STDOUT: %W.as_wit.iface1.loc12_14.3: = facet_access_witness %W.loc11_22.2, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)] // CHECK:STDOUT: %Eats.lookup_impl_witness: = lookup_impl_witness %W.loc11_22.2, @Eats [symbolic = %Eats.lookup_impl_witness (constants.%Eats.lookup_impl_witness)] +// CHECK:STDOUT: %W.as_wit.iface1.loc12_14.3: = facet_access_witness %W.loc11_22.2, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)] // CHECK:STDOUT: %facet_value.loc12_14.3: %facet_type.6ff = facet_value %W.as_type.loc11_44.2, (%Eats.lookup_impl_witness, %W.as_wit.iface1.loc12_14.3) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] // CHECK:STDOUT: %FeedTame2.specific_fn.loc12_3.2: = specific_function constants.%FeedTame2, @FeedTame2(%facet_value.loc12_14.3) [symbolic = %FeedTame2.specific_fn.loc12_3.2 (constants.%FeedTame2.specific_fn)] // CHECK:STDOUT: diff --git a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon index 0ebc81e8fa0d..442b9c06429e 100644 --- a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon +++ b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon @@ -335,9 +335,9 @@ fn F() { // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete.loc31_45: = require_complete_type @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad) [symbolic = %require_complete.loc31_45 (constants.%require_complete.234)] // CHECK:STDOUT: %require_complete.loc31_54: = require_complete_type @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) [symbolic = %require_complete.loc31_54 (constants.%require_complete.444)] -// CHECK:STDOUT: %Eats.type: type = facet_type <@Eats, @Eats(%Food.as_type.loc31_56.2)> [symbolic = %Eats.type (constants.%Eats.type.f54c3d.2)] +// CHECK:STDOUT: %Eats.type.2: type = facet_type <@Eats, @Eats(%Food.as_type.loc31_56.2)> [symbolic = %Eats.type.2 (constants.%Eats.type.f54c3d.2)] // CHECK:STDOUT: %Eats.lookup_impl_witness: = lookup_impl_witness %T.loc31_17.2, @Eats, @Eats(%Food.as_type.loc31_56.2) [symbolic = %Eats.lookup_impl_witness (constants.%Eats.lookup_impl_witness)] -// CHECK:STDOUT: %Eats.facet.loc31_76.2: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value %T.as_type.loc31_47.2, (%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)] +// CHECK:STDOUT: %Eats.facet.loc31_76.2: @HandleAnimal.%Eats.type.2 (%Eats.type.f54c3d.2) = facet_value %T.as_type.loc31_47.2, (%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)] // CHECK:STDOUT: %Feed.specific_fn.loc31_64.2: = specific_function constants.%Feed, @Feed(%Food.loc31_29.2, %Eats.facet.loc31_76.2) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.ea3)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%T.patt.loc31_17.1: %Animal.type, %Food.patt.loc31_29.1: %Edible.type](%a.param_patt: @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad), %food.param_patt: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae)) { @@ -347,12 +347,14 @@ fn F() { // CHECK:STDOUT: %food.ref: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) = name_ref food, %food // CHECK:STDOUT: %.loc31_76.1: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)] // CHECK:STDOUT: %.loc31_76.2: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)] +// CHECK:STDOUT: %Food.as_type.1: type = facet_access_type constants.%Food.5fe [symbolic = %Food.as_type.loc31_56.2 (constants.%Food.as_type.fae)] +// CHECK:STDOUT: %Eats.type.1: type = facet_type <@Eats, @Eats(constants.%Food.as_type.fae)> [symbolic = %Eats.type.2 (constants.%Eats.type.f54c3d.2)] // CHECK:STDOUT: %.loc31_76.3: %Edible.type = converted constants.%Food.as_type.fae, constants.%Food.5fe [symbolic = %Food.loc31_29.2 (constants.%Food.5fe)] // CHECK:STDOUT: %T.as_type.loc31_76: type = facet_access_type constants.%T.fd4 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc31_76.4: type = converted constants.%T.fd4, %T.as_type.loc31_76 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc31_76.5: %Animal.type = converted %.loc31_76.4, constants.%T.fd4 [symbolic = %T.loc31_17.2 (constants.%T.fd4)] -// CHECK:STDOUT: %Eats.facet.loc31_76.1: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value constants.%T.as_type.2ad, (constants.%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)] -// CHECK:STDOUT: %.loc31_76.6: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = converted constants.%T.as_type.2ad, %Eats.facet.loc31_76.1 [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)] +// CHECK:STDOUT: %Eats.facet.loc31_76.1: @HandleAnimal.%Eats.type.2 (%Eats.type.f54c3d.2) = facet_value constants.%T.as_type.2ad, (constants.%Eats.lookup_impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)] +// CHECK:STDOUT: %.loc31_76.6: @HandleAnimal.%Eats.type.2 (%Eats.type.f54c3d.2) = converted constants.%T.as_type.2ad, %Eats.facet.loc31_76.1 [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.512)] // CHECK:STDOUT: %Feed.specific_fn.loc31_64.1: = specific_function %Feed.ref, @Feed(constants.%Food.5fe, constants.%Eats.facet.512) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.ea3)] // CHECK:STDOUT: %Feed.call: init %empty_tuple.type = call %Feed.specific_fn.loc31_64.1(%a.ref, %food.ref) // CHECK:STDOUT: return @@ -495,7 +497,7 @@ fn F() { // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete.loc31_45 => constants.%complete_type.357 // CHECK:STDOUT: %require_complete.loc31_54 => constants.%complete_type.357 -// CHECK:STDOUT: %Eats.type => constants.%Eats.type.1ae +// CHECK:STDOUT: %Eats.type.2 => constants.%Eats.type.1ae // CHECK:STDOUT: %Eats.lookup_impl_witness => constants.%impl_witness.4f1 // CHECK:STDOUT: %Eats.facet.loc31_76.2 => constants.%Eats.facet.fa6 // CHECK:STDOUT: %Feed.specific_fn.loc31_64.2 => constants.%Feed.specific_fn.d82 diff --git a/toolchain/check/testdata/facet/min_prelude/fail_convert_class_type_to_generic_facet_value.carbon b/toolchain/check/testdata/facet/min_prelude/fail_convert_class_type_to_generic_facet_value.carbon index e1d8d3238bb3..a12615bce1e1 100644 --- a/toolchain/check/testdata/facet/min_prelude/fail_convert_class_type_to_generic_facet_value.carbon +++ b/toolchain/check/testdata/facet/min_prelude/fail_convert_class_type_to_generic_facet_value.carbon @@ -210,6 +210,7 @@ fn G() { // CHECK:STDOUT: %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod] // CHECK:STDOUT: %WrongGenericParam.ref: type = name_ref WrongGenericParam, file.%WrongGenericParam.decl [concrete = constants.%WrongGenericParam] // CHECK:STDOUT: %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric] +// CHECK:STDOUT: %Generic.type: type = facet_type <@Generic, @Generic(constants.%WrongGenericParam)> [concrete = constants.%Generic.type.c3b] // CHECK:STDOUT: %CallGenericMethod.specific_fn: = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%WrongGenericParam, ) [concrete = ] // CHECK:STDOUT: %CallGenericMethod.call: init %empty_tuple.type = call %CallGenericMethod.specific_fn() [concrete = ] // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/facet/min_prelude/fail_deduction_uses_runtime_type_conversion.carbon b/toolchain/check/testdata/facet/min_prelude/fail_deduction_uses_runtime_type_conversion.carbon index 2f5966f79916..f930af7939e4 100644 --- a/toolchain/check/testdata/facet/min_prelude/fail_deduction_uses_runtime_type_conversion.carbon +++ b/toolchain/check/testdata/facet/min_prelude/fail_deduction_uses_runtime_type_conversion.carbon @@ -304,6 +304,7 @@ fn G(holds_to: HoldsType((RuntimeConvertTo, ))) { // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F] // CHECK:STDOUT: %from.ref: %RuntimeConvertFrom = name_ref from, %from [symbolic = constants.%from] // CHECK:STDOUT: %holds_to.ref: %HoldsType.066 = name_ref holds_to, %holds_to +// CHECK:STDOUT: %tuple.elem0: type = tuple_access constants.%tuple, element0 [concrete = constants.%RuntimeConvertTo] // CHECK:STDOUT: %impl.elem0: %.31e = impl_witness_access constants.%impl_witness, element0 [concrete = constants.%Convert.e81] // CHECK:STDOUT: %bound_method: = bound_method constants.%from, %impl.elem0 [symbolic = constants.%Convert.bound] // CHECK:STDOUT: %.loc40_19.1: ref %RuntimeConvertTo = temporary_storage diff --git a/toolchain/check/testdata/function/generic/call_method_on_generic_facet.carbon b/toolchain/check/testdata/function/generic/call_method_on_generic_facet.carbon index a129ae17db76..a8d1deefc10c 100644 --- a/toolchain/check/testdata/function/generic/call_method_on_generic_facet.carbon +++ b/toolchain/check/testdata/function/generic/call_method_on_generic_facet.carbon @@ -273,6 +273,7 @@ fn G() { // CHECK:STDOUT: %CallGenericMethod.ref: %CallGenericMethod.type = name_ref CallGenericMethod, file.%CallGenericMethod.decl [concrete = constants.%CallGenericMethod] // CHECK:STDOUT: %GenericParam.ref: type = name_ref GenericParam, file.%GenericParam.decl [concrete = constants.%GenericParam] // CHECK:STDOUT: %ImplsGeneric.ref: type = name_ref ImplsGeneric, file.%ImplsGeneric.decl [concrete = constants.%ImplsGeneric] +// CHECK:STDOUT: %Generic.type: type = facet_type <@Generic, @Generic(constants.%GenericParam)> [concrete = constants.%Generic.type.769] // CHECK:STDOUT: %Generic.facet: %Generic.type.769 = facet_value constants.%ImplsGeneric, (constants.%impl_witness.b42) [concrete = constants.%Generic.facet.8bd] // CHECK:STDOUT: %.loc34: %Generic.type.769 = converted constants.%ImplsGeneric, %Generic.facet [concrete = constants.%Generic.facet.8bd] // CHECK:STDOUT: %CallGenericMethod.specific_fn: = specific_function %CallGenericMethod.ref, @CallGenericMethod(constants.%GenericParam, constants.%Generic.facet.8bd) [concrete = constants.%CallGenericMethod.specific_fn] diff --git a/toolchain/check/testdata/generic/complete_type.carbon b/toolchain/check/testdata/generic/complete_type.carbon index 428acf5a300d..1b6d0436fef2 100644 --- a/toolchain/check/testdata/generic/complete_type.carbon +++ b/toolchain/check/testdata/generic/complete_type.carbon @@ -15,7 +15,7 @@ library "[[@TEST_NAME]]"; class B; class A(T:! type) { - // CHECK:STDERR: fail_incomplete_in_class.carbon:[[@LINE+6]]:10: error: type `B` is incomplete [IncompleteTypeInMonomorphization] + // CHECK:STDERR: fail_incomplete_in_class.carbon:[[@LINE+6]]:10: error: `T` evaluates to incomplete type `B` [IncompleteTypeInMonomorphization] // CHECK:STDERR: var v: T; // CHECK:STDERR: ^ // CHECK:STDERR: fail_incomplete_in_class.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere] @@ -61,7 +61,7 @@ library "[[@TEST_NAME]]"; class B; fn F(T:! type) { - // CHECK:STDERR: fail_incomplete_in_function_at_eof.carbon:[[@LINE+6]]:10: error: type `B` is incomplete [IncompleteTypeInMonomorphization] + // CHECK:STDERR: fail_incomplete_in_function_at_eof.carbon:[[@LINE+6]]:10: error: `T` evaluates to incomplete type `B` [IncompleteTypeInMonomorphization] // CHECK:STDERR: var v: T; // CHECK:STDERR: ^ // CHECK:STDERR: fail_incomplete_in_function_at_eof.carbon:[[@LINE-6]]:1: note: class was forward declared here [ClassForwardDeclaredHere] diff --git a/toolchain/check/testdata/if_expr/fail_not_in_function.carbon b/toolchain/check/testdata/if_expr/fail_not_in_function.carbon index 39329d71eea0..accff96f5a1d 100644 --- a/toolchain/check/testdata/if_expr/fail_not_in_function.carbon +++ b/toolchain/check/testdata/if_expr/fail_not_in_function.carbon @@ -94,7 +94,7 @@ class C { // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] // CHECK:STDOUT: } -// CHECK:STDOUT: %x: %i32 = bind_name x, .inst1063.loc27_14 +// CHECK:STDOUT: %x: %i32 = bind_name x, .inst1065.loc27_14 // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %y.patt: %i32 = binding_pattern y // CHECK:STDOUT: %.loc37: %i32 = var_pattern %y.patt diff --git a/toolchain/check/testdata/impl/assoc_const_self.carbon b/toolchain/check/testdata/impl/assoc_const_self.carbon index 8af42b5cec9d..032f39446c86 100644 --- a/toolchain/check/testdata/impl/assoc_const_self.carbon +++ b/toolchain/check/testdata/impl/assoc_const_self.carbon @@ -62,9 +62,9 @@ impl C as I where .V = () {} library "[[@TEST_NAME]]"; interface I(N:! Core.IntLiteral()) { - // CHECK:STDERR: fail_monomorphization_failure.carbon:[[@LINE+3]]:11: error: array bound of -1 is negative [ArrayBoundNegative] + // CHECK:STDERR: fail_monomorphization_failure.carbon:[[@LINE+3]]:17: error: array bound of -1 is negative [ArrayBoundNegative] // CHECK:STDERR: let V:! array(Self, N); - // CHECK:STDERR: ^~~~~~~~~~~~~~ + // CHECK:STDERR: ^~~~ let V:! array(Self, N); } diff --git a/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon b/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon index a047cf6f8108..2ac3c465cebe 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon @@ -336,8 +336,8 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %require_complete.loc18: = require_complete_type @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) [symbolic = %require_complete.loc18 (constants.%require_complete.cfebb2.2)] // CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @I, @I(%W.loc17_16.2) [symbolic = %I.assoc_type (constants.%I.assoc_type.1e5078.3)] // CHECK:STDOUT: %assoc0: @TestGeneric.%I.assoc_type (%I.assoc_type.1e5078.3) = assoc_entity element0, @I.%F.decl [symbolic = %assoc0 (constants.%assoc0.8f0422.3)] -// CHECK:STDOUT: %F.type: type = fn_type @F.1, @I(%W.loc17_16.2) [symbolic = %F.type (constants.%F.type.2aef59.3)] // CHECK:STDOUT: %I.lookup_impl_witness: = lookup_impl_witness %A.loc17_32.2, @I, @I(%W.loc17_16.2) [symbolic = %I.lookup_impl_witness (constants.%I.lookup_impl_witness)] +// CHECK:STDOUT: %F.type: type = fn_type @F.1, @I(%W.loc17_16.2) [symbolic = %F.type (constants.%F.type.2aef59.3)] // CHECK:STDOUT: %I.facet: @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) = facet_value %A.loc17_32.2, (%I.lookup_impl_witness) [symbolic = %I.facet (constants.%I.facet.6d2)] // CHECK:STDOUT: %.loc18_11: type = fn_type_with_self_type %F.type, %I.facet [symbolic = %.loc18_11 (constants.%.fe1)] // CHECK:STDOUT: %impl.elem0.loc18_11.2: @TestGeneric.%.loc18_11 (%.fe1) = impl_witness_access %I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc18_11.2 (constants.%impl.elem0)] diff --git a/toolchain/check/testdata/impl/use_assoc_const.carbon b/toolchain/check/testdata/impl/use_assoc_const.carbon index 3af51e9737d8..fb5339a28e6a 100644 --- a/toolchain/check/testdata/impl/use_assoc_const.carbon +++ b/toolchain/check/testdata/impl/use_assoc_const.carbon @@ -557,6 +557,8 @@ fn F() { // CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc] // CHECK:STDOUT: %impl.elem0.loc9_46: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82] // CHECK:STDOUT: %bound_method.loc9_46.1: = bound_method %u.ref, %impl.elem0.loc9_46 +// CHECK:STDOUT: %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] // CHECK:STDOUT: %specific_fn.loc9_46: = specific_function %impl.elem0.loc9_46, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn] // CHECK:STDOUT: %bound_method.loc9_46.2: = bound_method %u.ref, %specific_fn.loc9_46 // CHECK:STDOUT: %impl.elem0.loc9_48: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956] @@ -815,6 +817,8 @@ fn F() { // CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba] // CHECK:STDOUT: %impl.elem0.loc11_34: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82] // CHECK:STDOUT: %bound_method.loc11_34.1: = bound_method %u.ref, %impl.elem0.loc11_34 +// CHECK:STDOUT: %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] // CHECK:STDOUT: %specific_fn.loc11_34: = specific_function %impl.elem0.loc11_34, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn] // CHECK:STDOUT: %bound_method.loc11_34.2: = bound_method %u.ref, %specific_fn.loc11_34 // CHECK:STDOUT: %impl.elem0.loc11_36: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956] @@ -1224,6 +1228,8 @@ fn F() { // CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] // CHECK:STDOUT: %impl.elem0.loc12_16: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82] // CHECK:STDOUT: %bound_method.loc12_16.1: = bound_method %u.ref, %impl.elem0.loc12_16 +// CHECK:STDOUT: %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] // CHECK:STDOUT: %specific_fn.loc12_16: = specific_function %impl.elem0.loc12_16, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn] // CHECK:STDOUT: %bound_method.loc12_16.2: = bound_method %u.ref, %specific_fn.loc12_16 // CHECK:STDOUT: %impl.elem0.loc12_18: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956] @@ -1245,6 +1251,8 @@ fn F() { // CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc] // CHECK:STDOUT: %impl.elem0.loc15_16: %.f1a = impl_witness_access constants.%impl_witness.01d, element0 [concrete = constants.%Op.c82] // CHECK:STDOUT: %bound_method.loc15_16.1: = bound_method %v.ref, %impl.elem0.loc15_16 +// CHECK:STDOUT: %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] // CHECK:STDOUT: %specific_fn.loc15_16: = specific_function %impl.elem0.loc15_16, @Op.2(constants.%int_32) [concrete = constants.%Op.specific_fn] // CHECK:STDOUT: %bound_method.loc15_16.2: = bound_method %v.ref, %specific_fn.loc15_16 // CHECK:STDOUT: %impl.elem0.loc15_18: %.be7 = impl_witness_access constants.%impl_witness.d39, element0 [concrete = constants.%Convert.956] @@ -1392,6 +1400,10 @@ fn F() { // CHECK:STDOUT: %T.as_wit.iface0.loc25: = facet_access_witness constants.%T, element0 [symbolic = %T.as_wit.iface0.loc24_34.2 (constants.%T.as_wit.iface0)] // CHECK:STDOUT: %impl.elem1.loc25_11.1: @GenericCallF.%.loc25_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc25, element1 [symbolic = %impl.elem1.loc25_11.2 (constants.%impl.elem1)] // CHECK:STDOUT: %u.ref: @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = name_ref u, %u +// CHECK:STDOUT: %as_wit.iface0.1: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc24_34.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.1: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc24_34.2 (constants.%impl.elem0.d9c3a6.2)] +// CHECK:STDOUT: %as_wit.iface0.2: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc24_34.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.2: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc24_34.2 (constants.%impl.elem0.d9c3a6.2)] // CHECK:STDOUT: %specific_impl_fn.loc25_11.1: = specific_impl_function %impl.elem1.loc25_11.1, @F.1(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc25_11.2 (constants.%specific_impl_fn)] // CHECK:STDOUT: %.loc25_15: init @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = call %specific_impl_fn.loc25_11.1(%u.ref) // CHECK:STDOUT: %.loc25_16.1: @GenericCallF.%impl.elem0.loc24_34.2 (%impl.elem0.d9c3a6.2) = value_of_initializer %.loc25_15 @@ -1667,7 +1679,11 @@ fn F() { // CHECK:STDOUT: %impl.elem1.loc9_11.1: @GenericAddResult.%.loc9_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc9_11, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)] // CHECK:STDOUT: %u.ref.loc9_14: @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = name_ref u, %u // CHECK:STDOUT: %.loc9_15.1: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] +// CHECK:STDOUT: %as_wit.iface0.1: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.1: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] // CHECK:STDOUT: %.loc9_15.2: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] +// CHECK:STDOUT: %as_wit.iface0.2: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.2: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] // CHECK:STDOUT: %specific_impl_fn.loc9_11.1: = specific_impl_function %impl.elem1.loc9_11.1, @F(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn.5d8)] // CHECK:STDOUT: %.loc9_15.3: init @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = call %specific_impl_fn.loc9_11.1(%u.ref.loc9_14) // CHECK:STDOUT: %T.ref.loc9: %J.type = name_ref T, %T.loc8_21.1 [symbolic = %T.loc8_21.2 (constants.%T)] @@ -1678,7 +1694,11 @@ fn F() { // CHECK:STDOUT: %impl.elem1.loc9_20: @GenericAddResult.%.loc9_11.2 (%.4d2) = impl_witness_access %T.as_wit.iface0.loc9_20, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)] // CHECK:STDOUT: %u.ref.loc9_23: @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = name_ref u, %u // CHECK:STDOUT: %.loc9_24.1: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] +// CHECK:STDOUT: %as_wit.iface0.3: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.3: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] // CHECK:STDOUT: %.loc9_24.2: %Add.type = converted constants.%as_type.6b96b1.2, constants.%impl.elem0.c57618.2 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] +// CHECK:STDOUT: %as_wit.iface0.4: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_38.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.4: %Add.type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_38.2 (constants.%impl.elem0.c57618.2)] // CHECK:STDOUT: %specific_impl_fn.loc9_20: = specific_impl_function %impl.elem1.loc9_20, @F(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn.5d8)] // CHECK:STDOUT: %.loc9_24.3: init @GenericAddResult.%as_type.loc8_38.2 (%as_type.6b96b1.2) = call %specific_impl_fn.loc9_20(%u.ref.loc9_23) // CHECK:STDOUT: %as_wit.iface0.loc9_17.1: = facet_access_witness constants.%impl.elem0.c57618.2, element0 [symbolic = %as_wit.iface0.loc9_17.2 (constants.%as_wit.iface0)] @@ -1892,6 +1912,10 @@ fn F() { // CHECK:STDOUT: %impl.elem1.loc9_11.1: @GenericCallInterfaceQualified.%.loc9_11 (%.9ac) = impl_witness_access %T.as_wit.iface0.loc9, element1 [symbolic = %impl.elem1.loc9_11.2 (constants.%impl.elem1)] // CHECK:STDOUT: %bound_method.loc9_11: = bound_method %t.ref, %impl.elem1.loc9_11.1 // CHECK:STDOUT: %u.ref: @GenericCallInterfaceQualified.%impl.elem0.loc8_51.2 (%impl.elem0.d9c3a6.2) = name_ref u, %u +// CHECK:STDOUT: %as_wit.iface0.1: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_51.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.1: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_51.2 (constants.%impl.elem0.d9c3a6.2)] +// CHECK:STDOUT: %as_wit.iface0.2: = facet_access_witness constants.%J.facet.085e97.2, element0 [symbolic = %T.as_wit.iface0.loc8_51.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.2: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.loc8_51.2 (constants.%impl.elem0.d9c3a6.2)] // CHECK:STDOUT: %specific_impl_fn.loc9_11.1: = specific_impl_function %impl.elem1.loc9_11.1, @G(constants.%J.facet.085e97.2) [symbolic = %specific_impl_fn.loc9_11.2 (constants.%specific_impl_fn)] // CHECK:STDOUT: %bound_method.loc9_19: = bound_method %t.ref, %specific_impl_fn.loc9_11.1 // CHECK:STDOUT: %.loc9_19: init @GenericCallInterfaceQualified.%impl.elem0.loc8_51.2 (%impl.elem0.d9c3a6.2) = call %bound_method.loc9_19(%t.ref, %u.ref) @@ -2081,10 +2105,10 @@ fn F() { // CHECK:STDOUT: %J.facet: %J.type = facet_value %T.as_type.loc8_45.2, (%T.as_wit.iface0.loc26_11.2) [symbolic = %J.facet (constants.%J.facet.869)] // CHECK:STDOUT: %.loc26_11.2: type = fn_type_with_self_type constants.%F.type, %J.facet [symbolic = %.loc26_11.2 (constants.%.861)] // CHECK:STDOUT: %impl.elem1.loc26_11.2: @GenericCallFI32.%.loc26_11.2 (%.861) = impl_witness_access %T.as_wit.iface0.loc26_11.2, element1 [symbolic = %impl.elem1.loc26_11.2 (constants.%impl.elem1)] +// CHECK:STDOUT: %impl.elem0.3: type = impl_witness_access %T.as_wit.iface0.loc26_11.2, element0 [symbolic = %impl.elem0.3 (constants.%impl.elem0.37e)] // CHECK:STDOUT: %specific_impl_fn.loc26_11.2: = specific_impl_function %impl.elem1.loc26_11.2, @F(%J.facet) [symbolic = %specific_impl_fn.loc26_11.2 (constants.%specific_impl_fn)] -// CHECK:STDOUT: %impl.elem0.loc26: type = impl_witness_access %T.as_wit.iface0.loc26_11.2, element0 [symbolic = %impl.elem0.loc26 (constants.%impl.elem0.37e)] -// CHECK:STDOUT: %require_complete.loc26_15: = require_complete_type @GenericCallFI32.%impl.elem0.loc26 (%impl.elem0.37e) [symbolic = %require_complete.loc26_15 (constants.%require_complete.8bd)] -// CHECK:STDOUT: %ImplicitAs.type: type = facet_type <@ImplicitAs, @ImplicitAs(%impl.elem0.loc26)> [symbolic = %ImplicitAs.type (constants.%ImplicitAs.type.820)] +// CHECK:STDOUT: %require_complete.loc26_15: = require_complete_type @GenericCallFI32.%impl.elem0.3 (%impl.elem0.37e) [symbolic = %require_complete.loc26_15 (constants.%require_complete.8bd)] +// CHECK:STDOUT: %ImplicitAs.type: type = facet_type <@ImplicitAs, @ImplicitAs(%impl.elem0.3)> [symbolic = %ImplicitAs.type (constants.%ImplicitAs.type.820)] // CHECK:STDOUT: %require_complete.loc26_14: = require_complete_type @GenericCallFI32.%ImplicitAs.type (%ImplicitAs.type.820) [symbolic = %require_complete.loc26_14 (constants.%require_complete.1ce)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%T.patt.loc8_20.1: %J_where.type](%t.param_patt: @GenericCallFI32.%T.as_type.loc8_45.2 (%T.as_type)) -> %i32 { @@ -2096,9 +2120,13 @@ fn F() { // CHECK:STDOUT: %T.as_wit.iface0.loc26_11.1: = facet_access_witness constants.%T, element0 [symbolic = %T.as_wit.iface0.loc26_11.2 (constants.%T.as_wit.iface0)] // CHECK:STDOUT: %impl.elem1.loc26_11.1: @GenericCallFI32.%.loc26_11.2 (%.861) = impl_witness_access %T.as_wit.iface0.loc26_11.1, element1 [symbolic = %impl.elem1.loc26_11.2 (constants.%impl.elem1)] // CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2] +// CHECK:STDOUT: %as_wit.iface0.1: = facet_access_witness constants.%J.facet.869, element0 [symbolic = %T.as_wit.iface0.loc26_11.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.1: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.3 (constants.%impl.elem0.37e)] +// CHECK:STDOUT: %as_wit.iface0.2: = facet_access_witness constants.%J.facet.869, element0 [symbolic = %T.as_wit.iface0.loc26_11.2 (constants.%T.as_wit.iface0)] +// CHECK:STDOUT: %impl.elem0.2: type = impl_witness_access constants.%T.as_wit.iface0, element0 [symbolic = %impl.elem0.3 (constants.%impl.elem0.37e)] // CHECK:STDOUT: %specific_impl_fn.loc26_11.1: = specific_impl_function %impl.elem1.loc26_11.1, @F(constants.%J.facet.869) [symbolic = %specific_impl_fn.loc26_11.2 (constants.%specific_impl_fn)] -// CHECK:STDOUT: %.loc26_14: @GenericCallFI32.%impl.elem0.loc26 (%impl.elem0.37e) = converted %int_2, [concrete = ] -// CHECK:STDOUT: %.loc26_15: init @GenericCallFI32.%impl.elem0.loc26 (%impl.elem0.37e) = call %specific_impl_fn.loc26_11.1() [concrete = ] +// CHECK:STDOUT: %.loc26_14: @GenericCallFI32.%impl.elem0.3 (%impl.elem0.37e) = converted %int_2, [concrete = ] +// CHECK:STDOUT: %.loc26_15: init @GenericCallFI32.%impl.elem0.3 (%impl.elem0.37e) = call %specific_impl_fn.loc26_11.1() [concrete = ] // CHECK:STDOUT: %.loc26_16: %i32 = converted %.loc26_15, [concrete = ] // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/struct/import.carbon b/toolchain/check/testdata/struct/import.carbon index 8a6689fe1c83..88fbd9dae811 100644 --- a/toolchain/check/testdata/struct/import.carbon +++ b/toolchain/check/testdata/struct/import.carbon @@ -328,7 +328,7 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1138 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1142 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -505,7 +505,7 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.c81: %struct_type.a.b = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1138 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1142 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -622,7 +622,7 @@ var c_bad: C({.a = 3, .b = 4}) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.c81: %struct_type.a.b.5ca = import_ref Implicit//default, loc8_9, loaded [symbolic = @C.%S (constants.%S)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc8_34, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1138 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.b8b = import_ref Implicit//default, inst1142 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/testdata/tuple/import.carbon b/toolchain/check/testdata/tuple/import.carbon index 81250825a2a9..55dfc46412ec 100644 --- a/toolchain/check/testdata/tuple/import.carbon +++ b/toolchain/check/testdata/tuple/import.carbon @@ -358,7 +358,7 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1174 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1179 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -551,7 +551,7 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1174 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1179 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -669,7 +669,7 @@ var c_bad: C((3, 4)) = F(); // CHECK:STDOUT: } // CHECK:STDOUT: %Implicit.import_ref.48d: %tuple.type.c2c = import_ref Implicit//default, loc7_9, loaded [symbolic = @C.%X (constants.%X)] // CHECK:STDOUT: %Implicit.import_ref.8f2: = import_ref Implicit//default, loc7_26, loaded [concrete = constants.%complete_type.357] -// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1174 [no loc], unloaded +// CHECK:STDOUT: %Implicit.import_ref.964 = import_ref Implicit//default, inst1179 [no loc], unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/type.cpp b/toolchain/check/type.cpp index 2a39feeffe16..fc196bc98e54 100644 --- a/toolchain/check/type.cpp +++ b/toolchain/check/type.cpp @@ -72,10 +72,8 @@ auto ValidateFloatType(Context& context, SemIRLoc loc, SemIR::FloatType result) template static auto GetTypeImpl(Context& context, EachArgT... each_arg) -> SemIR::TypeId { - // TODO: Remove inst_id parameter from TryEvalInst. InstT inst = {SemIR::TypeType::SingletonTypeId, each_arg...}; - return context.types().GetTypeIdForTypeConstantId( - TryEvalInst(context, SemIR::InstId::None, inst)); + return context.types().GetTypeIdForTypeConstantId(TryEvalInst(context, inst)); } // Gets or forms a type_id for a type, given the instruction kind and arguments, diff --git a/toolchain/sem_ir/inst_kind.h b/toolchain/sem_ir/inst_kind.h index 1356562720e8..fb02d48e2f59 100644 --- a/toolchain/sem_ir/inst_kind.h +++ b/toolchain/sem_ir/inst_kind.h @@ -123,6 +123,7 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) { llvm::StringLiteral ir_name; InstIsType is_type = InstIsType::Never; InstConstantKind constant_kind = InstConstantKind::Indirect; + bool constant_needs_inst_id = constant_kind == InstConstantKind::Unique; TerminatorKind terminator_kind = TerminatorKind::NotTerminator; bool is_lowered = true; bool deduce_through = false; @@ -160,6 +161,22 @@ class InstKind : public CARBON_ENUM_BASE(InstKind) { return definition_info(*this).constant_kind; } + // Returns whether we need an `InstId` referring to the instruction to + // constant evaluate this instruction. If this is set to `true`, then: + // + // - `Check::TryEvalInst` will not allow this instruction to be directly + // evaluated without an `InstId`. + // - `Check::EvalConstantInst` will be passed an `InstId` for the original + // instruction being evaluated. + // + // This is set to true for instructions whose evaluation either might need a + // location, for example for diagnostics or for newly-created instructions, + // and for instructions whose evaluation needs to inspect the original form of + // its operands. + auto constant_needs_inst_id() const -> bool { + return definition_info(*this).constant_needs_inst_id; + } + // Returns whether this instruction kind is a code block terminator, such as // an unconditional branch instruction, or part of the termination sequence, // such as a conditional branch instruction. The termination sequence of a @@ -214,6 +231,11 @@ class InstKind::Definition : public InstKind { return info_.constant_kind; } + // Returns whether constant evaluation of this instruction needs an InstId. + constexpr auto constant_needs_inst_id() const -> bool { + return info_.constant_needs_inst_id; + } + // Returns whether this instruction kind is a code block terminator. See // InstKind::terminator_kind(). constexpr auto terminator_kind() const -> TerminatorKind { diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index c5de14ffb100..700c346c11a5 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -188,6 +188,7 @@ struct ArrayType { {.ir_name = "array_type", .is_type = InstIsType::Always, .constant_kind = InstConstantKind::Conditional, + .constant_needs_inst_id = true, .deduce_through = true}); TypeId type_id; @@ -771,6 +772,7 @@ struct FloatType { {.ir_name = "float_type", .is_type = InstIsType::Always, .constant_kind = InstConstantKind::Conditional, + .constant_needs_inst_id = true, .deduce_through = true}); TypeId type_id; @@ -909,6 +911,7 @@ struct ImplWitnessAccess { {.ir_name = "impl_witness_access", .is_type = InstIsType::Maybe, .constant_kind = InstConstantKind::SymbolicOnly, + .constant_needs_inst_id = true, .is_lowered = false}); TypeId type_id; @@ -1058,6 +1061,7 @@ struct IntType { {.ir_name = "int_type", .is_type = InstIsType::Always, .constant_kind = InstConstantKind::Conditional, + .constant_needs_inst_id = true, .deduce_through = true}); TypeId type_id; @@ -1082,6 +1086,7 @@ struct LookupImplWitness { InstKind::LookupImplWitness.Define( {.ir_name = "lookup_impl_witness", .constant_kind = InstConstantKind::SymbolicOnly, + .constant_needs_inst_id = true, .is_lowered = false}); // Always the type of the builtin `WitnessType` singleton instruction. @@ -1285,6 +1290,7 @@ struct RequireCompleteType { InstKind::RequireCompleteType.Define( {.ir_name = "require_complete_type", .constant_kind = InstConstantKind::SymbolicOnly, + .constant_needs_inst_id = true, .is_lowered = false}); // Always the builtin witness type. TypeId type_id; @@ -1423,7 +1429,8 @@ struct SpecificConstant { struct SpecificFunction { static constexpr auto Kind = InstKind::SpecificFunction.Define( {.ir_name = "specific_function", - .constant_kind = InstConstantKind::Conditional}); + .constant_kind = InstConstantKind::Conditional, + .constant_needs_inst_id = true}); // Always the builtin SpecificFunctionType. TypeId type_id; @@ -1459,7 +1466,8 @@ struct SpecificImplFunction { static constexpr auto Kind = InstKind::SpecificImplFunction.Define( {.ir_name = "specific_impl_function", - .constant_kind = InstConstantKind::SymbolicOnly}); + .constant_kind = InstConstantKind::SymbolicOnly, + .constant_needs_inst_id = true}); // Always the builtin SpecificFunctionType. TypeId type_id;