Pursuant to recent decisions on #6124, switch `Destroy` to use a
`CustomWitness` for its implementation. Right now this is manufacturing
no-op implementation functions on each lookup, which obviously isn't
ideal but is intended as a first pass. I'm mostly trying to find the
right balance between updating the approach to reflect new decisions,
while still breaking apart work in a way.
The `CoreInterface` logic is intended to build on `CoreIdentifier`
support. We have a number of additional interfaces that require
specialized logic, and that'll extend pretty far with C++ interop, so it
seemed easiest to have a generic function for it. That's what's
replacing the logic inside C++ interop that was doing string comparisons
(which could have already been moved to `CoreIdentifier`, I just missed
it in my first pass).
This adds `CustomWitness` support because the `Destroy` witnesses can be
imported cross-file. `CustomWitness` was previously only used for C++
types, which don't yet support import, which is why that wasn't
previously an issue. The addition of `query_specific_interface_id` is
similarly needed in order to get correct sorting of witness blocks when
imported.
This PR also removes builtin constraint logic (note this is in a
separate commit to help review; it's not a separate PR because it's
difficult to split apart without tests breaking). This had been made
generic with the expectation that destroy, copy, move, and conversions
would all need related support. Under the new decision, we are not going
to do blanket impls and will instead just manufacture a `CustomWitness`
for everything.
A lot of SemIR fingerprints change, but that's probably because the
addition of `Destroy` on core classes is yielding structural changes.
The impl's body block has to end before we make its ImplDecl
instruction, and the witness instructions come later, so they don't end
up in the body block. Currently they just end up in the enclosing (file,
typically, or class) scope block.
Add a new InstBlockId to Impl for holding witness instructions, and
explicitly insert them into that block. Then include those instructions
into the scope of the Impl for naming, and format them into the Impl
right after the body block.
This is based on #6484
Instead of burying operations to pop the generic stack in
`GetOrAddImpl`, we move them up to handle_impl.cpp in `BuildImplDecl`,
which puts them at the same level as other operations on the generic
stack, like `StartGenericDecl` or `FinishGenericDefinition`.
To do so, we split `GetOrAddImpl` into a few pieces:
- `FindImplId` finds an existing Impl that matches the declaration, or
returns a LookupBucketRef and whether an error was diagnosed instead.
- `AddImpl` takes a fully built `Impl`, makes an `ImplId` for it, and
does additional steps for a new `Impl` verifying it and applying
`extend`.
- `AddImplWitnessForDeclaration` constructs the `Impl`'s witness, which
must be done between two generic steps in order to use the generic's
self specific but also add the witness instruction to the generic.
We group the logic to build the initial table in the definition and to
complete it in the definition together in `impl.cpp`. And we save a
lookup into the ImplStore by passing Impl by reference to
`FinishImplWitness`, as we now do for other similar functions in
`impl.h`.
This is based on #6470.
Instead of naming the root namespace `package` (because it's accessed by
the `package` keyword), change it to use the current package name. Note,
buried in the checksum changes,
`toolchain/check/testdata/package_expr/fail_not_found.carbon`:
```
- // CHECK:STDERR: fail_not_found.carbon:[[@LINE+4]]:16: error: member name `x` not found in `package` [MemberNameNotFoundInInstScope]
+ // CHECK:STDERR: fail_not_found.carbon:[[@LINE+4]]:16: error: member name `x` not found in `Main` [MemberNameNotFoundInInstScope]
```
for:
```
// CHECK:STDERR: var y: i32 = package.x;
// CHECK:STDERR: ^~~~~~~~~
```
I'll leave it to you if you prefer this; the alternative I see is to
just rename `IsCorePackage` to `IsImportedCorePackage`, and/or change it
to a helper that takes a `Context` and does the right thing with
`parse_tree` (which, I need for `Destroy`-related reasons and was my
default approach).
Explicitly run `RequireCompleteType` for an impl's facet type constraint
in two places:
- For a new `Impl` declaration that is `extend`
- At the start of the `Impl` definition
Stop trying to RequireCompleteType in the definition when constructing
the witness. If we have a rewrite of a name in `.Self`, then we can
construct a full witness, otherwise we defer to the definition.
Now GetOrAddImpl does not need to track `is_definition` anymore, so we
remove a lot of plumbing.
We inline the `AllocateFacetTypeImplWitness` since it has a single
caller and it is just 2 lines, to help improve understanding of the
steps and comments in setting up the impl definition.
Note that this puts the `RequreCompleteType` instruction into the
definition's generic eval block always, avoiding the issue of ensuring
that each generic redecl has the exact same instructions, and forcing
coordination to have `RequireCompleteType` inserted into every
declaration's eval block or none. The result also more closely matches
the design, with the complete type not being required until inside the
definition.
This is part of #6420 which is being split up into a chain of smaller
PRs. It is based on #6469.
The orphan rule is defined here:
https://docs.carbon-lang.dev/docs/design/generics/details.html#orphan-rule
**Orphan rule:** Some name from the type structure of an `impl`
declaration must be defined in the same library as the `impl`, that is
some name must be *local*.
Update tests that were running afoul of the orphan rule unintentionally.
Add tests that do violate the rule intentionally and test edge cases.
Propagate error state in an `extend impl` declaration out to the
enclosing scope. We can do this generically in `ApplyExtendImplAs` so we
don't have to do it explicitly in other places.
Collapse `DiagnoseExtendImplOutsideClass` into `ApplyExtendImplAs` as it
had only the one caller and is very small, so this simplifies the code,
making `ApplyExtendImplAs` a clear set of diagnostics. And push the
construction of the SpecificConstant down into `ApplyExtendImplAs` so it
is only constructed if it's needed, instead of constructing it and
throwing it away in error cases.
Ensure any error in the declaration results in the witness being an
ErrorInst so the impl will not be used in impl lookup. This simplifies
some branches by combining them into a single if statement.
This is part of #6420 which is being split up into a chain of smaller
PRs. It is based on #6467.
I need this in a forthcoming PR, to reliably get the `Function` that was
originally used to build a `Call` inst, but even as a stand-alone
change, it seems to nicely improve the textual SemIR.
This separates the return type from the return pattern, and replaces the
return pattern with a block of return patterns. This is a step toward
support for `ref` returns (where there's no corresponding return
pattern) and compund-form returns (where there may be multiple return
patterns).
Just as names from an `extend` scope get included in the containing
scope, so do errors. Apply this logic to `extend require impls`,
propagating any errors up.
This is based on #6465.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
We encode the state of looking that the parent scope is a Class into a
type so that we can avoid extra lookups. Then use that in refactoring
where diagnostics are generated for an explicit `Self` in an `extend
impl` declaration.
We add tests that we don't double-diagnose the Self type when it's
already an error, and make the behaviour of `extend require` match that
of `extend impl as`.
This avoids some fragile/complex parse-node lookups (such as
`context.parse_tree_and_subtrees().ExtractAs<Parse::ImplTypeAs>`) by
using the parse node at the point where we are handling it instead of
much later.
This is part of #6420 which is being split up into a chain of smaller
PRs.
This is a prerequisite for support for interop with C++ template names.
No behavior change here, except that it sadly changes the fingerprinting
for a lot of tests.
The FacetTypeId should never be used directly, since the RequireImpls is
a generic and the facet type may be parameterized by generic bindings.
So instead, it should be accessed through GetConstantValueInSpecific,
which works with the facet type InstId that is also already present on
RequireImpls. This change to use GetConstantValueInSpecific was done in
#6435, so the FacetTypeId is now unused except in formatting. So we can
remove it.
This depends on #6435.
When forming an IdentifiedFacetType, we collect interfaces named by
require decls in named constraints that the facet type refers to. These
interfaces come with a specific, but the require decl is inside an named
constraint which may be generic. So we need the specific being applied
to the containing named constraint to also be applied to the require
decl and its target interfaces.
This uncovered that the facet type in require decls was not being
imported correctly, as it was not being attached to the require decl's
generic. This is fixed by making import of RequireImplsDecl multiphase,
so that the decl instruction exists before we resolve the facet type
within it. And by pointing the generic importing machinery to the
RequireImplsDecl, and from there to the RequireImpls structure to get
the generic id.
Then `ImplStore::GetOrAddLookupBucket` can use an IdentifiedFacetType to
correctly get the interface being impl'd, both in the local and the
imported named constraint case. Which allows us to correctly diagnose
redeclarations in the impl file of an impl of an interface through a
named constraint. And to correctly _not_ diagnose them when the specific
in the generic named constraint differs from other decls.
Define rules for `extend` declarations (`extend require`, `extend impl
as`, `extend base`, `extend adapt`) that say the target scope they name
must be complete at the point of the declaration. Define completeness
for a facet type to include all interfaces and named constraints that
provide unqualified name lookup through the facet type.
---------
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Right now, the impl lookup can both fail to resolve the specific
definition because it's symbolic, and return a "final" constant because
it's a `final impl`. This is adding an instruction to help ensure the
specific is resolved.
The constant evaluation is fully recursive, but I'm not adding a TODO
since that's a known issue with impl lookup in general.
I was trying to figure out the right way to get specifics to be added to
the work.
Technically, we could keep the pending_specific list; this is taking a
different approach of inserting inside the work stack, which will do
extra work moving entries, although typically that should be expected to
be small. One challenge of `pending_specifics` is that if we would need
to shift them to work after both `Done` (for immediate processing) and
`Retry` (for processing after the current instruction is later revisited
and done). That feels kind of awkward as additional tracking to do.
Also, the common case is probably that there's either 0 or 1 specifics
being added, so an additional vector may be significant overhead. That's
why I leaned more in this direction of just inserting them in the vector
of work.
Identifying a facet type is an operation on a pair of (self type, facet
type). It substitutes that self in as the `Self` of any require
declarations in order to form the set of (self type, SpecificInterface)
pairs that constitute the requirements of the IdentifiedFacetType.
Currently we don't pass around any self type, and assume all require
declarations are written against `Self` but this will change in the
future.
By contrast, type completion is done in the abstract and does not form
specifics for the require declarations. The purpose of type completion
is to enumerate the scopes where name lookup can occur and ensure they
are completed.
With this change, type completion is:
- No longer built on top of identification for facet types.
- Recursively ensures all `extend` scopes are complete since name lookup
can find symbols in them.
We add some test cases that demonstrate consistency between a resolving
the specific of a generic class, and a generic interface/constraint,
both used in a type position. In all cases, an invalid specific is not
materialized for the type completion when the specific's arguments are
used in a non-extend context. But they specific is materialized and
checked for type completion when in an extend context (extend impl or
extend require).
Type completion itself does not need to recurse into named constraints
or interfaces as the `extend require` declarations require the type to
be complete immediately, just as for `extend impl` in a class.
We had a test (`fail_incomplete_where.carbon`) with `impl as J where
.Self impls K` and `J` is incomplete, which used to be diagnosed but no
longer is, because we don't require non-extend interfaces to be complete
in type completion, nor in identification. The test was trying to test
the presence of rewrite constraints though, which it didn't even use. So
we remove the diagnostic that we can't hit anymore and replaced it with
a TODO, and add a test that should reach that TODO once qualified
rewrite constraints work.
This continues work to eliminate pending generics/specifics and get them
to be interleaved with instruction imports. I'm trying to use
`FinishGenericOrDone` here as a way to help ensure that code correctly
handles generics, where the simple alternative would be for each
`TryResolveTypedInst` call `SetGenericData` directly (but which might
make it easier to call the wrong `ResolveResult` function, and we do
need the `GenericId`s to be passed).
Replace all unexpected instruction ids in a line, not just the first
one. Otherwise you get something like this:
```
// CHECK:STDOUT: impl @<null name>: <unexpected>.inst{{[0-9A-F]+}}.loc20_6 as <unexpected>.inst6000002E.loc20_11;
```
This is just an incremental step towards removing pending logic. The
rest seems like it'll be more complex due to interdependencies (I've
been poking at behavior).
We add tests showing that `ImplStore::GetOrAddLookupBucket` is doing the
wrong thing for impls of a named constraint, as the impl-file
redeclarations of impls in the api file are not getting flagged as such.
To do the right thing requires us to be able to get the constraint from
a require declaration with the specific of the named
constraint/interface applied, which is future work as described in the
[open discussion
notes](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.1ji9ixn9bbnn#heading=h.kijomnov90rz).
Every test that used `addr` before #6283 should be using `ref` after
this PR. In most cases that was done in #6283, but this PR transitions a
few that I missed in that first pass. In addition, #6283 cloned the old
`addr` tests from `foo.carbon` to `foo_addr.carbon` in order to maintain
test coverage during the transition; this PR removes those cloned tests.
Proposal #5168 defines when a facet type must be identified or complete,
and what it means for an interface and a named constraint to be
identified or complete. This updates the toolchain to match the
requirements.
This implements identification of a facet type to require completed
named constraints and to include any interfaces from named constraints
into the resulting IdentifiedFacetType.
To complete a facet type, each interface in the IdentifiedFacetType, and
any interface named though a require declaration from them, must be
complete.
Give TupleLiteral and StructLiteral a constant value, if their contents
have constant values. Their constant values are TupleValue and
StructValue respectively. This supports their ability to convert to a
constant type (or facet type).
This way when deduce finds a TupleLiteral as the argument to a
_symbolic_ facet type, it can also find a constant value to use for that
argument. This allows deduction to move onto step two, where it can
substitute into the symbolic parameter from previous deduced arguments,
and then perform the conversion from the TupleValue to the desired facet
type.
Allow `PerformBuiltinConversion()` to convert from a canonical
TupleValue or StructValue to `type` instead of only from literals. Then,
also support conversion from a symbolic binding of type TupleType or
StructType to `type`.
When the missing definition is diagnosed at the end of the file, the
witness is set to an error. Impl lookup was skipping impls entirely when
the witness was an error, which means a non-final LookupImplWitness
could be later evaluated against a specific and crash since the lookup
fails instead of returning the error.
The same crash could also occur when verifying poisoned queries hadn't
changed, but now it can find an ErrorInst witness instead, so it is
changed to handle that gracefully.
They are not used for impl lookup or verifying anything yet, but now
they appear in the textual semir.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This requires declared FacetTypes to hold NamedConstraintIds (along with
a specific) that are named in an extend or impls requirement. We add
support to stringify and formatter to display the named constraints in
the facet type, and special case when a facet type contains a single
extend named constraint, like we did for a single extend interface.
This means that `RequireIndentifiedFacetType` can now fail, if the facet
type contains a forward-declared named constraint. Add the appropriate
diagnostics for each call to this function, and note the ones that
should change to `RequireCompleteFacetType` in the future with TODOs.
We also add tests for using facet types that can or can't be identified,
or completed, with named constraints in them.
#6289 absentmindedly added fields in more places, and this is undoing
that plus further fixes.
This does some cleanup of types with relation to singletons. For
`TypeType` and `ErrorInst`, they're always complete due to a
`SetComplete` call in `file.cpp`. For `CppVoidType`, it's intended to be
incomplete by construction, and so a `TypeId` should be okay. The intent
though on not generally providing these had been that `GetSingletonType`
needs to be called to get a type to be marked as complete.
In the case of `AutoType`, removing `TypeId`does change a small printing
detail. I think that's old legacy that's just been carried forward.
Otherwise, for both `InstType` and `AutoType`, I've added
`GetSingletonType` calls where they were used in order to ensure
completeness is applied correctly. These calls cause small SemIR
permutations.
This causes `AutoType` to be seen by lowering, so I'm adding a
placeholder for it. Also merging two functions that look like they're
identical in intent -- not sure why they're separate.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
We give `Self` in an interface/constraint a location so it's not elided
when trying to dump the interface/constraint. We use the location of the
start of the definition, which is the scope for which the `Self` is
constructed and is available in.
This resolves a TODO in `expr_info.cpp` by using the inst kind rather
than the bound value to track the binding's category.
Since we're churning all the `bind_name` insts in testdata anyway, I'm
also taking this opportunity to align the inst naming with the design's
terminology, by calling these insts "bindings" (this aspect of the PR is
dependent on #6231 resolving an ambiguity in that terminology). For
consistency we'll need to rename several other insts as well (see the
TODO on `RefBinding`); I'm deferring that to a separate PR to minimize
the review load, but I think those name changes are in-scope for this
review.
When deducing arguments for generic parameters of an `impl`, the
deduction calls `Convert` on the input arguments. Often, the input
argument is a facet, and needs to be converted to a type via
FacetAccessType in order to produce a different facet. These
instructions end up being added to the semir, but only their constant
values are needed for the resulting specific returned from Deduce.
In the best case, these extra instructions are just noise in the semir,
or they just cause instruction names to get differentiated with larger
suffixes.
In the worst case, these extra instructions contain references to
instructions from a generic context, and leak them out of that generic
context and into another. In particular, when importing a
LookupImplWitness instruction, the re-evaluation of it can do deduce
(when the lookup is against a generic `impl`). The instructions created
in Deduce are not part of the import, and end up referring to imported
instructions from the local context, which leads to confusion in the
toolchain, and can crash.
The `import_self_specific.carbon` test demonstrates this. It causes the
`I.F` function to be imported from the `I` interface when building the
witness table for the `impl`. Doing so imports the specific of `C` which
includes a LookupImplWitness for `Self.Accoc` in `I`. The `Self` is a
BindSymbolicName with generic binding index 0, in `I`. When Convert
creates instructions in the generic `impl forall D`, however, they end
up referencing and including this BindSymbolicName into its eval block.
But the generic binding 0 in the `impl` is a very different thing (a
value of type `E`). This confusion leads to crashes.
This change makes dumping and debugging work again with InstIds that are
now tagged with the CheckIRId. The textual representation of an InstId
is changed from `irN.instM` back to `instM` but the `M` is now a hex
value with the tag as part of it, which is the same number that is
physically in the `InstId::index` field. This prevents any cases where
we would potentially print incorrect values for large InstIds.
We teach the `dump` command in lldb to parse hex values for InstId so
that we can paste these numbers back into the debugger.
The SymbolicBindingType refers to the type value that will be
substituted in for the BindSymbolicName, but holds onto the EntityNameId
from the BindSymbolicName instead of (or in addition to, for now) the
instruction.
The EntityNameId will be used to look in the ScopeStack to find the
witnesses either from the BindSymbolicName instruction, or other
instructions that specify `impls` constraints against the EntityName.
This will allow us to have the `T` in `I(T)` resolve to a `.Self`
reference in the type so that we get type equality with the binding's
type: `T:! I(.Self)`.
When deducing an argument against a type that is `<facet value> as type`
we don't care about the `as type` part of that expression. We want to
find an argument that can convert to the `FacetType` of the facet value
for the generic binding that is the `<facet value>`.
This was done after-the-fact in the Deduce switch, but we move this
canonicalization step to be more explicit and done up front at the start
of the Deduce loop. This:
- Avoids a trip through the Deduce loop for a `FacetAccessType`
parameter, just to deduce through it in the switch, which avoids convert
and creation of extraneous constant values.
- Uses the `GetCanonicalFacetOrTypeValue()` function so that when we add
`SymbolicBindingType` handling to that function it will apply to Deduce
as well correctly, instead of needing to handle both in the switch.
This fixes and tests two crashes related to what I was observing [on
#toolchain](https://discord.com/channels/655572317891461132/655578254970716160/1422723976483831848).
The approach to Cpp imports taken in #6086 is problematic because it
returns before the work stack is completed, and doesn't store the
resulting constants. This fixes the approach taken in that PR.
This also does a little restructuring in the same direction, following
#6124.
Leads want `Destroy` to work similarly now for all types. As a
consequence, there doesn't seem to be as much benefit to splitting off
aggregate destruction. In this PR, the `type.destroy` function can now
be expected to destroy anything that's destructible; that means it'll be
usable for the `final fn` once that support is available.
Similarly, this gets rid of the impls other than the single blanket
impl, now using `type.can_destroy`. Since they all need to use the same
function, there's no benefit to splitting approaches. Also, now it can
just be a `final impl` since there should be no need for people to
create specializations -- if this blanket impl applies, it means the
`final fn` is the same.
This also slips in `partial` support since there's no reason to have it
diverge anymore. Also `abstract`, which I'm not sure is broadly testable
since most cases it'd come up, the `abstract` keyword is explicitly
detected/rejected.
Note though that this doesn't make any really big changes. It's just
realigning on the leads decision. I'm going this way to try to reduce
name-related churn for other changes.
# Changes
## Terminology Updates
This PR updates documentation to align with the expression phase
terminology changes introduced in
[#2964](https://github.com/carbon-language/carbon-lang/pull/2964):
* **"symbolic value" → "symbolic constant"**: Updated all remaining
instances using find-and-replace
## Scope of Changes
* Focused on documentation that predates the July 2023 terminology
change
* Used git blame history to identify instances likely using the old
"constant" definition
* Manually reviewed each "constant" usage to distinguish between:
- New definition (unchanged): the broader category including symbolic
constants
Closes
[#5599](https://github.com/carbon-language/carbon-lang/issues/5599)
---------
Co-authored-by: Hitesh Joshi <hitesh@mitsu.care>
Locations are similarly fragile, because adding a comment changes them.
This has made me pause when making prelude changes in #6144, so dropping
them for those cases.
Instruction ids aren't actually that interesting outside debugging, and
can be churny when doing other structural changes. I've seen this in
particular when doing singleton changes, which bump every instruction
id.
Note there are still other ways fragility from locations can crop up.
This shouldn't be considered a complete fix, but hopefully a small
improvement.