Implementation of unused pattern bindings #2022, continued.
Whereas previous PR #6460 took care of parsing, and PR #6479 prepared
the stage by using _ in some test cases, this PR has the the actual
implementation, using a simple dataflow analysis.
---------
Co-authored-by: Burak Emir <bqe@google.com>
Co-authored-by: jonmeow <jperkins@google.com>
Currently each interface has a `Self` facet internally that becomes a
binding to every entity inside the interface: associated constants,
functions, and require decls. Each of these has to be independently
generic as a result. This makes is challenging in extended name lookup
to move into an extended scope of an interface, as we have a specific
for the interface, but the names within require a different specific
that includes a `Self` facet value.
We generalize this relationship by adding a second generic to Interface,
called `generic_with_self`. When we want to work with entities inside
the interface, we move from the interface-without-specific to the
interface-with-self specific by adding a Self to the specific. This is
done independently of any particular entity inside the Interface, as
those entities are now all members of the interface-with-self generic.
Associated constants no longer need a generic of their own, as they do
not have separate generic bindings. Functions retain a generic, but if
the function has no generic arguments, it will have no bindings of its
own now.
Require decls retain a generic so that their specific can be
instantiated separately from the interface. Requiring the interface to
be complete does not require the types in a require decl to be complete
unless it is modified by `extend`. So we allow them to be completed
later by keeping them in a separate generic.
Named constraints look like interfaces and gain the additional inner
generic-with-self, with the same relationship to require decls.
This removes the need for name lookup to perform Substitution of a Self
facet into the extended scope instruction. Instead, the
`SpecificConstant` instruction inserted by a `require` decl is part of
the interface-with-self generic. When looking through a FacetType for
extended scopes, for each interface, we push the scope with the specific
for the interface-with-self. Then the constant value of the
`SpecificConstant` is correctly modified by the provided self
automatically through applying that specific.
This TODO had been written before C++ types were generating destroy
implementations, which is resolved now.
Assisted-by: Google Antigravity with Gemini 3 Flash
This is related to #6727, but is generally a necessary fix even without
that issue. I'm not adding a specific test of #6727 because it should
also be covered by the tests in #6726.
Assisted-by: Google Antigravity with Gemini 3 Flash
The primary change in this PR is to split the `Initializing` expression
category into separate `ReprInitializing` and `InPlaceInitializing`
categories, depending on whether initialization uses the types
initializing representation, or is guaranteed to be in place. It also
rationalizes and documents the SemIR-level semantics of those categories
(including where #5545's "ephemeral entire reference" category will
fit), and introduces two new inst kinds to close gaps exposed in the
process.
Some additional secondary changes:
- Consistently format the storage arguments of initializers with `to`,
regardless of whether initialization is in-place, and document the `to`
notation.
- Rename some inst kinds and functions, and restructure some of the
code, for clarity and consistency with the new documentation.
- Resolve a TODO to handle more category conversions in
`CategoryConverter`, in order to make it easier to reason about category
conversions.
See #6588 and the review history of this PR for background.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
When performing an implicit conversion to or from a C++ class type, look
for a C++ implicit conversion, and if that conversion involves a
function call (to a constructor or conversion function), call that
function to perform the conversion.
Note that this is just a first pass at supporting implicit conversions.
There are a lot of other things that can happen in a C++ implicit
conversion, such as aggregate initialization or `std::initializer_list`
initialization that aren't handled here. In addition, we intentionally
leave all standard conversions to Carbon to perform, so that we will
reject conversions such as `i32 -> unsigned` that C++ would select but
Carbon considers to be invalid.
Also support `as` conversions. These are treated analogously, but
perform direct-initialization instead of copy-initialization, so they
also find `explicit` constructors and conversion functions.
In order to give good diagnostics, also track the original C++ source
location for imported C++ functions on the imported version of the
function.
Assisted-by: Gemini 3 Pro via Antigravity
Members of `std::string_view` can't be accessed directly, because that
type maps into Carbon's `str` type (`Core.String`), so member access
doesn't find the C++ members. But they can be named via qualified name
lookup into a derived type. That crashed because we didn't expect the
non-Cpp type `Core.String` to be the parent of a Cpp-imported member.
Plus add some more test coverage for related cases (not involving `str`)
that already worked.
---------
Co-authored-by: Geoff Romer <gromer@google.com>
The key changes are:
- Function output parameters are now prefixed with `out`, and more
consistently formatted as named parameters.
- Function and inst output arguments are now written as part of the inst
form, rather than as one of the inst arguments.
As a drive-by fix, this also changes `Temporary::storage_id` from
`DestInstId` to `InstId`, because it doesn't represent an output
parameter of the `Temporary` inst itself.
See the review of
[#6532](https://github.com/carbon-language/carbon-lang/pull/6532) and
[this Discord
discussion](https://discord.com/channels/655572317891461132/999638000126394370/1458268977020141589)
for additional background.
Also clarify and enforce that `ConversionTarget::init_id` is used only
as storage for in-place initialization, and correspondingly rename it to
`storage_id`.
* When a C++ static data member is imported, evaluate its address to a
constant like we would for a namespace-scope variable.
* When an imported variable is used in a way that doesn't require its
type to be complete, emit the variable with an opaque type instead
of skipping it (and potentially crashing later).
Not all functions have a return slot, and once we have composite forms,
functions will be able to have any number of return slots. Obtaining a
unique return slot for a function only makes sense in `returned var`
handling.
Remove the unnecessary two-phase creation of variables in C++ import. We
don't need to create a placeholder and overwrite it here, so stop doing
so.
Also, add the patterns to the imports table and don't create a
NameBindingDecl. The NameBindingDecl would never be used for anything.
This matches what we do when importing a Carbon variable, and improves
the formatted SemIR output.
The main changes here are:
- Introducing `InitForm` and `RefForm` to represent initializing and
reference forms (the two return forms currently supported by the
parser).
- Introducing the `FormType` singleton inst to represent their type
(i.e. `Core.Form`).
- Emitting an inst representing a function's declared return form as
part of handling the function signature.
The return form inst is currently ignored. Subsequent PRs will expose it
in `SemIR::Function` and use it to determine the form of call
expressions.
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.
### Description
Currently, unqualified access to private members of the base class
compiles without error. This is due to `LookupUnqualifiedName` calling
`LookupQualifiedName` internally with `access_info` parameter set to
`std::nullopt`. This causes `IsAccessProhibited` to return `false`
immediately.
This PR fixes this issue.
### Changes
- Added a check where if the `access_info` is null and the current scope
we are looking is an extended scope (parent), initializes the
`access_info` with `highest_allowed_access` set to `Protected`.
Fixes#6239
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).
Expose C++ class templates, variable templates, alias templates, and
concepts as callable values in Carbon, and map calls to them into
template-id formation, mirroring how Carbon generics behave. For now,
only type template parameters are supported; non-type and template
template parameters produce a TODO error.
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.
For now, treat such classes as being final, since we can't correctly
derive from them.
This removes the last category of C++ class that we are entirely unable
to interop with, and is a prerequisite for interop with C++ iostreams
(which have a virtual base class).
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.
This turns `Cpp` into a keyword, and makes it map to `NameId::Cpp` and
`PackageNameId::Cpp`.
Per discussion with zygoloid, the keyword versus identifier question is
deliberately kept open by #4846. This PR switches to a keyword because
mapping to a specific `PackageNameId` works best with a special `NameId`
not backed by an `IdentifierId`. We could in theory make it work using
`IdentifierId` or a runtime-tracked `PackageNameId` for `Cpp` (e.g.
stored on `SemIR::File`), but this approach is consistent with `Core`
and so seemed like a good starting point.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
#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>
For now, map C++ reference types to const-qualified Carbon pointer types
rather than picking between a (non-const) pointer or a value type. This
fixes misbehavior in lowering for reference members in classes and
reference return types.
Update the special-case handling for references as function parameters
so that it continues to map const reference parameters to Carbon
pass-by-value, and unify the code paths for `self` parameters and other
parameters, which were mostly doing the same thing but had some subtle
differences.
Add references to the list of types that we can pass to and from C++
directly, without needing an additional layer of thunks.
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.
`const` doesn't mean much on the type of a value expression; it's valid
to remove it because we can't perform modifications to a const value
regardless.
We already allowed most of this, but only as part of adapter conversion
rather than in general, and we didn't previously allow it when the
source of the conversion was a reference expression.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
This demonstrates two issues:
1. It seems like we wrongly treat private static data members the same
way we treat protected and allow access to them from within derived
classes member functions.
2. Calling instance member functions of a base C++ class using a derived
class as self (no implicit upcast) is not yet supported. This isn't
related to access control, but prevents us from testing some access
control use cases.
Part of #5859.
Implemented by generalizing the reference type support for parameters
and return values to other use cases.
The changes to the `method.carbon` test are due to to supporting the
reference types but not supporting the necessary conversions.
C++ Interop Demo:
```c++
// global.h
struct C {
int member = 0;
int& member_ref = member;
};
extern C& global;
```
```c++
// global.cpp
#include "global.h"
static C static_c;
C& global= static_c;
```
```carbon
// main.carbon
library "Main";
import Core library "io";
import Cpp library "global.h";
fn Run() -> i32 {
Core.Print(Cpp.global->member);
++(*Cpp.global->member_ref);
Core.Print(Cpp.global->member);
++(*Cpp.global->member_ref);
Core.Print(Cpp.global->member);
return 0;
}
```
```shell
$ clang++ -stdlib=libc++ -c global.cpp
$ bazel build toolchain:carbon && bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link global.o main.o --output=demo
$ ./demo
0
1
2
```
**Without this change**:
```shell
main.carbon:10:14: error: semantics TODO: `Unsupported: var type: C &`
Core.Print(Cpp.global->member);
^~~~~~~~~~
main.carbon:10:14: note: in `Cpp` name lookup for `global`
Core.Print(Cpp.global->member);
^~~~~~~~~~
```
Part of #6006 and #6186.
The tests are almost identical and test the same logic so basically
duplicated.
The extra coverage that was in `struct.carbon` is added to
`class.carbon`.
One basic test in `struct.carbon` was left just to make sure `struct` is
supported.
Part of #5150.
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 fixes a bug, which seems to have been introduced in #6108.
In the new test, without this change, we will diagnose with
```
error: semantics TODO: `Unsupported: parameter type: ExplicitObjectParam` [SemanticsTodo]
```
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)`.
After this change, we correctly increment the offset by the next switch
case type.
Before this change, we accidentally incremented the offset by
`functions()` size instead of `cpp_overload_sets()` size and vice versa.
Also sorted the switch cases according to the order of the enum, for
consistency. This might help prevent a future similar incident.
This fix prevents crashing in the newly introduced test
`multiple_too_few_args_calls`.
This also has the side effect of showing `null name` for
`cpp_overload_set_type` and `cpp_overload_set_value`, instead of having
an arbitrary name.
Examples that demonstrate the old name is arbitrary can easily be seen
in tests like `cpp_namespace.carbon` and `decayed_param.carbon`, but
careful review would show that all old names are arbitrary, though often
luckily almost make sense.
We might want to have a proper name for these, but it's beyond the scope
of this crash fixing change.
See #6156.
Part of #5915.
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.
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.
Right now, the class destroy impl is incorrectly generated (first
discussed [in
Discord](https://discord.com/channels/655572317891461132/941071822756143115/1418614787449032826)).
If we want it to be correct, deferred definition logic would need to be
added, and the declaration would need to be moved inside the `class`
scope (along with whatever generic logic that needs).
This instead switches to a blanket impl, to avoid creating latent bugs
with generating the `impl` and function body in the wrong scope. This
approach uses the same blanket impl as aggregate destruction that was
added by #6098.
The intent here is to allow progress on other parts of `Destroy`. For
example, under this model the implementation of the function body could
be done as part of lowering the specific.
This turns out to be quite important, as several important standard
library types (such as `std::string`) have mixed-access overload sets
for their constructors as an implementation detail. The overall approach
here is:
- Use the most permissive access to determine the access of the overload
set itself. This affects whether name lookup finds the member name at
all.
- After overload resolution, re-check the access of the selected member,
if it's protected or private.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
If there's a unique "preferred" base class, then treat that as "the"
base class for Carbon's purposes. In particular:
* If there's exactly one polymorphic base class, that's our preferred
base class.
* If there's exactly one non-empty base class, that's our perferred base
class.
* (Degenerate case) If there's exactly one base class, that's our
preferred base class.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Don't ignore deleted constructors in overload resolution. If one is the
best match, we want an error rather than picking something else. Don't
crash if we find a constructor template or other weird thing; use
`getConstructorInfo` to map it into a constructor and skip it if it
isn't one, like Clang does.
The general strategy here is to force use of a thunk when we want to use
default arguments, and have Clang generate uses of the default arguments
on its side of the thunk.
To support this, change the key type used in `clang_decls` from being
just a `Decl*` to being a pair of `Decl*` and number of parameters in
the case of function decls. Import distinct `SemIR::Function`s for each
number of parameters that's used, and corresponding distinct thunks.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>