Skip to content

[Constraint solver] Introduce one-way binding constraints. #25983

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 2 commits into from
Aug 14, 2019

Conversation

DougGregor
Copy link
Member

@DougGregor DougGregor commented Jul 5, 2019

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.

Implements the core of rdar://problem/50150793.

@DougGregor
Copy link
Member Author

The changes to the connected-components algorithm are separated out into #26383.

@DougGregor DougGregor force-pushed the one-way-constraints branch 2 times, most recently from c2296e5 to 07c8a64 Compare August 1, 2019 04:19
@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please test compiler performance

@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility

@DougGregor
Copy link
Member Author

@swift-ci please test compiler performance

@swift-ci
Copy link
Contributor

swift-ci commented Aug 3, 2019

Summary for master full

Unexpected test results, excluded stats for RxCocoa, SwifterSwift

Regressions found (see below)

Debug-batch

debug-batch brief

Regressed (0)
name old new delta delta_pct
Improved (0)
name old new delta delta_pct
Unchanged (delta < 1.0% or delta < 100.0ms) (3)
name old new delta delta_pct
Frontend.NumInstructionsExecuted 42,960,287,543,718 43,204,611,352,784 244,323,809,066 0.57%
LLVM.NumLLVMBytesOutput 1,740,136,658 1,740,141,238 4,580 0.0%
time.swift-driver.wall 4352.6s 4366.8s 14.2s 0.33%

debug-batch detailed

