-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[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
Conversation
There was a problem hiding this 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.
lib/Sema/TypeChecker.cpp
Outdated
}, /*placeholderHandler*/ [&]() { | ||
// FIXME: Don't let placeholder types escape type resolution. | ||
// For now, just return the placeholder type. | ||
return Ctx.ThePlaceholderType; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
@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. |
@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 Just want to make sure we're on the same page! |
Let's take the approach of: basically everything that doesn't touch the surface syntax can come along for the ride. |
That includes all the type checker changes, type resolution changes, AST changes, etc. Just not the parser bits. |
@Jumhyn Why not use |
Isn't |
@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. |
Ahh I had interpreted your suggestion to "separate the parsing code" the other way around. 🤦♂️ That makes way more sense, thank you. Will do!
So under this model we'd want to add |
@Jumhyn Currently
|
No worries! |
a088b5c
to
df9d2f2
Compare
Hey @xedin @CodaFi @hborla, please take a look at the latest and let me know your thoughts. I've merged |
df9d2f2
to
1c10526
Compare
There was a problem hiding this 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, |
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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.
1c10526
to
9536e17
Compare
There was a problem hiding this 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
There was a problem hiding this 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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, will update!
For now, don't do anything useful in clients. Specifying a placeholder type is still an error
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.
9536e17
to
ddd4842
Compare
@xedin Updated to allocate a |
@swift-ci please smoke test |
Thank you @hborla! |
@Jumhyn No problem! If you'd like, I think it's time for you to request commit access 🙂 |
@swift-ci please smoke test Windows platform |
@swift-ci please smoke test macOS platform |
@swift-ci please test source compatibility |
@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? |
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 |
Let's wait for @hborla to take a look and I think if there is nothing major this should be good to go. |
There was a problem hiding this 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); |
There was a problem hiding this comment.
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 🙂
There was a problem hiding this comment.
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.
@hborla Done! |
@swift-ci please smoke test |
@swift-ci please test |
@Jumhyn done, thanks again for your work on this! |
Thank you both (+ @CodaFi) for your feedback and guidance! |
This is a first pass at an implementation for placeholder types. Not yet ready for prime-time but much of the functionality is there!