Refactors the link driver to automatically compile and cache the carbon
prelude for use in linking.
Implements a `carbon_library` rule for compiling the Core library
dependencies in the examples.
We can't use a `CallExpr` to call a constructor; use a
`CXXConstructExpr` instead. While this fixes the crash and gets us past
the initial constant evaluation, we still can't map the constant value
back into Carbon, so this doesn't actually make constexpr constructors
work yet. But it does stop Clang from crashing.
Fixes#7498.
Instead of tracking the cleanup scope depth on entry to each scope,
track an "ambient" cleanup scope depth that's *after* the destructors of
local variables in that scope. This gets increased to include the
destructors of local variables when we create a name-binding
declaration. Then, when we reach a point where temporaries should be
destroyed, run cleanups that are after the ambient cleanup scope depth
on the stack. This happens:
* At the `;` of a statement expression.
* At the `)` of an `if` or `while` statement.
* After performing the implied `HasValue()` call in a `for` statement.
Per informal agreement with leads, this means we lifetime-extend all
temporaries created in the initializer of a name-binding declaration to
the full scope of that declaration, but that temporaries created in an
expression statement are destroyed at the `;`.
Allow (don't diagnose) impls that have the same type structure if they
are associated with the same match_first block. Similarly, allow final
impls (made final by their enclosing match_first block) that overlap in
type structure when they are associated with the same match_first block.
If the type structures are the same, choose the first impl from the
match_first block.same.
If the type structures overlap but are not the same, and share a
match_first block, then we should choose the first overlapping impl from
the match_first block. This is true both for final and non-final impls.
See
https://github.com/carbon-language/carbon-lang/blob/de8b03faa3178ae683d8e7124fbcba81eb88e00c/proposals/p005337-interface-extension-and-final-impl-update.md#impl-selection-algorithm
But in the non-final case if there is an overlapping impl outside the
match_first, it can win if it's more specific.
When a Carbon virtual function overrides a C++ virtual function, we need
to export it with the C++ signature in order for it to work as an
override. Instead of mapping the C++ signature into Carbon and then back
again, use the original C++ signature from the base class as the
signature exported to C++.
Also add documentation explaining how we use thunks in C++ interop,
including in this new virtual function handling logic.
Previously the last decl had to be the definition. Now we allow a
declaration after a definition, so that the user can write a match_first
block last, and put (re-)declarations of impls in it, after the
definitions have already been written elsewhere.
We track the location of the decl that was associated with a match_first
block so that we can correctly point to it in diagnostics when an impl
is written twice in match_first blocks. Since impls may not be
redeclared across an import boundary, we will never have a `SemIR::Impl`
with a match_first from a different file in a redeclaration, so we don't
need to import the location of a previous decl that was in a match_first
for diagnostics. As such we just store a LocId on the `SemIR::Impl`
struct.
The type of `.Self` introduced by `where` may contain a `.Self` inside
it. Freeze the type so that we have a consistent view of `.Self` inside
the facet type, where they are all frozen.
The type of `.Self` only has extend constraints from the LHS of the
`where`. So we need to copy any non-extend constraints into the
`where_stack` so they are available as early-impls and can be used for
impl lookups on the RHS of the where. We need to freeze any `.Self`
references in these just as we do for rewrite constraints.
Destroy local variables and temporaries at each `}`, and when branching
with `break` and `continue`. In `for` statements, destroy loop variables
along with anything created within the loop at the end of each loop
iteration, and destroy the cursor and range object when the loop
terminates.
Assisted-by: Gemini via Antigravity
---------
Co-authored-by: Geoff Romer <gromer@google.com>
Instead of manually creating a map from symbolic types to concrete
types, create a Specific and look up parameter types via that Specific.
This allows C++ to call a Carbon function like `fn F[T: type](unused t:
T*) {}`. See generic_pointer.carbon.
When we check an `impl` decl, find the containing `match_first` block,
if any, and store a connection to it in the `SemIR::Impl` structure,
along with the impl's position in that `match_first` block so that we
can sort/prioritize the `SemIR::Impl`s later.
Also, update the `is_final` flag if the `match_first` block is modified
as `final`. But ensure we diagnose trying to put a `final impl`, or a
redeclaration of one, in a `match_first` block. Also diagnose if an impl
is attached to a `match_first` block more than once - either in two
different blocks or in the same block at different positions.
Putting the `match_first` connection on the `SemIR::Impl` structure
means we have to import it, so implement import and add a smoke test for
that, which ensures nothing explodes.
Drop the `scope_stack` entry for the `match_first` block, as it was not
needed. Once we started tracking the `match_first` size on the `Context`
class, it became more straightforward to just store the `match_first`
decl `InstId` in the same place. The `match_first` block is not supposed
to act like a different scope for the purpose of redecls anyhow, so it's
a bit simpler this way.
It must be in a namespace, function, or class. In particular, it can't
be in another match_first, doing so immediately associates any impl
inside with two different match_first scopes, but we only want them
associated with one for prioritization.
Push a scope_stack entry for match_first blocks, and handle impls being
inside those scope entries. An impl should not use the `match_first`
block as its "enclosing scope" for the purpose of deciding if the impl
is a redecl of another impl. We should look through it to the class or
namespace the impl (and match_first) are located inside.
We don't yet store the relationship between the impl and its match_first
block, nor then can we use it in impl lookup for prioritization.
Implement the toolchain side of proposal #7254, removing the `:!`
binding
syntax for generic and template parameters in favor of the keywords
`generic`,
`template`, and `runtime` plus contextual defaults for phase.
For valid programs this is semantics-preserving: each binding resolves
to the
same phase, and produces the same SemIR, as it did under `:!`/`:`. The
parser
derives a binding's phase from its syntactic context plus any explicit
phase
keyword; new diagnostics and error recovery for misused keywords are
described
below.
Implementation details for each component:
- Lexer: remove the `:!` (`ColonExclaim`) token, move its virtual
parse-node
budget onto `:`, and add the `generic` and `runtime` keywords.
- Parser: thread a `BindingContext` (`ExplicitParam`, `DeducedParam`, or
`CompileTimeEntityParam`) from declaration introducers down through
parameter
lists to each binding pattern, using a one-token lookahead to
distinguish a
name-qualifier parameter list from a declaration's own final list.
Parameters
of a compile-time entity (`class`, `interface`, `constraint`, `choice`,
`alias`, `export`, `namespace`) and deduced `[]` parameters default to
checked
generic; explicit function parameters and local bindings default to
runtime.
`HandleBindingPattern` resolves the phase from that context plus the
keyword: a
`generic` keyword needs no node of its own (the phase is carried by the
binding's node kind), while a `runtime` keyword is preserved as a
`RuntimeBindingName` node so `check` can name it in a diagnostic. A
phase
keyword that is merely redundant with the contextual default is
diagnosed
here, without invalidating the parse tree.
- Check: a phase keyword that is invalid for its context (for example
`runtime`
on a checked-generic parameter) is diagnosed here, and recovers by
building an
error binding that still introduces the name so that later uses of it do
not
produce cascading errors.
The removed `:!` syntax is now rejected as an ordinary parse error.
The `form`/`:?`/`->?` ("extended types") portion of proposal #7254 is
left for a
separate change.
Assisted-by: Claude Code
When formatting an impl definition, include in the textual output if the
impl is final. Since we (mostly) write them as `final impl` in the code,
use the same notation in the textual semir.
The implicit/explicit `.Self` concept is a heuristic at best, so we
should avoid relying on it. We now only have one value of `.Self` in a
facet type (we have banned nested `where` on the RHS of a `where`). So
we don't need to preserve any `.Self` for the purpose of disambiguation,
and we can subst all `.Self` on the the RHS of a rewrite constraint.
`LookupImplWitness` instructions inside the impl declaration can't use
the impl they are apart of. Previously we had an heuristic in eval which
would try to prevent finding the impl for a lookup from inside that
impl. But it breaks when the `.Self` is replaced in a generic impl with
a symbolic, and then that symbolic is replaced in a specific. The
specific's decl block contains that `LookupImplWitness` instruction and
it tries to use the impl it came from. This causes the same specific to
be formed again, but now it exists, so it's used as-is but it has no
decl block yet, and so we crash.
Now we ban an impl while we resolve its specific, both deduction of its
arguments and from any other substitution. The prevents instructions
from inside the impl (which are evaluated when resolving the specific)
from finding their own impl. We do so by adding the ImplId to a stack on
the Context, and then skipping such impls when looking for candidates
during eval.
This fixes a crash, which was demonstrated by the new test being added.
It also makes another todo test pass.
There's a whole lot of other semir churn, which seems to be mostly
reordering of constants. There are some fingerprint changes in
constants, but it appears they are the same canonical instructions, so
they don't represent a behaviour change. For example in
`toolchain/check/testdata/for/actual.carbon` the `%N.patt` constant has
been given its fingerprint suffix now as `%N.patt.aa5`. But they are
both this instruction, so it is just a formatting change:
```
inst6100001A: {kind: SymbolicBindingPattern, arg0: entity_name61000002, type: type(inst61000018)}
- name: `N`
- type: type(inst61000018): <pattern for Core.IntLiteral>; {kind: PatternType, arg0: inst(IntLiteralType), type: type(TypeType)} (concrete)
- value: symbolic_constant61000001
```
`.Self` will only be replaced in a facet type, as the facet type
constrains a facet. If it's part of a (non-facet) type, then the object
of that type is not a facet, and we can never replace that `.Self`.
We used to have to batch these at the end of pattern traversal in order
to avoid accidentally adding them to a block that was speculatively
pushed for an expression within a pattern, but that's no longer a
concern with the more precise handling of those speculative blocks in
#7445.
In #7436 we stopped substituting `.Self` when collecting witnesses out
of a facet type. While this was correct, it did not capture all the
cases that need to avoid substituting `.Self`. And it poisoned the
`IdentifiedFacetType` cache by not replacing `.Self` but storing the
result in the cache. This led to incoherent behaviour, where the result
of an impl lookup would change depending on which ones had been done
previously.
Now we use a flag to track for each `.Self` if we're currently
type-checking inside the scope where it was introduced in a facet type.
While inside that scope, identify should not replace the `.Self`. Any
use of it should remain as-is since we don't yet know what value will
replace it. We call this state "frozen" since it should not be modified
by identify. This requires a substitution step when we leave the scope
that introduced the `.Self`, to remove the flag. The flag is set in the
`EntityName` of the `SymbolicBinding`, and is part of the canonical
value, since `.Self` can become part of types, which are constants, and
the flag needs to follow it for correct behaviour.
We also have to ensure the flag is the same when doing comparison with
constants from inside a facet type and constants from outside. For
instance in `(Z where .Z1 = ()) where .Z2 = .Z1`, when we arrive at the
second `.Z1` its `.Self` will be frozen, while the `.Z1 = ()` contains a
non-frozen `.Self`. So we add the frozen flag to the first when storing
it in `where_stack` in order to compare the constant values of the two
`.Z1`.
The `WhereExpr` requirement inst kinds now have an `InstConstantKind` of
`AlwaysUnique` instead of `Never`. This allows us to add them to the
usual InstBlocks, and in an `eval fn` body they have a constant value,
so eval does not fail when trying to call that function. We have to be
careful to not consider `AlwaysUnique` as being actually concrete
though, since their constant value erases `.Self`-dependence. This
allows us to stop special casing them when thawing the requirements
block in a `WhereExpr`, and we can just thaw each `InstId` in the block
in a straightforward manner.
We add the new flag to the instruction's fingerprint and name in
formatted semir.
This adds SemIR structs and implements building `observe` lists, as well
as naming, formatting, and importing `observe` declarations.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
This allows C++ to call Carbon functions with generic type parameters,
with some conditions. Example:
```carbon
interface I {
fn Doit(self);
}
class A {
impl as I { fn Doit(unused self) {} }
}
class B {
impl as I { fn Doit(unused self) {} }
}
fn F[T:! I](t: T) {
t.Doit();
}
inline Cpp '''
void G() {
Carbon::A a;
Carbon::B b;
Carbon::F(a);
Carbon::F(b);
}
''';
```
The initial support is limited; only explicit parameters are handled
currently.
`CarbonExternalASTSource::GetOrExportFunctionToCpp` now generates a
`clang::FunctionTemplateDecl` for generic Carbon functions. If C++ code
attempts to call that templated function,
`CarbonExternalASTSource::LoadExternalSpecializations` will be called
with the template argument types of that call site. Then we can generate
a specialized thunk for those argument types for C++ to call.
In some cases the pattern block can depend on the initializer, so it
must be sequenced after it. See #7469 for a more detailed explanation of
why this is necessary.
This performs `.Self` substitution in a single step, for the whole facet
type, instead of doing it individually for each constraint visited in
the top-level facet type. Then we don't need to track state to avoid
subst in constraints that come from other named constraints.
The semir changes are because we now generate a whole other FacetType
from the substitution.
Carbon currently requires a comment to be the only non-whitespace on its
line. A `//` comment that follows other content on a line, called a
_trailing comment_, is a lexer error. This proposal removes that
restriction, allowing a comment to follow other content on a line.
Everything else about comments is unchanged: a comment still begins with
`//`, still requires whitespace after the `//`, and still runs to the
end of the line. Carbon continues to provide only line comments; no
block or intra-line comments are added.
Three observations motivate the change. First, trailing comments are
well suited to short _annotations_ attached to a specific entity or
value on a line. Second, the lexer design now makes it trivial to lex
trailing comments, and in fact requires extra logic and potentially cost
to reject them. Third, C++ code routinely uses trailing comments, so
allowing them lets Carbon carry the layout of migrated code over
directly, rather than reworking each comment to read well in a different
structure.
Implementation notes (beyond the proposal's design):
Keeping trailing comments cheap to lex required a few supporting
changes, all of which keep the cost off the lexer's hot path:
- The lexer already dispatches `//` to comment lexing wherever it
appears, so classifying a comment as trailing is a single O(1) check of
whether the `//` is the line's first non-whitespace (`start + indent`).
The hot comment path is otherwise unchanged.
- That check relies on each line's recorded indentation being its real
leading whitespace. Multi-line string literals previously recorded the
column where the literal opened for the lines they span; they now record
the true (closing-delimiter) indentation instead.
- Parser error recovery (`SkipPastLikelyEnd`) had relied on that
opening-column indentation to keep tokens following a multi-line string
literal attached to the same construct. It now reconstructs that
relationship directly by consulting the line on which the literal
opened, including when other tokens follow the closing delimiter (such
as `''' + "more"`). This is on the cold recovery path.
- `CommentData` records the trailing bit in the high bit of its length
field, keeping it at 8 bytes.
Assisted-by: Claude Code
When we find a named constraint during identity, we recurse into it. The
specific args of the named constraint may contain references to `.Self`
which can then make `.Self` appear inside the named constraint, which
was making us replace `.Self` at multiple levels and incorrectly. The
first specific argument replaces `Self` in the named constraint, and we
pass in the self-type of the identify operation. This may contain
`.Self` and we should _not_ be replacing the `.Self` references with the
self-type that they are contained within. This led to infinite cycles.
In the meantime, we have made the toolchain reject any ambiguous `.Self`
from being constructed. So we know there is only one value of `.Self`
around in a facet type.
So now we replace `.Self` only in the top level facet type during
identity. That means replacing `.Self` in the specifics of the named
constraints that we recurse into. But we do _not_ replace `.Self`
anymore inside those named constraints. This resolves the infinite loop.
At the same time, when we are identifying an `impls` constraint from
earlier in the same facet type, like `C impls Z(.Self)` we are
identifying with a self-type of `C`. We want the output to use `C` as
the self-type since we should get back an identified facet type that
says `C impls Z(.Self)`. But we do _not_ want to replace the `.Self`
there since we're inside a facet type and the `.Self` does not refer to
`C`. So we parameterize `TryToIdentifyFacetType` to not replace `.Self`
when identifying an `impls` constraint from the `where_stack()`. This
resolves a large number of `fail_todo_` tests.
Impl lookup identifies the types of facets in the query, replacing
`.Self` in each type with the facet. This allows references using the
facet from outside the facet type to match similar structures inside the
facet type.
However replacing `.Self` with the facet can re-evaluate symbolic impl
lookups inside the facet type. These can perform deduction in generic
`final impl`s, which can attempt to convert the facet. Convert does an
impl lookup with that facet in the query, which causes us to form an
infinite recursion cycle.
Add tests that caused such a cycle, to demonstrate we no longer crash.
Some of these tests fail impl lookups using concrete values in the query
that match values from a `final impl`, with TODOs to address them.
Instead of traversing the entire pattern block looking for
`VarPattern`s, we keep track of them on creation, and then build
`VarStorage`s directly from that list.
This also gets rid of the global `var_storage_map`, and instead keep
that information narrowly scoped to each full-pattern, and consume it in
a single linear traversal instead of with random-access lookups. To
enable that, this fixes a parse bug where nested `var` patterns were
getting diagnosed but not marked as errors.
In #7378 we forbid writing `where` on the RHS of another `where`
expression. However it's still possible to inject a `where` expression
through eval, using an `alias` or an `eval fn`. We address this by
looking in the constant value of constraints of a `WhereExpr` (which
sees the outcome of eval) and searching for a nested `where` there. We
can determine a facet type was written with a nested `where` by seeing
that it has some non-extend constraint.
---------
Co-authored-by: David Blaikie <dblaikie@gmail.com>
If the deduction fails while forming the parameter type, ensure that we
print an actual diagnostic saying what went wrong.
And always ensure that an invalid array bounds error points at a
location. The `inst_id` given to `EvalConstantInst` always has a
location, but the `bounds_id` instruction inside it may be canonical
when it's coming from inside a larger type. So when it is, fall back to
using the location of the whole array inst.
This disallows building a facet type that contains another facet type
with non-extend constraints in it. Which in turn prevents the
possibility of introducing a different `.Self` into a facet type.
Eval can still insert a facet type with non-extend constraints, as we
only prevent it for `where` being written into the facet type. There is
a TODO in handle_where.cpp for this and some tests in
toolchain/check/testdata/facet/nested_facet_types_from_eval.carbon
In `PerformActionHelper`, use the unqualified type for lookup.
In `PerformInstanceBinding`, propagate qualifiers to the unbound element
type's class type when doing the `ConvertToValueOrRefOfType` conversion,
and to the element type when forming the `ClassElementAccess` instr
(except for `partial`, which is only used if the member being accessed
is `base`).
In handle_operator.cpp, prevent assignment to a reference to a const
type.
Move the existing derived->base conversion earlier in
`PerformBuiltinConversion`, into the block that handles qualifier
conversions. This allows, for example, converting from `partial Derived`
to `partial Base` -- see the tests in
`toolchain/check/testdata/class/inheritance/derived_to_base.carbon`.
The function to set the visible declarations with a given name
overwrites any existing declarations imported from an AST file, so we
need to avoid calling that for declaration contexts whose names are
managed by Clang to avoid clobbering names imported from modules.
Assisted-by: Gemini via Antigravity
Depending on the order in which type completion identifies things in the
facet type, it may try to replace `.Self` with a facet that fails to
convert to the type of `.Self` due to a monomorphization error. We
should fail gracefully, not crash.
Formatting an instruction with an initializing expr category will call
`FindStorageArgForInitializer()` to get the target id.
`GetExprCategory()` supports imported instructions by walking to the
imported IR, in order to get the expr category. We do the same in
`FindStorageArgForInitializer()`, instead of hitting a CARBON_CHECK.
The new test crashes without the changes here.
Notably this allows accessing fields in an abstract base class via a
derived class without going through `base`. E.g.
`my_obj.field_in_base_class` rather than
`my_obj.base.field_in_base_class`.
In `Convert`, allow forming a value or reference of abstract class type,
but not an initializer.
For now, limit the scope to just `ClassElementAccess` to avoid affecting
tests where I'm unclear if allowing abstract types is correct.
This test was assuming that we'd allow qualified lookup in rewrite
constraints, but that is not in agreement with the design. The design
says that the LHS of a rewrite must be a member access designator like
`.Member`.
If C++ overload resolution selects a builtin operator candidate for an
enum comparison or bitwise operator, provide support for that operator
by generating a corresponding Carbon builtin function. This is
structured to be easily extensible to other C++ builtin overload
candidates if we so choose, but for now the operators defined in the
prelude are doing what we want in most cases.
Bitwise operators on enums produce the same enum type as a result. This
intentionally deviates from C++, where they produce a promoted integral
type.
Assisted-by: Gemini via Antigravity