`SubstInst()` replaces individual instructions, and then rebuilds them
into instructions that contain those instructions. If any instruction is
an `ErrorInst`, the final result will also be an `ErrorInst`. In
pathological cases, it's possible to generate large types, [such
as](https://github.com/carbon-language/carbon-lang/issues/5672) tuples
of tuples of tuples of tuples of `something`. If that `something` is
`ErrorInst`, we can save a lot of work by avoiding building the
surrounding types, and evaluating them all to `ErrorInst`.
The none.carbon min-prelude is not just an empty prelude, it also
prevents any prelude from being imported at all. So no import machinery
runs before the test, only the `package` statement from the prelude
would run.
Use the none.carbon min-prelude in a few tests that were specifying
`--no-prelude-import` to give it a trial run.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Follow up of #5594.
Trying to compromise SemIR size, having enough information and
complexity of tests, I've duplicated representative tests to a separate
test file with `--dump-sem-ir-ranges=if-present`.
When building a FacetType from an existing FacetType, don't diagnose
rewrite constraints that are compatible with the existing FacetType.
To do this, we consider two RHS as identical[1] if they have the same
constant value after substituting from available rewrite constraints in
the being-constructed FacetType, since the syntactic representation of
the RHS is lost during eval.
[1]
https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.qti4vn50zwy
Adds min-preludes more tests which were seen as slow and their
surrounding neighbours. This drops the file_test runtime on my machine
from about 6s to about 4.5s.
For a few files that are clearly only testing diagnostics, we drop the
if-present semir ranges and the associated TODO.
Adds min-preludes more tests which were seen as slow and their
surrounding neighbours. This drops the file_test runtime on my machine
from about 7s to about 6s.
For a few files that are clearly only testing diagnostics, we drop the
if-present semir ranges and the associated TODO.
Adds min-preludes to a few more slowest tests, and adds them to most of
the lowering tests, with a few exceptions that make use of operators.
This take the runtime of file_test down from about 8s to about 7s on my
machine.
We add support for Negate on uints in the min-preludes.
This drops the wall clock time for running file_test from 10s to 8s on
my machine. There's many more tests to convert, as each one takes the
test from ~1s to ~100ms. Compiling the full prelude is a bit slow now
since #5653, and before that file_test was taking about 3.5s.
We introduce a few more flavours of min_prelude to support more tests.
Remove use of i32/bool when a builtin type or test-define class type can
work. Make `Sub` user-defines in a test that is testing builtin
functions and not trying to test the prelude, in the same way that it
defines its own Negate. Reduce use of the + operator when it isn't
contributing to the test's coverage, since the + operator needs the full
prelude. Remove use of Core.Print when it's not required for the test.
Move `deduce_nested_facet_value.carbon` to its own file since it uses
TypeAnd, and the rest of deduce.carbon does not, but uses i32. This
means they can each use a different min-prelude.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
When the binding pattern appears within a `var` pattern, convert to a
reference. Otherwise, convert to a value.
This gets the advent of code examples to produce the right answers again
:)
---------
Co-authored-by: Geoff Romer <gromer@google.com>
import_use_generic.carbon has the comment "// We're just checking that
this doesn't crash. It's not expected to compile." Because it involves
import behavior by name, I'm not touching it. Other than that, while
maybe it's better to test with less, the `ImplicitAs` errors at best
feel difficult to understand, and at worst could be masking an issue.
Factor out the logic for mapping from a `LocId` into a diagnostic
location from check into sem_ir so it can be reused by lowering. Include
the function and instruction being lowered in the pretty stack trace.
Example stack trace:
```carbon
2. filename: examples/sieve.carbon
3. core/prelude/types/int.carbon:213:3: lowering function Core.Op(Core.IntLiteral as Core.ImplicitAs(i32))
fn Op[addr self: Self*](other: Self) = "int.sadd_assign";
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4. core/prelude/operators/arithmetic.carbon:22:27: lowering call
fn Op[addr self: Self*](other: Other);
^~~~~~~~~~~~
```
Establish some guidance on using AI coding tools when contributing to
the Carbon
Language project. These tools have growing popularity and interest, and
it would
be good to have a clear and actively documented set of guidance for
folks
interested or already using them.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This is based on #5664 because it's fixing an issue which `DEBUG` would
catch. That's also why I'm switching to `DEBUG` from `EXTENSIVE`; I
think we should be okay with the performance cost in `file_test`, which
is probably our main concern.
Note digging into this also got me to notice that the flags weren't
actually enabled; this is fixing the define names.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
The sort and dedupe operations in facet type resolution explicitly work
with `ImplWitnessAccess` instructions as being a reference to an
associated constant on some entity. If only one of the instructions is
an `ImplWitnessAccess`, we still want to consider that one as such, not
get its constant value, which may be some concrete type, and use that
for comparison instead.
This makes the new test fail (which we don't want) in a consistent way
with a similar test of TypeAnd (which we also don't want to fail),
making the system more consistent, while leaving some improvements to be
done.
Avoid inconsistent orderings between instructions, by making the
comparison function into a total order. To do so, we sort
ImplWitnessAccess instructions first, and sort them by their InstId.
Non-ImplWitnessAccess instructions come second, and sort them by their
constant InstId. Thanks to jonmeow for figuring out that the function
was not producing a total order and why.
Since this means the order is no longer relative to source order, we
order the two assignments in the diagnostic by source order(ish) by
putting the lower InstId first in the diagnostic output.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Uses of `ConstantValueStore::GetConstantInstId` or
`ConstantValueStore::GetInstId` in eval indicate that the code expects a
constant value. Instead of just ending up with `None` in strange places,
diagnose this and convert to an `ErrorInst` when expectations are not
met.
We add `RequireConstantValue` to pair with `GetConstantValue`, and
rename `GetConstantValueIgnoringPeriodSelf` to
`RequireConstantValueIgnoringPeriodSelf` since the former would just be
unused.
Adds a test where a runtime value ends up in the RHS of a rewrite
constraint, where a constant value is expected. This issue was uncovered
by a fuzzer.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Replace the binary `Operation` interfaces with the `OperationWith(T:!
type)` interfaces described in the design, and add a `Result` associated
type for both unary and binary operations. Update the `impl`s in the
prelude for integer types to use the new form, including supporting
implicit conversion of either operand.
I've tried to split this PR up into commits focused on distinct changes
for review convenience. It may be simplest to review it one commit at a
time.
Given a facet type: `(Z where .X = .Y) where .X =.Y`
The rewrite constraints in the inner facet type are each an
`ImplWitnessAccess` into a witness for the self of type `Z` (which is
the facet type before the `where`). The rewrite constraints in the outer
facet type are each an `ImplWitnessAccess` for the self of type `Z where
.X = .Y`, which is a different self facet type.
This means when deduping in canonicalization, the first `.X` and the
second `.X` are different instructions, and different constant values,
so they both remain in the rewrite constraints, incorrectly. Then if the
outer `.X` is allowed to evaluate to a value from its facet type, it
finds `.Y` resulting in `.Y = .Y` which is also incorrect.
Because of the failure to dedupe the first facet type, that is also
diagnosed as two different assignments to the same `.X`. To resolve
that, we introduce `CompareFacetTypeConstraintValues()` compare values
in facet type constraints, and treat accesses to the same associated
constant in the same facet value as `equivalent` even when through
different witnesses. This allows us to dedupe the two `.X = .Y` rules
into one in the combined facet type.
Given a different facet type: `(Z where .X = ()) where .X = {}`. Here we
want to diagnose that `.X` has been assigned two different values. To do
so, we need to see that the two `.X` values are the same, and we use
`CompareFacetTypeConstraintValues()` to do this comparison. Then we see
two rewrite rules for the same LHS, and we can diagnose that.
We enable evaluating `ImplWitnessAccess` on `.Self` to pull a value from
rewrite constraints in a facet type so that we can see that we are not
incorrect evaluating the LHS of rewrite constraints and producing
cycles. By doing so, also enable generic code to see and use concrete
values in associated constants in facet types.
The `BitAnd` operation combines two `FacetTypeInfo` structures by
concatenating their lists, but did not apply the current specific to the
instructions in the `FacetTypeInfo` as it forgot to go through
`GetContantFacetTypeInfo`.
`WhereExpr` handling duplicates a lot of the logic in
`GetConstantFacetTypeInfo` by calling `GetConstantValue` on things,
instead of calling `GetConstantFacetTypeInfo` on the `FacetTypeInfo` it
constructs. This meant it also needed to call `GetConstantFacetTypeInfo`
on the base facet type, and on any `impls`-requirement facet types
before merging their values together into a single `FacetTypeInfo`.
Instead, make `WhereExpr` more like `BitAnd`, and have it concatenate
things together as-is to construct a `FacetTypeInfo`. Then call
`GetConstantFacetTypeInfo` to canonicalize it and return a constant
value referring to it.
In `GetConstantFacetTypeInfo` we fix a crasher by propagating errors
inserted into the `FacetTypeInfo` out to the `Phase` so that the
resulting instruction depending on the `FacetTypeInfo` is not resolved
to a constant value with errors inside it. A test is added for this,
which was crashing on import of the `FacetType` with an error within
from the imported `impl` decl.
This refactoring gives us three benefits:
* There's now only a single place that does
`ResolveRewriteConstraintsAndCanonicalize`, which is inside
`GetConstantFacetTypeInfo`. This makes the inputs/behaviour of
`ResolveRewriteConstraintsAndCanonicalize` more consistent.
* There's now only a single place that updates the instructions in
`FacetTypeInfo` constraints with new constant values, so that changes
that rely on observing and interacting with that code only need to be
written in a single place. This will avoid duplicating logic in
https://github.com/carbon-language/carbon-lang/pull/5644.
* This will make it easier to move `WhereExpr` handling to a
`EvalConstantInst` function, as it no longer directly depends on
`GetConstantValue()` from `eval.cpp`.
The `SemIR::File` has access to the `Parse::ParseTree` and
`Lex::TokenizedBuffer` now, so `semir/` can dump a friendly source
location for `LocId`. There were a few other Dump functions in `check/`
that added location info to things, and these can be consolidated into
`semir/` as well. Now `check/` dump functions all just forward over to
`SemIR`, `Parse` or `Lex`.
As we've been discussing stack trace behavior, I was thinking having the
version in crashes would be helpful. e.g.:
```
1. Carbon version: 0.0.0-0.dev+bdcef04bb.dirty
```
When finding an executable, this validates that the returned binary is a
symlink back to the same thing as /proc/self/exe, also using that as a
fallback for different things.
Looking back at #3912, we started using `findProgramByName` in order to
avoid path canonicalization done by `GetMainExecutable`. That created
issues as in #5096, wherein an `argv[0]` that's not explicit enough
(`llvm-symbolizer` instead of the full path, done in [LLVM's
Signals.cpp](https://github.com/llvm/llvm-project/blob/4f60f45130c6bd96c79e468fe9927a29af760f56/llvm/lib/Support/Signals.cpp#L198))
leads to incorrect results (finding an `llvm-symbolizer` in `$PATH`).
One option to fix this would be to patch LLVM to provide an absolute
path for `llvm-symbolizer`. However, I'll suggest that passing a
filename in `argv[0]` is not terribly uncommon, and could be a migration
limitation if we force it. The failure mode is also opaque; for example:
```
$ /bin/sh -c "exec -a llvm-symbolizer ./bazel-bin/toolchain/carbon"
error: expected carbon-busybox symlink at `/usr/lib/llvm-19/bin/llvm-symbolizer`
```
Combined with the `setenv` of `LLVM_SYMBOLIZER_PATH` in
`busybox_main.cpp`, this is intended to fix#5096.
This preserves the constant values of the arguments to the thunk, which
is important if the thunk requires conversion of an `IntLiteral` to some
other type. This should become unnecessary once we have form support,
but avoiding the indirection through a thunk function seems valuable
even once that support is in place.
To support this, track whether a function is a thunk on the Function
object, and if so, what the callee of the thunk is. This information is
also included in formatted SemIR when dumping the thunk.
If the RHS of a rewrite constraint refers to an associated constant,
pull the value for that constant from other rewrite constraints. We
repeat this each time a RHS value is changed until we reach a fixed
point, as per the "Rewrite constraint resolution" rule:
https://docs.carbon-lang.dev/docs/design/generics/appendix-rewrite-constraints.html#rewrite-constraint-resolution
While replacing references to associated constants in the RHS, if the
reference is to the LHS of the same rewrite constraint, we diagnose it
as a cycle which has no fixed point, and replace reference to the
associated constant with `ErrorInst`.
Currently it's called `assign_reviewers` as it was copied from the
workflow that does said task. But this workflow is setting labels, so
call it `set_labels`.
All except
`toolchain/check/testdata/interop/cpp/function_param_int*.carbon` and
`toolchain/check/testdata/interop/cpp/function_return.carbon`.
Don't output SemIR for cases that are intended to fail.
Use it to replace most existing modernize-loop-convert lints with
range-based for loops. As requested in review of #5475.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Instead of using somewhat different approaches for defining in-line
methods at the end of the enclosing scope and defining thunks at the end
of the enclosing scope, we now use the same worklist for both.
This fixes a bug where we would crash when defining thunks if there
happens to be nothing else on the deferred definition worklist, leading
to our leaving the enclosing impl scope before we try to define the
pending thunk. That would only happen if the impl contains no in-line
member function bodies, so only if the impl has only a forward
declaration or a builtin declaration for every method. The latter
case happens (a lot) if we start using thunks in the prelude impls.
One complicating factor here is that this means the deferred definition
worklist moves from the layer containing `check/handle*` and
`check/check_unit.cpp` into the layer containing `check/context.cpp`.
Allowing that required moving a couple of other things that it depends
on -- notably `SuspendedFunction` and `HandleSuspendedFunction` --
around.
Build a `SpecificConstant` (if needed) and `NameRef` instruction when
referencing the thunk target from a thunk. The former is necessary if
the impl is generic in order to call the right version of the thunk
target. This previously caused a crash in lowering.
Also add some more check testing for the interaction of thunks and
generics. This testing uncovered an unrelated bug with thunks for
generic interface functions for which I've added a TODO.
Changes the vectors on `Lower::FileContext` to be `FixedSizeValueStore`
where possible, which we have several at this point.
This changes `FixedSizeValueStore` to prefer inferring the size from a
`ValueStore<IdT>`, which should make adding incorrect sizes harder. Note
I wasn't sure that adding a `size()` to `TypeStore` that returned
`insts().size()` would be good because it doesn't directly work that
way; `ConstantValueStore` would've also required more work since it
doesn't have access to that right now.