Commit Graph
48 Commits
Author SHA1 Message Date
Jon Ross-Perkins 55da026a46 Remove the SemIRLoc typedef (#5299)
Replace SemIRLoc typedef uses with explicitly SemIR::LocId, loc ->
loc_id for consistency.
2025-04-14 14:28:15 +00:00
Richard Smith c33adfafd3 Replace GetTypeInSpecific with GetTypeOfInstInSpecific. (#5232)
Reduce usage of `GetConstantInSpecific` to a single caller in constant
evaluation, with a TODO to remove that.

This gets us closer to being able to fully perform type-checking against
abstract types instead of types anchored within a particular generic.
2025-04-02 22:52:11 +00:00
Jon Ross-Perkins acbe6530c3 Move diagnostics into a namespace (#5173)
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.
2025-03-26 19:12:10 +00:00
Jon Ross-Perkins 84a8c458f9 Error when using emitter.Build().Emit() (#5152)
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.
```
2025-03-19 23:33:52 +00:00
Geoff Romer d264f14027 Clean up handling of Call params (#5061)
- Explicitly document that `*Param` and `*ParamPattern` insts represent
`Call` parameters.
- Stop wrapping compile-time parameter patterns in `ValueParamPattern`
insts (because they aren't `Call` parameters).
- Document how `MatchContext::results_` relates to the `Call`
parameters, and be more consistent about when it's written to.
- Remove `RuntimeParamIndex::Unknown`: we no longer need to distinguish
"this `Param`'s runtime index is unknown" from "this `Param` isn't a
runtime param", because we no longer use `Param`s at all in the latter
case.
- Rename `RuntimeParamIndex` to `CallParamIndex`.

As a side effect of removing the `ValueParamPattern` insts, this fixes a
minor diagnostic bug where `NoteInitializingParam` didn't identify the
specific parameter that led to a deduction failure, because it expects
generic parameters to only be represented by `SymbolicBindingPattern`s,
but before this change they could be wrapped in `ValueParamPattern`s.
2025-03-04 21:01:59 +00:00
f97f1a3e11 Add error for virtual member function without self (#5005)
This tripped over a lowering crash when a member function with self was
declared-but-not-defined, so that's why some test cases were updated to
have (empty) function definitions.

I'll follow-up with/look into a fix for the
self-declared-but-not-defined cases separately.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
2025-02-27 17:01:29 +00:00
Jon Ross-Perkins 8af64ceca6 Change Context::IsImplFile to File::is_impl (#4931)
Note this mirrors parse_tree().packaging_decl().is_impl, but I'm
preferring to keep the version that doesn't access the parse tree so
that we could change tree storage without hurting as much.
2025-02-12 19:42:07 +00:00
Boaz Brickner 3d39ab67bf Wrap lookup result in a new ScopeLookupResult (#4831)
Benefits:
* Provide a proper API for accessing lookup information.
* Make assumptions on whether the result is poisoned or not and how we
can use `InstId` explicit.
* Allow safely reusing the `InstId` value for pointing to the poisoning
entity for poisoned results (in a future PR).
* Consolidate `LookupNameInExactScopeResult`, `std::pair<SemIR::InstId,
bool>` and part of `LookupResult`.
Part of #4622.
2025-01-27 10:05:23 +00:00
Jon Ross-Perkins 9c0faf007e Invalid comment cleanup (#4836)
This is a followup from #4834, I searched for "invalid" uses in our
codebase. This is mostly changing comments, and a couple debug
functions, but shouldn't affect testable behavior.

Note a couple things I'll highlight as not changing (but could) are:
- `ReturnTypeInfo::is_valid`
- `"invalid"` uses in the formatter
- `AddInvalid` for `!has_value` in `inst_fingerprinter` (because the
cases it's called sound invalid-ish)
2025-01-23 02:21:48 +00:00
Jon Ross-Perkins 6b5eb1a101 Id::Invalid -> Id::None (#4834)
High level, replacing `Id::Invalid` with `Id::None` and `Id::is_valid`
with `Id::has_value` for clarity, as discussed
[here](https://discord.com/channels/655572317891461132/655578254970716160/1331664574545395794).
The `IntId` refactoring is needed together with `AnyIdBase` because it's
also used with `ValueStore`.

Note, trying to be careful not to rewrite `EnumBase::InvalidIndex`, or
`is_valid` in general (e.g., `IdKind::is_valid`).

I've tried to sequence commits here:

1. Automatic replacements:

- `((?:Id|Index)(?: |::|\(|Base(?:\(|::)))Invalid((?:Index)?\W)` ->
`$1None$2`
  - `<invalid>` -> `<none>`
  - `InvalidNodeId` -> `NoneNodeId`
  - `/\*invalid\*/` -> `/*none*/`
  - `id((?:_|\(\))(?:\.|->))is_valid` -> `id$1has_value`

2. Manual edits:

  - In `int.h` and `int_test.cpp`
    - `IntT` has `is_value`, which I'm renaming to `is_embedded_value`.
    - Manual edits to comments in this file.
  - `AnyIdBase` and `IdBase`
- Declaration of `is_valid` -> `has_value`, `InvalidIndex` ->
`NoneIndex`.
  - In `ids.h` and `ids.cpp`
    - `is_valid` -> `has_value`
- `// An explicitly invalid ID.` -> `// An ID with no value.`; similar
for index
    - Various math on `InvalidIndex` -> `NoneIndex`
    - Various mentions of "valid" in comments
  - In `value_store.h`, for `IdT::Invalid`, plus one comment
- In `impl.h` and `tokenized_buffer.h`, we had different initialization
of `::None` values (versus `ids.h` syntax) that I fixed manually.
  - Spot checks to compile
- Particularly where `is_valid` replacements didn't catch spots due to
different naming.

3. Autoupdate tests

4. verbose.carbon (NOAUTOUPDATE)

5. Comment spot checks

Note there are probably other mentions of "Invalid" that should be swept
up, but I'd like to argue for merging and separating out remaining
cleanup since this is so sweeping (and likely to hit merge conflicts
from churn). We'll probably have lingering mentions of "invalid" for a
bit regardless, just because there are uses of "invalid" in non-Id APIs.
2025-01-22 23:15:00 +00:00
Jon Ross-Perkins d958caaff3 Refactor CheckIsAllowedRedecl and stop function definition merging (#4800)
Rename `CheckIsAllowedRedecl` to `DiagnoseIfInvalidRedecl` to try to
better document behavior, and clean up comments.

This extends the no-merge-if-defined behavior to functions. It was
already the case for class/interface, and just added for impl, so if
anything functions were now inconsistent. I was kind of tempted to make
a helper for it, but I didn't think of a great structure/name to get
there: `DiagnoseRedef` isn't always called when it's a redefinition, for
example due to `extern` diagnostics, it's hard to combine.

Cleans up `is_defined` calls to rely more on `has_definition_started`,
removing some code paths that are unused since definitions aren't
merged.
2025-01-14 21:13:21 +00:00
josh11bandJosh L 1d379ff7f8 Syntactic impl declaration matching updates (#4762)
* Implement ignoring the difference between `Self as` and `as`, as well
as `where` clauses at the end of an `impl` declaration when checking
whether `impl` declarations match, from #3763.
* Allow impl declarations with different constraint ids to match, as
long as the facet type of the constraint has the same interface_id and
specific_id.
* Add some TODOs reflecting future facet type resolution.

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
2025-01-07 23:31:31 +00:00
Boaz Bricknerandjonmeow daba2c72cf [NFC] Convert NameScope from struct to class (#4623)
This is a preparation change for adding name poisoning support
(https://github.com/carbon-language/carbon-lang/issues/4622), which is
expected to require more elaborate logic around NameScope since a name
can be not defined yet, defined, or poisoned.

The API separates looking up a name from getting the full entry since we
have cases where the entries are invalidated between the time we're
looking for the name and when we access (and sometimes modify) the
entry.

This change has the following benefits:
* `names` and `name_map` are internal to `NameScope` and are guaranteed
to match.
* `extended_scopes` and `import_ir_scopes` can not be manipulated (only
new scopes can be added).
* `inst_id`, `name_id` and `parent_scope_id` are constants.
* `has_error` can only be mutated from false to true.

---------

Co-authored-by: jonmeow <jperkins@google.com>
2024-12-06 21:50:50 +00:00
Jon Ross-Perkins 0e92e6cc5a Switch TypeId::TypeType to TypeType::SingletonTypeId, and similar (#4619)
`ids.h` and `ids.cpp` are the manual edits, everything else is
search-and-replace.

The full list of things moved is:

- `TypeId::TypeType`
- `TypeId::AutoType`
- `TypeId::Error`
- `ConstantId::Error`

This is to unblock removing `InstId::Builtin*`.
2024-12-04 18:40:50 +00:00
67f2c9ce26 Add a FacetValue instruction (#4545)
The new `FacetValue` instruction represents `C as I` for some type `C`
and facet type `I`. It is named `FacetValue` instead of just `Facet` to
parallel the `FacetType` instruction.

This PR uses this instruction represent the facet value `Self` in an
`impl` declaration. This instruction will be used in the future to also
support things like:

* `C as I` where `C` is a class; and
* forming a specific for a generic with a `T:! I` parameter where `T` is
being given a concrete value.

(Here `I` is an interface or other non-`type` facet type.)

Also do some renaming and add some comments to make things a bit more
clear.

* `FacetTypeAccess` -> `FacetAccessType` to clarify this is not access
of a facet type, but access of the type of a facet
* `.facet_id` -> `.facet_value_inst_id` to parallel the `FacetValue`
instruction

`FacetAccessWitness` will be in a future PR.

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-11-21 22:29:53 +00:00
Geoff Romer b67d03126e Separate inst kind for out params (#4442) 2024-10-24 15:22:32 +00:00
Jon Ross-Perkins e3950298cf Update for llvm::formatv changes (#4427)
dwblaikie changed this upstream:
https://github.com/llvm/llvm-project/pull/112625
2024-10-18 20:26:15 +00:00
Jon Ross-Perkins 96964ee534 Implement basic bool and int formatting for diagnostics (#4411)
Note, this supports plurals, but doesn't apply it anywhere. I'm mainly
doing that to demonstrate the approach regarding syntax. See
format_providers.h for details.
2024-10-16 22:46:15 +00:00
Geoff RomerandJon Ross-Perkins 9d942f4633 Generate parameter pattern-match IR from pattern IR (#4388)
Also propagate the pattern IR along with the pattern-match IR, and use
it where appropriate.

Strictly speaking, some parts of the pattern-match IR are allocated
eagerly, while traversing the pattern's parse tree, but they still
aren't actually emitted until we traverse the associated pattern insts.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-10-16 19:15:29 +00:00
Richard SmithandJon Ross-Perkins 2f3ad26f0e Basic support for declaring generic impls. (#4336)
Update impl handling to more closely match other kinds of declaration,
including support for declaring and defining gneeric `impl`s.

When of performing redeclaration lookup for impls by looking for the
self and constraint type, produce a list of impls rather than a single
impl because it's possible for there to be multiple impls with different
deduced parameters but the same self type and constraint. Following
#3763, only consider impls to be redeclarations if they're spelled the
same, not just if they have the same self and constraint types.

No support yet for impl selection to deduce the arguments of a generic
impl.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-09-27 21:18:24 +00:00
Jon Ross-PerkinsandRichard Smith e7aebbe581 Update basic diagnostic capitalization/punctuation (#4328)
This is a primarily automated change:

- Search & replace for capitalization
-
`(CARBON_DIAGNOSTIC\((?:\n\s+)?\w+,(?:\n\s+)?\s\w+,(?:\n\s+)?\s")([A-Z])`
    - `$1\L$2`
- Search & replace for period
-
`(CARBON_DIAGNOSTIC\((?:\n\s+)?\w+,(?:\n\s+)?\s\w+,(?:\n\s+)?\s"(?:[^)]|\n)+)\.("[,)])`
    - `$1$2`
- Limited search & replace for `ERROR: ` -> `error: ` in streamed things
- Leaving a TODO for command_line because there's more cleanup that can
be done there
- Modify diagnostic_consumer.cpp
    - ERROR -> error
    - WARNING -> warning

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-09-19 21:32:53 +00:00
4845f40dff Switch CARBON_CHECK to a format string API (#4285)
This switches `DCHECK` and `FATAL` as well.

The goal is to reduce the code size impact of these assertions so that
we can keep more of them enabled. Currently, the largest cost I see from
`CHECK` is not the actual check or the cold code itself, but actually
the failure to inline trivial functions due to the presence of the cold
code. This means that our goal isn't to reduce apparent code size in the
final binary but the LLVM IR cost assessed for these routines in the
inliner, which closely correlates with code size but is a bit different.

As discussed in #4283, experimentation shows that a single function call
with a minimal number of arguments is the lowest cost model for these.
This is easily achieved with a format-string API that internally uses
`llvm::formatv`. This PR is essentially the `CHECK` version of #4283.

However, the check macros are substantially harder to make work with
both format strings and streaming because they also take a condition.
Also, unexpectedly, I was very successful at devising a regular
expression based automated rewrite from the streaming to the format
string form with only low 10s of manual fixes. This includes compacting
strings broken up across lines, etc. Given how well that went, I've
prepared this PR which just directly switches to the format string API
and migrate everything to use it.

One nice side-effect is that the format string approach ends up greatly
simplifying the implementation here as well.

This is ... *shockingly* effective. Parsing speeds up by more than 3%
with just this change. And checking speeds up by **8%** with this change
alone:
```
BM_CompileAPIFileDenseDecls<Phase::Parse>/256      86.3µs ± 1%  82.9µs ± 1%  -3.94%  (p=0.000 n=17+19)
BM_CompileAPIFileDenseDecls<Phase::Parse>/1024      431µs ± 1%   415µs ± 1%  -3.76%  (p=0.000 n=18+19)
BM_CompileAPIFileDenseDecls<Phase::Parse>/4096     1.77ms ± 1%  1.71ms ± 1%  -3.18%  (p=0.000 n=18+19)
BM_CompileAPIFileDenseDecls<Phase::Parse>/16384    7.44ms ± 1%  7.17ms ± 2%  -3.56%  (p=0.000 n=18+20)
BM_CompileAPIFileDenseDecls<Phase::Parse>/65536    30.7ms ± 1%  29.7ms ± 1%  -3.15%  (p=0.000 n=18+20)
BM_CompileAPIFileDenseDecls<Phase::Parse>/262144    131ms ± 1%   127ms ± 1%  -2.81%  (p=0.000 n=18+18)
BM_CompileAPIFileDenseDecls<Phase::Check>/256       878µs ± 2%   800µs ± 1%  -8.91%  (p=0.000 n=19+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/1024     1.88ms ± 2%  1.72ms ± 1%  -8.56%  (p=0.000 n=19+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/4096     5.78ms ± 2%  5.28ms ± 1%  -8.70%  (p=0.000 n=20+18)
BM_CompileAPIFileDenseDecls<Phase::Check>/16384    21.9ms ± 1%  20.1ms ± 1%  -8.02%  (p=0.000 n=18+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/65536    90.4ms ± 2%  83.1ms ± 1%  -8.04%  (p=0.000 n=19+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/262144    381ms ± 2%   352ms ± 1%  -7.79%  (p=0.000 n=19+19)
```

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
2024-09-12 16:42:08 +00:00
Jon Ross-PerkinsandRichard Smith bed5fdcbbe Fix indirect import handling for functions. (#4258)
The particular test this focused on is indirect_two_file in
toolchain/check/testdata/function/definition/no_prelude/extern_library.carbon.

This removes `parent_scope_id_for_new_inst` because I think it's
returning unhelpful results. The use was at the root of incorrect
results for the indirect import chain. `name_id_for_new_inst` is
actually wrapping a union, so it's more important.

The merging of `is_extern` and `first_owning_decl_id` in
`handle_function.cpp` feels like it's less correct with the changes
that've been made to `extern`. This ripples in tests, because the error
recovery shifts.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-08-27 20:26:23 +00:00
Jon Ross-Perkins 2d3842fc06 Implement 'extern library' support for functions. (#4220)
Support for types (particularly classes) is left as a TODO.

There's also an issue I'm observing with a "define in impl" test, but
this is probably an issue with resolving the prior declaration which is
imported indirectly. The PR was already feeling big, so I'm choosing to
cut here.

Note, this does not implement the rule "The owning library's API file
must import the `extern` declaration, and must also contain a
declaration."
2024-08-19 22:12:21 +00:00
Richard Smith 4a21b6af9b Basic support for implementing and using a parameterized interface. (#4203)
The main change here is to form a specific when checking an interface
function against an impl function, instead of just substituting the
`Self` type.
2024-08-09 01:05:03 +00:00
Jon Ross-Perkins 43c0b0a1f2 Refactor some check-phase postorder iterator use. (#4175)
Allow directly constructing a PostorderIterator, to get rid of
`tree.postorder(node_id).end()` indirect construction. For ranges that
don't need tree data, make it clearer that they're not validated.

Note, this subtly gets rid of a subtree size use in the
`tree.postorder(node_id).end()` case (to get the discarded `begin()`
value).
2024-07-27 02:15:56 +00:00
Richard Smith 07bad72d86 Support for calling non-generic methods in a specific class. (#4156)
Use the specific parameter types for checking, and the specific return
type as the type of the call.
2024-07-24 20:27:01 +00:00
Jon Ross-Perkins db022658c6 Implement syntactic merge checks for parameters. (#4149)
Note this isn't implementing checking through imports. The parse node
there is harder to access through the context, so would require
examining the entity in order to get the import declaration, to get at
the ImportIR. We also don't have a parse tree attached in that case, and
would need to add one to SemIR::File. But I believe we do want to add
that, so it's explicitly a TODO.

Note GetTokenText re-lexes literal values, so there's a bit of potential
overhead there. Not sure if we want a more efficient manner for
comparing in cases like this.
2024-07-23 20:32:24 +00:00
Richard Smith 7322a1e220 Build a list of dependent constants to recompute in each instance of a generic. (#4110)
For each generic, build a list of instructions describing the
computations we need to do when resolving an instance of the generic:
this is a list of the instance-specific constants and types that the
generic uses. Another way of viewing this list is as a block of Carbon
SemIR code that is evaluated in order to form an instance of the generic
-- this is referenced in the code as the "eval block" for the generic.

For each instruction in the generic whose type or value is a symbolic
constant, replace that type or constant value with a symbolic reference
that says "to find the actual type or value, look at index N in the list
of values for the generic instance".

For an instruction with a symbolic constant value, we can just add that
instruction to our list. For an instruction with a symbolic constant
type, however, we may not have a corresponding instruction computing the
type within the generic and may need to build a new instruction, but
will reuse one where possible. In the case where we build a new
instruction, we use the existing substitution code to build the type
within the eval block.

For now, this transformation is only done in the declaration region of
the generic, not in the definition region. Also, we map back from the
symbolic references to the underlying constant value in a few places
where we will eventually need to do a lookup into a generic instance, in
order to avoid regressing the tests.
2024-07-08 22:29:37 +00:00
Chandler CarruthandJon Ross-Perkins 8992d22ab3 Port the toolchain to use the new Carbon hashtable (#4097)
This works to leverage the capabilities of the hashtable as much as
possible, for example using the key context in the value stores.
However, there may still be opportunities to refactor more deeply and
use the functionality even better. Hopefully this is at least
a reasonable start and gets us a clean baseline.

On an Arm M1, this is a 15% improvement on my large lexing stress test,
but ends up a wash on my x86-64 server. This is a smaller benefit than
I expected, and it's because we're using a set-of-IDs and looking up
values with a key context for things like identifiers. This pattern has
a surprising tradeoff. The new hashtable uses significantly less memory,
a 10% peak RSS reduction just from the hashtable change. But indirecting
through the vector of values makes growing the hashtable dramatically
less cache-friendly: it causes growth to randomly access every key when
rehashing. On x86, everything gained by the faster hashtable is lost in
even slower growth. And even on Arm, this eats into the benefits.

But I have a plan to tweak how identifiers specifically work to avoid
most of the growth, and so I suspect this is the right tradeoff on the
whole. It gives us significant working set size reduction and we can
likely avoid the regressed operation (growth with rehash) in most cases
by clever reserving and if necessary by adding a hash caching layer to
the table infrastructure.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-07-03 01:10:44 +00:00
Chandler CarruthandRichard Smith b70cfd0be9 Remove another hashtable iteraiton order dependency. (#4070)
Name scopes store the names in their scope in a `DenseMap`. Several
places reasonably avoid depending on the iteration order by sorting the
names -- they're in the formatting code path where that's a solid
approach.

Unfortunately, when we're importing one scope into another, we also need
to walk the entire scope and do something for each name. =[ This doesn't
seem like a great place to sort things to stabilize them.

I've switched to a fairly simplistic solution of having a vector of name
entries that can be iterated stably, and a separate map for lookups. I
didn't use the set-of-indices trick here because it's not clear that's
the right trade-off for a scope: likely a lot of small scopes here with
relatively hot name lookups. And the key here isn't a large or
dynamically sized thing that we're canonicalizing, it's a `NameId`. That
made me lean towards duplicating the name in the hashtable for lookup
and the vector for iteration.

I thought about a fancy approach of sorting the hashtable keys by their
values (the indices), but that would still require a bit of copying and
more code.

I also thought a bit about other optimizations, but decided to leave a
comment for now -- it's not obvious to me exactly how hot this is and
whether it's better served by faster lookups, being more memory dense,
etc. And that might involve more of an SOA layout change or some other
approach. Rather than do that here, and especially before switching
hashtables, I stuck with a simple approach to address the ordering.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-06-21 22:13:03 +00:00
Jon Ross-Perkins 807a3f1370 Add namespace-scoped private keyword support. (#4026)
Adds access to the name lookup table in name scopes. This is so that we
can quickly check access during name lookup without resolving the entity
itself. Does this for names in general, but does not implement handling
for entity-scoped names, only namespace-scoped names (where they're
essentially just not exported).

Excludes `private` names from exports. Although names should be
accessible to `impl` files, that's not implemented here because we'll
probably want to do it by directly copying name lookup tables.
2024-06-06 00:19:56 +00:00
Richard SmithandJon Ross-Perkins 7792e5fce3 Support out-of-line definitions of members of generic classes and interfaces. (#4029)
Check the parameters specified in a name qualifier against the
parameters of the entity that the qualifier refers to.

For interfaces, this required adding minimal support for parameterized
interface names.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-06-05 18:52:17 +00:00
Jon Ross-Perkins 76471cf701 Move decl-specific merge logic back to respective handlers. (#3937)
I'd split out the decl-specific handlers so that import_ref.cpp could
also call them. However, with the current model for imports and
constants, we shouldn't use them there. As a consequence, merge them
back into individual files for greater consistency with other helper
functions (and better visibility when making related code changes).
2024-05-07 00:13:04 +00:00
Jon Ross-PerkinsandRichard Smith 292a9d3cb4 Replace ResolvePrevInstForMerge with decl logic. (#3936)
This addresses the const reliance of ResolvePrevInstForMerge by checking
the imported instruction, testing with `alias` name conflicts. Given the
need to examine structure, the helper function feels like it now gets in
the way, so I'm just removing it.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-05-06 21:27:21 +00:00
Richard Smith d5c0c9cfe3 Accept generic parameter lists in class declarations. (#3933)
Check that they match across redeclarations.

Fix some importing bugs for symbolic bindings which were uncovered when
testing this.
2024-05-04 02:08:38 +00:00
Jon Ross-Perkins 92fa0ac1ac Remove ImportRefUsed (#3934)
This was to track use of a declaration after import, prior to a
redeclaration. Per [discussion on
Discord](https://discord.com/channels/655572317891461132/1217182321933815820/1236016521059237962),
we likely don't need this check due to the change in behavior of
`extern`.

Rather than potentially getting one of many `extern` decls and depending
on it by accident, it is now planned to be _required_ to be imported,
and the library doing a non-`extern` decl must _know_ it's importing the
`extern` decl. The stricter requirement on the library means it now
seems more reasonable to use the `extern` decl.

So kind of rolling back #3831, though keeping `ImportIRInstId` (at least
for now) and keeping `Loaded`/`Unloaded` terminology (seems a nicer
fit).
2024-05-03 23:33:42 +00:00
Jon Ross-Perkins 6483044597 Switch import logic to rely on constants. (#3917)
Breaks extern handling, makes other things work. TODOs in import_ref for
extern, the tests need rewritten too under the new model.
2024-04-29 21:33:47 +00:00
Jon Ross-Perkins 377262d358 Remove ExternDecl and ExternType (#3909)
These should no longer be helpful under the new `extern` strategy.
2024-04-24 21:16:46 +00:00
Jon Ross-Perkins 5694dd152e Add ExternDecl and ExternType for extern classes. (#3893)
This expands `extern` handling for most cases.
2024-04-22 15:04:16 +00:00
Jon Ross-Perkins db324c7247 Initial, extern-ignoring support for extern class decls. (#3891)
This doesn't actually track whether a declaration is `extern`. It does,
however:

- Factor out and expand merge support for classes, sharing handling with
functions.
- This makes the ClassRedefinition diagnostic redundant, as the
redeclaration checking overlaps.
- Add partial `extern` handling to class handling; just some
verifications of correct use.
- Factor out `extern` on member handling for sharing with `fn`.
- Fixes a bug in import_ref where a class's definition_id wasn't
assigned when defining.

This changes how a redefinition is handled (replaced, rather than
merged). I don't know whether that's ideal, but I think it results in
easy-to-understand consequences, and it's more consistent with how `fn`
works.

There's enough work here that this felt like a decent cut point,
particularly as the amount of work to actually add `extern` tracking
will be significant.
2024-04-19 16:08:29 +00:00
Jon Ross-Perkins 3d113b9769 Refactor pre-merge redeclaration checking for sharing. (#3884)
I'm poking at adding similar validation for `class` merging; this
refactors support so that it can easily be shared.
2024-04-16 16:48:03 +00:00
Jon Ross-Perkins 2361830592 Special-case api/impl implicit imports and verify relevant redeclarations. (#3843)
Adds ImportIRId::ApiForImpl to reserve a specific slot for the `api`
import, so that the code can trivially determine whether an import is
from the same library. This is then used for merging function
declarations, because the rules for redeclarations in the same library
slightly differ as compared to other imports (note they're also not
identical to same-file rules).

The main thing this leaves from the recent #3762 is verifying that
entities forward declared in the `impl` file are also defined, but
that's not in-scope for merging; it's moreso post-checking validation.

Note, a lot of our `invalid <entity> ID` comments in ids.h were
incorrectly copy-pasted, so I've cut `<entity>`.
2024-04-04 16:03:41 +00:00
Jon Ross-Perkins 5c567b892d Address invalid redeclaration and definitions across imports. (#3842)
Note, there's still a TODO "Allow non-extern declarations in the same
library."
2024-04-02 18:01:25 +00:00
Jon Ross-Perkins dffe4a36de When merging functions, detect uses of imports prior to a redecl. (#3836)
LookupNameInDecl is only called from DeclNameStack, but I'm adding
mark_imports_used there because it feels more consistent. Not sure if we
want a better API boundary. I admit I'm also suspicious of its call to
LookupInCurrentScope but maybe it's okay due to how imports work.

I was choosing to print multiple diagnostics when a declaration is
previously used _and_ doesn't match because I think the "previously
used" is more important, but the "doesn't match" may give an additional
hint about why it didn't work.

The merge.h utility function is because I think we can follow a similar
model for identifying errors with other declarations: classes,
interfaces, etc.
2024-04-02 17:44:55 +00:00
Jon Ross-Perkins f8c8861e5f Change ImportRef to a triple state: Unloaded, Loaded, Used (#3831)
This doesn't significantly change logic, although I'm trying to add the
location to used state.

The issue I'm trying to address is how to identify a declaration as
"allowed to be redeclared". Consider:

```
library "a" api;
extern fn F();
```
```
library "b" api;
extern fn F();
```
```
library "c" api;
import library "a";
import library "b";
var x: auto = F();
fn F();
```

What currently happens is:

1. On import of "a", `F` becomes ImportRefUnused
2. On import of "b", `F` becomes ImportRefUsed in order to merge.
3. In "c", the call `F()` doesn't change the state.
4. In "c", the declaration `fn F();` needs some breadcrumb to understand
whether "F" has been referenced, as in step (3) here.

What I want to happen is:

1. On import of "a", `F` becomes ImportRefUnloaded
2. On import of "b", `F` becomes ImportRefLoaded in order to merge.
3. In "c", the call `F()` causes `F` to become ImportRefUsed
4. In "c", the declaration `fn F();` detects that `F` is already
ImportRefUsed, and can use the associated `used_id` for a diagnostic
about why redeclaring is invalid.

Note this PR isn't implementing (4). I'm focused on the refactoring to
add a new ImportRef state here.
2024-04-02 17:20:09 +00:00
Jon Ross-Perkins b5d28f2c4b location -> loc abbreviation (#3826) 2024-03-28 18:15:18 +00:00
Jon Ross-Perkins 0001f53ec1 Implement merging of conflicts found during import. (#3819)
Note we only identify conflicts between libraries in the current package
during import.

This restructures the BUILD because of dependency cycles between cpp
files... We're going to need context's name lookup to handle things such
as merging, merging requires function logic, function logic requires
context access. Per discussion, going with a single large cc_library for
now rather than trying to split out small libraries.

I'm envisioning the new merge.* as a hub for cross-declaration merge
logic. Note function.cpp is already pretty sizable, and I think it may
lean a little function-specific even if there are some utilities that
could be split out.
2024-03-27 23:38:10 +00:00