Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Augmenting declarations do not introduce a binding into any scope, right? #3739

Closed
eernstg opened this issue Apr 30, 2024 · 4 comments
Closed
Labels
augmentation-libraries question Further information is requested

Comments

@eernstg
Copy link
Member

eernstg commented Apr 30, 2024

Thanks to @mit-mit for bringing up this issue! Consider the following program:

// --- Library augmentation 'augment.dart'.
augment library 'main.dart';

augment class C {
  void foo(); // Introduction.
  augment void foo() {} // Augmentation.
}

// --- Library 'main.dart'.
import augment 'augment.dart';

class C {}

This program is accepted by the analyzer (8dabf6a7524689a0c89e241bdb4b18daf2b479e3), but the CFE (same commit) rejects it as follows:

augment.dart:6:16: Error: 'foo' is already declared in this scope.
  augment void foo() {} // Augmentation.
               ^^^
augment.dart:5:8: Context: Previous declaration of 'foo'.
  void foo(); // Introduction.
       ^^^
main.dart:4:7: Error: The non-abstract class 'C' is missing implementations for these members:
 - C.foo
Try to either
 - provide an implementation,
 - inherit an implementation from a superclass or mixin,
 - mark the class as abstract, or
 - provide a 'noSuchMethod' implementation.

class C {}
      ^
augment.dart:5:8: Context: 'C.foo' is defined here.
  void foo(); // Introduction.
       ^^^

I haven't found explicit language about the effect of augmenting declarations on the enclosing scope. That is, does an augmenting declaration introduce a name into the scope just like a regular declaration? I'd assume the answer is no.

In particular, the feature specification contains several examples where a declaration and one or more augmenting declarations with the same name occur in the same scope, e.g., the declarations named trace in this section. These examples are concerned with declarations in the library scope, there are no examples involving class member declarations.

However, if we do adopt the rule that augmenting declarations refer to an existing declaration by name, and they don't introduce any bindings of that name into any scopes, then we'd allow the original declaration and any number of augmenting declarations to coexist in the same scope, at any level where they can otherwise occur.

@munificent, @jakemac53, WDYT?

@eernstg eernstg added question Further information is requested augmentation-libraries labels Apr 30, 2024
@jakemac53
Copy link
Contributor

#3738 seems like it is also related here?

If we are using a pure lexical scope, does an augmenting declaration introduce something into the lexical scope or not?

@jakemac53
Copy link
Contributor

In general though yes, augmenting declarations do not introduce a new declaration, and you are supposed to be able to introduce a declaration and augment it in the same file.

@lrhn
Copy link
Member

lrhn commented Apr 30, 2024

Agree. An augmenting declaration doesn't have to introduce a name.
More to the point, the original non-augmenting syntactic declaration also doesn't introduce a declaration into the scope, because the thing that is in the scope is the entire stack of base-and-augmenting syntactic declarations.
If you look up something by name in a library, you don't get the original syntactic declaration, you get the result of applying all its augmentations on top, that collected entity is what is in the scope, not a single syntactic declaration.

About #3738, that's a good question.
I'd say that an augment member declaration does introduce the name into the surrounding lexical scope. That is:

int method = 42;
augment class C {
  augment void method() {} // Introduces *name* into lexical scope.
  void bar() {
    method(); // Calls this.method();
  }
}

the augment void method() {} declaration does introduce method into the lexical scope, so that the method() inside bar can resolve to it.
The name still denotes the entire augment stack, not just the single syntactic declaration.

For the outer augment class C, it doesn't make sense to distinguish that declaration from the library's declaration scope which contains the same name.

If you have multiple declarations with the same name in the same scope, then they only introduce the name once.

int foo = 42;
class C {
  void foo() {}
  augment void foo() {}
  augment void foo() {}
  void bar() {
    foo(); // Resolves to an instance member, so becomes `this.foo()`.
  }
}

@eernstg
Copy link
Member Author

eernstg commented May 10, 2024

Closing: At this time every proposed model for augmentations imply that the augmentation declaration does not introduce the name of the declaration into the enclosing scope (or any other scope). So the answer is "Correct, they don't".

@eernstg eernstg closed this as completed May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
augmentation-libraries question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants