We have an implicit conversion where a closure with a non-Void
result type can be passed as a function value with a Void
result; this makes single-expression closures more usable in
the case where you want the single expression to be a
statement -- discarding it's result.
Unfortunately we were checking if the locator contains a
ClosureResult component *anywhere* in the path. This is too
permissive. The correct check is that the *last* path component
is a ClosureResult.
Otherwise, we happily convert anything to () *anywhere*
in a closure result, which crashes immediately in SILGen.
Fixes <https://bugs.swift.org/browse/SR-403>.
Currently isAnyHashableType method validates only structs but
it doesn't account for situation when type is represented via type
variable with type already fixed to AnyHashable, that results in
infinite loop in the solver because restriction [hashable-to-
anyhashable] is going to add new type variable recursively.
withoutActuallyEscaping has a signature like `<T..., U, V, W> (@nonescaping (T...) throws<U> -> V, (@escaping (T...) throws<U> -> V) -> W) -> W, but our type system for functions unfortunately isn't quite that expressive yet, so we need to special-case it. Set up the necessary type system when resolving an overload set to reference withoutActuallyEscaping, and if a type check succeeds, build a MakeTemporarilyEscapableExpr to represent it in the type-checked AST.
The prior formulation of bridging conversions allowed conversion to
more-optional types, e.g., converting an "NSDate" to "Date?", which
was broken by my recent refactoring in this area. Allow bridging
conversions to more-optional types by introducing extra optional
injections at the end.
Fixes rdar://problem/29780527.
Specialize and improve the "downcast only unwraps optionals"
diagnostic to provide specific diagnostics + Fix-Its for the various
casts of forced cast, conditional cast, and "isa" check. Specifically:
* With a forced cast, customize the diagnostic. We still insert the
appropriate number of !'s, but now we remove the 'as! T' (if an
implicit conversion would suffice) or replace the 'as!' with 'as'
(if we still need a bridge)
* With a conditional cast, only emit a diagnostic if we're removing
just one level of optional. In such cases, we either have a no-op
(an implicit conversion would do) or we could just use 'as' to the
optional type, so emit a customized warning to do that. If we are
removing more than one level of optional, don't complain:
conditional casts can remove optionals. Add the appropriate Fix-Its
here.
* With an 'is' expression, only emit a diagnostic if we're removing
just one level of optional. In this case, the 'is' check is
equivalent to '!= nil'. Add a Fix-It for that.
Across the board, reduce the error to a warning. These are
semantically-well-formed casts, it's just that they could be written
better.
Fixes rdar://problem/28856049 and rdar://problem/22275685.
The type checker implements logic for handling checked casts in two
places: the constraint solver (for type-checking expressions
containing "as!" or "as?") and as a top-level entrypoint for
type-checking as?/as! for diagnostics and is/as patterns. Needless to
say, the two implementations were inconsistent, and in fact both were
wrong, leading to various problems---rejecting perfectly-valid "as!"
and "as?" casts outright, bogus warnings that particular as!/as? casts
always-succeed or always-fail when they wouldn't, and so on.
Start detangling the mess in two ways. First, drastically simplify the
handling of checked casts in the constraint solver, eliminating the
unprincipled "subtype" constraint checks that (among other things)
broke the handling of checked casts that involved bridging or optional
unwrapping. The simpler code is more permissive and more correct; it
essentially accepts that the user knows what she is doing with the
cast.
Second, make the type checker's checking of casts far more thorough,
which includes:
* When we're performing a collection cast, actually check that the
element types (and key types, for a dictionary) are castable, rather
than assuming all collection casts are legitimate. This means we'll
get more useful "always fails" and "always succeeds" diagnostics for
array/set/dictionary.
* Handle casts from a bridged value type to a subclass of the
corresponding bridged class type. Previously, these would be
incorrectly classified as "always fails".
While I'm here, eliminate a spurious diagnostic that occurs when using
a conditional cast ("as?") that could have been a coercion/bridging
conversion ("as"). The optional injection we synthesize to get the
resulting type correct was getting diagnosed as an implicit coercion,
but shouldn't have been.
Previously, bridging conversions were handled as a form of "explicit
conversion" that was treated along the same path as normal
conversions in matchTypes(). Historically, this made some
sense---bridging was just another form of conversion---however, Swift
now separates out bridging into a different kind of conversion that is
available only via an explicit "as". This change accomplishes a few
things:
* Improves type inference around "as" coercions. We were incorrectly
inferring type variables of the "x" in "x as T" in cases where a
bridging conversion was expected, which cause some type inference
failures (e.g., the SR-3319 regression).
* Detangles checking for bridging conversions from other conversions,
so it's easier to isolate when we're applying a bridging
conversion.
* Explicitly handle optionals when dealing with bridging conversions,
addressing a number of problems with incorrect diagnostics, e.g.,
complains about "unrelated type" cast failures that would succeed at
runtime.
Addresses rdar://problem/29496775 / SR-3319 / SR-2365.
Follow the pattern set by isDictionaryType() of performing the query
and extracting the underlying key/element types directly. We often
need both regardless. NFC
We currently have an element in the solution score related to whether we
had a binding or equality constraint involving Any.
Doing this yields some strange results, e.g. if overload resolution
results in a property declared as Any we end up discarding that solution
in favor of solutions that involve other overloads that are not declared
as Any but are also not actually better solutions (e.g. overloads that
are declared as function types).
We really want to retain both solutions in this case and allow the
ranking step of the solver to decide on the better choice.
Fixes rdar://problem/29374163, rdar://problem/29691909.
Previously, validateDecl() would check if the declaration had an
interface type and use that as an indication not to proceed.
However for functions we can only set an interface type after
checking the generic signature, so a recursive call to validateDecl()
on a function would "steal" the outer call and complete validation.
For generic types, this meant we could have a declaration with a
valid interface type but no generic signature.
Both cases were problematic, so narrow workarounds were put in
place with additional new flags. This made the code harder to
reason about.
This patch consolidates the flags and establishes new invariants:
- If validateDecl() returns and the declaration has no interface
type and the isBeingValidated() flag is not set, it means one
of the parent contexts is being validated by an outer recursive
call.
- If validateDecl() returns and the declaration has the
isBeingValidated() flag set, it may or may not have an interface
type. In this case, the declaration itself is being validated
by an outer recursive call.
- If validateDecl() returns and the declaration has an interface
type and the isBeingValidated() flag is not set, it means the
declaration and all of its parent contexts are fully validated
and ready for use.
In general, we still want name lookup to find things that have an
interface type but are not in a valid generic context, so for this
reason nominal types and associated types get an interface type as
early as possible.
Most other code only wants to see fully formed decls, so a new
hasValidSignature() method returns true iff the interface type is
set and the isBeingValidated() flag is not set.
For example, while resolving a type, we can resolve an unqualified
reference to a nominal type without a valid signature. However, when
applying generic parameters, the hasValidSignature() flag is used
to ensure we error out instead of crashing if the generic signature
has not yet been formed.
- The DeclContext versions of these methods have equivalents
on the DeclContext class; use them instead.
- The GenericEnvironment versions of these methods are now
static methods on the GenericEnvironment class. Note that
these are not made redundant by the instance methods on
GenericEnvironment, since the static methods can also be
called with a null GenericEnvironment, in which case they
just assert that the type is fully concrete.
- Remove some unnecessary #includes of ArchetypeBuilder.h
and GenericEnvironment.h. Now changes to these files
result in a lot less recompilation.
In Swift 3.0.1, argument labels are ignored when calling a function
having a single parameter of 'Any' type. That is, if we have:
func foo(_: Any) {}
Both of the following were accepted in a no-assert build (an assert
build would crash, but the GM builds of Xcode ship with asserts off):
foo(123)
foo(data: 123)
This behavior was fixed by 578e36a7e1,
but unfortunately we have to revert to the old behavior *and* defeat
the assertion when in Swift 3 mode.
Swift 4 mode still has the correct behavior, where the second call
'foo(data: 123)' produces a diagnostic.
Now, I have to pour myself a strong drink to forget this ever happened.
Fixes <rdar://problem/28952837>.
Fix matchTypes() to be more careful about stripping off ParenType
sugar, in order to match the behavior outlined in SE-0110.
Note that the new logic only executes in Swift 4 mode; there's
no functional change here in Swift 3 mode.
This makes a second copy of the tuple_arguments test:
- Compatibility/tuple_arguments is a test for Swift 3, updated to
note differences with Swift 3.
- Constraints/tuple_arguments has been updated for the new Swift 4
mode behavior.
Fixes <rdar://problem/27383557>.
Make SolverState manage whether the ConstraintSystem it belongs to has a
current SolverState.
Also a couple minor formatting fixes for ternary expressions involving
solverState.
In the constraint solver, we've traditionally modeled nested type via
a "type member" constraint of the form
$T1 = $T0.NameOfTypeMember
and treated $T1 as a type variable. While the solver did generally try
to avoid attempting bindings for $T1 (it would wait until $T0 was
bound, which solves the constraint), on occasion we would get weird
behavior because the solver did try to bind the type
variable.
With this commit, model nested types via DependentMemberType, the same
way we handle (e.g.) the nested type of a generic type parameter. This
solution maintains more information (e.g., we know specifically which
associated type we're referring to), fits in better with the type
system (we know how to deal with dependent members throughout the type
checker, AST, and so on), and is easier to reason able.
This change is a performance optimization for the type checker for a
few reasons. First, it reduces the number of type variables we need to
deal with significantly (we create half as many type variables while
type checking the standard library), and the solver scales poorly with
the number of type variables because it visits all of the
as-yet-unbound type variables at each solving step. Second, it
eliminates a number of redundant by-name lookups in cases where we
already know which associated type we want.
Overall, this change provides a 25% speedup when type-checking the
standard library.
When we process a constraint, the first step is generally to call
getFixedTypeRecursive() to look through type variables. When this
operation actually does non-trivial work, we could save
that result by considering the current constraint "solved" and
generating a new constraint (if needed!) with the simplified types.
This commit adds the infrastructure to do that, because it's important
when getFixedTypeRecursive() starts performing more interesting
substitutions (e.g., handling member types of type
variables). However, enabling for the common case of looking through a
type variable isn't profitable (it's ~2% slower to type-check the
standard library). Stage in this infrastructure change now.
When performing the occurs check, look for the *representative* of the
type variable we're about to bind, rather than the type variable
itself. Fixes rdar://problem/26845038, SR-1512, SR-1902, SR2635,
SR-2852, and SR-2766.
We've been performing the "occurs" check when computing potential
bindings for type variables, but we weren't actually performing the
check for bindings that *must* occur. Perform the occurs check before
binding type variables, which fixes a few crashers and is far more principled.
Note that this obviates the need for tracking the type variables we've
substituted in simplifyType(), so simplify that as well.
Fixes rdar://problem/27879334 / SR-2351.
Our existential metatype conversion/conformance handling in the type
checker was tripped up the refactoring to lazily introduce
constraints, because it dependended on the otherwise-unused
TypeMatchKind::ConformsTo. Eliminate TypeMatchKind::ConformsTo and
simplify the code here.
Start migrating the main ConstraintSolver::addConstraint() entrypoint
for relational constraints over to the model where it simplifies
first, then only creates a new constraint if the constraint it built
cannot be solved. This covers only the main relational
constraints--there are a number of other relational constraint kinds
to handle this way.
When adding a new member constraint, try to immediately simplify it,
generating a constraint when it cannot be resolved. Note that we also
generate constraints in top-level failure cases, so that the
diagnostics machinery can find it after-the-fact.
When adding a 'restricted' constraint, go straight into the 'simplify'
operation. A new constraint will only be allocated and recorded if it
cannot be immediately simplified. To get here, be more rigorous about passing TMF_GenerateConstraints through simplifyRestrictedConstraint().
When we're creating a new constraint because we couldn't solve it (and
need to record the result), do so without trying to simplify it yet
again. It's just wasted work.