From 8101a372c3f729e833737667503c60751459798c Mon Sep 17 00:00:00 2001 From: Robert Nystrom Date: Thu, 23 Oct 2025 17:25:29 -0700 Subject: [PATCH 1/2] Clarify how augmentations affect existing compile-time errors. Fix #3690. --- .../augmentations/feature-specification.md | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/working/augmentations/feature-specification.md b/working/augmentations/feature-specification.md index bdff47b0e..bd8613b5b 100644 --- a/working/augmentations/feature-specification.md +++ b/working/augmentations/feature-specification.md @@ -2,7 +2,7 @@ Author: rnystrom@google.com, jakemac@google.com, lrn@google.com -Version: 1.38 (see [Changelog](#Changelog) at end) +Version: 1.40 (see [Changelog](#Changelog) at end) Experiment flag: augmentations @@ -1003,6 +1003,43 @@ the combined declaration.* [analyzer package]: https://pub.dev/packages/analyzer +### Compile errors with augmentations + +Many existing compile-time errors in the language specification are only +meaningful after semantic analysis so only make sense to check after +augmentations are applied. For example: + +> Let `C` be a concrete class declared in library `L`, with interface `I`. +> Assume that `I` has a member signature `m` which is accessible to `L`. It is a +> compile-time error if `C` does not have a concrete member with the same name as +> `m` and accessible to `L`, ... + +This error says that a non-abstract class must fully implement its interface. +We don't know what methods a class even has until semantic analysis lets us +see inherited methods, and that happens after augmentation. Thus this error is +checked after augmentations have been applied. Therefore, there is no error in: + +```dart +abstract class I { + m(); +} + +class C implements I {} + +augment class C { + m() {} +} +``` + +The general rule is that compile-time errors should be checked after +augmentations are applied when possible to do so. In other words, if the +library is well-formed enough that augmentations *can* be applied, then they +should be. And if doing so eliminates what would otherwise be a compile-time +error, then that error should not be reported. + +Put another way, moving code out of an introductory declaration into an +augmentation of it should not cause new errors to appear. + ## Dynamic semantics The application of augmentation declarations to an augmented declaration @@ -1216,6 +1253,11 @@ and assume the third point is always true. ## Changelog +### 1.40 + +* Clarify how applying augmentations interacts with compile-time errors + (#3690). + ### 1.39 * Non-semantic copy editing. Remove some redundant specification. Clarify From 4feec1ce46eec20974bf31fac21f89be02cb0607 Mon Sep 17 00:00:00 2001 From: Robert Nystrom Date: Thu, 30 Oct 2025 11:26:29 -0700 Subject: [PATCH 2/2] Take another stab at describing how compile errors are handled. --- .../augmentations/feature-specification.md | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/working/augmentations/feature-specification.md b/working/augmentations/feature-specification.md index bd8613b5b..74289e33e 100644 --- a/working/augmentations/feature-specification.md +++ b/working/augmentations/feature-specification.md @@ -1005,40 +1005,54 @@ the combined declaration.* ### Compile errors with augmentations -Many existing compile-time errors in the language specification are only -meaningful after semantic analysis so only make sense to check after -augmentations are applied. For example: +Prior to augmentations, the definition of a semantic entity is produced by a +single syntactic declaration. That allows the language specification to refer to +those entities interchangeably. With augmentations, that is no longer the case. +A single semantic entity may be the product of multiple syntactic declarations +(an introductory and any number of augmentations). This raises the question of +whether existing compile errors apply to syntactic declarations or semantic +definitions. For example, the specification says: -> Let `C` be a concrete class declared in library `L`, with interface `I`. -> Assume that `I` has a member signature `m` which is accessible to `L`. It is a -> compile-time error if `C` does not have a concrete member with the same name as -> `m` and accessible to `L`, ... +> It is a compile-time error if two elements in the type list of the +> `implements` clause of a class `C` specifies the same type `T`. -This error says that a non-abstract class must fully implement its interface. -We don't know what methods a class even has until semantic analysis lets us -see inherited methods, and that happens after augmentation. Thus this error is -checked after augmentations have been applied. Therefore, there is no error in: +Thus this is an error: ```dart -abstract class I { - m(); -} +class C implements I, I {} +``` +But what about: + +```dart class C implements I {} -augment class C { - m() {} -} +augment class C implements I {} ``` -The general rule is that compile-time errors should be checked after -augmentations are applied when possible to do so. In other words, if the -library is well-formed enough that augmentations *can* be applied, then they -should be. And if doing so eliminates what would otherwise be a compile-time -error, then that error should not be reported. - -Put another way, moving code out of an introductory declaration into an -augmentation of it should not cause new errors to appear. +Each syntactic declaration of `C` only mentions the interface once. But the +resulting definition produced by applying augmentations has an `implements` +clause with `I` in it twice. To which entity does the error apply? + +The general rule is that **compile-time errors apply to semantic definitions +whenever possible.** In other words, if the library is syntactically well-formed +enough that augmentations *can* be applied, then they should be. And if doing so +eliminates what would otherwise be a compile-time error, then that error should +not be reported. + +In the example above, there is an error because the resulting definition does +have the same interface twice in the `implements` clause. *(Though note that +[#4542](https://github.com/dart-lang/language/issues/4542) tracks whether we +want to change this specific error.)* + +The motivation for this principle is that reorganizing code into or out of +augmentations shouldn't affect the errors that are reported as much as possible. +Augmentations are a syntactic tool for organizing code, but what the user cares +about -- and what static analysis should thus focus on -- is the semantics of +the resulting definitions. Also, in most cases the error relies on semantic +information that isn't even well defined for syntactic entities and is only +known from the resolved semantic definition which can't be produced without +applying augmentations. ## Dynamic semantics