Skip to content

Commit d22e6b1

Browse files
committed
---
yaml --- r: 349390 b: refs/heads/master-next c: 7eddc0b h: refs/heads/master
1 parent e2d17a5 commit d22e6b1

File tree

5 files changed

+175
-49
lines changed

5 files changed

+175
-49
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
refs/heads/master: 3574c513bbc5578dd9346b4ea9ab5995c5927bb5
3-
refs/heads/master-next: 00788e519c871dd0053e37e79472da50ec61d064
3+
refs/heads/master-next: 7eddc0b53722f4e395ed619671885bb07a4de080
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea
66
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-b: 66d897bfcf64a82cb9a87f5e663d889189d06d07

branches/master-next/include/swift/Basic/Statistics.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ FRONTEND_STATISTIC(Sema, NumLeafScopes)
166166
/// This is a measure of complexity of the contraction algorithm.
167167
FRONTEND_STATISTIC(Sema, NumConstraintsConsideredForEdgeContraction)
168168

169+
/// Number of constraint-solving scopes created in the typechecker, while
170+
/// solving expression type constraints. A rough proxy for "how much work the
171+
/// expression typechecker did".
172+
FRONTEND_STATISTIC(Sema, NumCyclicOneWayComponentsCollapsed)
173+
169174
/// Number of declarations that were deserialized. A rough proxy for the amount
170175
/// of material loaded from other modules.
171176
FRONTEND_STATISTIC(Sema, NumDeclsDeserialized)

branches/master-next/lib/Sema/BuilderTransform.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class BuilderClosureVisitor
5252
/// Produce a builder call to the given named function with the given arguments.
5353
Expr *buildCallIfWanted(SourceLoc loc,
5454
Identifier fnName, ArrayRef<Expr *> args,
55-
ArrayRef<Identifier> argLabels = {}) {
55+
ArrayRef<Identifier> argLabels,
56+
bool allowOneWay) {
5657
if (!wantExpr)
5758
return nullptr;
5859

@@ -86,7 +87,7 @@ class BuilderClosureVisitor
8687
/*trailing closure*/ nullptr,
8788
/*implicit*/true);
8889

89-
if (ctx.LangOpts.FunctionBuilderOneWayConstraints) {
90+
if (ctx.LangOpts.FunctionBuilderOneWayConstraints && allowOneWay) {
9091
// Form a one-way constraint to prevent backward propagation.
9192
result = new (ctx) OneWayExpr(result);
9293
}
@@ -176,7 +177,9 @@ class BuilderClosureVisitor
176177

177178
// Call Builder.buildBlock(... args ...)
178179
return buildCallIfWanted(braceStmt->getStartLoc(),
179-
ctx.Id_buildBlock, expressions);
180+
ctx.Id_buildBlock, expressions,
181+
/*argLabels=*/{ },
182+
/*allowOneWay=*/true);
180183
}
181184

182185
Expr *visitReturnStmt(ReturnStmt *stmt) {
@@ -201,7 +204,8 @@ class BuilderClosureVisitor
201204
if (!arg)
202205
return nullptr;
203206

204-
return buildCallIfWanted(doStmt->getStartLoc(), ctx.Id_buildDo, arg);
207+
return buildCallIfWanted(doStmt->getStartLoc(), ctx.Id_buildDo, arg,
208+
/*argLabels=*/{ }, /*allowOneWay=*/true);
205209
}
206210

207211
CONTROL_FLOW_STMT(Yield)
@@ -286,7 +290,12 @@ class BuilderClosureVisitor
286290
// so we just need to call `buildIf` now, since we're at the top level.
287291
if (isOptional) {
288292
chainExpr = buildCallIfWanted(ifStmt->getStartLoc(),
289-
ctx.Id_buildIf, chainExpr);
293+
ctx.Id_buildIf, chainExpr,
294+
/*argLabels=*/{ },
295+
/*allowOneWay=*/true);
296+
} else if (ctx.LangOpts.FunctionBuilderOneWayConstraints) {
297+
// Form a one-way constraint to prevent backward propagation.
298+
chainExpr = new (ctx) OneWayExpr(chainExpr);
290299
}
291300

292301
return chainExpr;
@@ -406,7 +415,8 @@ class BuilderClosureVisitor
406415
bool isSecond = (path & 1);
407416
operand = buildCallIfWanted(operand->getStartLoc(),
408417
ctx.Id_buildEither, operand,
409-
{isSecond ? ctx.Id_second : ctx.Id_first});
418+
{isSecond ? ctx.Id_second : ctx.Id_first},
419+
/*allowOneWay=*/false);
410420
}
411421

412422
// Inject into Optional if required. We'll be adding the call to

branches/master-next/lib/Sema/ConstraintGraph.cpp

Lines changed: 135 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,26 @@ namespace {
723723
}
724724

