And make an attempt to use the constraint system's contextualType to bind type information; this makes things better but doesn't seem to be a complete solution for contextually typing key paths.
The openType() function did two things:
- Replace unbound generic types like 'G' with fresh type variables
applied to bound generic types, like 'G<$T0>'.
- Replace generic parameters with type variables from the replacement
map.
The two behaviors were mutually exclusive and never used from the
same call site, so split them up into two independent functions.
Also, eliminate ConstraintSystem::openBindingType() since it was only
used in one place and could be expressed in terms of existing functions.
It's particularly likely someone will try to type `\(foo)`, which looks like a string interpolation segment, outside of a string literal, so give that case a special diagnostic. Fixes rdar://problem/32315365.
Teach preCheckExpression() about UnresolvedSpecializeExpr
where the base is a TypeExpr.
This allows us to type check expressions like
'[Outer<T>.Inner<U>]()' by folding them down to a TypeExpr
with an array type.
This is a bit more robust and user-friendly than hoping more brittle recovery in SILGen or IRGen for unsupported components kicks in. rdar://problem/32200714
The "common return type" optimization that occurs at
constraint-generation time was overly complicated and wrong in a
couple of places. Fix up these issues:
* Don't cache information about this optimization in the decls
themselves; it ignores visibility as well as invalidation that
occurs in script mode and playgrounds. Just do the the work again
* Don't map type into context; we can bail out when there are type
parameters present
* Skip the "self" parameters of operators in types (since this only
ever occurs for operators).
Longer term, this optimization should move into the solver itself. But
for now, at least it's cleaner/more correct.
An early optimization in constraint generation attempted to simplify
type construction (e.g., X(...)) when the type in question has no
failable initializers. However, the optimization didn't appropriately
clear out the cached bit when new information became available (e.g.,
new conformances, new extensions), and didn't seem to help anything
performance-wise (type-checking times didn't increase at all when I
turned this off).
Fixes rdar://problem/30588177.
This prevents one invalid declaration from causing cascades of subsequent errors.
Fixes:
* test/NameBinding/scope_map_lookup.swift
* test/decl/var/variables.swift
CSGen can see an AssignExpr where the destination has an
unresolved type, even in a case where no diagnostic has been
emitted yet.
It is then wrong to return an empty type from here, because
this stops us from attempting to solve the expression, which
results in no diagnostic being emitted in the end.
The test case I added produces a decent diagnostic now,
but the original one in the radar now just says 'ambiguous
without more context'. Still, better than crashing.
Fixes <rdar://problem/30685195>.
This introduces a few unfortunate things because the syntax is awkward.
In particular, the period and following token in \.[a], \.? and \.! are
token sequences that don't appear anywhere else in Swift, and so need
special handling. This is somewhat compounded by \foo.bar.baz possibly
being \(foo).bar.baz or \(foo.bar).baz (parens around the type), and,
furthermore, needing to distinguish \Foo?.bar from \Foo.?bar.
rdar://problem/31724243
We have various hacks in the constraint solver to improve the
compile-time performance characteristics of operators. Some of those
didn't respect availability annotations, causing us to incorrectly
choose an unavailable operator when available options exist.
Fixes rdar://problem/31592529.
There were various problems with layout constraints either
being ignored or handled incorrectly. Now that I've exercised
this support with an upcoming patch, there are some fixes
here.
Also, introduce a new ExistentialLayout::getLayoutConstriant()
which returns a value for existentials which are class-constrained
but don't have a superclass or any class-constrained protocols;
an example would be AnyObject, or AnyObject & P for some
non-class protocol P.
NFC for now, since these layout-constrained existentials cannot
be constructed yet.
When creating disjunctions with favored constraints in constraint
optimization, we actually ended up duplicating the constraint that we
favor, resulting with extra constraints in the disjunction.
Noticed while debugging other issues.
TODO:
- Select the KeyPath subclass corresponding to the write capability of the key path components
- Figure out an issue with unresolved solutions being chosen with contextually-typed keypaths
- Diagnostic QoI
For instance:
protocol P1 {
func foo()
}
protocol P2 : P1 {
func bar()
}
extension P2 {
func foo() {}
}
We report the foo() in P2's extension as the default implementation of foo() declared in P1.
It is generally useful to allow 'super' method calls inside a
closure, so you can have overrides that do things like:
override func foo() {
doSomething { super.foo() }
}
However this didn't work if the closure was a local generic
function because we didn't map the 'super' type into the
right generic context.
We have a quirk where TypeBase::getSuperclass() on DynamicSelfType
returns the underlying class type, and not the superclass of the
underlying class type. As a result, we would emit a SuperRefExpr
whose type was the type of 'self' and not the type of 'super'.
Fixes <rdar://problem/30853768>.
This lets you match `case .foo` when `foo` resolves to any static member, instead of only a `case`, albeit without the exhaustiveness checking and subpattern capabilities of proper cases. While we're here, adjust the type system we set up for unresolved patterns embedded in expressions so that we give better signal in the error messages too.
This is disabled by default but enabled under the frontend option
-propagate-constraints.
The idea here is to have a pass that enforces local consistency in our
constraint system, in order to reduce the domains of constraint
variables, speeding up the solving of the constraint system.
The initial focus will be on reducing the size of the disjunctions for
function overloads with the hope that it substantially improves the
performance of type checking many expressions.
First, add some new utility methods to create SubstitutionMaps:
- GenericSignature::getSubstitutionMap() -- provides a new
way to directly build a SubstitutionMap. It takes a
TypeSubstitutionFn and LookupConformanceFn. This is
equivalent to first calling getSubstitutions() with the two
functions to create an ArrayRef<Substitution>, followed by
the old form of getSubstitutionMap() on the result.
- TypeBase::getContextSubstitutionMap() -- replacement for
getContextSubstitutions(), returning a SubstitutionMap.
- TypeBase::getMemberSubstitutionMap() -- replacement for
getMemberSubstitutions(), returning a SubstitutionMap.
With these in place, almost all existing uses of subst() taking
a ModuleDecl can now use the new form taking a SubstitutionMap
instead. The few remaining cases are explicitly written to use a
TypeSubstitutionFn and LookupConformanceFn.
Constraint generation for interpolated string literals was
meticulously producing a constraint system that included all of the
generated calls to init(stringInterpolationSegment:). While accurate,
this is completely unnecessary (because the
ExpressibleByStringInterpolation protocol allows *anything* to be
interpolated) and leads to large, intertwined constraint systems
where:
(1) There are two additional type variables per string interpolation
segment, and
(2) Those type variables form a bridge between the string
interpolation's type variable and the type variables of each string
interpolation segment, and
(3) init(stringInterpolationSegment:) tends to be overloaded (4
overloads, down from 17 due to
29353013c0)
which left each string interpolation as a large connected component
with big disjunctions.
Drop the calls to init(stringInterpolationSegment:) from the
constraint system. This eliminates two type
variables per segment (due to (1) going away), and breaks the bridge
described in (2), so that each string interpolation segment is
treated as an separate connected component and, therefore, will be
solved independently. The actual resolution of
init(stringInterpolationSegment:) overloads is pushed to the
constraint application phase, where we are only dealing with concrete
types and *much* smaller constraint systems.
Fixes rdar://problem/29389887 more thoroughly.
The type checker introduces fresh type variables for editor
placeholders that are encountered in the source. If there are many
such editor placeholders, we'll create a large number of type
variables with very little context, which can cause poor scaling in
the type checker. Since we get very little information out of these
type variables, artificially limit the number of type variables we
create (to 2) and rotate through them.
Another piece of rdar://problem/29389887.
Without this, CSGen/CSSimplify and CSApply may have differing
opinions about whether e.g. a let property is settable, which
can lead to invalid ASTs.
Arguably, a better fix would be to remove the dependency on the
exact nested DC. For example, we could treat lets as settable
in all contexts and then just complain later about invalid
attempts to set them. Or we could change CSApply to directly
use the information it already has about how an l-value is used,
rather than trying to figure out whether it *might* be getting set.
But somehow, tracking a new piece of information through the
entire constraint system seems to be the more minimal change.
Fixes rdar://29810997.
In ConstraintGenerator::visitDictionaryExpr(), if the dictionary_expr has a
contextual type which is also a dictionary type, use it to add a new type
constraint for each of the dictionary_expr's elements. This has a huge effect
on solver performance for dictionary literals with elements that have
overloading. The approach closely follows that used in
ConstraintGenerator::visitArrayExpr(), which has included a similar
optimization (from git commit a22b391) for over two and a half years.
I've also added a couple of new test cases which would trigger the bug without
this fix.
FailureDiagnosis::visitApplyExpr is going to attempt to type-check
argument expression multiple times - with and without allowing free
type variables, since first type-check might mutate AST if (sub-expression
type-checks correctly) it's required to fix up ternary operations
represented as IfExpr to it's original condition form, because IfExpr
is going to convert Bool into implicit call `(Bool) -> () -> Int1`
upon successful type-check, which is not handled by either
ConstraintGenerator nor ExprRewriter because they don't expect
well-formed type-checked IfExpr is input.
Resolves: <rdar://problem/29850459>.