Skip to content

[Variadic Generics] require pack ident type within a pack expansion t… #63208

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

Conversation

sophiapoirier
Copy link
Contributor

…o form a pack reference

@hborla
Copy link
Member

hborla commented Jan 25, 2023

Woohoo, thank you! One minor piece of initial feedback - there are quite a few formatting changes, which make it difficult to spot the functional changes. Could you please either apply the formatting changes in a separate commit or drop them from this PR?

@xedin
Copy link
Contributor

xedin commented Jan 25, 2023

I suspect that clang-format has been ran for the whole file, you can use git clang-format instead and it would format only git added files before commit.

@sophiapoirier
Copy link
Contributor Author

sophiapoirier commented Jan 25, 2023

Yeah that was definitely not intentional, and I will figure out why it happened so I can stop it in the future, and revert that all here. Definitely none of that showed up locally when I did a confirming git diff --staged before committing.
I did follow the PR instructions which included running git clang-format after the commit, but when I did it printed that no files had changed. ¯\(ツ)

@sophiapoirier sophiapoirier force-pushed the require-pack-reference-within-pack-expansion branch from d7f41c8 to 8cd02bf Compare January 25, 2023 06:05
@sophiapoirier
Copy link
Contributor Author

sophiapoirier commented Jan 25, 2023

I figured out the over-eager clang-formatting and fixed it, though what caused the cause remains mysterious.

@sophiapoirier sophiapoirier force-pushed the require-pack-reference-within-pack-expansion branch from bc6c647 to 9ab5def Compare January 25, 2023 20:24
@@ -76,6 +76,12 @@ enum class TypeResolutionFlags : uint16_t {
/// Pack references are only allowed inside pack expansions
/// and in generic requirements.
AllowPackReferences = 1 << 11,

/// Whether this is a resolution based on a pack expansion.
FromPackExpansion = 1 << 12,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned this offline, but I wonder if FromPackExpansion and AllowPackReferences can be one flag, as their uses seem to be very similar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost same... maybeResolvePackExpansionType (where the AllowPackReferences flag is added) can be called from resolvePackExpansionType (where the FromPackExpansion flag is added) but also from resolveASTFunctionTypeParams. AllowPackReferences is also added in a few other places outside of TypeCheckType.cpp
So running the tests in pack-expansion-expressions.swift, I see cases where resolvePackReference is reached and AllowPackReferences is set but FromPackExpansion is not. However in none of these cases is the new failure case logic in resolveDeclRefTypeRepr any different, because in every case of the flag mismatch, either isParameterPack and FromPackReference are both true or both false (the failure case is only when isParameterPack is true but FromPackReference is false).
That all said, I don't at this point have the insight into the several other places where the AllowPackReferences flag is added to know how they are reached and whether there could be a scenario where this new diagnostic could give a false negative?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm I wonder if that code in resolveASTFunctionTypeParams is now unnecessary / a remnant from when parameter packs used the same syntax as varargs parameters. I commented that code out and am running the tests now locally to see...

The other places where AllowPackReferences is set are all during constraint generation when we see an each T type repr inside an expression. All of those call-sites look like this:

      // Add a PackElementOf constraint for 'each T' type reprs.
      PackExpansionExpr *elementEnv = nullptr;
      if (!PackElementEnvironments.empty()) {
        options |= TypeResolutionFlags::AllowPackReferences;
        elementEnv = PackElementEnvironments.back();
      }

and !PackElementEnvironments.empty() is a guarantee that the each type repr appears inside of a PackExpansionExpr, so I don't think these places can cause any false negatives.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! There's one other place AllowPackReferences is set in RequirementRequest because you can write each T in a generic requirement without repeat, e.g.

protocol P {}

func generic<each T>() where each T: P {}

...and I think we do want to diagnose something like where T: P!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @hborla for the further insights. I have examined and tested more and concluded that it will indeed be best to get rid of my new FromPackExpansion flag and just rely on AllowPackReferences.
I also found a couple of more tests that needed syntax fixing.

@sophiapoirier sophiapoirier force-pushed the require-pack-reference-within-pack-expansion branch from 9ab5def to 8f4216e Compare January 27, 2023 02:00
@sophiapoirier sophiapoirier force-pushed the require-pack-reference-within-pack-expansion branch from 1460fba to 89e5648 Compare January 27, 2023 21:20
Copy link
Member

@hborla hborla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

… tests, but also disable them due to triggering a constraints checker assertion
@sophiapoirier sophiapoirier force-pushed the require-pack-reference-within-pack-expansion branch from 39579e2 to e8361dd Compare January 28, 2023 00:50
@sophiapoirier
Copy link
Contributor Author

@swift-ci Please smoke test

@sophiapoirier sophiapoirier merged commit 7016679 into swiftlang:main Jan 30, 2023
@@ -77,3 +77,19 @@ func sameShapeDiagnostics<T..., U...>(t: repeat each T, u: repeat each U) {
_ = repeat Array<(each T, each U)>() // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
_ = repeat (Array<each T>(), each u) // expected-error {{pack expansion requires that 'U' and 'T' have the same shape}}
}

func returnPackExpansionType<T...>(_ t: repeat each T) -> repeat each T { // expected-error {{variadic expansion 'T' cannot appear outside of a function parameter list, function result, tuple element or generic argument list}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message seems inaccurate. Is says an expansion cannot appear outside a function result, but syntactically the expansion is the function result.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "function result" should just be removed from the message. A previous experimental implementation of variadic generics that modeled packs as tuples (where this message was added) allowed returning a pack type T, but the current design does not allow for that. I also think we should eliminate the phrase "variadic expansion". I can update this message in a separate PR.

@sophiapoirier sophiapoirier deleted the require-pack-reference-within-pack-expansion branch July 20, 2023 00:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants