Skip to content

[AST, Sema] Replace HoleType with PlaceholderType #35589

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

Merged
merged 14 commits into from
Feb 22, 2021

Conversation

Jumhyn
Copy link
Member

@Jumhyn Jumhyn commented Jan 25, 2021

This is a first pass at an implementation for placeholder types. Not yet ready for prime-time but much of the functionality is there!

@hborla hborla self-requested a review January 25, 2021 21:34
Copy link
Contributor

@CodaFi CodaFi left a comment

Choose a reason for hiding this comment

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

A fantastic first go. I can only speak to the type AST and type resolution bits though.

}, /*placeholderHandler*/ [&]() {
// FIXME: Don't let placeholder types escape type resolution.
// For now, just return the placeholder type.
return Ctx.ThePlaceholderType;
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe not something to do here specifically, but I was really hoping we could use placeholder types to make UnboundGenericType obsolete. Wherever type resolution forms one, it could instead build a bound generic type full of placeholders. With that in mind, having them escape unopened is not so bad.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah this was on my mind as well, especially since one of the goals of the proposal is to have UnboundGeneric be semantically equivalent to UnboundGeneric<_, ..., _>. Obsoleting UnboundGenericType would really help validate that approach.

It's been a bit since I worked on this but IIRC I started down that path, and then realized there was enough complexity (and bits that I didn't quite understand) in ConstraintSystem::openUnboundGenericType that it was going to turn into a bit of a rabbit hole, so I punted on that in favor of getting the basic functionality working.

Thank you for taking a look at this!

@CodaFi
Copy link
Contributor

CodaFi commented Feb 2, 2021

@Jumhyn @slavapestov and I are really excited to see this go in sooner rather than later. If you could separate the parsing code from everything else, we could get this merged immediately. Even if the proposal is not accepted, the re-model in here is extremely valuable.

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 2, 2021

@CodaFi Thank you for the heads up. I'll work on separating those parts out. Could you provide just a bit more specificity on which aspects you'll want to merge right away? (E.g., do you want just the minimum to support the changes made in ParseType.cpp, or do you want basically everything here excluding the changes to TypeResolution::forContextual that actually generate the type variables for placeholder types?)

Just want to make sure we're on the same page!

@CodaFi
Copy link
Contributor

CodaFi commented Feb 2, 2021

Let's take the approach of: basically everything that doesn't touch the surface syntax can come along for the ride.

@CodaFi
Copy link
Contributor

CodaFi commented Feb 2, 2021

That includes all the type checker changes, type resolution changes, AST changes, etc. Just not the parser bits.

@xedin
Copy link
Contributor

xedin commented Feb 2, 2021

@Jumhyn Why not use HoleType as an explicit placeholder the same way we use it as implicit one for diagnostics? It's already has originating type variable so it could be used to suggest possible types.

@CodaFi
Copy link
Contributor

CodaFi commented Feb 2, 2021

Why not use HoleType as an explicit placeholder the same way we use it as implicit one for diagnostics?

Isn't HoleType a contextual type and PlaceholderType an interface type? You can't create a HoleType without a type variable for example. We could certainly open a PlaceholderType as a HoleType.

@xedin
Copy link
Contributor

xedin commented Feb 2, 2021

@CodaFi I would be great if we could unify three things here - HoleType, PlaceholderType and UnresolvedType - all three effectively aim to represent the same thing... I think we can rename HoleType into a PlaceholderType if that fits better and use it for unknown types in constraint system and AST - currently it's possible to use HoleType for type variable, declaration type and dependent member type.

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 2, 2021

That includes all the type checker changes, type resolution changes, AST changes, etc. Just not the parser bits.

Ahh I had interpreted your suggestion to "separate the parsing code" the other way around. 🤦‍♂️ That makes way more sense, thank you. Will do!

I think we can rename HoleType into a PlaceholderType if that fits better and use it for unknown types in constraint system and AST.

So under this model we'd want to add PlaceholderTypeRepr as another potential Originator for a HoleType, and then type resolution in the constraint system context would turn HoleTypes into TypeVariableTypes, which would get turned back into HoleTypes if they could not be solved. Does that sound like the right approach?

@xedin
Copy link
Contributor

xedin commented Feb 2, 2021