Regressed (9)
name old new delta delta_pct
Driver.NumDriverPipePolls 85,147 86,176 1,029 1.21% ⛔
Driver.NumDriverPipeReads 76,296 77,288 992 1.3% ⛔
Sema.AccessLevelRequest 12,500,116 12,647,937 147,821 1.18% ⛔
Sema.CollectOverriddenDeclsRequest 7,857,791 7,961,578 103,787 1.32% ⛔
Sema.NumConstraintScopes 24,706,557 27,299,216 2,592,659 10.49% ⛔
Sema.NumConstraintsConsideredForEdgeContraction 74,460,220 93,285,264 18,825,044 25.28% ⛔
Sema.NumLeafScopes 15,975,599 17,488,910 1,513,311 9.47% ⛔
Sema.ProvideDefaultImplForRequest 7,857,791 7,961,578 103,787 1.32% ⛔
Sema.USRGenerationRequest 9,012,122 9,118,919 106,797 1.19% ⛔
Improved (2)
name old new delta delta_pct
Driver.ChildrenMaxRSS 195,385,724,928 192,086,364,160 -3,299,360,768 -1.69% ✅
Sema.DefaultTypeRequest 498,354 479,307 -19,047 -3.82% ✅
Unchanged (delta < 1.0% or delta < 100.0ms) (130)
name old new delta delta_pct
AST.NumASTBytesAllocated 61,288,037,852 61,696,881,804 408,843,952 0.67%
AST.NumDecls 136,738 136,738 0 0.0%
AST.NumDependencies 242,881 242,878 -3 -0.0%
AST.NumInfixOperators 52,921 52,921 0 0.0%
AST.NumLinkLibraries 0 0 0 0.0%
AST.NumLoadedModules 313,357 313,357 0 0.0%
AST.NumLocalTypeDecls 241 241 0 0.0%
AST.NumObjCMethods 24,471 24,471 0 0.0%
AST.NumPostfixOperators 23 23 0 0.0%
AST.NumPrecedenceGroups 24,973 24,973 0 0.0%
AST.NumPrefixOperators 99 99 0 0.0%
AST.NumReferencedDynamicNames 189 189 0 0.0%
AST.NumReferencedMemberNames 6,213,629 6,213,420 -209 -0.0%
AST.NumReferencedTopLevelNames 466,175 466,175 0 0.0%
AST.NumSourceBuffers 384,044 384,044 0 0.0%
AST.NumSourceLines 4,600,323 4,600,323 0 0.0%
AST.NumSourceLinesPerSecond 3,381,643 3,397,902 16,259 0.48%
AST.NumTotalClangImportedEntities 5,703,178 5,708,424 5,246 0.09%
Driver.DriverDepCascadingDynamic 0 0 0 0.0%
Driver.DriverDepCascadingExternal 0 0 0 0.0%
Driver.DriverDepCascadingMember 0 0 0 0.0%
Driver.DriverDepCascadingNominal 0 0 0 0.0%
Driver.DriverDepCascadingTopLevel 0 0 0 0.0%
Driver.DriverDepDynamic 0 0 0 0.0%
Driver.DriverDepExternal 0 0 0 0.0%
Driver.DriverDepMember 0 0 0 0.0%
Driver.DriverDepNominal 0 0 0 0.0%
Driver.DriverDepTopLevel 0 0 0 0.0%
Driver.NumDriverJobsRun 27,113 27,113 0 0.0%
Driver.NumDriverJobsSkipped 0 0 0 0.0%
Driver.NumProcessFailures 0 0 0 0.0%
Frontend.MaxMallocUsage 969,069,166,952 971,125,051,312 2,055,884,360 0.21%
Frontend.NumInstructionsExecuted 42,960,287,543,718 43,204,611,352,784 244,323,809,066 0.57%
Frontend.NumProcessFailures 0 0 0 0.0%
IRModule.NumIRAliases 193,566 193,566 0 0.0%
IRModule.NumIRBasicBlocks 6,954,547 6,954,547 0 0.0%
IRModule.NumIRComdatSymbols 0 0 0 0.0%
IRModule.NumIRFunctions 3,254,545 3,254,545 0 0.0%
IRModule.NumIRGlobals 3,314,055 3,314,055 0 0.0%
IRModule.NumIRIFuncs 0 0 0 0.0%
IRModule.NumIRInsts 85,119,563 85,119,563 0 0.0%
IRModule.NumIRNamedMetaData 130,380 130,380 0 0.0%
IRModule.NumIRValueSymbols 5,934,066 5,934,066 0 0.0%
LLVM.NumLLVMBytesOutput 1,740,136,658 1,740,141,238 4,580 0.0%
Parse.NumFunctionsParsed 262,365 262,365 0 0.0%
Parse.NumIterableDeclContextParsed 1,260,072 1,260,072 0 0.0%
SILModule.NumSILGenDefaultWitnessTables 0 0 0 0.0%
SILModule.NumSILGenFunctions 1,677,113 1,677,113 0 0.0%
SILModule.NumSILGenGlobalVariables 53,716 53,716 0 0.0%
SILModule.NumSILGenVtables 17,510 17,510 0 0.0%
SILModule.NumSILGenWitnessTables 70,974 70,974 0 0.0%
SILModule.NumSILOptDefaultWitnessTables 0 0 0 0.0%
SILModule.NumSILOptFunctions 2,348,662 2,348,662 0 0.0%
SILModule.NumSILOptGlobalVariables 55,331 55,331 0 0.0%
SILModule.NumSILOptVtables 29,880 29,880 0 0.0%
SILModule.NumSILOptWitnessTables 155,614 155,614 0 0.0%
Sema.AttachedFunctionBuilderRequest 7 7 0 0.0%
Sema.AttachedPropertyWrapperTypeRequest 502,429 502,429 0 0.0%
Sema.AttachedPropertyWrappersRequest 2,233,371 2,233,371 0 0.0%
Sema.CursorInfoRequest 0 0 0 0.0%
Sema.CustomAttrNominalRequest 17 17 0 0.0%
Sema.DefaultAndMaxAccessLevelRequest 85,927 85,928 1 0.0%
Sema.DefaultDefinitionTypeRequest 7,918 7,918 0 0.0%
Sema.EnumRawTypeRequest 22,995 22,995 0 0.0%
Sema.ExistentialConformsToSelfRequest 20,587 20,611 24 0.12%
Sema.ExistentialTypeSupportedRequest 16,176 16,176 0 0.0%
Sema.ExtendedNominalRequest 4,722,637 4,739,432 16,795 0.36%
Sema.FunctionBuilderTypeRequest 7 7 0 0.0%
Sema.HasDynamicMemberLookupAttributeRequest 0 0 0 0.0%
Sema.InheritedDeclsReferencedRequest 5,697,794 5,719,989 22,195 0.39%
Sema.InheritedTypeRequest 306,580 306,520 -60 -0.02%
Sema.InitKindRequest 114,856 114,856 0 0.0%
Sema.IsAccessorTransparentRequest 307,887 307,887 0 0.0%
Sema.IsDeclApplicableRequest 0 0 0 0.0%
Sema.IsDynamicRequest 1,596,130 1,596,130 0 0.0%
Sema.IsFinalRequest 4,490,526 4,502,716 12,190 0.27%
Sema.IsGetterMutatingRequest 471,557 471,557 0 0.0%
Sema.IsObjCRequest 1,616,705 1,618,223 1,518 0.09%
Sema.IsSetterMutatingRequest 363,978 363,978 0 0.0%
Sema.LazyStoragePropertyRequest 2,825 2,825 0 0.0%
Sema.MangleLocalTypeDeclRequest 482 482 0 0.0%
Sema.NamedLazyMemberLoadFailureCount 29,496 29,499 3 0.01%
Sema.NamedLazyMemberLoadSuccessCount 29,044,186 29,062,672 18,486 0.06%
Sema.NominalTypeLookupDirectCount 36,403,527 36,458,268 54,741 0.15%
Sema.NumAccessorBodiesSynthesized 183,607 183,607 0 0.0%
Sema.NumAccessorsSynthesized 375,987 375,987 0 0.0%
Sema.NumConformancesDeserialized 9,509,623 9,571,674 62,051 0.65%
Sema.NumDeclsDeserialized 70,306,347 70,719,634 413,287 0.59%
Sema.NumDeclsFinalized 675,994 675,994 0 0.0%
Sema.NumDeclsTypechecked 1,369,622 1,369,622 0 0.0%
Sema.NumDeclsValidated 2,633,797 2,633,815 18 0.0%
Sema.NumFunctionsTypechecked 513,556 513,556 0 0.0%
Sema.NumGenericSignatureBuilders 1,360,257 1,364,826 4,569 0.34%
Sema.NumLazyGenericEnvironments 12,732,148 12,814,072 81,924 0.64%
Sema.NumLazyGenericEnvironmentsLoaded 301,604 301,604 0 0.0%
Sema.NumLazyIterableDeclContexts 8,412,438 8,433,981 21,543 0.26%
Sema.NumLazyRequirementSignatures 845,573 846,392 819 0.1%
Sema.NumLazyRequirementSignaturesLoaded 563,964 564,590 626 0.11%
Sema.NumTypesDeserialized 20,407,430 20,487,932 80,502 0.39%
Sema.NumTypesValidated 2,239,753 2,239,775 22 0.0%
Sema.NumUnloadedLazyIterableDeclContexts 5,086,826 5,081,551 -5,275 -0.1%
Sema.OpaqueReadOwnershipRequest 361,380 361,380 0 0.0%
Sema.OverriddenDeclsRequest 2,468,182 2,480,607 12,425 0.5%
Sema.PropertyWrapperBackingPropertyInfoRequest 497,355 497,355 0 0.0%
Sema.PropertyWrapperBackingPropertyTypeRequest 502,429 502,429 0 0.0%
Sema.PropertyWrapperMutabilityRequest 644,826 644,826 0 0.0%
Sema.PropertyWrapperTypeInfoRequest 5 5 0 0.0%
Sema.ProtocolRequiresClassRequest 80,098 80,028 -70 -0.09%
Sema.RangeInfoRequest 0 0 0 0.0%
Sema.RequirementRequest 105,896 105,911 15 0.01%
Sema.RequirementSignatureRequest 650,353 650,912 559 0.09%
Sema.RequiresOpaqueAccessorsRequest 602,131 602,131 0 0.0%
Sema.RequiresOpaqueModifyCoroutineRequest 431,645 431,645 0 0.0%
Sema.ResolveProtocolNameRequest 0 0 0 0.0%
Sema.RootAndResultTypeOfKeypathDynamicMemberRequest 0 0 0 0.0%
Sema.RootTypeOfKeypathDynamicMemberRequest 0 0 0 0.0%
Sema.SelfAccessKindRequest 5,526,317 5,527,418 1,101 0.02%
Sema.SelfBoundsFromWhereClauseRequest 7,549,519 7,585,487 35,968 0.48%
Sema.SetterAccessLevelRequest 147,953 147,953 0 0.0%
Sema.StorageImplInfoRequest 889,280 889,280 0 0.0%
Sema.StoredPropertiesAndMissingMembersRequest 30,636 30,636 0 0.0%
Sema.StoredPropertiesRequest 359,853 359,853 0 0.0%
Sema.StructuralTypeRequest 0 0 0 0.0%
Sema.SuperclassDeclRequest 443,530 444,013 483 0.11%
Sema.SuperclassTypeRequest 56,972 56,973 1 0.0%
Sema.SynthesizeAccessorRequest 375,987 375,987 0 0.0%
Sema.TypeCheckFunctionBodyUntilRequest 513,556 513,556 0 0.0%
Sema.TypeDeclsFromWhereClauseRequest 46,765 46,766 1 0.0%
Sema.TypeRelationCheckRequest 0 0 0 0.0%
Sema.UnderlyingTypeDeclsReferencedRequest 251,906 252,367 461 0.18%

