From 3384b8e1928795ca5b6302de02228772c016383c Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Mon, 7 Oct 2024 19:52:03 +0200 Subject: [PATCH 1/3] Update augmentation specification. * Says that the entire class scope is in the lexical scope for members. * Update `augemented` specification, include constructors. * Only reserved inside expressions and bodies of augmenting member-like declarations, not type-like declarations. * Try to give grammar. It's really a parameterized grammar per kind of declaration. We don't have good parameterized grammars, so it's said in prose. * Changes specification for non-redirecting generative constructors. * Adds order of initialization of instance variables with initializers. * Says that body cannot use `augmented`. * Therefore no longer needs to reuse variable bindings, so don't. * Each augmenting declaration binds actuals to formals, remember any super parameters or super initializers, executes initializer list entries, and then executes its augmented declaration. When that comes back, it executes its body. * (Layering an augmentation on top of an NRG-constructor auto-calls augmented at the end of its initializer list.) The initializing formals and super parameters need more work. * Some small tweaks to disallow invalid combinations. --- .../feature-specification.md | 499 +++++++++++------- 1 file changed, 313 insertions(+), 186 deletions(-) diff --git a/working/augmentation-libraries/feature-specification.md b/working/augmentation-libraries/feature-specification.md index 5352fadb2..2b8ecceab 100644 --- a/working/augmentation-libraries/feature-specification.md +++ b/working/augmentation-libraries/feature-specification.md @@ -182,13 +182,15 @@ declaration which is smaller than _D_, according to the 'after' ordering)*. A compile-time error occurs if no declaration satisfies the requirements on _D1_. -We say that _D1_ is the declaration which is _augmented_ by _D_. +We say that _D1_ is the declaration which is _augmented_ by _D_, +or just, in the context of _D_, *the augmented declaration*. *Note that _D1_ can be an augmentation declaration or an introductory declaration.* An augmentation declaration does not introduce a new name into the surrounding -scope. *We could say that it attaches itself to the existing name.* +scope. *It attaches itself to the existing name in the scope, which must exist +for the augmentation to be valid.* Making `augment` a built-in identifier is language versioned, to make it non-breaking for pre-feature code. @@ -212,8 +214,7 @@ including the ones that are induced by variables. *This means that augmentation of a variable declaration can be a getter declaration that augments the induced getter, a setter declaration that augments the induced setter, or a variable declaration that augments the -initializer. The augmenting declarations can themselves be an implicitly -induced getter or setter, or an explicitly declared one.* +initializer expression.* *Note that an abstract variable declaration and an external variable declaration correspond to a getter declaration and possibly a setter @@ -222,8 +223,8 @@ also no support for augmenting it.* These operations cannot be expressed today using only imports, exports, or part files. Any Dart file (library file or part file) can contain -augmentation declarations. *In particular, an augmentation can augment a -declaration in the same file in which it occurs.* +augmenting declarations. *In particular, an augmentation can augment a +declaration in the file in which it occurs.* A type augmentation can add new members to an existing type, or augment a member declaration in the same context *(that is, in the same type @@ -237,16 +238,16 @@ which may be used to provide a body for an abstract member._ An augmentation that replaces the body of a function may also want to preserve and run the code of the augmented declaration (hence the name -"augmentation"). It may want to run its own code before the augmented -code, after it, or both. To support that, we allow a new expression syntax +"augmentation"). It may want to run its own code before the augmented +code, after it, or both. To support that, we allow a new expression syntax inside the "bodies" of augmenting declarations (function bodies, constructor bodies, and variable initializers). Inside an expression in an augmenting member declaration, the identifier `augmented` can be used to refer to the augmented function, getter, or setter body, or variable -initializer. This is a contextual reserved word within `augment` -declarations, and has no special meaning outside of that context. See the -next section for a full specification of what `augmented` means, and how it -must be used, in the various contexts. +initializer. This is a contextual reserved word within `augment` function +or variable declarations, and has no special meaning outside of that context. +See the next section for a full specification of what `augmented` means, +and how it must be used, in the various contexts. *Note that within an augmenting member declaration, a reference to a member by the same name refers to the final version of the member (and not the one @@ -307,7 +308,7 @@ can `// ignore:` it if they know what they’re doing. ### Type inheritance -An augmenting declaration may have no type annotations for a return type, +An augmenting declaration may omit type annotations for a return type, variable type, parameter type, or type parameter bound. In the last case, that includes omitting the `extends` keyword. For a variable or parameter, a `var` keyword may replace the type. @@ -321,82 +322,150 @@ doesn't, it must repeat the type from the augmented definition__. ### Augmented Expression -The exact result of an `augmented` expression depends on what is being -augmented, but it generally follows the same rules as any normal identifier: - -* **Augmenting getters**: Within an augmenting getter `augmented` invokes - the augmented getter and evaluates to its return value. If augmenting a - variable with a getter, this will invoke the implicitly induced getter - from the augmented variable declaration. - -* **Augmenting setters**: Within an augmenting setter `augmented` must be - followed by an `=` and will directly invoke the augmented setter. If - augmenting a variable with a setter, this will invoke the implicitly - induced setter from the augmented variable declaration. - -* **Augmenting fields**: Within an augmenting variable declaration, - `augmented` can only be used in an initializer expression, and refers - to the augmented variable's initializing expression, which is - immediately evaluated. - - It is a compile-time error to use `augmented` in an augmenting - variable's initializer if the member being augmented is not a variable - declaration with an initializing expression. +The identifier `augmented` is a reserved word, with associated special syntax, +when it occurs inside an expression or body of an augmenting variable, getter, +setter, function, operator or constructor declaration. + +The exact grammar and meaning of the `augmented` keyword depends on what is +being augmented. + +* **Augmenting variables**: Within an augmenting variable declaration's + initializer expression, `augmented` can only be used in an initializer + expression, and it refers to the augmented variable's initializing + expression. The reserved words parses as a `` expression. + Evaluating `augmented` evaluates the augmented declaration's initializer + expression, and evaluates to the same result. + The static type of `augmented` is the static type of the initializer + expression of the augmented declaration. + +* **Augmenting getters**: Within an augmenting getter's body, the `augmented` + expression invokes the augmented getter and evaluates to its return value. + When augmenting a variable with a getter, this will invoke the implicitly + induced getter of the augmented variable declaration. + _This applies even to `late` variable declarations, where the implicit + getter does more than just access the underlying storage._ + The reserved words parses as a `` expression. + Evaluating `augmented` invokes the augmented declaration's getter + function, and evaluates to the returned value. + The static type of `augmented` is the declared return type of the augmented + declaration. + +* **Augmenting setters**: Within an augmenting setter's body, `augmented` + must be followed by an `= expression`. + _The `augmented` term is not an expression that evaluates to a value. + Like `super` it is a special syntactic form that can only be used + in specific ways. Except for the prior two cases, where that specific way + was to be read and evaluate to a value, `augmented` cannot be used + as an expression with a value._ + The clause augmented = *e* parses as an ``. + Performing the assignment of the assignment expression, after evaluating + the right-hand-side to a value, invokes the augmented setter function. + When augmenting an assignable variable declaration, that setter function + is the implicitly induced setter of the variable declaration. + _This also applies to `late` and `late final` variable declarations._ + Type inference of `augmented = e1` is performed as a setter invocation + with the setter signature of the augmented declaration. * **Augmenting functions**: When augmenting a function, `augmented` - refers to the augmented function. Tear offs are not allowed, so this - function must immediately be invoked. - -* **Augmenting operators**: When augmenting an operator, `augmented` - refers to the augmented operator method, which must be immediately - invoked using function call syntax. For example, when augmenting + in the function body refers to the augmented function, and it must + occur only as the function of a function invocation, which means + it is immediately followed by one, or no, type argument list + and then an argument list. + _Tear offs are not possible, neither are member accesses like + `augmented.call()`._ + The expression `augmented` must not occur in an optional parameter + default value expressions _It is a reserved word in such expressions, + but is currently cannot be used._ + The term 'augmented' \ words parses + as a `` expression. + Evaluating the function invocation, after having evaluated the + argument list, invokes the augmented function with the provided + type arguments and evaluated argument list, and evaluates to the + returned value. + Type inference of augmented\<_typeArgs_\>(_args_) + is performed as a function invocation with the function signature + of the augmented declaration. + +* **Augmenting operators**: Operators are methods with special + invocation syntax. When augmenting an operator declaration, `augmented` + refers to the augmented operator *method*, and it must occur only + as the function of a function invocation. For example, when augmenting `operator +` you could use `augmented(1)` to call the augmented - operator, and when augmenting `operator []=` you would use the - `augmented(key, value)` syntax. - - * Note that `augmented` in such an augmenting operator method body is - not an expression by itself, and cannot be used to tear off the - augmented operator method. Similar to `super`, it is a syntactic - form which can only be used in limited ways. + operator, when augmenting `operator []=` you would use the + `augmented(key, value)` syntax, and when augmenting `operator -()`, + you would use `augmented()`. + Parsing, evaluation and type inference is handled like a + function augmentation. * **Augmenting enum values**: When augmenting an enum value, `augmented` - has no meaning and is not allowed. + has no meaning and is not allowed to occur in constructor argument + expressions. + +* **Augmenting constructors**: + * **Non-redirecting generative constructor**: + The term `augmented` has no meaning, and must not occur in + optional parameter default value expressions, initializer list + entry expressions (whether initializing or asserts), + super-constructor invocation argument expressions, or in the + body. _Non-redirecting generative constructors automatically + invoke their augmented constructor after executing their + initializer list, and will execute their body after that of + their augmented constructor._ + * **Non-redirecting Factory constructor**: An `augmented` in the + constructor body refers to the augmented non-redirecting factory + constructor. It must occur only as the function of a (non-generic) + function invocation. + The term 'augmented' \ clause parses + as a `` expression. + When evaluated, it invokes the augmented constructor on the same + class and evaluates to the returned value. + Type inference is performed as for invoking a constructor with + the same function type. + The term `augmented` must not occur in optional parameter + default value expressions. + * **Redirecting generative constructor**: + The term `augmented` has no meaning, and must not occur in + optional parameter default value expressions or in + target constructor arguments expressions. + * **Redirecting factory constructor**: Contains no expressions. + + The term 'augmented' \ words parses + as a `` expression. In all relevant cases, if the augmented member is an instance member, it is -invoked with the same value for `this`. - -Assume that the identifier `augmented` occurs in a source location where no -enclosing declaration is augmenting. In this case, the identifier is taken -to be a reference to a declaration which is in scope. - -*In other words, `augmented` is just a normal identifier when it occurs -anywhere other than inside an augmenting declaration.* - -*Note that, for example, `augmented()` is an invocation of the augmented -function or method when it occurs in an augmenting function or method -declaration. (In the latter case, the augmenting method declaration must -occur inside an augmenting type-introducing declaration, e.g., an -augmenting class or mixin declaration). This is also true if `augmented()` -occurs inside a local function declaration inside the body of that function -or method declaration. We could say that `augmented` is a contextual -reserved word because it is unable to refer to a declaration in scope when -it occurs inside an augmenting declaration, it always has the special -meaning which is associated with augmentations.* - -A compile-time error occurs if a declaration with the basename `augmented` -occurs in a location where any enclosing declaration is augmenting. *This -error is applicable to all such declarations, e.g., local functions, local -variables, parameters, and type parameters.* - -Consider a non-augmenting member declaration _Dm_ that occurs inside an -augmenting type declaration _Dt_. A compile-time error occurs if the -identifier `augmented` occurs in _Dm_. - -*For example, inside `augment class C` we could have a declaration like -`void f() {...augmented()...}`. This is an error because the outer -`augment` forces the meaning of `augmented` to be about augmentation in the -entire scope, but the method declaration is introductory and hence there is -no earlier declaration to augment.* +invoked with the same value for `this`. For a non-redirecting factory +constructor, it's invoked with the same type parameter bindings for the +surrounding type. + +The grammar change for `augmented` adds the following productions: +```ebnf + ::= 'augmented' + ::= 'augmented' '=' + ::= 'augmented' + ::= 'augmented' + + ::= ... + | -- augmenting variable or getter body + | -- augmenting setter body + | -- augmenting function, operator body + | -- augmenting factory constructor body +``` +and makes `augmented` a reserved word inside any expression or body of an +augmenting declaration in the list above. The grammar production is only +allowed inside the scopes mentioned. _This makes occurrences in parameter +default values and initializer list expressions invalid._ + +_The word is also reserved, and has its designated meaning, inside the bodies of +nested functions inside the expressions or bodies of the augmenting declarations. +It's possible to close over `augmented` inside an augmenting function, to, +for example, do `list.forEach((x) => augmented(x));` in a function augmentation, +but doing `List.forEach(augmented)` is not allowed. That would treat the +augmented function as if it had an identity._ + +If the identifier `augmented` occurs in a source location where no +enclosing declaration is one of the augmenting declarations listed above, +it is treated as a normal ``. +_Where it's treated as a reserved word, it cannot be used as an identifier._ ### Augmenting class-like declarations @@ -705,10 +774,10 @@ It is a **compile-time error** if: variable, and that will not add any setter. An augmenting variable declaration only affects the initializer expression, not setters. -* A variable is augmented with another variable, and one is `late` and - the other is not. *(Augmentation cannot change `late`-ness, and since being - `late` does affect the initializer expression, the augmenting variable is - required to repeat the `late`.)* +* A variable is augmented by another variable declaration, and one is `late` + and the other is not. *(Augmentation cannot change `late`-ness, and since + being `late` does affect the initializer expression, the augmenting + variable is required to repeat the `late`.)* * A getter or setter declaration is augmented by an augmenting variable. @@ -724,11 +793,11 @@ It is a **compile-time error** if: * An `abstract` variable is augmented with a non-abstract variable. -* An `external` variable is augmented with an `abstract` variable. +* An `external` variable is augmented with a variable declaration. ### Augmenting enum members -Some enum members can not be augmented: It is a compile-time error if an +Some enum members cannot be augmented: It is a compile-time error if an augmenting declaration in an enum declaration (introductory or augmenting) has the name `values`, `index`, `hashCode`, or `==`. @@ -737,22 +806,23 @@ named `index`, `hashCode`, `==`, or `values`, and this rule just clarifies that this error is applicable for augmenting declarations as well.* Enum values can _only_ be augmented by enum values, and the implicit getter -introduced by them is not augmentable. The only thing you are allowed to do -when augmenting an enum value is add metadata annotations or doc comments. +introduced by them is not augmentable _(also because it's constant)_. +The only thing you are allowed to do when augmenting an enum value is add +metadata annotations or doc comments. -When augmenting an enum value, no constructor invocation should be provided. -The original value is always used, and the explicit constructor invocation (if -present) should not be copied. +When augmenting an enum value, no constructor name or arguments should be +provided. The original value is always used, and the explicit constructor +invocation (if present) should not be copied. -New enum values may be defined in an augmenting enum, and they will be appended +New enum values may be added in an augmenting enum, and they will be appended to the current values of the declaration in augmentation application order. -Augmenting an existing enum value never changes the order in which it appears in -`values`. +Augmenting an existing enum value does not change its order, neither its +`index` nor its position in `values`. For example: -``` +```dart // main.dart part 'a.dart'; part 'c.dart'; @@ -762,12 +832,9 @@ enum A { second.custom(1); final int b; - const A() : b = 0; - const A.custom(this.b); } -} // a.dart part of 'main.dart'; @@ -795,10 +862,6 @@ part of 'main.dart'; augment enum A { fifth; - - // Error, enum value augmentations cannot have an explicit constructor - // invocation. - augment third.custom(3); } ``` @@ -808,7 +871,13 @@ It is a compile-time error if: * An augmenting getter is defined for an enum value. _An enum value counts as a constant variable._ -* An enum value augmentation provides an explicit constructor invocation. +* An augmenting enum value declaration provides an explicit constructor + invocation (a constructor name or an argument part). For example: + ```dart + augment enum A { + augment third.custom(3); // Error. + } + ``` ### Augmenting constructors @@ -843,17 +912,17 @@ It is a compile-time error if: *Default values are defined solely by the introductory constructor.* * The introductory constructor is `const` and the augmenting constructor - is not or vice versa. + is not, or vice versa. * The introductory constructor is marked `factory` and the augmenting constructor is not, or vice versa. -* The introductory constructor has a super initializer _(super +* The augmented constructor has a super initializer _(super constructor invocation at the end of the initializer list)_ and the - augmenting constructor does too. _An augmentation can replace the - implicit default `super()` with a concrete super-invocation, but cannot - replace a declared super constructor._ **(TODO: Why not? We allow - "replacing implementation", and this is *something* like that.)** + augmenting constructor does too. _An augmentation can add a declared + super-initializer to a declaration that has none, and which would otherwise + get a default `super()` super-initializer, but it cannot replace an + existing super-initializer._ * The resulting constructor is not valid (has a redirecting initializer and other initializers, multiple `super` initializers, etc). @@ -870,35 +939,15 @@ These are probably the most complex constructor, but also the most common. A non-redirecting generative constructor marked `augment` may: -* Add or replace the body of the augmented constructor with a new body. +* Add a body to be executed after the augmented constructor. * If the augmenting constructor has an explicit block body, then that body - replaces any existing constructor body. - - * In the augmenting constructor's body, an `augmented()` call executes the - augmented constructor's body in the same parameter scope that the - augmenting body is executing in. The expression has type `void` and - evaluates to `null`. **(TODO: This is slightly under-specified. We can - use the current bindings of the parameters of the augmenting constructor - as the initial binding of parameter variables in the augmented body, or - we can execute the body in the current *scope*, using the same variables - as the current body. The latter is not what we do with functions - elsewhere, and allows the `augmented()` expression to modify local - variables, but the former introduces different variables than the ones - that existed when evaluating the initializer list. If the initializer - list captures variables in closures, that body may not work.)** + will be executed *after* the body blocks of its augmented declaration. * Initializer lists _are not_ re-run, they have already executed and shouldn't be executed twice. The same goes for initializing formals and super parameters. - * If a parameter variable is overwritten prior to calling `augmented()`, - the augmented body will see the updated value, because the parameter - scope is identical. - - * Local variables in scope where `augmented()` is evaluated are not in - scope for the execution of the augmented constructor's body. - * Add initializers to the initializer list. If the augmenting constructor has an initializer list then: @@ -910,7 +959,66 @@ A non-redirecting generative constructor marked `augment` may: initializer list containing first the assertions and field initializers of the augmented constructor, if any, then the assertions and field initializers of the augmenting constructor, and finally any - super-initializer of either the augmeted or augmenting constructor. + super-initializer of either the augmented or augmenting constructor. + +Invoking a non-redirecting generative constructor, with an argument list and a +new object to initialize, two effects. + +* First it initializes any instance variables in the class which have + initializing expressions: + * For each instance variable declared by the class, in source order + of their introducing declarations: + + * If the fully augmented declaration has an initializer expression, + evaluate the initializer expression of the *last* declaration + of the variable _(an augmenting declaration if there are any, + otherwise the introducing declaration)_ to a value. + + * If the last augmenting declaration declares no initializer expression, + then that evaluates the initializer expression of its augmented + declaration, until an actual expression is evaluated. + _If that expression contains an `augmented` expression, then + that evaluates the initializer expression of the augmented declaration + of the augmenting declaration introducing that expression._ + + * Initialize the instance variable to the resulting value. + + (In short: For each instance variable in source order, from earlier to + later, evaluate any initializer expression if the declarations of that + instance variable, starting with the latest.) + +* Then it "executes the constructor to initialize the object". + To do that for a constructor which may have augmentations, start with the + *latest* augmenting declaration for the constructor, and invoke + it with the given argument list, and no remembered super initializer + or super arguments. Executing it that way does the following: + + * Bind the actual arguments to formal parameters. + * An initializing formal initializes the instance variable at + this point. + * All super-parameters are remembered, along with any already + remembered super arguments. + * Execute initializer list entries of the declaration in source order + in the initializer list scope introduced by the prior step. + * If this declaration has a super-initializer clause, then remember + that. + * If this declaration is an augmenting declaration, then recursively + execute it to initialize the same object with the same argument list + and the now remembered super invocation and super arguments. + * Otherwise this is the introducing declaration. + If there is no remembered super initializer, use `super()`, + otherwise use the remembered super initializer. + Append all remembered super arguments to the argument list + of the super initializer, positional ones in the source order of the + super parameters that introduced them. + Then *invoke that super initializer*. + * In either case, when that execution or invocation completes, if this + declaration has a body, execute that body of this declaration in a + scope that has the parameter scope of the binding-actuals-to-formals + step as parent scope, and with `this` bound to the object being + initialized. + +TODO: Describe the super-initializer part more formally. #### Non-redirecting factory constructors @@ -931,7 +1039,9 @@ potentially non-redirecting property of the constructor. It is a compile-time error if: -* The augmented constructor has any initializers or a body. +* The augmented constructor has any initializer list entries, + a declared super-initializer, a body, or any initializing + formal or super-parameters. #### Redirecting factory constructors @@ -945,7 +1055,8 @@ constructor. It is a compile-time error if: -* The augmented constructor has a body. +* The augmented constructor has a body or any optional parameter default + values. #### Extension types @@ -1002,6 +1113,16 @@ different platforms or tools. **TODO: Should we add a syntax to let the augmentation dynamically detect whether there is an external implementation to call?** +### Augmenting with external members + +An augmenting declaration cannot be `external`. +_If it could, it would effectively have a body with an opaque implementation +that is supplied by the compiler. It would likely not be able to refer to +the `augmented` declaration. For now, this combination is not allowed._ + +It's a compile-time error if a declaration is marked both `augment` and +`external`. + ### Augmenting with metadata annotations and doc comments All declarations can be augmented with metadata annotations and/or doc comments @@ -1013,25 +1134,14 @@ metadata annotations, these may trigger additional macro applications. ## Scoping The static and instance member namespaces for a type or extension declaration, -augmenting or not, are lexical only. Only the declarations (augmenting or not) -declared inside the actual declaration are part of the lexical scope that -member declarations are resolved in. +augmenting or not, contain all members declared by any declaration of the +type or extension. All members, static or instance, are present in the +lexical scope of member declarations. _This means that a static or instance member declared in the augmented -declaration of a class is not *lexically* in scope in a corresponding -augmenting declaration of that class, just as an inherited instance member -is not in the lexical scope of a class declaration._ - -If a member declaration needs to reference a static or instance member -declared in another introductory or augmenting declaration of the same -type, it can use `this.name` for instance members an `TypeName.name` for -static members to be absolutely sure. Or it can rely on the default if -`name` is not in the lexical scope at all, in which case it’s interpreted -as `this.name` if it occurs inside a scope where a `this` is -available. _This approach is always potentially dangerous, since any -third-party import adding a declaration with the same name would break the -code. In practice that’s almost never a problem, because instance members -and top-level declarations usually use different naming strategies._ +declaration of a class is in scope in a corresponding augmenting declaration +of that class, just as if every member declaration had been inside the same +class declaration._ Example: @@ -1041,8 +1151,6 @@ import 'other_lib.dart'; part 'some_augment.dart'; -const b = 37; - class C { static const int b = 42; bool isEven(int n) { @@ -1056,9 +1164,11 @@ part of 'some_lib.dart'; import 'also_lib.dart'; +const b = 37; + augment class C { bool _isOdd(int n) => !this.isEven(n - 1); - void printB() { print(b); } // Prints 37 + void printB() { print(b); } // Prints 42, not 37. } ``` @@ -1070,8 +1180,8 @@ ensure it calls the correct method. You can visualize the namespace nesting sort of like this: ``` -some_lib.dart : - : Date: Wed, 9 Oct 2024 11:21:48 +0200 Subject: [PATCH 2/3] Update working/augmentation-libraries/feature-specification.md Co-authored-by: Jacob MacDonald --- working/augmentation-libraries/feature-specification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/working/augmentation-libraries/feature-specification.md b/working/augmentation-libraries/feature-specification.md index 2b8ecceab..f775413cc 100644 --- a/working/augmentation-libraries/feature-specification.md +++ b/working/augmentation-libraries/feature-specification.md @@ -344,7 +344,7 @@ being augmented. induced getter of the augmented variable declaration. _This applies even to `late` variable declarations, where the implicit getter does more than just access the underlying storage._ - The reserved words parses as a `` expression. + The reserved word parses as a `` expression. Evaluating `augmented` invokes the augmented declaration's getter function, and evaluates to the returned value. The static type of `augmented` is the declared return type of the augmented From e8c9804c888a45a736749a4e57189a08f2b9d62c Mon Sep 17 00:00:00 2001 From: "Lasse R.H. Nielsen" Date: Wed, 9 Oct 2024 11:37:33 +0200 Subject: [PATCH 3/3] Update working/augmentation-libraries/feature-specification.md Co-authored-by: Jacob MacDonald --- working/augmentation-libraries/feature-specification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/working/augmentation-libraries/feature-specification.md b/working/augmentation-libraries/feature-specification.md index f775413cc..e43c1edab 100644 --- a/working/augmentation-libraries/feature-specification.md +++ b/working/augmentation-libraries/feature-specification.md @@ -375,7 +375,7 @@ being augmented. `augmented.call()`._ The expression `augmented` must not occur in an optional parameter default value expressions _It is a reserved word in such expressions, - but is currently cannot be used._ + but it currently cannot be used._ The term 'augmented' \ words parses as a `` expression. Evaluating the function invocation, after having evaluated the