Skip to content

[ConstraintSystem] A few improvements to key path handling and diagnostics #69031

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 8 commits into from
Oct 10, 2023

Conversation

xedin
Copy link
Contributor

@xedin xedin commented Oct 7, 2023

  • Makes sure that key path types are not assigned eagerly when the literal is passed as an argument to a call or coerced
  • Fixes locators used for root and value type matching
  • Fixes diagnostics related to missing optional unwraps of the key path root and members
  • Prevents inference from using type-erased superclasses as bindings for a key path type
  • Avoids propagating contextual placeholders into key paths

Resolves: rdar://116376651
Resolves: #55436

xedin added 7 commits October 5, 2023 17:10
If key path literal is passed as an argument to a function/subscript
application its type cannot be resolved until the overload for the
call is selected, otherwise it could prevent a valid keypath-to-function
conversion in cases were argument ends up being a function type.
…ing constraints

`tryMatchRootAndValueFromType` anchored both root and value match
constraints directly on the key path expression. That is incorrect
because we have special locators for that.
…xplicit type

A key path without an explicit root cannot be unwrapped since the
optionality is inferred from context and we cannot suggest removing
that, adding explicit type is not going to change anything and
`!` and `?` after the leading dot is not supported.
…h type

Such types are not going to be applied by `ConstraintSystem::resolveClosure`
anyway and they impede diagnostics by forcing the solver to produce mutliple
equal solutions.
For methods there are two possibilities - force unwrap and
conditional, that's why we need a disjunction with two choices.

This is not the case for key path root type it could only
be force unwrapped.
… a placeholder

If there is something wrong with the context, let's assign a default
KeyPath type to the key path literal to avoid propagating placeholder
into the key path inference.
@xedin xedin requested a review from Jumhyn October 7, 2023 00:45
@xedin
Copy link
Contributor Author

xedin commented Oct 7, 2023

@swift-ci please test

If key path is connected to a disjunction directly or indirectly
(i.e. via ApplicableFunction constraint) do not attempt to bind
it until disjunction is taken, otherwise there is a risk to miss
a valid keypath-to-function conversion.
@xedin
Copy link
Contributor Author

xedin commented Oct 7, 2023

@swift-ci please test

Comment on lines +12445 to +12448
auto resolvedKPTy =
BoundGenericType::get(kpDecl, nullptr, {rootTy, valueTy});
return matchTypes(resolvedKPTy, keyPathTy, ConstraintKind::Bind,
subflags, loc);
Copy link
Member

Choose a reason for hiding this comment

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

In the little digging I did on this issue, it struck me that it seems like in this path we're basically using the simplification step to infer a KeyPath-type binding for the literal (by simplifying to a Bind constraint). Do you know why we wouldn't want to use the usual PotentialBindings::infer machinery to do that? It seems like we could then use BindingSet::favoredOverDisjunction to ensure we don't attempt the binding until we've resolved disjunctions rather than searching for the constraints here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We cannot use binding inference for this because constraint gets re-activated when adjacent types are bound.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I put a branch into resolveKeyPath to handle contextual placeholder but here I think we actually want to have it bound to propagate “unknown type” information out.

Comment on lines +12439 to +12441
return match->getKind() ==
ConstraintKind::ApplicableFunction ||
match->getKind() == ConstraintKind::Disjunction;
Copy link
Member

Choose a reason for hiding this comment

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

If we're just looking for function/disjunction constraints, how does this handle the let fn = \User.email as (User) -> String?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Coercions form disjunctions

@xedin
Copy link
Contributor Author

xedin commented Oct 9, 2023

@swift-ci please test windows platform

@xedin
Copy link
Contributor Author

xedin commented Oct 9, 2023

@swift-ci please test Windows platform

@xedin
Copy link
Contributor Author

xedin commented Oct 10, 2023

@swift-ci please test source compatibility

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants