What this does:
- Adds tracking where storage is allocated.
- Determines if that storage supports destruction and, if so, records
the `destroy` function for it.
- Calls any found `destroy` functions when going out-of-scope.
What this does not do:
- Precise scope tracking of temporaries. We currently don't define
temporary scopes, which would probably be the solution.
- Destruction for anything but a `class` with `fn destroy`, in an
implicit return. That excludes:
- Classes with members that need destruction, particularly in the
absence of `fn destroy`.
- Structs, tuples, and arrays.
- Explicit returns, break, continue, nested scopes.
Noting the exclusions in particular, I think those will need work to
support, but this should set the right framework.
The cleanup block concept stems from clang and trying to share code
across cleanups, from discussion with chandlerc. Note in this
implementation I try to find `destroy` functions early on: that's so
that, when destruction is present on multiple paths, particularly
non-shared paths, we only bind the `destroy` method once.
Implementation-wise, I'll note this adds a `has_cleanup` flag to
`TemporaryStorage` and `VarStorage`. There are several related options,
but this felt similar to other information we're trying to track on
instructions. My goal with this is to mitigate the chance of accidental
calls where the storage may not be tracked for destruction. Alternatives
I considered were to not add the flag (I was worried about heightened
risk of errors), or to just add a concept for the relevant `requires`
(which just felt inconsistent).
Cleanup logic ends up in control_flow in this change because I thought
it was a reasonably consistent place for the cleanup block concept and
its pretty direct control flow interactions.
The instruction does act somewhat like a witness, saying that an impl
does exist for a lookup, but the instruction more concretely represents
an impl lookup - since that is done when it is evaluated.
As of #5087, these terms are no longer synonyms. This change preserves
the original meaning.
---------
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
These parameters are never deduced, so they prevent the impl decl from
ever being used. But we also don't emit diagnostics inside impl lookup,
so there's nothing provided to the user explaining that they made an
impl that is useless.
Given the namespacing of `Diagnostics` in #5173, now we can use
`DiagnosticEmitter` for phase-specific emitters. This is consistent with
how we do `Context`, and also check had started this with
`DiagnosticBuilder` in anticipation of the namespacing.
Also renames `Emitter::DiagnosticBuilder` to `Emitter::Builder` for
consistency with other `Diagnostics` entities.
In check, I'm still splitting `DiagnosticEmitterBase` and
`DiagnosticEmitter` just to keep the emitter definition separate from
the context.
Also cleans up some incorrect check diagnostic emitter dependencies in
lower.
- A concrete query should poison any further specializations of an impl
that are found in the same file.
- A symbolic query should poison any final specializations of an impl
that are found in the same file.
- A final generic specialization should allow generic code to use the
concrete type in an associated constant.
The last one was discussed in open discussion:
https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.g7v3y38ydkc7
We decided to take this approach for now, as it reduces possible states
that we have to deal with in the toolchain. And we can revisit if it's
causing problems for ordering impls in carbon code.
Seems the instructions got emitted out of order & that caused problems
for lowering. This was because most of the initialization instructions
were added to a PendingBlock, but the vptr initialization instructions
were added to the (non-pending) block directly.
(I don't fully understand the pending stuff (is there a different test I
could/should write that demonstrates the vptr init instructions not
being discarded because they didn't go in the pending block (before this
patch)), or the out of order instruction problem (could we add more
robust checking for instruction ordering?) - but perhaps this is
adequate understanding for this bug fix at least)
Fixes#5094
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
My intent with `Push` is to make it easier to see the ordering
relationship between output and , at least in some cases.
I'm using a variant with `Push`, but that could've also been a function
with variadic arguments. The `ArrayRef` approach felt useful in that it
generates less code, and allows the `PushItem` construction in
`FunctionTypeWithSelfType` handling. Note I didn't really use that
elsewhere, but in theory it could be.
Adds support for `llvm::ListSeparator` in order to help eliminate
`llvm::seq` use.
Also increases the variant use here. The discriminated `Step` union was
added in #4511, and it's not clear to me from that PR why variant wasn't
used. In general I'm trying not to change API choices that were made
there.
I considered renaming all the `PushString` etc functions to just be
`Push` overloads, but I'm on the fence about whether that's just going
to be a naming bikeshed, so I left them alone. Also considered a
`WriteAndPush("foo", {...});`, but that'd require merging `StepStack`
and `Stringifier` and I'm hesitant to go ahead with that. This PR I view
as more objective refactoring that hopefully makes everyone happier.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
I was thinking about this after `seq` changes in #5182, and looked for
other uses that might be replaceable. Here's the resulting cleanup
around `seq`:
- Switch to `enumerate` or `zip` when possible.
- `int _` -> `auto _` (it's typically a `size_t`, but there's no reason
to cast when unused)
- Fix a case of cast style `(size_t)...` -> `static_cast<size_t>(...)`
- Switch `(void)close_children_count` to `[[maybe_unused]]`
What this really does is avoids shadowing names, so that we can
comfortable have things like `Check::DiagnosticEmitter` or
`Check::DiagnosticLoc` without shadowing being a concern.
Note, down this path I'm also thinking about:
- Renaming misc DiagnosticConsumer/DiagnosticEmitter classes, possibly
just to DiagnosticConsumer/DiagnosticEmitter (so
`Check::DiagnosticEmitter` instead of `SemIRLocDiagnosticEmitter`).
- Dropping `Diagnostic` from `Emitter::DiagnosticBuilder`.
- But not for `Check::DiagnosticBuilder`, because `Check::Builder` would
be ambiguous.
- Renaming diagnostics/diagnostic_* to drop "diagnostic".
[Discussion about SemIRLoc ->
DiagnosticLoc](https://discord.com/channels/655572317891461132/655578254970716160/1353771570463768698)
reminded me of this (in particular the older [Check::DiagnosticBuilder
discussion](https://discord.com/channels/655572317891461132/655578254970716160/1344363562608627763)),
but I'd only do that rename if there's matching consensus about a path
forward where we keep SemIRLoc, and in a way that it's only ever used
for diagnostics (the divergence from which is at the root of current
LocId discussion).
I'm trying to keep that separate from a namespace addition for clarity.
Add a new instruction called ImplSymbolicWitness which represents a
search for an impl declaration given a self type and an interface to
find implemented for the self type. The self type is stored as a
constant instruction id, rather than as a ConstantId, as instructions
don't currently support holding ConstantId. The interface is stored as a
SpecificInterface but we can't fit all of it directly into the
instruction. So we add a new id to refer to the SpecificInterface as
follows.
Add a new SpecificInterfaceId which indexes into a canonical value store
on SemIR::File. This tracks all `SpecificInterface`s stored in an
instruction - specifically the ImplSymbolicWitness instruction.
The SpecificInterface on Impl is still stored there as a value, not as
an id, and no id is eagerly constructed for it. We wait until an id is
needed to make one. Since they are canonical, a new id is only create
when a new SpecificInterface value is seen.
When doing impl lookup, and the query is not concrete, and the impl is
not effectively final, the query needs to consider future impls that may
specialize either the self type or the constaint to make a more precise
match and replace the found impl declaration. Instead of returning the
ImplWitness instruction from the found impl, we generate a
ImplSymbolicWitness instruction, storing the query so that it can be
replayed later. This instruction is added to the generic eval block and
thus will be re-evaluated later with a SpecificId that may make the
query more concrete. When evaluating the instruction and replaying the
query, the lookup has the same conditions and if it does not decide to
use the found impl concretely, then the same instruction is returned
from eval, leaving it as symbolic.
--- Impl lookup changes ---
Impl lookup gets a little more interesting now. It continues to look in
the facet value for a witness if the self type is a facet value. Then
falls back to looking for an impl declaration. This step is no longer
done directly. Instead, we construct a ImplSymbolicWitness instruction
and evaluate it immediately for each interface that are in the query
facet type.
The ImplSymbolicWitness instruction, when evaluated, calls back to the
impl lookup code, with a query specific interface. There we resume back
into the same code path as from before, finding a witness in an impl
declaration. But we may return "found a non-final impl" instead of a
concrete witness. If eval receives this back, it evaluates to the
current ImplSymbolicWitness instruction as the resulting constant value.
To pass lookup failures back through eval, a result of InstId::None from
the second step of impl lookup will result in a non-constant value,
which is used as a signal back up the stack to the original impl lookup
function that the lookup failed. Using a non-constant value here would
break evaluation of the generic eval block if impl lookup could fail
there, however we know it will not since we only leave behind an
ImplSymbolicWitness instruction in the eval block if we found at least
one matching impl already, and we just want to look for a better match
with a more specific query.
We must take care to not store a reference into any value store across
computation in impl lookup, since impl lookup can recurse into itself
invalidate those stores. That includes the SpecificInterface obtained
from a SpecificInterfaceId, which impl lookup also inserts into the
store.
--- The long tail ---
Adding a new instruction and a new id type requires a myriad of changes
to support them:
We add Dump() support for SpecificInterfaceId. And fix a crash in Dump
for SpecificId::None. We also add MakeSpecificInterfaceId() for dumping
arbitrary ids.
The type of ImplSymbolicWitness is a new singleton builtin type
instruction called WitnessSymbolicType (like WitnessType is the type for
an ImplWitness).
Both ImplSymbolicWitness and WitnessSymbolicType are given `Value` as
their expression category as they are builtin constant values. And
BuildInfo() in TypeCompleter is taught about them both, returning a
`ValueRepr::Copy`.
WitnessSymbolicType is added to the set of SingletonInstKinds, so that
it can have a singleton instrution id as a static member.
Lower's BuildTypeForInst() is taught to make an empty struct for
WitnessSymbolicType, similar to WitnessType.
Instruction formatter (FormatterImpl) grows support for printing a
SpecificInterfaceId so that it can print both arguments of
ImplSymbolicWitness on the RHS when printing the SemIR instruction. To
print a SpecificInterfaceId, it prints both the interface id and the
specific id (if there is one). For example, for a query on a generic
interface `Z` with one parameter, the RHS includes the query, interface,
and specific:
```
%Z.impl_symbolic_witness: <symbolic witness> = impl_symbolic_witness %U, @Z, @Z(%U.as_type) [symbolic]
```
IdKind is extended to include SpecificInterfaceId.
InstFingerprinter is taught to look through SpecificInterfaceId and use
the interface and specific ids in the fingerprint.
InstNamer is taught about SpecificInterfaceId, counting the interfaces
when building an index. It is also tought about ImplSymbolicWitness,
using the name of the interface within and the `.impl_symbolic_witness`
suffix. For example, here the LHS is named after the interface in the
query:
```
%Z.impl_symbolic_witness: <symbolic witness> = impl_symbolic_witness %U, @Z, @Z(%U.as_type) [symbolic]
```
StringifyTypeExpr is taught about WitnessSymbolicType, which uses its IR
name since it's a singleton. And about ImplSymbolicWitness which uses
its constant value. The handling of ImplWitnessAccess also needed to be
adjusted, since it assumed that ImplWitnessAccess::witness_id would
always be a FacetAccessWitness, but it can now also be an
ImplSymbolicWitness. (It seems that the witness_id is also assigned
ImplWitness instructions, but those ImplWitnessAccess instructions don't
ever seem to get stringified in a diagnostic at this time.) At the
moment the ImplWitnessAccess with a symbolic witness is just stringified
as "<symbolic>", such as in:
```
x.carbon:1:2: error: cannot implicitly convert value of type `()` to `<symbolic>` [ConversionFailure]
let a: C(D).(Z.X) = ();
^~
```
There is a TODO left behind to include more information there.
The TypeStructure builder is made to handle WitnessSymbolicType and
WitnessType. These come up now in deduce where a generic impl will have
a ImplSymbolicWitness in a FacetValue for a generic self type. The query
may have a concrete ImplWitness in the same position. Since deduce tries
to deduce through the FacetValue, it tries to convert ImplWitness to
ImplSymbolicWitness, tries to do an impl lookup for `impl ImplWitness as
ImplicitAs(ImplSymbolicWitness)` and causes us to build type structures
with each of these.
Subst is updated to handle pushing and popping SpecificInterfaceId.
Without this, when finishing a generic's eval block, we would walk into
the ImplSymbolicWitness instruction, and its arguments, and fail to
recurse down into the SpecificInterfaceId. Then any specifics inside
would be left as "orphaned" without any generic id attached to them, and
we would never update the instructions in the SpecificInterface's
instructions (inside its own SpecificId) with new constant values when
evaluating the generic eval block against a specific. To do this we push
the specific_id inside the SpecificInterface, and when popping we pop
the specific_id then construct a new canonical SpecificInterface with it
and return that id.
We add support for importing ImplSymbolicWitness by importing its self
constant instruction and specific interface id. However we also had to
add import support for SpecificImplFunction, which can now appear in the
generic eval block for a generic impl declaration, and thus must be
imported with the declaration. This is done very similarly to
SpecificFunction, except the `type_id` is a singleton value.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
When transforming instructions with symbolic constant values into the
eval block, we previously special-cased `bind_symbolic_name` (and
`symbolic_binding_pattern`) because they are places where symbolicness
is introduced, rather than propagated from operands, and just copied
them into the eval block. However, `bind_symbolic_name` can be dependent
on other symbolic constants, because it can have a type that is
dependent. In this case, the copy in the eval block would not have its
type properly adjusted to refer to the type within the eval block.
Fix this by performing substitution into `bind_symbolic_name` rather
than copying it directly, and instead, detect cases where substitution
determined that the instruction was unchanged despite having a symbolic
constant value, and force it to be rebuilt in that case.
I've not found any way that the previous behavior actually caused
problems, or affected the observable behavior of the toolchain. The type
of these instructions in the eval block doesn't make much difference to
anything because they get immediately replaced by their corresponding
argument values when we run the eval block. But this came up and caused
some test output churn when I was making a different change, and it
seems like a fix to our representation even if it's not changing
behavior, so I'm splitting it out so it can be handled separately.
StringifyTypeExpr has gotten a little long. I know there's some
preference for the effects of explicitly handling cases, but maybe it's
okay to adopt an overload pattern similar to what we do elsewhere? Note
I'm trying to force types to provide overloads, as a case which are
clearly intended to be handled.
Also, perhaps subtly, the list of "singleton" instructions previously
included Vtable, which is not a singleton. With this change, which
instead directly handles singleton instructions by
`requires(IsSingletonInstKind(InstT::Kind))`, Vtable will switch default
handling. But it's not directly printed for types, so there is no net
impact on IR.
At present I have this split from `StepStack` because with these changes
it'd no longer be a simple stack. It felt like maybe the type separation
would help readers.
Merges in the "subtyping" tests from the `impl/lookup` directory along
with some new tests into
`convert_facet_value_to_narrowed_facet_type.carbon` in the `facet`
directory.
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
This fixes a `copy constructor must pass its first argument by
reference` compilation error when compiled with a recent enough Clang
(after
https://github.com/llvm/llvm-project/commit/fe0d3e3764961b62f43f1b129f30aaec5f30bc16,
targeted for LLVM 21 release).
```
carbon/lang/common/set.h:81:59: error: copy constructor must pass its first argument by reference
81 | SetView(SetView<std::remove_const_t<KeyT>, KeyContextT> other_view)
| ^
```
`AddDefaultValue` doesn't quite capture the intended semantics; it
should typically be replaced with an actual value when dealing with
control flows. Trying to indicate the "assign later" with
`AddPlaceholder`, mirroring `AddPlaceholderInst`.
Shifting the `protected` functionality on `BlockValueStore` so that it's
not providing functions just for `InstBlockStore` to use. Also hoping
that seeing the comments next to the function name makes them easier to
understand, whereas `using` buries that a little.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
When a generic function declaration was encountered for the second or
more time, we would FinishGenericRedecl() for the function decl, but
this just popped the generic region stack and moved on.
The issue with that is when the stack entry is gone, we lose the
symbolic constants from that declaration, and are unable to rewrite them
to point to the actual generic. This left us with a function declaration
with abstract symbolic values that were not useful, and in a function
call we use the declaration attached to the definition, which would be a
declaration with broken symbolic values. Then the function would be
uncallable since deduce would be unable to determine argument types
without the generic bindings.
This resolves the issue for functions, as well as ensuring the correct
generic id from a previous declaration is used for other generic entity
types that have redeclarations.
When a function declaration is qualified, such as defining a class
method outside the class body, we need only the function declaration to
contribute to its generic region stack. The code was collecting constant
values from all qualifier segments together incorrectly.
So when we PushNameQualifierScope(), we also drop the current generic
region stack and rewrite its constant values by calling
FinishGenericRedecl(), and open a new stack entry for the next part of
the qualified declaration.
If a generic declaration somehow has more dependent instruction than a
previous declaration, it would add new instructions to its eval block
with indices beyond the elements in the actual declaration eval block,
since we only store the block from the first declaration found. To avoid
this we plumb through that we are in a redeclaration, and terminate with
an ICE instead of adding new instructions to crash on later.
Fixes#5136.
Building on #5151 reducing `UncheckedLoc` use, further remove uses of
the `SemIR::LocIdAndInst` constructor where we typically have overloads
that don't need it. Add parallel convenience wrappers for placeholder
insts.
Also refactors `MergeReplacing`. I don't think it makes sense to add an
overload for `ReplaceLocIdAndInstBeforeConstantUse`, but we can still
reduce the `LocIdAndInst` construction there.
- A test that should fail that looks to see we poison impls when we do a
concrete lookup, so you can't define an impl specialization after we
looked for it. This currently passes but should fail.
- A test with a final specialization with a type constant written before
a generic function using it. The generic function should be able to know
the concrete type of the constant. This currently fails, and was
discussed in open discussion here:
https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.swr8311y952x
- A test with a specialization written after a generic function, which
will be used symbolically so the type constant will not be known. This
fails and should continue to, though the error diagnostic may change in
time.
- A test with a specialization written after a generic function, and
which returns a value typed as the type constant from that
specialization. The generic is called with types that should cause it to
use that specialization in the specific, so the caller gets back the
type expected. This currently fails but should pass.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
It's helpful for stability to not have the path in the repo reflected in
test files, something I'm separately running into. So to reduce this,
align INCLUDE-FILE with other split behavior:
- Use the filename (with a "include_files/" subdir to disambiguate),
rather than the full path.
- Note if we eventually want to support splits in these, the same
approach could be extended.
- Only provide as an arg if the user requests files as args.
Factoring AddFile back because it's hard to share; I'm also advocating
to remove the prelude manifest, which would mean the remaining call
could be removed.
The type structure is built for the impl lookup query for the
combination of the self type and the interface being queried. Then it is
built for each `impl` definition that is a potential candidate.
The type structures are compared to ensure they have a compatible
structure, and the `impl` declaration is not considered if they do not.
Finally, the type structures are used as a sorting key for the candidate
`impl` declarations, with the most-specified type structures (the ones
with the furthest distance to the first symbolic value) coming first in
the ordering.
See
https://docs.carbon-lang.dev/docs/design/generics/overview.html#parameterized-impl-declarations
for the design of the type structure and related ordering.
Most of the commits in this PR landed in #5158 (11ae0e27ab) by
mistake, but this includes the final changes since that PR was written.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
When the parameter is a deduced symbolic FacetValue, refering to a
BindSymbolicName, and the argument is a concrete FacetValue that would
match the FacetType requirements on the BindSymbolicName's type, we
currently do not deduce that the argument matches the parameter.
The argument is not _converted_ to the parameter type because they are
both FacetValues of the same FacetType type. However they are also not
equal constant values so the argument is not saved as a deduced match
for the parameter.
In order to accept the FacetValue, we need to consider them as
`deduce_through`, which attempts to deduce each of the fields in the
argument FacetValue against the fields in the parameter FacetValue.
This deduces that the argument's concrete type matches the symbolic
BindSymbolicName and its witnesses are the same.
Since the parameter is a FacetValue, its argument is not the type that
needs to be recorded as the deduced type for the binding. The
BindSymbolicName inside the parameter is the place that we need to find
the deduced type for the binding. So simply walking into the FacetValue
gets us to that position, where we eventually record the deduced
argument type as being the concrete type from the original argument
FacetValue.
Similarly, when determining what interfaces are satisfied by a
FacetValue for deduce, we want to use the full type available in the
FacetValue rather than just those from its FacetType. Determining
availability of interfaces here is equivalent to converting, and we want
converting a FacetValue to always work on the full available type info.
Only API access (member lookup) is restricted by a FacetValue to the
interfaces provided by its FacetType type.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
If a self type is FacetAccessType, we look through it at the facet
value, both for the query and the impl declaration. This ensures that
while FacetAccessTypes match each other for constant value equality
still, they an also match with facet value queries, such as:
```
impl forall [T:! Y] T as Z {}
^ FacetAccessType for BindSymbolicName of type FacetType(provides Y).
fn F(y:! Y) {
y as Z;
^ Facet value
}
```
Here the facet value and FacetAccessType don't have the same constant
value. Deduction will give the `T!: y` binding the facet value of `y`,
but the `T` in `T as Z` is a FacetAccessType to that binding, which is a
different constant value. Looking through the FacetAccessType gives us
the desired constant value for comparison with the query.
Additionally if the query self value is a FacetValue instruction, look
through that at the underlying type value. Impl lookup is used to
convert from one type or facet value to a new facet value of the desired
facet type. We want facet values to always be able to convert to
everything possible, rather than to have that restricted to just their
current FacetType:
https://github.com/carbon-language/carbon-lang/issues/5137. So this
allows queries such as `(C as Y) as Z` for a class `C` and interfaces
`Y` and `Z`.
This example motivated a decision to add a feature where we do impl
lookup to see if there is a matching `final` impl even in some cases
where it is already established that the type implements the interface.
I don't know when we plan on implementing this, but I wanted to capture
the example as test so we would have a TODO to address it.
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
This makes it friendlier in interactive debuggers. If you want to print
a value without a newline from code, you will have to be calling Print()
anyway since Dump() is private, and Print() does not add a newline.
Resolves TODO by creating new function `GetAssociatedValue` with the
logic from `PerformCompoundMemberAccess` restricted to the
non-instance-binding case.
---------
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Adds subset conversion of `NodeIdOneOf` due to the choice usage, plus
the pre-existing TODO. Fixes incorrect information about nodes on
StructLiteral and TupleLiteral.
After this change, `UncheckedLoc` is only used in a couple import
contexts (hard to verify) plus `InstStore::GetWithLocId`.
I've found myself cleaning up other cases of this, so moving to disallow
it.
```
In file included from toolchain/check/merge.cpp:5:
In file included from ./toolchain/check/merge.h:8:
In file included from ./toolchain/check/context.h:13:
In file included from ./toolchain/check/decl_introducer_state.h:8:
In file included from ./toolchain/check/keyword_modifier_set.h:11:
In file included from ./toolchain/sem_ir/name_scope.h:10:
In file included from ./toolchain/sem_ir/ids.h:12:
./toolchain/diagnostics/diagnostic_emitter.h:95:11: error: static assertion failed: Use `emitter.Emit(...)` or `emitter.Build(...).Note(...).Emit(...)` instead of `emitter.Build(...).Emit(...)`
95 | false,
| ^~~~~
toolchain/check/merge.cpp:92:61: note: in instantiation of function template specialization 'Carbon::DiagnosticEmitter<Carbon::Check::SemIRLoc>::DiagnosticBuilder::Emit<>' requested here
92 | context.emitter().Build(loc, ExternRequiresDeclInApiFile).Emit();
| ^
1 error generated.
```
Allow qualified name lookup into classes and interfaces as soon as we
reach the `{` of the definition, rather than disallowing such lookups
until we reach the `}`.
This prevents conversion from an InstId which is its base class, and
documents that this is invalid in the code.
Also expand the comment on the AbsoluteInstBlockId, which I had locally
but seem to have not saved and included in #5141.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
We were going to lengths to make these functions callable only if
`LocIdAndInst` was constructible, but nothing was depending on that and
it was harming readability and probably making diagnostics worse. So
stop doing that.
Move call_params_id from EntityBaseWithParams to FunctionFields.
No visible difference for Function. Since field call_params_id is
function specific fits better in FunctionFields.
Currently we do `settings set` twice which means the second one
overrides the first one, instead of ending up with a source-map that has
both entries in it.
When performing a call through an impl witness, the callee that we
type-check against is the function in the interface, so we form a
specific for that callee. However, once the impl witness access
resolves, the eventual callee is a different function -- the function in
the impl -- so this would cause us to form a `SpecificFunction` where
the callee is one function but the specific refers to a different
function.
Address this by adding another instruction, `SpecificImplFunction`, that
takes a function in an impl and a specific for the corresponding
function in the interface, and computes and returns a `SpecificFunction`
referring to the corresponding specific function in the impl, or returns
a direct reference to the function in the `impl` if it's not a generic
function.