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

Can a library augmentation be an entry point? #3642

Closed
eernstg opened this issue Mar 6, 2024 · 15 comments
Closed

Can a library augmentation be an entry point? #3642

eernstg opened this issue Mar 6, 2024 · 15 comments
Labels
augmentation-libraries question Further information is requested

Comments

@eernstg
Copy link
Member

eernstg commented Mar 6, 2024

[Edit: Updated the title to use 'library augmentation' rather than the older terminology 'augmentation library'. The comments on this issue generally use the older term because they were written before the renaming of that concept.]

As of https://dart-review.googlesource.com/c/sdk/+/315420 (and based on dart-lang/sdk#52575), the compile-time error for a part file that contains a script tag is implemented in the CFE.

It is still possible to use a part file as the only argument to dart in order to use a library that has said part file as a part as the entry point, except that it is an error when the part file uses a library name in its part of directive. For example:

// ---------- Part file 'part.dart'.
part of test_lib;

final foo = "foo";
final bar = "bar";

// ---------- Library 'test1.dart'
library test_lib;
part 'part.dart';

var foo2;

main() {
  foo2 = 1;
  print(bar);
}

// ---------- Library 'test2.dart'.
library test_lib;
part 'part.dart';

var foo;

main() {
  foo = 1;
  print(bar);
}

dart part.dart is an error (because test1.dart is not uniquely determined to be the library that has part.dart as a part). But if part.dart had used a URI to denote the owning library then it would not be an error.

In other words, executing a part file is partially supported because there are some situations where a library is uniquely determined to be the owner of the given part file, and that library is a script, i.e., a library that exports a main top-level function. When no such unique determination can be made, it's an error to execute that part file.

Augmentation libraries have a uniquely determined augmented library (that is, "its owner"), so we could allow an augmentation library to be executed, there is no ambiguity.

However, I tend to see this as a misfeature: It does not add expressive power (just execute the augmented library rather than the augmentation library). Moreover, it may cause some confusion about the semantics ("OK, I'm running augmentation_lib_1.dart and it seems to do the same thing as augmentation_lib_2.dart, and the same thing as main.dart, so what's the difference?")

I'd recommend that we avoid this messy behavior up front and make it a an error to execute an augmentation library.

Of course, this may be seen as a tool specific behavior rather than a language rule, and different tool teams might have different preferences (and it may or may not be a front-end only issue), but I still think it makes sense to have at least a brief shared discussion.

@dart-lang/language-team, @johnniwinther, @sigmundch, @mkustermann, WDYT? @srawlins, does it make any difference for the analyzer (presumably, the analyzer doesn't care which library would the entry point, if any)?

@lrhn
Copy link
Member

lrhn commented Mar 6, 2024

Only allow library files as entry points, not part or augmentation files. 👍

Only allow #! at the start of library files too. (It solves a particular use-case, allowing it in part or augmentation files doesn't solve any problem we want to solve.)

I believe this is mostly a tooling issue, and if tools want to allow a part/augmentation file to act as an entry-point for compilation, then there is on big reason to prevent it. It's a short-hand for "use the library file of this file".
I don't see that reason, but what do I know?
(The analyzer should be able to start at any file, so I think this is mainly about compilation.)

@sigmundch
Copy link
Member

Agree - allowing parts or augmentations as entry points doesn't seem to add value, but make things more confusing. If we can uniquely identify what is the library that would have been used as the effective entry point, then we can produce a nice static error message to guide users to use it instead.

Of course, in tool invocations where there isn't an entry point, like modular compilation with the CFE, I'd prefer we can continue to accept all kinds of input files like we do today (e.g. today we expect .part files to be provided as inputs to the CFE).

@jakemac53
Copy link
Contributor

I agree we shouldn't allow dart some_augmentation.dart, but if that augmentation adds a main function, should its original library be considered an entry point? That I think would be nice, but probably several tools would have to be updated to support it.

@lrhn
Copy link
Member

lrhn commented Mar 7, 2024

if that augmentation adds a main function, should its original library be considered an entry point?

Yes.

It's a library. It exports a compatible main function.

You can declare main functions in part files, and should be able to export main functions from other libraries, and count as a script file.

Augmentations are just fancy part files in that they add declarations to a library.

@jakemac53
Copy link
Contributor

Sounds good, I bet today that main functions in part files don't work in all scenarios but are also very rare.

@mkustermann
Copy link
Member

👍 Agree

@jakemac53
Copy link
Contributor

One hiccup with supporting main functions in augmentations, is that means you can't know if something is an entrypoint until after macros have ran.

That does sound concerning to me. Should we require in that case a hand-written declaration of main in the original library, even if it has no body? cc @johnniwinther does the CFE do entrypoint detection early, prior to any resolution/execution of macros?

@johnniwinther
Copy link
Member

The CFE doesn't detect entrypoints - just uses what was requested. We lookup up the main method in the entrypoint library at the end of compilation so macro generated main methods should be fine.

For modular compilation we allow the part file to be read before the library it belongs to - we will do similarly with augmentation libraries.

@jakemac53
Copy link
Contributor

jakemac53 commented Mar 12, 2024

This would be problematic for build_runner for sure, but it is probably fine if we just say that build_runner doesn't support main functions generated by macros, or it requires some explicit config for that to work.

@eernstg
Copy link
Member Author

eernstg commented Apr 4, 2024

@johnniwinther, @mkustermann, @sigmundch, @nshahan, @osa1, the language team supports the proposal that an augmentation library can not be specified as the entry point for a program execution, only a library can be executed.

// --- Library 'main.dart'.
import augment 'augment.dart';
...
void main() {}

// --- -Augmentation library 'augment.dart'.
augment library 'main.dart';
...

With these files, dart augment.dart would be rejected with an error before any part of the program is executed, but dart main.dart is fine.

Following @lrhn's comment here, the same treatment should be given to those two commands if the declaration of main is moved to augment.dart.

However, this is not a language property, it is a tool property, and it would be decided by each tool team. It might be useful to agree on the answer for consistency, though, and it would be convenient if it can be implemented once and for all in the CFE.

WDYT, do you want this error to be reported by your tool?

@sigmundch
Copy link
Member

sigmundch commented Apr 4, 2024

I like where we ended in the design. I think a single CFE implementation is preferable here.

@nshahan
Copy link

nshahan commented Apr 4, 2024

I agree, an error from the CFE is preferable.

@johnniwinther
Copy link
Member

This is a CFE issue.

@eernstg
Copy link
Member Author

eernstg commented Apr 8, 2024

Very good, thanks all! I hear no arguments against implementing this error. I created dart-lang/sdk#55403 in order to track the implementation.

@eernstg eernstg closed this as completed Apr 8, 2024
@eernstg
Copy link
Member Author

eernstg commented Apr 8, 2024

So the answer was "no, an augmentation library can not be an entry point".

@eernstg eernstg changed the title Can an augmentation library be an entry point? Can a library augmentation be an entry point? Apr 8, 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
Development

No branches or pull requests

7 participants