@Jumhyn Currently HoleType is a replacement for a type variable since we need all type variables to be bound to some type before valid solution could be formed. My suggestion would be:

  • If placeholder arrives from a declaration - turn it into a type variable and record in the locator that type variable has originated from a placeholder (so that finalization could replace type variables back into originating placeholders if they weren't bound);
  • if type variable couldn't be determined bind it to a placeholder to form a valid solution (place holder becomes a replacements for HoleType) in diagnostic mode;
  • If solution has a PlaceholderType in it - use it in the AST instead of using UnresolvedType, currently HoleType are turned into UnresolvedTypes.

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 5, 2021

@CodaFi @xedin Sorry for the delay—this turned out to be a bit of a busy week for me. Hoping to get to this over the weekend!

@xedin
Copy link
Contributor

xedin commented Feb 5, 2021

No worries!

@Jumhyn Jumhyn force-pushed the placeholder-types branch from a088b5c to df9d2f2 Compare February 8, 2021 14:24
@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 8, 2021

Hey @xedin @CodaFi @hborla, please take a look at the latest and let me know your thoughts. I've merged HoleType and PlaceholderType under the PlaceholderType name, basically implementing the first two items from your last comment, @xedin. If this seems like the right direction I can move forward with merging UnresolvedType and PlaceholderType as well, either in this PR or a follow-up.

@Jumhyn Jumhyn force-pushed the placeholder-types branch from df9d2f2 to 1c10526 Compare February 8, 2021 17:11
@Jumhyn Jumhyn changed the title [DNM] WIP: placeholder types implementation [AST, Sema] Replace HoleType with PlaceholderType Feb 8, 2021
@Jumhyn Jumhyn marked this pull request as ready for review February 8, 2021 17:12
@Jumhyn Jumhyn requested a review from CodaFi February 8, 2021 17:12
Copy link
Contributor

@xedin xedin left a comment

Choose a reason for hiding this comment

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

Looks good to me so far!


/// This type contains a DependentMemberType.
HasDependentMember = 0x200,
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a note - making unrelated whitespace changes like this sometimes complicates the review since it's easy to miss value changes...

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, that must have been clang-format, I didn't make any intentional whitespace changes here. I'll revert!

/// regardless of where hole type originated.
bool isHole() const {
if (isDirectHole())
/// if there is only one binding and it's a placeholder type, consider
Copy link
Contributor

Choose a reason for hiding this comment

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

@Jumhyn @hborla What do you think about keeping "hole" terminology in the constraint system? My personal preference would be to keep calling "untyped" places in constraint system holes and call them placeholders in AST.

Copy link
Member

Choose a reason for hiding this comment

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

I agree - I like the term "hole" for the constraint system because "placeholder" implies that it can be replaced, but if we bind to a placeholder in the constraint system, that means it solver could not replace it with a real type.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds good to me, I don't have super strong feelings either way! So we'd keep the type name as PlaceholderType, but all the constraint system methods (such as isDirectHole()) stay as is?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, that’s the idea.

Copy link
Contributor

Choose a reason for hiding this comment

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

Effectively we are just utilizing a placeholder in a solution and AST to represent places which couldn’t be inferred.

Copy link
Member Author

Choose a reason for hiding this comment

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

@hborla @xedin Thoughts on TVO_CanBindToPlaceholder vs. TVO_CanBindToHole? This is the only one in the constraint system that seems to me like the use of "hole" is perhaps more confusing than "placeholder", since it most literally represents whether we will bind the type var to a PlaceholderType or not. But I'm good with whatever y'all think is best!

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should leave it as hole since it would be consistent with the rest.

@Jumhyn Jumhyn force-pushed the placeholder-types branch from 1c10526 to 9536e17 Compare February 9, 2021 13:41
@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 9, 2021

@xedin @hborla Have updated to restore the "hole" terminology throughout the constraint system except where we are actually referring to the PlaceholderType type directly. Let me know if y'all have further thoughts!

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 16, 2021

Hey @xedin @hborla @CodaFi, just wanted to check in on the status here—is there further work this needs to be merge-able? Should we fold the work of combining UnresolvedType and PlaceholderType as part of this same PR?

Copy link
Contributor

@CodaFi CodaFi left a comment

Choose a reason for hiding this comment

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

Holly and Pavel will have more to say. But LGTM

Copy link
Contributor

@xedin xedin left a comment

Choose a reason for hiding this comment

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

LGTM!

@@ -5024,6 +5024,24 @@ class OpenUnboundGenericType {
}
};

class HandlePlaceholderType {
ConstraintSystem &cs;
const ConstraintLocatorBuilder &locator;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest we allocate a locator here instead of referencing a builder since we'd have to build a locator per placeholder anyway.

Copy link
Member Author

Choose a reason for hiding this comment

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

Gotcha, will update!

Rename `openUnboundGenericTypes` to `convertInferableTypes`. In addition to unbound generics, this method also converts placeholder types to fresh type variables.
Move markAcceptableDiscardExprs into PreCheckExpr so that we can perform this analysis before we convert expressions like `_? = <value>` into `_ = <value>` since `_?` is now an expression with meaning, and we only want to perform this transformation when `_?` is on the LHS of an assignment
HoleType basically served the same purpose as PlaceholderType. This commit unifies the two.
Now that we're checking DiscardAssignmentExprs in PreCheckExpr, we have to be careful to make sure we don't diagnose anything until after SequenceExprs have been folded, since the relevant AssignExprs won't even have a "right hand side" and "left hand side" until after folding.
@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 17, 2021

@xedin Updated to allocate a ConstraintLocator upon construction of HandlePlaceholderType! Mind giving this a test run for me?

@hborla
Copy link
Member

hborla commented Feb 17, 2021

@swift-ci please smoke test

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 17, 2021

Thank you @hborla!

@hborla
Copy link
Member

hborla commented Feb 17, 2021

@Jumhyn No problem! If you'd like, I think it's time for you to request commit access 🙂

@xedin
Copy link
Contributor

xedin commented Feb 17, 2021

@swift-ci please smoke test Windows platform

@xedin
Copy link
Contributor

xedin commented Feb 17, 2021

@swift-ci please smoke test macOS platform

@xedin
Copy link
Contributor

xedin commented Feb 17, 2021

@swift-ci please test source compatibility

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 19, 2021

@xedin Do these failures in the release source compat run seem related to you? What's the best way for me to investigate those failures locally?

@xedin
Copy link
Contributor

xedin commented Feb 19, 2021

I don't think these errors are related to your changes because they also happen in main branch - https://ci.swift.org/view/Source%20Compatibility/job/swift-main-source-compat-suite/

In general to investigate source compatibility issues you'd have to clone swift-source-compat-suite repository and use runner.py script with projects.json file to trigger build of a project you are interested in. That would clone the project locally, checkout revision specified in projects.json and run xcodebuild or swiftpm build (depending on project configuration). runner.py also allows you to pass additional swift/clang flags and use custom compiler path as well.

@xedin
Copy link
Contributor

xedin commented Feb 19, 2021

Let's wait for @hborla to take a look and I think if there is nothing major this should be good to go.

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.

LGTM! I just have one tiny opinion about a function name

/// \returns The opened type.
Type openUnboundGenericTypes(Type type, ConstraintLocatorBuilder locator);
/// \returns The converted type.
Type convertInferableTypes(Type type, ConstraintLocatorBuilder locator);
Copy link
Member

Choose a reason for hiding this comment

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

Subjective nit: I don't love the term "convert/conversion" here, because a type conversion means something different. I would rather use something like replaceInferableTypes or substituteInferableTypes. We could also go for the long form and tack on WithTypeVar[iable]s at the end depending on how verbose we want to be 🙂

Copy link
Member Author

Choose a reason for hiding this comment

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

That makes sense to me re: "convert"! I'll swap this out with one of your suggestions.

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 19, 2021

@hborla Done!

@xedin
Copy link
Contributor

xedin commented Feb 19, 2021

@swift-ci please smoke test

@xedin
Copy link
Contributor

xedin commented Feb 20, 2021

@swift-ci please test

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 22, 2021

@hborla or @xedin looks like we are good to go, mind merging? 🙂

@hborla hborla merged commit 1102835 into swiftlang:main Feb 22, 2021
@hborla
Copy link
Member

hborla commented Feb 22, 2021

@Jumhyn done, thanks again for your work on this!

@Jumhyn
Copy link
Member Author

Jumhyn commented Feb 22, 2021

Thank you both (+ @CodaFi) for your feedback and guidance!

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