725725
private:
726+
/// Perform the union of two type variables in a union-find data structure
727+
/// used for connected components.
728+
///
729+
/// \returns true if the two components were separate and have now been
730+
/// joined, \c false if they were already in the same set.
731+
bool unionSets(TypeVariableType *typeVar1, TypeVariableType *typeVar2) {
732+
auto rep1 = findRepresentative(typeVar1);
733+
auto rep2 = findRepresentative(typeVar2);
734+
if (rep1 == rep2)
735+
return false;
736+
737+
// Reparent the type variable with the higher ID. The actual choice doesn't
738+
// matter, but this makes debugging easier.
739+
if (rep1->getID() < rep2->getID())
740+
representatives[rep2] = rep1;
741+
else
742+
representatives[rep1] = rep2;
743+
return true;
744+
}
745+
726746
/// Perform the connected components algorithm, skipping one-way
727747
/// constraints.
728748
///
@@ -773,24 +793,24 @@ namespace {
773793
vector.push_back(typeVar);
774794
}
775795

776-
/// Build the directed graph of one-way constraints among components.
777-
void buildOneWayConstraintGraph(ArrayRef<Constraint *> oneWayConstraints) {
778-
/// Retrieve the set of representatives for the type variables that
779-
/// occur within the given type.
780-
auto getRepresentativesInType = [&](Type type) {
781-
TinyPtrVector<TypeVariableType *> results;
782-
783-
SmallVector<TypeVariableType *, 2> typeVars;
784-
type->getTypeVariables(typeVars);
785-
for (auto typeVar : typeVars) {
786-
auto rep = findRepresentative(typeVar);
787-
insertIfUnique(results, rep);
788-
}
796+
/// Retrieve the (uniqued) set of type variable representations that occur
797+
/// within the given type.
798+
TinyPtrVector<TypeVariableType *>
799+
getRepresentativesInType(Type type) const {
800+
TinyPtrVector<TypeVariableType *> results;
789801

790-
return results;
791-
};
802+
SmallVector<TypeVariableType *, 2> typeVars;
803+
type->getTypeVariables(typeVars);
804+
for (auto typeVar : typeVars) {
805+
auto rep = findRepresentative(typeVar);
806+
insertIfUnique(results, rep);
807+
}
808+
809+
return results;
810+
}
792811

793-
// Add all of the one-way constraint edges to the digraph.
812+
/// Add all of the one-way constraints to the one-way digraph
813+
void addOneWayConstraintEdges(ArrayRef<Constraint *> oneWayConstraints) {
794814
for (auto constraint : oneWayConstraints) {
795815
auto lhsTypeReps =
796816
getRepresentativesInType(constraint->getFirstType());
@@ -803,30 +823,82 @@ namespace {
803823
// be solved before the left-hand type variables.
804824
for (auto lhsTypeRep : lhsTypeReps) {
805825
for (auto rhsTypeRep : rhsTypeReps) {
826+
if (lhsTypeRep == rhsTypeRep)
827+
break;
828+
806829
insertIfUnique(oneWayDigraph[rhsTypeRep].outAdjacencies,lhsTypeRep);
807830
insertIfUnique(oneWayDigraph[lhsTypeRep].inAdjacencies,rhsTypeRep);
808831
}
809832
}
810833
}
834+
}
835+
836+
using TypeVariablePair = std::pair<TypeVariableType *, TypeVariableType *>;
837+
838+
/// Build the directed graph of one-way constraints among components.
839+
void buildOneWayConstraintGraph(ArrayRef<Constraint *> oneWayConstraints) {
840+
auto &cs = cg.getConstraintSystem();
841+
auto &ctx = cs.getASTContext();
842+
bool contractedCycle = false;
843+
do {
844+
// Construct the one-way digraph from scratch.
845+
oneWayDigraph.clear();
846+
addOneWayConstraintEdges(oneWayConstraints);
847+
848+
// Minimize the in-adjacencies, detecting cycles along the way.
849+
SmallVector<TypeVariablePair, 4> cycleEdges;
850+
removeIndirectOneWayInAdjacencies(cycleEdges);
851+
852+
// For any contractions we need to perform due to cycles, perform a
853+
// union the connected components based on the type variable pairs.
854+
contractedCycle = false;
855+
for (const auto &edge : cycleEdges) {
856+
if (unionSets(edge.first, edge.second)) {
857+
if (ctx.LangOpts.DebugConstraintSolver) {
858+
auto &log = ctx.TypeCheckerDebug->getStream();
859+
if (cs.solverState)
860+
log.indent(cs.solverState->depth * 2);
861+
862+
log << "Collapsing one-way components for $T"
863+
<< edge.first->getID() << " and $T" << edge.second->getID()
864+
<< " due to cycle.\n";
865+
}
866+
867+
if (ctx.Stats) {
868+
ctx.Stats->getFrontendCounters()
869+
.NumCyclicOneWayComponentsCollapsed++;
870+
}
811871

812-
// Minimize the in-adjacencies.
813-
removeIndirectOneWayInAdjacencies();
872+
contractedCycle = true;
873+
}
874+
}
875+
} while (contractedCycle);
814876
}
815877

816878
/// Perform a depth-first search to produce a from the given type variable,
817-
/// notifying the function object \c postVisit after each reachable
818-
/// type variable has been visited.
879+
/// notifying the function object.
880+
///
881+
/// \param getAdjacencies Called to retrieve the set of type variables
882+
/// that are adjacent to the given type variable.
883+
///
884+
/// \param preVisit Called before visiting the adjacencies of the given
885+
/// type variable. When it returns \c true, the adjacencies of this type
886+
/// variable will be visited. When \c false, the adjacencies will not be
887+
/// visited and \c postVisit will not be called.
888+
///
889+
/// \param postVisit Called after visiting the adjacencies of the given
890+
/// type variable.
819891
static void postorderDepthFirstSearchRec(
820892
TypeVariableType *typeVar,
821893
llvm::function_ref<
822894
ArrayRef<TypeVariableType *>(TypeVariableType *)> getAdjacencies,
823-
llvm::function_ref<void(TypeVariableType *)> postVisit,
824-
SmallPtrSet<TypeVariableType *, 4> &visited) {
825-
if (!visited.insert(typeVar).second)
895+
llvm::function_ref<bool(TypeVariableType *)> preVisit,
896+
llvm::function_ref<void(TypeVariableType *)> postVisit) {
897+
if (!preVisit(typeVar))
826898
return;
827899

828900
for (auto adj : getAdjacencies(typeVar)) {
829-
postorderDepthFirstSearchRec(adj, getAdjacencies, postVisit, visited);
901+
postorderDepthFirstSearchRec(adj, getAdjacencies, preVisit, postVisit);
830902
}
831903

832904
postVisit(typeVar);
@@ -835,14 +907,17 @@ namespace {
835907
/// Minimize the incoming adjacencies for one of the nodes in the one-way
836908
/// directed graph by eliminating any in-adjacencies that can also be
837909
/// found indirectly.
838-
void removeIndirectOneWayInAdjacencies(TypeVariableType *typeVar,
839-
OneWayComponent &component) {
910+
void removeIndirectOneWayInAdjacencies(
911+
TypeVariableType *typeVar,
912+
OneWayComponent &component,
913+
SmallVectorImpl<TypeVariablePair> &cycleEdges) {
840914
// Perform a depth-first search from each of the in adjacencies to
841915
// this type variable, traversing each of the one-way edges backwards
842916
// to find all of the components whose type variables must be
843917
// bound before this component can be solved.
844918
SmallPtrSet<TypeVariableType *, 4> visited;
845919
SmallPtrSet<TypeVariableType *, 4> indirectlyReachable;
920+
SmallVector<TypeVariableType *, 4> currentPath;
846921
for (auto inAdj : component.inAdjacencies) {
847922
postorderDepthFirstSearchRec(
848923
inAdj,
@@ -855,14 +930,37 @@ namespace {
855930

856931
return oneWayComponent->second.inAdjacencies;
857932
},
933+
[&](TypeVariableType *typeVar) {
934+
// If we haven't seen this type variable yet, add it to the
935+
// path.
936+
if (visited.insert(typeVar).second) {
937+
currentPath.push_back(typeVar);
938+
return true;
939+
}
940+
941+
// Add edges between this type variable and every other type
942+
// variable in the path.
943+
for (auto otherTypeVar : reversed(currentPath)) {
944+
// When we run into our own type variable, we're done.
945+
if (otherTypeVar == typeVar)
946+
break;
947+
948+
cycleEdges.push_back({typeVar, otherTypeVar});
949+
}
950+
951+
return false;
952+
},
858953
[&](TypeVariableType *dependsOn) {
954+
// Remove this type variable from the path.
955+
assert(currentPath.back() == dependsOn);
956+
currentPath.pop_back();
957+
859958
// Don't record dependency on ourselves.
860959
if (dependsOn == inAdj)
861960
return;
862961

863962
indirectlyReachable.insert(dependsOn);
864-
},
865-
visited);
963+
});
866964

867965
// Remove any in-adjacency of this component that is indirectly
868966
// reachable.
@@ -879,11 +977,12 @@ namespace {
879977
/// Minimize the incoming adjacencies for all of the nodes in the one-way
880978
/// directed graph by eliminating any in-adjacencies that can also be
881979
/// found indirectly.
882-
void removeIndirectOneWayInAdjacencies() {
980+
void removeIndirectOneWayInAdjacencies(
981+
SmallVectorImpl<TypeVariablePair> &cycleEdges) {
883982
for (auto &oneWayEntry : oneWayDigraph) {
884983
auto typeVar = oneWayEntry.first;
885984
auto &component = oneWayEntry.second;
886-
removeIndirectOneWayInAdjacencies(typeVar, component);
985+
removeIndirectOneWayInAdjacencies(typeVar, component, cycleEdges);
887986
}
888987
}
889988

@@ -922,13 +1021,15 @@ namespace {
9221021

9231022
return oneWayComponent->second.outAdjacencies;
9241023
},
1024+
[&](TypeVariableType *typeVar) {
1025+
return visited.insert(typeVar).second;
1026+
},
9251027
[&](TypeVariableType *typeVar) {
9261028
// Record this type variable, if it's one of the representative
9271029
// type variables.
9281030
if (validComponents.count(typeVar) > 0)
9291031
orderedReps.push_back(typeVar);
930-
},
931-
visited);
1032+
});
9321033
}
9331034

9341035
assert(orderedReps.size() == representativeTypeVars.size());
@@ -1211,6 +1312,8 @@ void ConstraintGraph::printConnectedComponents(
12111312
}
12121313

12131314
void ConstraintGraph::dumpConnectedComponents() {
1315+
llvm::SaveAndRestore<bool>
1316+
debug(CS.getASTContext().LangOpts.DebugConstraintSolver, true);
12141317
printConnectedComponents(CS.TypeVariables, llvm::dbgs());
12151318
}
12161319

branches/master-next/test/Constraints/function_builder_one_way.swift

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ enum Either<T,U> {
88

99
@_functionBuilder
1010
struct TupleBuilder {
11+
static func buildBlock<T1>(_ t1: T1) -> T1 {
12+
return t1
13+
}
14+
1115
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
1216
return (t1, t2)
1317
}
@@ -44,16 +48,18 @@ func tuplify<C: Collection, T>(_ collection: C, @TupleBuilder body: (C.Element)
4448
}
4549

4650
// CHECK: ---Connected components---
47-
// CHECK-NEXT: 0: $T1 $T2 $T3 $T5 $T6 $T7 $T8 $T61 depends on 1
48-
// CHECK-NEXT: 1: $T9 $T11 $T13 $T16 $T30 $T54 $T55 $T56 $T57 $T58 $T59 $T60 depends on 2, 3, 4, 5, 6
49-
// CHECK-NEXT: 6: $T31 $T32 $T34 $T35 $T36 $T47 $T48 $T49 $T50 $T51 $T52 $T53 depends on 7
50-
// CHECK-NEXT: 7: $T37 $T39 $T43 $T44 $T45 $T46 depends on 8, 9
51-
// CHECK-NEXT: 9: $T40 $T41 $T42
52-
// CHECK-NEXT: 8: $T38
53-
// CHECK-NEXT: 5: $T17 $T18 $T19 $T20 $T21 $T22 $T23 $T24 $T25 $T26 $T27 $T28 $T29
54-
// CHECK-NEXT: 4: $T14 $T15
55-
// CHECK-NEXT: 3: $T12
56-
// CHECK-NEXT: 2: $T10
51+
// CHECK-NEXT: 0: $T1 $T2 $T3 $T5 $T6 $T7 $T8 $T69 depends on 1
52+
// CHECK-NEXT: 1: $T9 $T11 $T13 $T16 $T30 $T62 $T63 $T64 $T65 $T66 $T67 $T68 depends on 2, 3, 4, 5, 6
53+
// CHECK-NEXT: 6: $T32 $T43 $T44 $T45 $T46 $T47 $T57 $T58 $T59 $T60 $T61 depends on 7, 10
54+
// CHECK-NEXT: 10: $T48 $T54 $T55 $T56 depends on 11
55+
// CHECK-NEXT: 11: $T49 $T50 $T51 $T52 $T53
56+
// CHECK-NEXT: 7: $T33 $T35 $T39 $T40 $T41 $T42 depends on 8, 9
57+
// CHECK-NEXT: 9: $T36 $T37 $T38
58+
// CHECK-NEXT: 8: $T34
59+
// CHECK-NEXT: 5: $T17 $T18 $T19 $T20 $T21 $T22 $T23 $T24 $T25 $T26 $T27 $T28 $T29
60+
// CHECK-NEXT: 4: $T14 $T15
61+
// CHECK-NEXT: 3: $T12
62+
// CHECK-NEXT: 2: $T10
5763
let names = ["Alice", "Bob", "Charlie"]
5864
let b = true
5965
print(
@@ -67,5 +73,7 @@ print(
6773
if b {
6874
2.71828
6975
["if", "stmt"]
76+
} else {
77+
[1, 2, 3, 4]
7078
}
7179
})

0 commit comments

Comments
 (0)