-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[TypeChecker] Allow inference from default expressions in certain scenarios (under a flag) #41436
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
[TypeChecker] Allow inference from default expressions in certain scenarios (under a flag) #41436
Conversation
This type is going to be use to infer generic parameters at the call site.
…to a method It's a convenient way to use existing logic for default argument inference because suhc inference cannot open whole signature but only conformance and layout constraints associated generic parameters used in a particular parameter position.
…from defaults Contextual type could be a type variable or a type with type variables that have a set of generic requirements, so affected declaration is the owner of the generic parameter.
`typeCheckParameterDefault` needs access to `applySolution` in order to apply a solution found in `inference from defaults` mode.
…nt from parameter Use `getTypeOfDefaultExpr()` to fetch a type associated with default expression if any. This could only happen in situations where it's acceptable to infer type of generic parameter(s) associated with parameter from default expression.
…on (when enabled)
…ers into a method
…e nested generic parameters Adds support for parameter types like `[T?]` or `[(T, U?)]`, and relaxes restriction on same-type generic parameters. A same-type requirement is acceptable if it only includes in-scope generic parameters and concrete types i.e. `T.X == Int` if accepted if `T` is referenced only by a parameter default expression is being applied to.
…ore attempting inference from default
…ferred from result as well This enables support for inference in initializers of generic types and in `case`s of generic enums e.g. ``` struct S<T> { init(_: T = 42) {} } enum E<T: Collection> { case test(_: T = [42]) } ```
e7b4d91
to
eaa737c
Compare
@swift-ci please build toolchain |
1 similar comment
@swift-ci please build toolchain |
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! Left a few minor thoughts inline.
/// Computes the type of the default expression for a given parameter. | ||
class DefaultArgumentTypeRequest | ||
: public SimpleRequest<DefaultArgumentTypeRequest, Type(ParamDecl *), | ||
RequestFlags::SeparatelyCached> { |
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.
Out of curiosity, what's the reason for separately caching the result?
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.
It allows to cache the type during deserialization without having to run the request.
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, you can still do that with evaluator.cacheOutput
. Not saying you need to change this though
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, I know about that one, just seemed like a consistent thing to do since I'm not really sure which one is better and/or preferred here.
|
||
if (Type type = evaluateOrDefault( | ||
ctx.evaluator, | ||
DefaultArgumentTypeRequest{const_cast<ParamDecl *>(this)}, nullptr)) { |
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.
Here, can we use Type()
as the default value instead of nullptr
and return the result of evaluateOrDefault
directly?
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.
Type() is in fact nullptr (or rather a TypeBase *nullptr wrapped in a 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.
Either way is fine with me
@swift-ci please build toolchain |
@swift-ci please smoke test |
@swift-ci please smoke test macOS platform |
In some circumstances generic argument(s) could only be inferred from a parameter that has a
default expression associated with it, allow type-checker to infer types based on the default
expression(s), for example:
Callers of
test
are exempt from passing a value ofv
to resolve a type ofT
, generic argumentwould get inferred as
Int
for empty argument list.The same applies to generic parameters in nested positions i.e.
func test<T>(v: [T] = [...])
or multiple generic parameters:
func test<K, V>(_: [K: V] = ....)
The inference is not allowed when:
resolve it unambiguously via supplying explicit argument), for example:
test<T>(_: T, _: [T] = ...)
;generic requirements, for example:
func test<T: P, U>(_: T, _: U = ...) where U == T.X
It's allowed to specify generic conformance requirements, layout and supertype constraints if
they do not involve other generic parameters.
The behavior is gated under
-enable-experimental-type-inference-from-defaults
frontend flag.Resolves: rdar://86033180