Replace :! binding syntax with phase keywords and contextual defaults (#7479)

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
This commit is contained in:
Chandler Carruth
2026-07-11 01:22:44 +00:00
committed by GitHub
parent bf106c3b4b
commit 8be274cf60
482 changed files with 16917 additions and 16226 deletions
@@ -24,14 +24,14 @@ impl DD as Y {}
impl DD as W {}
// CC requires D to implement Y.
class CC(D:! Y) {}
class CC(D: Y) {}
interface Z {}
// The `D` interface provides `Y` but not `W`, so we need to see that the
// parameter to `CC` is `DD` which provides `Y & W`, not just a FacetValue
// abstractly providing `Y.
impl forall [E:! Y & W] CC(E) as Z {}
impl forall [E: Y & W] CC(E) as Z {}
fn F() {
(CC(DD)) as Z;
@@ -137,20 +137,20 @@ fn F() {
// CHECK:STDOUT: } {
// CHECK:STDOUT: %CC.ref: %CC.type = name_ref CC, file.%CC.decl [concrete = constants.%CC.generic]
// CHECK:STDOUT: %E.ref: %facet_type = name_ref E, %E.loc19_15.1 [symbolic = %E.loc19_15.2 (constants.%E)]
// CHECK:STDOUT: %E.as_type.loc19_29.1: type = facet_access_type %E.ref [symbolic = %E.as_type.loc19_29.2 (constants.%E.as_type)]
// CHECK:STDOUT: %Y.facet.loc19_29.1: %Y.type = facet_value %E.as_type.loc19_29.1, (constants.%Y.lookup_impl_witness) [symbolic = %Y.facet.loc19_29.2 (constants.%Y.facet.18f)]
// CHECK:STDOUT: %.loc19_29: %Y.type = converted %E.ref, %Y.facet.loc19_29.1 [symbolic = %Y.facet.loc19_29.2 (constants.%Y.facet.18f)]
// CHECK:STDOUT: %CC.loc19_29.1: type = class_type @CC, @CC(constants.%Y.facet.18f) [symbolic = %CC.loc19_29.2 (constants.%CC.db5)]
// CHECK:STDOUT: %E.as_type.loc19_28.1: type = facet_access_type %E.ref [symbolic = %E.as_type.loc19_28.2 (constants.%E.as_type)]
// CHECK:STDOUT: %Y.facet.loc19_28.1: %Y.type = facet_value %E.as_type.loc19_28.1, (constants.%Y.lookup_impl_witness) [symbolic = %Y.facet.loc19_28.2 (constants.%Y.facet.18f)]
// CHECK:STDOUT: %.loc19_28: %Y.type = converted %E.ref, %Y.facet.loc19_28.1 [symbolic = %Y.facet.loc19_28.2 (constants.%Y.facet.18f)]
// CHECK:STDOUT: %CC.loc19_28.1: type = class_type @CC, @CC(constants.%Y.facet.18f) [symbolic = %CC.loc19_28.2 (constants.%CC.db5)]
// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type]
// CHECK:STDOUT: %.loc19_20.1: type = splice_block %.loc19_20.3 [concrete = constants.%facet_type] {
// CHECK:STDOUT: %.loc19_19.1: type = splice_block %.loc19_19.3 [concrete = constants.%facet_type] {
// CHECK:STDOUT: %.Self.frozen: %type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen]
// CHECK:STDOUT: %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type]
// CHECK:STDOUT: %W.ref: type = name_ref W, file.%W.decl [concrete = constants.%W.type]
// CHECK:STDOUT: %impl.elem0: %.d56 = impl_witness_access constants.%BitAndWith.impl_witness, element0 [concrete = constants.%type.as.BitAndWith.impl.Op]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %Y.ref, %impl.elem0 [concrete = constants.%type.as.BitAndWith.impl.Op.bound]
// CHECK:STDOUT: %type.as.BitAndWith.impl.Op.call: init type = call %bound_method(%Y.ref, %W.ref) [concrete = constants.%facet_type]
// CHECK:STDOUT: %.loc19_20.2: type = value_of_initializer %type.as.BitAndWith.impl.Op.call [concrete = constants.%facet_type]
// CHECK:STDOUT: %.loc19_20.3: type = converted %type.as.BitAndWith.impl.Op.call, %.loc19_20.2 [concrete = constants.%facet_type]
// CHECK:STDOUT: %.loc19_19.2: type = value_of_initializer %type.as.BitAndWith.impl.Op.call [concrete = constants.%facet_type]
// CHECK:STDOUT: %.loc19_19.3: type = converted %type.as.BitAndWith.impl.Op.call, %.loc19_19.2 [concrete = constants.%facet_type]
// CHECK:STDOUT: }
// CHECK:STDOUT: %E.loc19_15.1: %facet_type = symbolic_binding E, 0 [symbolic = %E.loc19_15.2 (constants.%E)]
// CHECK:STDOUT: }
@@ -217,21 +217,21 @@ fn F() {
// CHECK:STDOUT: generic impl @CC.as.Z.impl(%E.loc19_15.1: %facet_type) {
// CHECK:STDOUT: %E.patt.loc19_15.2: %pattern_type.bd4 = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc19_15.2 (constants.%E.patt)]
// CHECK:STDOUT: %E.loc19_15.2: %facet_type = symbolic_binding E, 0 [symbolic = %E.loc19_15.2 (constants.%E)]
// CHECK:STDOUT: %E.as_type.loc19_29.2: type = facet_access_type %E.loc19_15.2 [symbolic = %E.as_type.loc19_29.2 (constants.%E.as_type)]
// CHECK:STDOUT: %E.as_type.loc19_28.2: type = facet_access_type %E.loc19_15.2 [symbolic = %E.as_type.loc19_28.2 (constants.%E.as_type)]
// CHECK:STDOUT: %Y.lookup_impl_witness: <witness> = lookup_impl_witness %E.loc19_15.2, @Y [symbolic = %Y.lookup_impl_witness (constants.%Y.lookup_impl_witness)]
// CHECK:STDOUT: %Y.facet.loc19_29.2: %Y.type = facet_value %E.as_type.loc19_29.2, (%Y.lookup_impl_witness) [symbolic = %Y.facet.loc19_29.2 (constants.%Y.facet.18f)]
// CHECK:STDOUT: %CC.loc19_29.2: type = class_type @CC, @CC(%Y.facet.loc19_29.2) [symbolic = %CC.loc19_29.2 (constants.%CC.db5)]
// CHECK:STDOUT: %Z.impl_witness.loc19_36.2: <witness> = impl_witness %Z.impl_witness_table, @CC.as.Z.impl(%E.loc19_15.2) [symbolic = %Z.impl_witness.loc19_36.2 (constants.%Z.impl_witness.6a9)]
// CHECK:STDOUT: %Y.facet.loc19_28.2: %Y.type = facet_value %E.as_type.loc19_28.2, (%Y.lookup_impl_witness) [symbolic = %Y.facet.loc19_28.2 (constants.%Y.facet.18f)]
// CHECK:STDOUT: %CC.loc19_28.2: type = class_type @CC, @CC(%Y.facet.loc19_28.2) [symbolic = %CC.loc19_28.2 (constants.%CC.db5)]
// CHECK:STDOUT: %Z.impl_witness.loc19_35.2: <witness> = impl_witness %Z.impl_witness_table, @CC.as.Z.impl(%E.loc19_15.2) [symbolic = %Z.impl_witness.loc19_35.2 (constants.%Z.impl_witness.6a9)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT:
// CHECK:STDOUT: impl: %CC.loc19_29.1 as %Z.ref {
// CHECK:STDOUT: impl: %CC.loc19_28.1 as %Z.ref {
// CHECK:STDOUT: %Z.impl_witness_table = impl_witness_table (), @CC.as.Z.impl [concrete]
// CHECK:STDOUT: %Z.impl_witness.loc19_36.1: <witness> = impl_witness %Z.impl_witness_table, @CC.as.Z.impl(constants.%E) [symbolic = %Z.impl_witness.loc19_36.2 (constants.%Z.impl_witness.6a9)]
// CHECK:STDOUT: %Z.impl_witness.loc19_35.1: <witness> = impl_witness %Z.impl_witness_table, @CC.as.Z.impl(constants.%E) [symbolic = %Z.impl_witness.loc19_35.2 (constants.%Z.impl_witness.6a9)]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: extend %Z.ref
// CHECK:STDOUT: witness = %Z.impl_witness.loc19_36.1
// CHECK:STDOUT: witness = %Z.impl_witness.loc19_35.1
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -306,11 +306,11 @@ fn F() {
// CHECK:STDOUT: specific @CC.as.Z.impl(constants.%E) {
// CHECK:STDOUT: %E.patt.loc19_15.2 => constants.%E.patt
// CHECK:STDOUT: %E.loc19_15.2 => constants.%E
// CHECK:STDOUT: %E.as_type.loc19_29.2 => constants.%E.as_type
// CHECK:STDOUT: %E.as_type.loc19_28.2 => constants.%E.as_type
// CHECK:STDOUT: %Y.lookup_impl_witness => constants.%Y.lookup_impl_witness
// CHECK:STDOUT: %Y.facet.loc19_29.2 => constants.%Y.facet.18f
// CHECK:STDOUT: %CC.loc19_29.2 => constants.%CC.db5
// CHECK:STDOUT: %Z.impl_witness.loc19_36.2 => constants.%Z.impl_witness.6a9
// CHECK:STDOUT: %Y.facet.loc19_28.2 => constants.%Y.facet.18f
// CHECK:STDOUT: %CC.loc19_28.2 => constants.%CC.db5
// CHECK:STDOUT: %Z.impl_witness.loc19_35.2 => constants.%Z.impl_witness.6a9
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Z.WithSelf(constants.%Z.facet.674) {
@@ -325,11 +325,11 @@ fn F() {
// CHECK:STDOUT: specific @CC.as.Z.impl(constants.%facet_value) {
// CHECK:STDOUT: %E.patt.loc19_15.2 => constants.%E.patt
// CHECK:STDOUT: %E.loc19_15.2 => constants.%facet_value
// CHECK:STDOUT: %E.as_type.loc19_29.2 => constants.%DD
// CHECK:STDOUT: %E.as_type.loc19_28.2 => constants.%DD
// CHECK:STDOUT: %Y.lookup_impl_witness => constants.%Y.impl_witness
// CHECK:STDOUT: %Y.facet.loc19_29.2 => constants.%Y.facet.2a4
// CHECK:STDOUT: %CC.loc19_29.2 => constants.%CC.d62
// CHECK:STDOUT: %Z.impl_witness.loc19_36.2 => constants.%Z.impl_witness.b3a
// CHECK:STDOUT: %Y.facet.loc19_28.2 => constants.%Y.facet.2a4
// CHECK:STDOUT: %CC.loc19_28.2 => constants.%CC.d62
// CHECK:STDOUT: %Z.impl_witness.loc19_35.2 => constants.%Z.impl_witness.b3a
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: }