`AddDefaultValue` doesn't quite capture the intended semantics; it
should typically be replaced with an actual value when dealing with
control flows. Trying to indicate the "assign later" with
`AddPlaceholder`, mirroring `AddPlaceholderInst`.
Shifting the `protected` functionality on `BlockValueStore` so that it's
not providing functions just for `InstBlockStore` to use. Also hoping
that seeing the comments next to the function name makes them easier to
understand, whereas `using` buries that a little.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
When a generic function declaration was encountered for the second or
more time, we would FinishGenericRedecl() for the function decl, but
this just popped the generic region stack and moved on.
The issue with that is when the stack entry is gone, we lose the
symbolic constants from that declaration, and are unable to rewrite them
to point to the actual generic. This left us with a function declaration
with abstract symbolic values that were not useful, and in a function
call we use the declaration attached to the definition, which would be a
declaration with broken symbolic values. Then the function would be
uncallable since deduce would be unable to determine argument types
without the generic bindings.
This resolves the issue for functions, as well as ensuring the correct
generic id from a previous declaration is used for other generic entity
types that have redeclarations.
When a function declaration is qualified, such as defining a class
method outside the class body, we need only the function declaration to
contribute to its generic region stack. The code was collecting constant
values from all qualifier segments together incorrectly.
So when we PushNameQualifierScope(), we also drop the current generic
region stack and rewrite its constant values by calling
FinishGenericRedecl(), and open a new stack entry for the next part of
the qualified declaration.
If a generic declaration somehow has more dependent instruction than a
previous declaration, it would add new instructions to its eval block
with indices beyond the elements in the actual declaration eval block,
since we only store the block from the first declaration found. To avoid
this we plumb through that we are in a redeclaration, and terminate with
an ICE instead of adding new instructions to crash on later.
Fixes#5136.
Building on #5151 reducing `UncheckedLoc` use, further remove uses of
the `SemIR::LocIdAndInst` constructor where we typically have overloads
that don't need it. Add parallel convenience wrappers for placeholder
insts.
Also refactors `MergeReplacing`. I don't think it makes sense to add an
overload for `ReplaceLocIdAndInstBeforeConstantUse`, but we can still
reduce the `LocIdAndInst` construction there.
- A test that should fail that looks to see we poison impls when we do a
concrete lookup, so you can't define an impl specialization after we
looked for it. This currently passes but should fail.
- A test with a final specialization with a type constant written before
a generic function using it. The generic function should be able to know
the concrete type of the constant. This currently fails, and was
discussed in open discussion here:
https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.swr8311y952x
- A test with a specialization written after a generic function, which
will be used symbolically so the type constant will not be known. This
fails and should continue to, though the error diagnostic may change in
time.
- A test with a specialization written after a generic function, and
which returns a value typed as the type constant from that
specialization. The generic is called with types that should cause it to
use that specialization in the specific, so the caller gets back the
type expected. This currently fails but should pass.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
It's helpful for stability to not have the path in the repo reflected in
test files, something I'm separately running into. So to reduce this,
align INCLUDE-FILE with other split behavior:
- Use the filename (with a "include_files/" subdir to disambiguate),
rather than the full path.
- Note if we eventually want to support splits in these, the same
approach could be extended.
- Only provide as an arg if the user requests files as args.
Factoring AddFile back because it's hard to share; I'm also advocating
to remove the prelude manifest, which would mean the remaining call
could be removed.
The type structure is built for the impl lookup query for the
combination of the self type and the interface being queried. Then it is
built for each `impl` definition that is a potential candidate.
The type structures are compared to ensure they have a compatible
structure, and the `impl` declaration is not considered if they do not.
Finally, the type structures are used as a sorting key for the candidate
`impl` declarations, with the most-specified type structures (the ones
with the furthest distance to the first symbolic value) coming first in
the ordering.
See
https://docs.carbon-lang.dev/docs/design/generics/overview.html#parameterized-impl-declarations
for the design of the type structure and related ordering.
Most of the commits in this PR landed in #5158 (11ae0e27ab) by
mistake, but this includes the final changes since that PR was written.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
When the parameter is a deduced symbolic FacetValue, refering to a
BindSymbolicName, and the argument is a concrete FacetValue that would
match the FacetType requirements on the BindSymbolicName's type, we
currently do not deduce that the argument matches the parameter.
The argument is not _converted_ to the parameter type because they are
both FacetValues of the same FacetType type. However they are also not
equal constant values so the argument is not saved as a deduced match
for the parameter.
In order to accept the FacetValue, we need to consider them as
`deduce_through`, which attempts to deduce each of the fields in the
argument FacetValue against the fields in the parameter FacetValue.
This deduces that the argument's concrete type matches the symbolic
BindSymbolicName and its witnesses are the same.
Since the parameter is a FacetValue, its argument is not the type that
needs to be recorded as the deduced type for the binding. The
BindSymbolicName inside the parameter is the place that we need to find
the deduced type for the binding. So simply walking into the FacetValue
gets us to that position, where we eventually record the deduced
argument type as being the concrete type from the original argument
FacetValue.
Similarly, when determining what interfaces are satisfied by a
FacetValue for deduce, we want to use the full type available in the
FacetValue rather than just those from its FacetType. Determining
availability of interfaces here is equivalent to converting, and we want
converting a FacetValue to always work on the full available type info.
Only API access (member lookup) is restricted by a FacetValue to the
interfaces provided by its FacetType type.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
If a self type is FacetAccessType, we look through it at the facet
value, both for the query and the impl declaration. This ensures that
while FacetAccessTypes match each other for constant value equality
still, they an also match with facet value queries, such as:
```
impl forall [T:! Y] T as Z {}
^ FacetAccessType for BindSymbolicName of type FacetType(provides Y).
fn F(y:! Y) {
y as Z;
^ Facet value
}
```
Here the facet value and FacetAccessType don't have the same constant
value. Deduction will give the `T!: y` binding the facet value of `y`,
but the `T` in `T as Z` is a FacetAccessType to that binding, which is a
different constant value. Looking through the FacetAccessType gives us
the desired constant value for comparison with the query.
Additionally if the query self value is a FacetValue instruction, look
through that at the underlying type value. Impl lookup is used to
convert from one type or facet value to a new facet value of the desired
facet type. We want facet values to always be able to convert to
everything possible, rather than to have that restricted to just their
current FacetType:
https://github.com/carbon-language/carbon-lang/issues/5137. So this
allows queries such as `(C as Y) as Z` for a class `C` and interfaces
`Y` and `Z`.
This example motivated a decision to add a feature where we do impl
lookup to see if there is a matching `final` impl even in some cases
where it is already established that the type implements the interface.
I don't know when we plan on implementing this, but I wanted to capture
the example as test so we would have a TODO to address it.
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
This makes it friendlier in interactive debuggers. If you want to print
a value without a newline from code, you will have to be calling Print()
anyway since Dump() is private, and Print() does not add a newline.
Resolves TODO by creating new function `GetAssociatedValue` with the
logic from `PerformCompoundMemberAccess` restricted to the
non-instance-binding case.
---------
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Adds subset conversion of `NodeIdOneOf` due to the choice usage, plus
the pre-existing TODO. Fixes incorrect information about nodes on
StructLiteral and TupleLiteral.
After this change, `UncheckedLoc` is only used in a couple import
contexts (hard to verify) plus `InstStore::GetWithLocId`.
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.
```
Allow qualified name lookup into classes and interfaces as soon as we
reach the `{` of the definition, rather than disallowing such lookups
until we reach the `}`.
This prevents conversion from an InstId which is its base class, and
documents that this is invalid in the code.
Also expand the comment on the AbsoluteInstBlockId, which I had locally
but seem to have not saved and included in #5141.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
We were going to lengths to make these functions callable only if
`LocIdAndInst` was constructible, but nothing was depending on that and
it was harming readability and probably making diagnostics worse. So
stop doing that.
Move call_params_id from EntityBaseWithParams to FunctionFields.
No visible difference for Function. Since field call_params_id is
function specific fits better in FunctionFields.
Currently we do `settings set` twice which means the second one
overrides the first one, instead of ending up with a source-map that has
both entries in it.
When performing a call through an impl witness, the callee that we
type-check against is the function in the interface, so we form a
specific for that callee. However, once the impl witness access
resolves, the eventual callee is a different function -- the function in
the impl -- so this would cause us to form a `SpecificFunction` where
the callee is one function but the specific refers to a different
function.
Address this by adding another instruction, `SpecificImplFunction`, that
takes a function in an impl and a specific for the corresponding
function in the interface, and computes and returns a `SpecificFunction`
referring to the corresponding specific function in the impl, or returns
a direct reference to the function in the `impl` if it's not a generic
function.
This is trying to reduce how much we run tidy over due to poor
performance of tidy.
It's opening the door for issues where a header file is modified in a
way that introduces tidy issues in a different target. However, that's
not the typical tidy issue we see.
There may also be a risk where a source file indirectly becomes a source
file for a target in a way that `same_pkg_direct_rdeps` doesn't return,
but I'm not sure that's applicable for how we use targets.
An example of this locating a diagnostic error can be found in the "Add
tidy issue" commit's run (which I cancelled before it finished running,
but note the error):
https://github.com/carbon-language/carbon-lang/actions/runs/13932649182/job/38993348130?pr=5144
Check can print the full location for a LocId properly, but SemIR can
not since File doesn't have access to Lex.
So when dumping InstId from Check, include the LocId, to avoid making us
type `call Dump(context, context.insts().GetLocId(x))` all the time.
Building on #5120, make a variant of `AddNode` that returns typed nodes,
and replace `UnsafeMake` uses with it. This switches to templating in
import parsing so that we can get type validation.
With this change, `UnsafeMake` ends up used in three places: `Tree::As`,
`Tree::TryAs`, and `Context::AddNode`. That should mean that all typed
nodes are verified.
This flows out of #5084 and trying to reduce UnsafeMake use. It turns
out imports and namespaces were using unexpected node kinds (previously
ImportIntroducer instead of ImportDecl, for example). This fixes and
adds validation.
I was uncertain about whether to just remove the is_convertible check,
since I don't see it as motivating creation of a conversion between
NodeIdOneOf types. So I've just left a TODO for now.
According to approved syntax at
https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p3848.md#syntax-defined,
`fn F[]` without explicit parameters should be valid. This makes it
work, then adds some validation to prevent `class C[]` in check.
Note that for `fn`, positional parameters are a TODO -- but this allows
me to test validation in `fn destroy[]` which is rejected, not just a
TODO.
Avoid duplicating a `Core` package into each test, point them to
//toolchain/testing/min_prelude/convert.carbon which we add in this PR
with the As and ImplicitAs interfaces.
Move the tests of facet conversions from builtin_conversions/ to facet/
and the test of deducing through a member access into deduce/. This
eliminates the check/testdata/builtin_conversions/ directory, which was
making it hard to find where tests are for facet conversions. Now we
have one fewer place, and facet/ seems to be a fine home for them.
This adds support for having different C++ `NameScope`s (and not just
the main `Cpp` scope), and we keep a pointer to `clang::DeclContext`
these scopes so we can look up C++ names in the right part of the AST.
C++ Interop Demo with a namespace:
```c++
// hello_world.h
namespace some_namespace {
void hello_world();
} // namespace some_namespace
```
```c++
// hello_world.cpp
#include <cstdio>
namespace some_namespace {
void hello_world() { printf("Hello World!\n"); }
} // namespace some_namespace
```
```carbon
// main.carbon
library "Main";
import Cpp library "hello_world.h";
fn Run() -> i32 {
Cpp.some_namespace.hello_world();
return 0;
}
```
```shell
$ clang -c hello_world.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo
$ ./demo
Hello World!
```
Closes#5102
New planned direction is to not require completeness. Updated comments
to reflect that some care will be needed once named constraints are
supported. Long term plan is [discussed in
#5089](https://github.com/carbon-language/carbon-lang/pull/5089#discussion_r1985908453):
> We have some options. In our last conversation, it sounded like it
would be beneficial for named constraints to have their own witnesses,
with entries in declaration order. This would allow accesses to the
named constraint while it was being defined. So there would be something
of a hierarchy in a facet type witness, with a named constraint taking a
single slot in a facet type witness, independent of its definition.
Co-authored-by: Josh L <josh11b@users.noreply.github.com>
When converting from a facet value (an instruction whose type is
FacetType), we require making a FacetAccessType
to have a type instruction when building the resulting FacetValue.
Otherwise, the conversion is the same for values of type TypeType, and
we relax the convert function to support either.
Corrects the test expectations for converting `Goat as Animal`, a facet
value of type FacetType, into `Eats`, a facet type of type TypeType.
This would be a promotion in the typish hierarchy which is incorrect. We
had an extra case in Convert that was handling this, and it's now
removed. `Animal`, a facet type, does still correctly convert into
`Eats`, a facet type, if `impl Animal as Eats` exists.
Modifiers came to mind since we had a bit of discussion way back when,
about whether parse or check was the best place to do validation. Trying
to capture the tradeoffs to consider here.
Note, I'm writing this up mainly because I was asked why I don't reject
`fn destroy;` in parse twice (but still allowing things like `fn
destroy();` or `fn destroy[]();`), so I've been thinking a reference of
the higher-level parsing philosophy would be helpful.
When converting to a facet there are three different failure modes:
1. You provided a non-type value. Only types can convert to facets. So
we tell you that we found a non-type value.
2. You provided a facet type (which has type TypeType) which does not
have witnesses for the the target facet's type. So we tell you that the
type `T` implements `X` but needs to implement `Y`.
2. You provided a (non-facet-type) concrete type (of type TypeType)
which does not implement the target facet's type (which is a FacetType).
So we tell you that we need the type to implement the FacetType but it
does not.
3. You provided a FacetAccessType (which is of type TypeType also, but
we special case this), whose underlying FacetType is not compatible with
the target facet's type. So we tell you that we need the type to
implement `X` but found a FacetAccessType `T` which implements `Y`.
Closes#5027
This changes the SemIR of invalid redeclarations, because previously
they lacked a name. We've avoided this in diagnostics so it doesn't
otherwise come up, but I plan to use it for more easily validating
redeclarations.
Deduction can do conversion, and conversion can import impls from the
Core package. If you have the right number of impls in your ImplStore at
that moment, it will reallocate and any pointer into context.impls()
will be invalidated.
In particular, in impl lookup, we currentl loop over context.impls() and
do deduction on each impl. So this can break the for loop. Additionally,
we pass around a reference to the currently-being-looked-at Impl, which
becomes invalidated.
This is very challenging to test in any reliable way as you need a
specific number of impls in your ImplStore. I hit it when making changes
to a test in the middle of a bunch of file splits. Putting the same test
in its own file did not trigger the issue. It was caught by ASAN, which
showed:
- The memory was allocated by SmallVector in handle_impl when making the
Impl.
- The memory was freed by SmallVector reallocating in import_ref.cpp
- The memory was accessed when reading through the `impl` reference in
FindWitnessInImpls(). I was able to reproduce by printing the
`impl.interface.interface_id` after the call to GetWitnessIdForImpl()
which does the deduction.
I didn't save the ASAN stack and now I can't find the exact permutation
of the test file that caused it to occur in order to reproduce. :(
To avoid the UAF we stop passing around the Impl reference, and pass
around either the ImplId, or values from the Impl. To avoid copying the
entirety of the impl ids in context.impls() into a separate container in
order to iterate safely, we move the early outs from
GetWitnessIdForImpl() up to the caller where it can use them to reduce
the number impl ids that we iterate over. Type structures will be able
to further reduce the size of this set.
Currently file tests for LSP must provide carbon source code as an
escaped string within notify params, i.e.
```
[[@LSP-NOTIFY:textDocument/didOpen:
"textDocument": {
"uri": "file:/class.carbon",
"languageId": "carbon",
"text": "class A {\n fn F();\n fn G() {}\n}\n"
}
]]
```
This works fine for simple, single line files but gets annoying when
working with more complicated files which are necessary when testing
more complicated features e.g. goto-definition
```
--- class.carbon
class A {
fn F();
fn G() {}
}
--- STDIN
[[@LSP-NOTIFY:textDocument/didOpen:
"textDocument": {
"uri": "file:/class.carbon",
"languageId": "carbon",
"text": "AUTOFILL"
}
]]
```
This PR extends file_test_base to be able to parse the notify/call
params and inject files from the test_file's splits into the JSON input.
I purposely avoid using the clangd types and manually parse the
llvm::json::Value here to avoid introducing a depdendency on clangd to
the generic file_test_base, but happy to change if we think that is
fine. Also happy to accept other suggestions on alternative methods to
achieve same result.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>