Skip to content

Commit 51d260d

Browse files
committed
---
yaml --- r: 349385 b: refs/heads/master-next c: 10dbe46 h: refs/heads/master i: 349383: 07e7e7e
1 parent 71d4651 commit 51d260d

26 files changed

+913
-89
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: d328e44ea8b241e0c97e1c7e7fcb0d23ef936771
3+
refs/heads/master-next: 10dbe46226bfa28ddce7f8af1d219776cdf008e7
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/AST/Expr.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5321,6 +5321,33 @@ class KeyPathDotExpr : public Expr {
53215321
}
53225322
};
53235323

5324+
/// Expression node that effects a "one-way" constraint in
5325+
/// the constraint system, allowing type information to flow from the
5326+
/// subexpression outward but not the other way.
5327+
///
5328+
/// One-way expressions are generally implicit and synthetic, introduced by
5329+
/// the type checker. However, there is a built-in expression of the
5330+
/// form \c Builtin.one_way(x) that forms a one-way constraint coming out
5331+
/// of expression `x` that can be used for testing purposes.
5332+
class OneWayExpr : public Expr {
5333+
Expr *SubExpr;
5334+
5335+
public:
5336+
/// Construct an implicit one-way expression from the given subexpression.
5337+
OneWayExpr(Expr *subExpr)
5338+
: Expr(ExprKind::OneWay, /*isImplicit=*/true), SubExpr(subExpr) { }
5339+
5340+
SourceLoc getLoc() const { return SubExpr->getLoc(); }
5341+
SourceRange getSourceRange() const { return SubExpr->getSourceRange(); }
5342+
5343+
Expr *getSubExpr() const { return SubExpr; }
5344+
void setSubExpr(Expr *subExpr) { SubExpr = subExpr; }
5345+
5346+
static bool classof(const Expr *E) {
5347+
return E->getKind() == ExprKind::OneWay;
5348+
}
5349+
};
5350+
53245351
inline bool Expr::isInfixOperator() const {
53255352
return isa<BinaryExpr>(this) || isa<IfExpr>(this) ||
53265353
isa<AssignExpr>(this) || isa<ExplicitCastExpr>(this);

branches/master-next/include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ EXPR(EditorPlaceholder, Expr)
191191
EXPR(ObjCSelector, Expr)
192192
EXPR(KeyPath, Expr)
193193
UNCHECKED_EXPR(KeyPathDot, Expr)
194+
UNCHECKED_EXPR(OneWay, Expr)
194195
EXPR(Tap, Expr)
195196
LAST_EXPR(Tap)
196197

branches/master-next/include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ namespace swift {
215215
/// before termination of the shrink phrase of the constraint solver.
216216
unsigned SolverShrinkUnsolvedThreshold = 10;
217217

218+
/// Enable one-way constraints in function builders.
219+
bool FunctionBuilderOneWayConstraints = false;
220+
218221
/// Disable the shrink phase of the expression type checker.
219222
bool SolverDisableShrink = false;
220223

branches/master-next/include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@ def Rmodule_interface_rebuild : Flag<["-"], "Rmodule-interface-rebuild">,
404404

405405
def solver_expression_time_threshold_EQ : Joined<["-"], "solver-expression-time-threshold=">;
406406

407+
def enable_function_builder_one_way_constraints : Flag<["-"],
408+
"enable-function-builder-one-way-constraints">,
409+
HelpText<"Enable one-way constraints in the function builder transformation">;
410+
407411
def solver_disable_shrink :
408412
Flag<["-"], "solver-disable-shrink">,
409413
HelpText<"Disable the shrink phase of expression type checking">;

branches/master-next/lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,6 +2794,13 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
27942794
PrintWithColorRAII(OS, ParenthesisColor) << ')';
27952795
}
27962796

2797+
void visitOneWayExpr(OneWayExpr *E) {
2798+
printCommon(E, "one_way_expr");
2799+
OS << '\n';
2800+
printRec(E->getSubExpr());
2801+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
2802+
}
2803+
27972804
void visitTapExpr(TapExpr *E) {
27982805
printCommon(E, "tap_expr");
27992806
PrintWithColorRAII(OS, DeclColor) << " var=";

branches/master-next/lib/AST/ASTWalker.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,18 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
11141114

11151115
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) { return E; }
11161116

1117+
Expr *visitOneWayExpr(OneWayExpr *E) {
1118+
if (auto oldSubExpr = E->getSubExpr()) {
1119+
if (auto subExpr = doIt(oldSubExpr)) {
1120+
E->setSubExpr(subExpr);
1121+
} else {
1122+
return nullptr;
1123+
}
1124+
}
1125+
1126+
return E;
1127+
}
1128+
11171129
Expr *visitTapExpr(TapExpr *E) {
11181130
if (auto oldSubExpr = E->getSubExpr()) {
11191131
if (auto subExpr = doIt(oldSubExpr)) {

branches/master-next/lib/AST/Expr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ ConcreteDeclRef Expr::getReferencedDecl() const {
368368
NO_REFERENCE(ObjCSelector);
369369
NO_REFERENCE(KeyPath);
370370
NO_REFERENCE(KeyPathDot);
371+
PASS_THROUGH_REFERENCE(OneWay, getSubExpr);
371372
NO_REFERENCE(Tap);
372373

373374
#undef SIMPLE_REFERENCE
@@ -539,6 +540,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
539540
case ExprKind::Error:
540541
case ExprKind::CodeCompletion:
541542
case ExprKind::LazyInitializer:
543+
case ExprKind::OneWay:
542544
return false;
543545

544546
case ExprKind::NilLiteral:

branches/master-next/lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
441441

442442
if (Args.getLastArg(OPT_solver_disable_shrink))
443443
Opts.SolverDisableShrink = true;
444+
if (Args.getLastArg(OPT_enable_function_builder_one_way_constraints))
445+
Opts.FunctionBuilderOneWayConstraints = true;
444446

445447
if (const Arg *A = Args.getLastArg(OPT_value_recursion_threshold)) {
446448
unsigned threshold;

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

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ class BuilderClosureVisitor
5050

5151
private:
5252
/// Produce a builder call to the given named function with the given arguments.
53-
CallExpr *buildCallIfWanted(SourceLoc loc,
54-
Identifier fnName, ArrayRef<Expr *> args,
55-
ArrayRef<Identifier> argLabels = {}) {
53+
Expr *buildCallIfWanted(SourceLoc loc,
54+
Identifier fnName, ArrayRef<Expr *> args,
55+
ArrayRef<Identifier> argLabels = {}) {
5656
if (!wantExpr)
5757
return nullptr;
5858

@@ -81,9 +81,17 @@ class BuilderClosureVisitor
8181
typeExpr, loc, fnName, DeclNameLoc(loc), /*implicit=*/true);
8282
SourceLoc openLoc = args.empty() ? loc : args.front()->getStartLoc();
8383
SourceLoc closeLoc = args.empty() ? loc : args.back()->getEndLoc();
84-
return CallExpr::create(ctx, memberRef, openLoc, args,
85-
argLabels, argLabelLocs, closeLoc,
86-
/*trailing closure*/ nullptr, /*implicit*/true);
84+
Expr *result = CallExpr::create(ctx, memberRef, openLoc, args,
85+
argLabels, argLabelLocs, closeLoc,
86+
/*trailing closure*/ nullptr,
87+
/*implicit*/true);
88+
89+
if (ctx.LangOpts.FunctionBuilderOneWayConstraints) {
90+
// Form a one-way constraint to prevent backward propagation.
91+
result = new (ctx) OneWayExpr(result);
92+
}
93+
94+
return result;
8795
}
8896

8997
/// Check whether the builder supports the given operation.
@@ -160,6 +168,9 @@ class BuilderClosureVisitor
160168
}
161169

162170
auto expr = node.get<Expr *>();
171+
if (wantExpr && ctx.LangOpts.FunctionBuilderOneWayConstraints)
172+
expr = new (ctx) OneWayExpr(expr);
173+
163174
expressions.push_back(expr);
164175
}
165176

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,6 +4634,10 @@ namespace {
46344634
llvm_unreachable("found KeyPathDotExpr in CSApply");
46354635
}
46364636

4637+
Expr *visitOneWayExpr(OneWayExpr *E) {
4638+
return E->getSubExpr();
4639+
}
4640+
46374641
Expr *visitTapExpr(TapExpr *E) {
46384642
auto type = simplifyType(cs.getType(E));
46394643

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,18 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
632632
result.FullyBound = true;
633633
}
634634
break;
635+
636+
case ConstraintKind::OneWayBind: {
637+
// Don't produce any bindings if this type variable is on the left-hand
638+
// side of a one-way binding.
639+
auto firstType = constraint->getFirstType();
640+
if (auto *tv = firstType->getAs<TypeVariableType>()) {
641+
if (tv->getImpl().getRepresentative(nullptr) == typeVar)
642+
return {typeVar};
643+
}
644+
645+
break;
646+
}
635647
}
636648
}
637649

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

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3080,6 +3080,14 @@ namespace {
30803080
llvm_unreachable("found KeyPathDotExpr in CSGen");
30813081
}
30823082

3083+
Type visitOneWayExpr(OneWayExpr *expr) {
3084+
auto locator = CS.getConstraintLocator(expr);
3085+
auto resultTypeVar = CS.createTypeVariable(locator, 0);
3086+
CS.addConstraint(ConstraintKind::OneWayBind, resultTypeVar,
3087+
CS.getType(expr->getSubExpr()), locator);
3088+
return resultTypeVar;
3089+
}
3090+
30833091
Type visitTapExpr(TapExpr *expr) {
30843092
DeclContext *varDC = expr->getVar()->getDeclContext();
30853093
assert(varDC == CS.DC || (varDC && isa<AbstractClosureExpr>(varDC)) &&
@@ -3113,7 +3121,8 @@ namespace {
31133121
Join,
31143122
JoinInout,
31153123
JoinMeta,
3116-
JoinNonexistent
3124+
JoinNonexistent,
3125+
OneWay,
31173126
};
31183127

31193128
static TypeOperation getTypeOperation(UnresolvedDotExpr *UDE,
@@ -3127,6 +3136,7 @@ namespace {
31273136

31283137
return llvm::StringSwitch<TypeOperation>(
31293138
UDE->getName().getBaseIdentifier().str())
3139+
.Case("one_way", TypeOperation::OneWay)
31303140
.Case("type_join", TypeOperation::Join)
31313141
.Case("type_join_inout", TypeOperation::JoinInout)
31323142
.Case("type_join_meta", TypeOperation::JoinMeta)
@@ -3135,14 +3145,14 @@ namespace {
31353145
}
31363146

31373147
Type resultOfTypeOperation(TypeOperation op, Expr *Arg) {
3138-
auto *tuple = dyn_cast<TupleExpr>(Arg);
3139-
assert(tuple && "Expected argument tuple for join operations!");
3148+
auto *tuple = cast<TupleExpr>(Arg);
31403149

31413150
auto *lhs = tuple->getElement(0);
31423151
auto *rhs = tuple->getElement(1);
31433152

31443153
switch (op) {
31453154
case TypeOperation::None:
3155+
case TypeOperation::OneWay:
31463156
llvm_unreachable(
31473157
"We should have a valid type operation at this point!");
31483158

@@ -3582,18 +3592,23 @@ namespace {
35823592
/// Once we've visited the children of the given expression,
35833593
/// generate constraints from the expression.
35843594
Expr *walkToExprPost(Expr *expr) override {
3585-
3586-
// Handle the Builtin.type_join* family of calls by replacing
3587-
// them with dot_self_expr of type_expr with the type being the
3588-
// result of the join.
3595+
// Translate special type-checker Builtin calls into simpler expressions.
35893596
if (auto *apply = dyn_cast<ApplyExpr>(expr)) {
35903597
auto fnExpr = apply->getFn();
35913598
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(fnExpr)) {
35923599
auto &CS = CG.getConstraintSystem();
35933600
auto typeOperation =
35943601
ConstraintGenerator::getTypeOperation(UDE, CS.getASTContext());
35953602

3596-
if (typeOperation != ConstraintGenerator::TypeOperation::None) {
3603+
if (typeOperation == ConstraintGenerator::TypeOperation::OneWay) {
3604+
// For a one-way constraint, create the OneWayExpr node.
3605+
auto *arg = cast<ParenExpr>(apply->getArg())->getSubExpr();
3606+
expr = new (CS.getASTContext()) OneWayExpr(arg);
3607+
} else if (typeOperation !=
3608+
ConstraintGenerator::TypeOperation::None) {
3609+
// Handle the Builtin.type_join* family of calls by replacing
3610+
// them with dot_self_expr of type_expr with the type being the
3611+
// result of the join.
35973612
auto joinMetaTy =
35983613
CG.resultOfTypeOperation(typeOperation, apply->getArg());
35993614
auto joinTy = joinMetaTy->castTo<MetatypeType>()->getInstanceType();

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
11461146
case ConstraintKind::BridgingConversion:
11471147
case ConstraintKind::FunctionInput:
11481148
case ConstraintKind::FunctionResult:
1149+
case ConstraintKind::OneWayBind:
11491150
llvm_unreachable("Not a conversion");
11501151
}
11511152

@@ -1208,6 +1209,7 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
12081209
case ConstraintKind::ValueMember:
12091210
case ConstraintKind::FunctionInput:
12101211
case ConstraintKind::FunctionResult:
1212+
case ConstraintKind::OneWayBind:
12111213
return false;
12121214
}
12131215

@@ -1385,6 +1387,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
13851387
case ConstraintKind::BridgingConversion:
13861388
case ConstraintKind::FunctionInput:
13871389
case ConstraintKind::FunctionResult:
1390+
case ConstraintKind::OneWayBind:
13881391
llvm_unreachable("Not a relational constraint");
13891392
}
13901393

@@ -2768,6 +2771,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
27682771
case ConstraintKind::ValueMember:
27692772
case ConstraintKind::FunctionInput:
27702773
case ConstraintKind::FunctionResult:
2774+
case ConstraintKind::OneWayBind:
27712775
llvm_unreachable("Not a relational constraint");
27722776
}
27732777
}
@@ -5175,6 +5179,29 @@ ConstraintSystem::simplifyDefaultableConstraint(
51755179
return SolutionKind::Solved;
51765180
}
51775181

5182+
ConstraintSystem::SolutionKind
5183+
ConstraintSystem::simplifyOneWayConstraint(
5184+
ConstraintKind kind,
5185+
Type first, Type second, TypeMatchOptions flags,
5186+
ConstraintLocatorBuilder locator) {
5187+
// Determine whether the second type can be fully simplified. Only then
5188+
// will this constraint be resolved.
5189+
Type secondSimplified = simplifyType(second);
5190+
if (secondSimplified->hasTypeVariable()) {
5191+
if (flags.contains(TMF_GenerateConstraints)) {
5192+
addUnsolvedConstraint(
5193+
Constraint::create(*this, kind, first, second,
5194+
getConstraintLocator(locator)));
5195+
return SolutionKind::Solved;
5196+
}
5197+
5198+
return SolutionKind::Unsolved;
5199+
}
5200+
5201+
// Translate this constraint into a one-way binding constraint.
5202+
return matchTypes(first, secondSimplified, ConstraintKind::Bind, flags,
5203+
locator);
5204+
}
51785205

51795206
ConstraintSystem::SolutionKind
51805207
ConstraintSystem::simplifyDynamicTypeOfConstraint(
@@ -7203,6 +7230,9 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
72037230
return simplifyFunctionComponentConstraint(kind, first, second,
72047231
subflags, locator);
72057232

7233+
case ConstraintKind::OneWayBind:
7234+
return simplifyOneWayConstraint(kind, first, second, subflags, locator);
7235+
72067236
case ConstraintKind::ValueMember:
72077237
case ConstraintKind::UnresolvedValueMember:
72087238
case ConstraintKind::BindOverload:
@@ -7558,6 +7588,13 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
75587588
case ConstraintKind::Disjunction:
75597589
// Disjunction constraints are never solved here.
75607590
return SolutionKind::Unsolved;
7591+
7592+
case ConstraintKind::OneWayBind:
7593+
return simplifyOneWayConstraint(constraint.getKind(),
7594+
constraint.getFirstType(),
7595+
constraint.getSecondType(),
7596+
TMF_GenerateConstraints,
7597+
constraint.getLocator());
75617598
}
75627599

75637600
llvm_unreachable("Unhandled ConstraintKind in switch.");

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,11 @@ Solution ConstraintSystem::finalize() {
150150
// multiple entries. We should use an optimized PartialSolution
151151
// structure for that use case, which would optimize a lot of
152152
// stuff here.
153+
#if false
153154
assert((solution.OpenedTypes.count(opened.first) == 0 ||
154155
solution.OpenedTypes[opened.first] == opened.second)
155156
&& "Already recorded");
157+
#endif
156158
solution.OpenedTypes.insert(opened);
157159
}
158160

@@ -1681,6 +1683,7 @@ void ConstraintSystem::ArgumentInfoCollector::walk(Type argType) {
16811683
case ConstraintKind::SelfObjectOfProtocol:
16821684
case ConstraintKind::ConformsTo:
16831685
case ConstraintKind::Defaultable:
1686+
case ConstraintKind::OneWayBind:
16841687
break;
16851688
}
16861689
}

0 commit comments

Comments
 (0)