Commit Graph
34 Commits
Author SHA1 Message Date
josh11bandJosh L 39ed62dad7 Add facet_types() accessor to Check::Context (#4518)
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
2024-11-13 01:20:07 +00:00
josh11bandJosh L 4f474fafb5 Remove some single-interface restrictions from some uses of facet types (#4508)
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
2024-11-12 00:43:45 +00:00
a69c2630f9 Replace InterfaceType with FacetType (#4499)
This does a few things:
* Replaces the single `TypeId` in the `FacetTypeInfo` struct with a
vector of `InterfaceId`, `SpecificId` pairs (sorted in id order)
representing the set of interface requirements of the facet type. This
will later be used to support facet types with multiple interface
requirements (as in `I & J` or `I where .Self impls J`).
* Replace `InterfaceType` instructions (used as the type of an
`InterfaceDecl` instruction) with `FacetType` instructions (introduced
in #4460) with a (newly introduced) `FacetTypeFromInterface()` function.
* Replace code that consumed `InterfaceType` values with code that
consumed `FaceType` values. I've generally left the assumption in the
code that it is dealing with a single interface, using the (newly
introduced) `FacetTypeInfo::TryAsSingleInterface`, and producing an
error otherwise. There isn't yet support for the `&` operator or `where
.Self impls`, so this is generally a good assumption for now, except you
can get a facet type with no associated interfaces from a `type
where`... expression. In some cases, the facet type value is pulled from
the evaluation of an `InterfaceDecl` instruction, where the single
interface assumption will hold permanently.
* Some related cleans up: nicer stringification and formatting of facet
types, suppression of some errors when there already was an error.

There is still a lot left to do, including:
* Type `type` should be a facet type with a reserved id, replacing the
built-in instruction.
* Code using `TryAsSingleInterface` should generally be upgraded to
handle more than (or less than) one interface. Name lookup should be
particularly exciting.
* Operator `&` should be defined on facet types, unioning their
interface and other requirements.
* Requirements from a `where` clause don't do anything yet.
* Impls and impl lookup need to resolve facet types, and do things like
determine if all the associated constants are given values.

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Co-authored-by: Geoff Romer <gromer@google.com>
2024-11-11 18:01:50 +00:00
Richard Smith 568ad197d1 Track the instruction used to name the type and constraint in an impl. (#4368)
This is necessary in order to have access to the specific versions of
their constant values in a generic impl.

Stub out impl deduction.
2024-10-04 00:06:55 +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
Brymer Meneses 8ac9c80e87 Enforce private and protected access modifiers for class member access (#4248)
Print diagnostics for invalid class member access. This doesn't take
into account compound member access.
2024-09-10 16:35:07 +00:00
Richard SmithandJon Ross-Perkins 891c7d8368 Enforce that the parse node for an instruction has the kind specified in the instruction definition (#4264)
Remove `ReusingLoc` and add enforcement that even for imported
locations, the kind of the parse node for an instruction matches the
kind specified in the instruction definition.

Change the node kind for a few instructions to `NodeId`:

- A couple of instructions had a typed node but could be created
implicitly with any node as part of a builtin implicit conversion. This
happened for `AddrOf`, `ArrayIndex`, and `Deref`.
- A bunch of instructions had `InvalidNodeId` as their associated parse
node kind but were actually always created with a location.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-08-29 21:10:14 +00:00
Richard Smith 16fd645663 Add source locations to interface_witness and interface_witness_access instructions. (#4265) 2024-08-28 23:30:00 +00:00
Jon Ross-Perkins 0feb757de0 Add fields for extern to EntityWithParamsBase (#4206)
This adds fields to `EntityWithParamsBase` to reflect the intention with
`extern library` design. I'm renaming `decl_id` because it shouldn't be
expected to be assigned anymore. import_ref.cpp I'm deliberately keeping
on `first_owning_decl_id` (which will break when importing `extern
library` declarations). Most other cases are for diagnostics, and I'm
using `latest_decl_id` to try and get the closest declaration to the
error. Note I'm partly splitting out this PR to show the test effect,
which apparently we don't test related cases.
2024-08-12 19:50:15 +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
Richard Smith 8a8c227163 Track an interface type, not an interface ID, on an associated entity. (#4188)
This prepares us for modeling associated entities of parameterized
interfaces.

We don't use the interface parameters when type-checking `impl`s or uses
of interface members yet, but we do now check interface arguments during
`impl` lookup.
2024-08-05 20:45:14 +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
Geoff Romer 326609857d Rename BindNameInfo to EntityName (#4090) 2024-07-19 22:43:50 +00:00
Jon Ross-Perkins a81d67c629 Rename Builtin to BuiltinInst, particularly to get BuiltinInstKind (#4115)
I'm trying to increase the distinction between BuiltinKind and
BuiltinFunctionKind. BuiltinKind is for instructions,
BuiltinFunctionKind is for function definitions. To get to this point,
I'm doing a few changes:

- BuiltinKind -> BuiltinInstKind
    - builtin_kind.* -> builtin_inst_kind.*: filename consistency
- Builtin -> BuiltinInst: mainly for consistency with the above
- Builtin::builtin_kind -> BuiltinInst::builtin_inst_kind: somewhat
repetitive but seems like a consistent edit
- Function::builtin_kind -> Function::builtin_function_kind: seems a
useful distinction

I'm leaving alone things like (and mentioning in case there's a desire
for more renames):

- InstId::BuiltinError, InstId::ForBuiltin: these I think are more
apparent because they're directly associated with Inst.
- GetBuiltinICmpPredicate in lowering: maybe builtin function handling
should be in its own file, but these local names don't feel problematic
to me.
- GetBuiltinType, BuildBuiltinValueRepr, PerformBuiltinIntComparison:
similar to the above, names don't feel too problematic
2024-07-11 18:24:17 +00:00
Richard Smith 9029cac727 Remove inst_id from the public interface of ConstantId. (#4053)
Require mapping from a `ConstantId` to an `InstId` to go through the
`ConstantValueStore`.

This is a preparatory step for an upcoming generics change where
symbolic `ConstantId`s are no longer just a thin wrapper around an
`InstId` but instead are indexes into a table with additional
information about the symbolic constant beyond its `InstId`.
2024-06-14 00:40:53 +00:00
Jon Ross-PerkinsandRichard Smith 5bb318cae6 Switch AddInst struct init style. (#4012)
Trying to conform with #4009. Changes SemIR::LocIdAndInst construction
to root out struct init cases with AddInst and related functions. I'm
using templating of AddInst functions in order to avoid `AddInst(loc_id,
InstName{...})` and instead have `AddInst<InstName>(loc_id, {...})` with
I think similar readability results. There are a couple cases where inst
construction is templated and so designated initializers couldn't be
used, so this may be better for those in particular due to the extra
type enforcement.

This probably doesn't clean up every last case, but I was trying to get
the bulk at once without bleeding over into less related changes.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-05-31 22:49:44 +00:00
Jon Ross-Perkins 40b2217421 Initial 'export name' handling. (#3949)
This adds a `BindExport` instruction in order to better track the
location of the `export` itself, but a `bind_name_id` is also added to
`ImportRef` so that we know quickly where to put it in name lookup.

Merging identical names is a TODO. I haven't quite decided how best to
achieve that, because I do think the BindExport should be what's
actually added to name lookup.

Also, I will probably add a mode to DeclNameStack that blocks
non-namespace scopes. This seems to already be an error, but the wrong
one (maybe due to lack of support for cross-file decl/def support).
2024-05-17 18:05:52 +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-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-PerkinsandRichard Smith 76ed3c73cb Promote FunctionType to a standard instruction. (#3931)
This removes the builtin FunctionType, replacing it with a FunctionType
instruction. The constant for a FunctionDecl is now a StructValue with
type of FunctionType.

Note this means a function declaration produces _both_ a type, and a
value of the type. This has some consequences in terms of circularity,
and makes the importing of function declarations a little more complex.

It'll get particularly peculiar for imports because of the behavior of
the reference, but that's a known issue due to other things such as
`alias`. The impact will hopefully be contained to
ResolvePrevInstForMerge (and ImportRefs).

To note a small formatting change in diagnostics:

```
-  // CHECK:STDERR: fail_member_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated <function> in Interface>` is not callable.
+  // CHECK:STDERR: fail_member_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated F in Interface>` is not callable.

-  // CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated <function> in Interface>` is not callable.
+  // CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: ERROR: Value of type `<associated F in Interface>` is not callable.
```

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-05-03 15:18:04 +00:00
Jon Ross-Perkins 5627f88c22 Switch ImportRefs to provide a LocId. (#3913)
This allows ImportRefs to point at a potentially distant instruction,
while still providing a LocId that can be used for diagnostics. I think
this'll be used if we're trying to point ImportRefs at canonical
instructions in distant IRs. It conveniently eliminates a special-case
in check.cpp.

Restructures LocIdAndInst::Untyped because I think it's not really
needed after this change (the key non-import use was GetWithLocId, which
I just give friend access for). Adding NoLoc for things that don't
provide _any_ location because it turns out Inst can easily be passed in
this way which was not what I had intended, but is used.
2024-04-25 21:08:57 +00:00
Richard Smith e0b8728263 Allocate de Bruijn levels to symbolic bindings. (#3906)
Use a level comparison during substitution to determine whether we're
substituting a particular binding. Evaluate symbolic bindings with the
same name and the same level to the same symbolic constant, for example
across redeclarations of a generic function.
2024-04-23 16:15:47 +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
Richard Smith e8cc089b2b Allow simple uses of Self in impls. (#3824)
Per #3714, some of the details here are not yet settled. In particular,
we might want `Self` to come into scope at the start of the definition,
not at the `as` keyword. However, this change allows us to accept the
uncontroversial examples.
2024-03-27 22:52:45 +00:00
cf361a83f3 Overloaded operator support. (#3796)
Support is added for all overloaded operator interfaces in the current
design apart from `Assign`, which is going to require some more work to
properly handle, given that primitive assignment currently has a special
implementation for quite a few builtin types.

As we don't have support for generics yet -- in particular, generic
interfaces -- there is no support for `*With` interfaces, but homogenous
interfaces such as `Add` are supported instead.

Factor out building of call expressions so that overloaded operators can
generate calls.

Switch a few places from using specific kinds of NodeId to a general
NodeId. Because overloaded operators and other things like implicit
conversions can result in member access and function calls, those
operations can't require a specific kind of NodeId.

Add import support for associated entities, and fix import support for
interfaces and symbolic bindings. We now import interfaces in two steps,
first importing a forward declaration then a definition, just like we do
for classes. For symbolic bindings, we ensure that each BindSymbolicName
is imported only once, because its ID is used as its symbolic identity.
This is necessary because we (only) support operator interfaces that are
defined in an imported Carbon package for now.

The entire contents of `check/operator.cpp` should probably be
rethought. In particular, doing a lot of name lookups on each operator
is likely to be bad for performance. But this gets us to the point where
overloaded operators are basically working, which seems like a good
place to iterate from.

For now, the tests that the individual operators map to the right
interfaces are mostly generated by a script, but that's just because I'm
expecting a fair bit of churn in how we define the prelude and the
`impl`s -- in particular, when we add support for `AddWith`, we'll need
to update all the tests. The plan is to remove the script once things
settle down.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
2024-03-19 19:47:29 +00:00
Jon Ross-Perkins 957f11587d Start pulling in names from cross-package imports. (#3789)
Note, I'm annotating the lookup partly so that the reason the conflict
comes up is clear, partly so that there's actually a diagnostic line
associated with the root cause as more tests get packed into a single
file.
2024-03-16 01:37:34 +00:00
8cb932b99c Substitute Self in associated function signatures before checking them against impls. (#3788)
Add a general substitution mechanism to support substituting symbolic
bindings with their values throughout symbolic constants and, more
specifically, types. This is done by decomposing the constant
instruction into its operands, substituting into the operands, and then
rebuilding the constant value by invoking the constant evaluator.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
2024-03-15 23:21:12 +00:00
Richard SmithandJon Ross-Perkins 1d720dc001 Basic support for looking up impl members when naming an associated entity. (#3776)
When a member access names an interface member, perform impl lookup to
find the impl and its corresponding member.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-03-14 18:31:21 +00:00
Jon Ross-Perkins 0217ec2d3b Switch Check's TODO to use SemIRLocation (#3779)
Allows dropping a few GetNodeId calls for code cleanliness.
2024-03-14 17:57:09 +00:00
Jon Ross-Perkins 86a7c9ff45 Rename parse_node -> node_id (#3760)
This was previously discussed at
https://discord.com/channels/655572317891461132/655578254970716160/1209975051588210729.
I'm initiating this mainly because we typically use "id" suffixes to
indicate an `IdBase` being passed around and the non-id suffix of
`parse_node` suggests at it carrying more data than it actually does.
There used to be more reason for avoiding `node_id` because
`SemIR::InstId` used to be named `NodeId`, but that's no longer
necessary. As a consequence, I'd like to rename `parse_node` to more
precisely reflect its type.

In full, this is doing:

```
parse_node_kind -> node_kind
parse_node -> node_id
ParseNodeCategory -> NodeCategory
ParseNodeKind -> NodeKind
ParseNode -> NodeId
```

This is primarily in check and sem_ir, but with some `parse_node_kind`
references in parse too.

Pluralization is consistent with name forms on both sides, so that
wasn't part of my replacements.
2024-03-09 00:21:29 +00:00
Richard SmithandJon Ross-Perkins a1317e61e0 Form the contents of the witness table. (#3756)
Check that functions in an `impl` are declared properly. For now, simply
reuse the redeclaration checking logic. Longer-term, we need to check
that the signatures match in a more approximate way, after substituting
the `Self` type into the signature in the `interface`.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-03-08 23:53:48 +00:00
Richard SmithandJon Ross-Perkins abf23ae7fe Initial scaffolding for building a witness table for an impl. (#3743)
Add an instruction to hold the witness table, along with a corresponding
type to keep things simpler. Add `check/impl.{h,cpp}` to house the new
logic. No checking of impls against interfaces is performed yet.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2024-03-07 23:10:14 +00:00