-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Diagnostics] Adding assignments directly to CS and diagnosing from there. #18950
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
@xedin This is the stuff I'm working on mentioned in my comment in #18948 Perhaps especially of interest, see |
@swift-ci Please smoke test. |
17f3c0d
to
35b5647
Compare
Squashed them merged. I had been working from a branch still passing solution to ConstraintFix diagnose() so lots of conflicts, but simple ones. @swift-ci Please smoke test. |
|
||
// Compute the type to which the source must be converted to allow | ||
// assignment to the destination. | ||
auto destTy = CS.computeAssignDestType(expr->getDest(), expr->getLoc()); |
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.
What happens to computeAssignDestType()?
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.
After I kill the other caller in CSApply, which shouldn't need it any more because any conversion restrictions should already be in the CS, then it gets deleted.
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.
Sweet
@swift-ci Please smoke test. |
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.
Overall this makes sense to me, thank you!
But previousDiagnosed
needs some more thought, I'd very much like to keep diagnostic interface free from flags like that. I think logic like that should live in constraint system - recordFixes
should identify situations where paling up fixes is not ideal and not record them just like you mentioned.
@xedin Well, I still want the fix to happen, because I want the solution to be reached rather than the system be unresolved. It's just the diagnosis that should be omitted. Another possible alternative for my use would be some sort of |
Solver can go on even without recording a fix if it's redundant (like we do right now if the locators are the same), it's just a matter of what |
I think it makes sense to either add that logic to |
Ah, that's true. Can you think of a good name for a function like |
Maybe something like |
That's a much better name, but supersedes implies being able to discard the existing one(s). |
yeah, probably |
Or maybe even as simple as |
More specific diagnoses for assigning to read-only keypaths. 'computeAssignDestType' is dead code now. ConstraintFix shouldRecordFix()
5730fbd
to
821f63f
Compare
@swift-ci Please smoke test |
Did the bits in "WIP" in the first comment above, and decided to go with |
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 once we get the story straight with shouldRecordFix
, it's indeed going to be good to go!
lib/Sema/CSFix.cpp
Outdated
@@ -44,6 +44,18 @@ void ConstraintFix::print(llvm::raw_ostream &Out) const { | |||
|
|||
void ConstraintFix::dump() const {print(llvm::errs()); } | |||
|
|||
bool ConstraintFix::constraintSystemContainsFixInExpr(Expr *expr) const { |
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 you can just fold this into new TreatRValueAsLValue::shouldRecordFix
overload you've added, since it's only used there anyway, it could be extracted later if needed...
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.
Actually on the second thought there is a kind attached to each fix, I think this could be moved to recordFix
because it's kind of weird that fix itself is trying to determine if it should be recorded or not. I think it shouldn't even worry about it, that's what constraint system is for...
@@ -689,6 +689,17 @@ resolveImmutableBase(Expr *expr, ConstraintSystem &CS) { | |||
return { expr, member }; | |||
} | |||
|
|||
if (auto tupleExpr = dyn_cast<TupleExpr>(SE->getIndex())) { |
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.
Is there no better way to check this, @jckarter ?
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.
Have SubscriptDecl
s been sufficiently parameter-list-ified that we can look at the argument labels and parameter list instead? cc @slavapestov
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, but here we're looking at the arguments to the call, not the subscript declaration.
return TupleType::get(destTupleTypes, CS.getASTContext()); | ||
} else { | ||
Type destTy = CS.createTypeVariable(CS.getConstraintLocator(expr)); | ||
CS.addConstraint(ConstraintKind::Bind, CS.getType(expr), LValueType::get(destTy), |
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.
Nit - I think this should be reversed - LValueType::get(destType)
bind CS.getType(expr)
because we'd rather always bind to something we are going to return (which also happens to be a type variable always).
|
||
if (type2->is<LValueType>() && !isTypeVarOrMember1) { | ||
if (attemptFixes && type2->is<LValueType>() && !isTypeVarOrMember1) { |
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.
Nice catch!
@xedin Is this more like what you were thinking for recordFix? |
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! I think this makes more sense.
lib/Sema/CSSimplify.cpp
Outdated
@@ -4986,6 +4987,15 @@ ConstraintSystem::simplifyRestrictedConstraint( | |||
llvm_unreachable("Unhandled SolutionKind in switch."); | |||
} | |||
|
|||
static bool isAugmentingFix(ConstraintFix *fix) { | |||
switch (fix->getKind()) { | |||
case swift::constraints::FixKind::TreatRValueAsLValue: |
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.
Does it really need to be qualified completely like that here?
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.
Nope. I didn't notice the overly helpful autocomplete.
@swift-ci please test source compatibility |
@swift-ci please test |
If the tests are green, this should be good to go. |
Build failed |
Build failed |
@swift-ci Please smoke test. |
@@ -689,6 +689,17 @@ resolveImmutableBase(Expr *expr, ConstraintSystem &CS) { | |||
return { expr, member }; | |||
} | |||
|
|||
if (auto tupleExpr = dyn_cast<TupleExpr>(SE->getIndex())) { | |||
if (tupleExpr->getNumElements() == 1 && tupleExpr->getElementName(0).str() == "keyPath") { |
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 would at least compare Identifiers and not strings, so tupleExpr->getElementName(0) == ctx.getIdentifier("keyPath").
However I imagine this check ("is this a subscript that's really a keypath application") must appear elsewhere in the compiler. Can we extract it into a common method?
Always CSGen assignment statements by making a typeVar, binding the dest to @lvalue-typeVar and binding the source to convertible-to-typeVar, and then let the CS figure things out, rather than the previous implementation, which was trying to eagerly figure out types. This makes most assignment failures now TreatRValueAsLValue FixConstraints, which can be figured out via the new diagnostics system and in some cases produce better, more specific errors.
WIP: