Commit Graph

188 Commits

Author SHA1 Message Date
Robert Widmann
f4d333d066 Sink a bunch of semantic options into TypeCheckerOptions
Sink
- DebugConstraintSolver
- DebugConstraintSolverAttempt
- DebugConstraintSolverOnLines
- DebugGenericSignatures
- DebugForbidTypecheckPrefix
- SolverMemoryThreshold
- SolverBindingThreshold
- SolverShrinkUnsolvedThreshold
- SolverDisableShrink
- EnableOperatorDesignatedTypes
- DisableConstraintSolverPerformanceHacks
- SolverEnableOperatorDesignatedTypes
2019-11-12 22:39:49 -08:00
Brent Royal-Gordon
17169fc1fe Merge pull request #27950 from brentdax/dumpster-fire
[NFC] Standardize dump() methods in frontend
2019-10-31 20:36:26 -07:00
Brent Royal-Gordon
ffbe53e290 [NFC] Eliminate const_casts in constraint system dumpers 2019-10-31 18:41:11 -07:00
Brent Royal-Gordon
99faa033fc [NFC] Standardize dump() methods in frontend
By convention, most structs and classes in the Swift compiler include a `dump()` method which prints debugging information. This method is meant to be called only from the debugger, but this means they’re often unused and may be eliminated from optimized binaries. On the other hand, some parts of the compiler call `dump()` methods directly despite them being intended as a pure debugging aid. clang supports attributes which can be used to avoid these problems, but they’re used very inconsistently across the compiler.

This commit adds `SWIFT_DEBUG_DUMP` and `SWIFT_DEBUG_DUMPER(<name>(<params>))` macros to declare `dump()` methods with the appropriate set of attributes and adopts this macro throughout the frontend. It does not pervasively adopt this macro in SILGen, SILOptimizer, or IRGen; these components use `dump()` methods in a different way where they’re frequently called from debugging code. Nor does it adopt it in runtime components like swiftRuntime and swiftReflection, because I’m a bit worried about size.

Despite the large number of files and lines affected, this change is NFC.
2019-10-31 18:37:42 -07:00
Robert Widmann
972e755e9b Give ConstraintSystem's outlet to the ASTContext
Make it less tempting to ask for the type checker embedded into
ConstraintSystem by using the accessor to the ASTContext.
2019-10-30 12:55:42 -07:00
Jordan Rose
171ff440fc Remove swift::reversed in favor of llvm::reverse (#27610)
The former predates the latter, but we don't need it anymore! The
latter has more features anyway.

No functionality change.
2019-10-10 17:16:09 -07:00
Doug Gregor
34a7515aee [Constraint graph] Use adjacency info for constraint gathering.
This reinstates the use of direct adjacency information when gathering
constraints, effectively reverting
54bdd7b840.
Fixes the regression that commit caused, which is tracked by
rdar://problem/54274245.
2019-08-22 10:15:54 -07:00
Doug Gregor
cf1732cce2 [Constraint graph] Reinstate the adjacencies of constraint graph nodes.
Reinstate the list of adjacencies in each constraint graph node,
effectively reverting
dfdd352d3d. Exclude one-way constraints
from this computation; we'll handle them separately.
2019-08-22 09:38:21 -07:00
Doug Gregor
17ea39accd [Constraint solver] Simplify one-way constraints to Equal, not Bind.
One-way constraint expressions, which are the only things that
introduce one-way constraints at this point, want to look through
lvalue types to produce values. Rename OneWayBind to OneWayEqual, map
it down to an Equal constraint when it is simplified (to drop
lvalue-ness), and apply that coercion during constraint application.

Part of rdar://problem/50150793.
2019-08-16 14:13:21 -07:00
Doug Gregor
da267bf7ca [Constraint system] Switch TypeVariables to a SetVector.
There were a few places where we wanted fast testing to see whether a
particular type variable is currently of interest. Instead of building
local hash tables in those places, keep type variables in a SetVector
for efficient testing.
2019-08-16 14:13:15 -07:00
Doug Gregor
aaf479642f [Constraint graph] Fix gathering of one-way constraints.
We only care about gathering a one-way constraint if (1) the left-hand
side is in the set of type variables we care about now, and (2) the
type variable we started from is in the right-hand side.
2019-08-16 14:13:04 -07:00
Doug Gregor
73e5a64bd1 [Constraint graph] Collapse cycles in the one-way component graph.
When we encounter a cycle in the one-way component graph due to constraints
that (e.g.) tie together the outputs of two one-way constraints, collapse
the components along the cycle into a single connected component, because
all of those type variables must be solved together.
2019-08-14 13:51:24 -07:00
Doug Gregor
f19016b94b [Constraint graph] Add preVisit hook for depth-first search.
Refactoring so we can use this in a moment.
2019-08-14 11:49:14 -07:00
Doug Gregor
0b7ef3445e [Constraint graph] Make sure we print type variables when dumping components.
Helps with debugging the constraint graph.
2019-08-14 09:20:41 -07:00
Doug Gregor
3c69f6a305 [Constraint solver] Introduce one-way constraints.
Introduce the notion of "one-way" binding constraints of the form

  $T0 one-way bind to $T1

which treats the type variables $T0 and $T1 as independent up until
the point where $T1 simplifies down to a concrete type, at which point
$T0 will be bound to that concrete type. $T0 won't be bound in any
other way, so type information ends up being propagated right-to-left,
only. This allows a constraint system to be broken up in more
components that are solved independently. Specifically, the connected
components algorithm now proceeds as follows:

1. Compute connected components, excluding one-way constraints from
consideration.
2. Compute a directed graph amongst the components using only the
one-way constraints, where an edge A -> B indicates that the type
variables in component A need to be solved before those in component
B.
3. Using the directed graph, compute the set of components that need
to be solved before a given component.

To utilize this, implement a new kind of solver step that handles the
propagation of partial solutions across one-way constraints. This
introduces a new kind of "split" within a connected component, where
we collect each combination of partial solutions for the input
components and (separately) try to solve the constraints in this
component. Any correct solution from any of these attempts will then
be recorded as a (partial) solution for this component.

For example, consider:

  let _: Int8 = b ? Builtin.one_way(int8Or16(17)) :
  Builtin.one_way(int8Or16(42\
))

where int8Or16 is overloaded with types `(Int8) -> Int8` and
`(Int16) -> Int16`. There are two one-way components (`int8Or16(17)`)
and (`int8Or16(42)`), each of which can produce a value of type `Int8`
or `Int16`. Those two components will be solved independently, and the
partial solutions for each will be fed into the component that
evaluates the ternary operator. There are four ways to attempt that
evaluation:

```
  [Int8, Int8]
  [Int8, Int16]
  [Int16, Int8]
  [Int16, Int16]

To test this, introduce a new expression builtin `Builtin.one_way(x)` that
introduces a one-way expression constraint binding the result of the
expression 'x'. The builtin is meant to be used for testing purposes,
and the one-way constraint expression itself can be synthesized by the
type checker to introduce one-way constraints later on.

Of these two, there are only two (partial) solutions that can work at
all, because the types in the ternary operator need a common
supertype:

  [Int8, Int8]
  [Int16, Int16]

Therefore, these are the partial solutions that will be considered the
results of the component containing the ternary expression. Note that
only one of them meets the final constraint (convertibility to
`Int8`), so the expression is well-formed.

Part of rdar://problem/50150793.
2019-08-13 11:48:42 -07:00
Doug Gregor
dec149ce62 [Constraint graph] Move component sorting into connected components. 2019-08-11 21:49:08 -07:00
Doug Gregor
ab38be128d [Constraint graph] Handle orphaned constraints within connected components
Move the logic for creating connected components of orphaned
constraints into the connected-components algorithm code, rather than
making it a special part of SplitterStep.
2019-08-11 21:28:34 -07:00
Doug Gregor
5a4af23a63 [Constraint graph] Maintain constraint order when splitting components.
Maintain the order of constraints when splitting the system into
connected components, to match the behavior prior to the refactoring
into a separate connected-components algorithm.
2019-08-11 21:25:24 -07:00
Doug Gregor
4c04ced939 [Constraint graph] Make connected components more self-contained.
Have the constraint graph's connected-component implementation be more
self-contained, producing a vector containing each of the actual
components (where each is defined by a list of type variables and a list
of constraints). This simplifies the contract with the client
(SplitterStep) and eliminates a bunch of separate mapping steps to
interpret the results.

It also lets us enrich the Component data structure in the future.
2019-08-07 08:32:34 -07:00
Doug Gregor
805b02da37 [Constraint graph] Associate all constraints with components.
The connected components computation was not forming components when all of
the type variables in a component were already bound. Any remaining
constraints involving those type variables would then arbitrarily end up
in component 0, due to the the default-construction behavior of a map’s
operator[] with missing keys, artificially increasing the size of that
component with (typically) additional disjunctions.

Ensure that all constraints get into a component, creating one to hold
the a constraint even when all of the type variables are already bound.
Then, assert the invariant that every constraint is associated with a
component.

In time, we should probably eliminate this notion of disjunctions that
remain even when the type variable has been bound. For now, strengthen the
invariant to at least ensure that they get solved in isolation.
2019-08-06 23:15:58 -07:00
Doug Gregor
c2a9286d1d [Constraint graph] Print only those type variables that are of interest now 2019-08-05 22:21:21 -07:00
Doug Gregor
14ca9d1461 [Constraint graph] Make connected components never touch all type variables.
Simplify the connected-components computation slightly and make sure
that it never performs work outside of the subgraph described by the
input set of type variables.
2019-07-27 01:18:20 -04:00
Doug Gregor
6be6401581 [Constraint solver] Fix incorrect bailout in connected-components.
Address a silly mistake that meant we were miscomputing connected
components.
2019-07-27 01:18:00 -04:00
Doug Gregor
62502efffb [Constraint graph] Restrict connected components to requested type variables.
The API of the connected-components algorithm asks clients to
provide the set of type variables of interest. However, the connected
components algorithm itself was operating across the entire set of
type variables, then narrowing the result down to the type variables
of interest. Instead, only perform connected components on those type
variables of interest, so that we are only doing work proportional to
the subgraph we're working in.
2019-07-25 23:41:14 -04:00
Doug Gregor
8355f3d270 [Constraint graph] Move constraint uniquing into gatherConstraints().
Simplify the interface to gatherConstraints() by performing the
uniquing within the function itself and returning only the resulting
(uniqued) vector of constraints.
2019-07-25 02:26:49 -04:00
Doug Gregor
dfdd352d3d [Constraint graph] Eliminate adjacency information in the graph nodes.
Each constraint graph node maintained adjacency information that was
fairly expensive---a vector of type variables and a dense map of extra
adjacency information---and that was continuously maintained. Remove
this adjacency information, instead recomputing it by walking the
constraints (to get their type variables) and having a separate
(smaller) list of type variables that are adjacent due to fixed
bindings. This simplifies the constraint graph code and reduces
per-node memory overhead.
2019-07-25 01:54:06 -04:00
Doug Gregor
54bdd7b840 [Constraint solver] Migrate ConstraintGraph::gatherConstraints() off adjacencies list.
Use the adjacencies implied by the constraints of a node rather than looking
at the "adjacency" list, and try to simplify this code path a bit. The
diagnostic change is because we are now uniformly recording the
members of the equivalence class.
2019-07-25 01:54:06 -04:00
Doug Gregor
6737cf9fb8 [Constraint graph] Generalize the implementation of depth-first search. 2019-07-25 01:54:06 -04:00
Doug Gregor
6a970a8736 [Constraint solver] Reimplement connected components using constraints.
The constraint graph maintains a fairly heavyweight list of
adjacencies that is only used in two operations: connected components
and gathering related constraints. Switch connected components over to
primarily use the set of constraints (which are necessary for many
reasons), reducing the need for the adjacencies list.
2019-07-25 01:54:05 -04:00
Gwen Mittertreiner
e51b72b3e0 Reduce the Stack Size of ConstraintSystem
The ConstraintSystem class is on the order of 1000s of bytes in size on
the stacka nd is causing issues with dispatch's 64k stack limit.

This changes most Small data types which store data on the stack to non
small heap based data types.
2019-05-13 11:40:43 -07:00
Slava Pestov
33871548b3 Clean up TypeVariableType::Implementation::mustBeMaterializable(), etc 2019-01-12 14:10:11 -05:00
Pavel Yaskevich
624c183fe0 [ConstraintGraph] Change gatherConstraints to take SetVector
For stable iteration order, let's switch from `SmallPtrSet`
to `SetVector` which ensures insertion order iteration.
2018-07-27 15:34:15 -07:00
Pavel Yaskevich
48dd1e837b [ConstraintGraph] Add filtering to gatherConstraints per type variable
Most of the use-cases of `gatherConstraints` require filtering
at least based on the constraint kind that caller is interested in,
so instead of returning unrelated results and asking caller to
filter separately, let's add that functionality directly to
`gatherConstraints`.
2018-07-26 22:41:15 -07:00
Pavel Yaskevich
dd798accd8 [ConstraintGraph] Use set to gather constraints for type variables
Since it's possible to find the same constraint through two different
but equivalent type variables, let's use a set to store constraints
instead of a vector to avoid processing the same constraint multiple
times.
2018-07-26 22:41:07 -07:00
Pavel Yaskevich
3e254678a2 [Sema] Add counter to track number of constraints considered by each edge contraction attempt 2018-05-12 02:37:52 -07:00
Pavel Yaskevich
e021691bae [ConstraintGraph] Fix contractEdges to gather constraints only once
Currently we have this non-optimal behavior in `contractEdges` where
for every type variable it gathers constraints for its whole equivalence
class before checking if any are "contractable", instead constraints
could be gathered/filtered once which removes a lot of useless work.
2018-05-11 16:08:53 -07:00
Huon Wilson
d4fbca1183 [Sema/CS] std::function -> llvm::function_ref for some non-escaping params. 2018-05-01 08:29:08 +10:00
Pavel Yaskevich
3b7e555c7e [CSSolver] Fix performance regression related to contraction of closure parameters
Improve situation around closure parameter/argument contractions
by allowing such action if it can be proved that none of the bindings
would result in solver attempting to bind parameter to `inout` type.

Resolves: rdar://problem/36838495
2018-01-31 14:21:14 -08:00
Pavel Yaskevich
80e4a2226b [ConstraintGraph] Don't try to contract edge of parameter bindings with inout attribute
Currently edge related to the parameter bindings is contracted
without properly checking if newly created equivalence class has
the same inout & l-value requirements. This patch improves the
situation by disallowing contraction of the edges related to parameter
binding constraint where left-hand side has `inout` attribute set.

Such guarantees that parameter can get `inout` type assigned when
argument gets `l-value` type.

Resolves: rdar://problem/33429010
2017-09-22 17:23:12 -07:00
Mark Lacey
8563911ac6 [Constraint system] Use llvm::any_of instead of std::any_of. 2017-09-13 15:29:15 -07:00
Mark Lacey
c960926b06 [Constraint system] Turn explicit loop into std::any_of. 2017-09-13 14:31:18 -07:00
Pavel Yaskevich
0a178fd263 [ConstraintGraph] Disallow subtype constraint contractions
Presently subtype constraint is considered a candidate for contraction
via `shouldContractEdge` when left-hand side of the subtype constraint
is an inout type with type variable inside. Although it's intended to
be used only in combination with BindParam constraint assigned to the
same variable, that is actually never checked and contraction of subtype
constraint like that is invalid.

Resolves: rdar://problem/34333874
2017-09-11 15:13:13 -07:00
Joe Groff
6e9f4dcd62 Sema: Avoid asking for the SecondType of Constraints that don't have them.
Assertions tripped while trying to reproduce SR-5513.
2017-07-20 16:04:30 -07:00
Mark Lacey
687624e317 [Constraint solver] Gather constraints from adjacencies of equiv class.
When gathering constraints for a type variable, we were gathering all of
the constraints for the members of the equivalence class, and then for
the adjacencies of the representative of the equivalence class, but not
from the adjacencies of other members of the equivalence class.

For example for:
  #3 = $T3
  #4 = $T4 equivalent to $T3
  #5 = $T5 as $T4.Element

after binding $T3 we would collect the constraints related to $T3 and
$T4, but not $T5. The end result can be that we finish examining all
disjunctions and type bindings but still have inactive constraints in
the constraint graph, which is treated as a failure in the solver.

Fixes SR-5120 / rdar://problem/32618740.
2017-06-23 09:43:06 -07:00
Doug Gregor
40b6764e80 [Constraint solver] Handle disjunctions as separate connected components.
The constraint graph models type variables (as the nodes) and
constraints (as the multi-edges connecting nodes). The connected
components within this (multi-)graph are independent subproblems that
are solved separately; the results from each subproblem are then
combined. The approach helps curtail exponential behavior, because
(e.g.) the disjunctions/type variables in one component won't ever be
explored while solving for another component

This approach assumes that all of the constraints that cannot be
immediately solved are associated with one or more type
variables. This is almost entirely true---constraints that don't
involve type variables are immediately simplified.

Except for disjunctions. A disjunction involving no type variables
would not appear *at all* in the constraint graph. Worse, it's
independence from other constraints could not be established, so the
constraint solver would go exponential for every one of these
constraints. This has always been an issue, but it got worse with the
separation of type checking of "as" into the "coercion" case and the
"bridging" case, which introduced more of these disjunctions. This led
to counterintuitive behavior where adding "as Foo" would cause the
type checking to take *more* time than leaving it off, if both sides
of the "as" were known to be concrete. rdar://problem/30545483
captures a case (now in the new test case) where we saw such
exponential blow-ups.

Teach the constraint graph to keep track of "orphaned" constraints
that don't reference any type variables, and treat each "orphaned"
constraint as a separate connected component. That way, they're solved
independently.

Fixes rdar://problem/30545483 and will likely curtain other
exponential behavior we're seeing in the solver.
2017-02-20 17:18:18 -08:00
Hugh Bellamy
f001b7562b Use relatively new LLVM_FALLLTHROUGH instead of our own SWIFT_FALLTHROUGH 2017-02-12 10:47:03 +07:00
practicalswift
6d1ae2a39c [gardening] 2016 → 2017 2017-01-06 16:41:22 +01:00
Doug Gregor
f68f87a56a [Constraint solver] After binding a type variable, activate affected constraints
Once we've bound a type variable, we find those inactive constraints
that mention the type variable and make them active, so they'll be
simplified again. However, we weren't finding *all* constraints that
could be affected---in particular, we weren't searching everything
related to the type variables in the equivalence class, which meant
that some constraints would not get visited... and we would to
type-check simply because we didn't look at a constraint again when we
should have.

Fixes rdar://problem/29633747.
2016-12-14 20:18:04 -08:00
Pavel Yaskevich
8208c94dcc [TypeChecker] Add getter/setter methods for generatedConstraints of SolverState 2016-12-11 21:46:03 -08:00
Michael Gottesman
59c6a64f5a [gardening] 0 => nullptr. Fixed with clang-tidy. 2016-12-06 23:14:13 -08:00