Release

release brief

Regressed (0)
name old new delta delta_pct
Improved (0)
name old new delta delta_pct
Unchanged (delta < 1.0% or delta < 100.0ms) (3)
name old new delta delta_pct
Frontend.NumInstructionsExecuted 46,019,141,398,078 46,117,464,253,953 98,322,855,875 0.21%
LLVM.NumLLVMBytesOutput 1,526,234,560 1,526,235,184 624 0.0%
time.swift-driver.wall 7200.4s 7218.9s 18.5s 0.26%

release detailed

Regressed (1)
name old new delta delta_pct
Sema.NumConstraintScopes 24,203,938 26,795,101 2,591,163 10.71% ⛔
Improved (0)
name old new delta delta_pct
Unchanged (delta < 1.0% or delta < 100.0ms) (20)
name old new delta delta_pct
AST.NumLoadedModules 29,573 29,573 0 0.0%
AST.NumTotalClangImportedEntities 1,211,995 1,210,849 -1,146 -0.09%
IRModule.NumIRBasicBlocks 6,289,118 6,289,118 0 0.0%
IRModule.NumIRFunctions 2,760,567 2,760,567 0 0.0%
IRModule.NumIRGlobals 2,931,157 2,931,157 0 0.0%
IRModule.NumIRInsts 55,373,498 55,373,498 0 0.0%
IRModule.NumIRValueSymbols 5,342,895 5,342,895 0 0.0%
LLVM.NumLLVMBytesOutput 1,526,234,560 1,526,235,184 624 0.0%
SILModule.NumSILGenFunctions 1,171,270 1,171,270 0 0.0%
SILModule.NumSILOptFunctions 1,563,873 1,563,873 0 0.0%
Sema.NumConformancesDeserialized 3,663,340 3,663,267 -73 -0.0%
Sema.NumDeclsDeserialized 10,164,570 10,164,441 -129 -0.0%
Sema.NumDeclsValidated 1,819,542 1,819,542 0 0.0%
Sema.NumFunctionsTypechecked 517,372 517,372 0 0.0%
Sema.NumGenericSignatureBuilders 299,534 299,510 -24 -0.01%
Sema.NumLazyGenericEnvironments 1,994,760 1,994,760 0 0.0%
Sema.NumLazyGenericEnvironmentsLoaded 35,000 35,000 0 0.0%
Sema.NumLazyIterableDeclContexts 1,296,805 1,296,732 -73 -0.01%
Sema.NumTypesDeserialized 5,172,826 5,172,812 -14 -0.0%
Sema.NumTypesValidated 1,105,968 1,105,968 0 0.0%

@DougGregor
Copy link
Member Author

I'm staging in all of the pieces for this (e.g., #26530) and will rebase shortly.

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.
…ilders

When we transform each expression or statement in a function builder,
introduce a one-way constraint so that type information does not flow
backwards from the context into that statement or expression. This
more closely mimics the behavior of normal code, where type inference
is per-statement, flowing from top to bottom.

This also allows us to isolate different expressions and statements
within a closure that's passed into a function builder parameter,
reducing the search space and (hopefully) improving compile times for
large function builder closures.

For now, put this functionality behind the compiler flag
`-enable-function-builder-one-way-constraints` for testing purposes;
we still have both optimization and correctness work to do to turn
this on by default.
@DougGregor DougGregor force-pushed the one-way-constraints branch from d457f42 to be73a9d Compare August 13, 2019 22:22
@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility

@DougGregor
Copy link
Member Author

@swift-ci please test compiler performance

@DougGregor
Copy link
Member Author

This should be a no-op, because all of the one-way constraints code is behind a flag. Performance + compatibility testing is to ensure I didn't inadvertently break things in this refactoring.

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

Successfully merging this pull request may close these issues.

3 participants