Skip to content

Commit 8269522

Browse files
authored
Merge pull request #28837 from xedin/rdar-56340587
[ConstraintSystem] Delay constraint generation for single-statement closure body
2 parents 53c008f + 4eda042 commit 8269522

27 files changed

+704
-314
lines changed

include/swift/AST/Types.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3388,7 +3388,6 @@ END_CAN_TYPE_WRAPPER(FunctionType, AnyFunctionType)
33883388
/// has a default argument.
33893389
struct ParameterListInfo {
33903390
SmallBitVector defaultArguments;
3391-
std::vector<Type> functionBuilderTypes;
33923391

33933392
public:
33943393
ParameterListInfo() { }
@@ -3406,9 +3405,6 @@ struct ParameterListInfo {
34063405

34073406
/// Retrieve the number of parameters for which we have information.
34083407
unsigned size() const { return defaultArguments.size(); }
3409-
3410-
/// Retrieve the function builder type for the given parameter.
3411-
Type getFunctionBuilderType(unsigned paramIdx) const;
34123408
};
34133409

34143410
/// Turn a param list into a symbolic and printable representation that does not

lib/AST/Type.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,6 @@ ParameterListInfo::ParameterListInfo(
818818
const ValueDecl *paramOwner,
819819
bool skipCurriedSelf) {
820820
defaultArguments.resize(params.size());
821-
functionBuilderTypes.resize(params.size());
822821

823822
// No parameter owner means no parameter list means no default arguments
824823
// - hand back the zeroed bitvector.
@@ -863,10 +862,6 @@ ParameterListInfo::ParameterListInfo(
863862
if (param->isDefaultArgument()) {
864863
defaultArguments.set(i);
865864
}
866-
867-
if (Type functionBuilderType = param->getFunctionBuilderType()) {
868-
functionBuilderTypes[i] = functionBuilderType;
869-
}
870865
}
871866
}
872867

@@ -875,12 +870,6 @@ bool ParameterListInfo::hasDefaultArgument(unsigned paramIdx) const {
875870
: false;
876871
}
877872

878-
Type ParameterListInfo::getFunctionBuilderType(unsigned paramIdx) const {
879-
return paramIdx < functionBuilderTypes.size()
880-
? functionBuilderTypes[paramIdx]
881-
: Type();
882-
}
883-
884873
/// Turn a param list into a symbolic and printable representation that does not
885874
/// include the types, something like (_:, b:, c:)
886875
std::string swift::getParamListAsString(ArrayRef<AnyFunctionType::Param> params) {

lib/Sema/BuilderTransform.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -615,13 +615,6 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::matchFunctionBuilder(
615615
assert(builder && "Bad function builder type");
616616
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
617617

618-
// FIXME: Right now, single-expression closures suppress the function
619-
// builder translation.
620-
if (auto closure = fn.getAbstractClosureExpr()) {
621-
if (closure->hasSingleExpressionBody())
622-
return getTypeMatchSuccess();
623-
}
624-
625618
// Pre-check the body: pre-check any expressions in it and look
626619
// for return statements.
627620
auto request = PreCheckFunctionBuilderRequest{fn};
@@ -716,6 +709,12 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::matchFunctionBuilder(
716709
fn,
717710
AppliedBuilderTransform{builderType, singleExpr, bodyResultType}));
718711

712+
// If builder is applied to the closure expression then
713+
// `closure body` to `closure result` matching should
714+
// use special locator.
715+
if (auto *closure = fn.getAbstractClosureExpr())
716+
locator = getConstraintLocator(closure, ConstraintLocator::ClosureResult);
717+
719718
// Bind the body result type to the type of the transformed expression.
720719
addConstraint(bodyResultConstraintKind, transformedType, bodyResultType,
721720
locator);

lib/Sema/CSApply.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
152152
return true;
153153
}
154154

155+
ConstraintLocator *Solution::getCalleeLocator(ConstraintLocator *locator,
156+
bool lookThroughApply) const {
157+
auto &cs = getConstraintSystem();
158+
return cs.getCalleeLocator(
159+
locator, lookThroughApply,
160+
[&](const Expr *expr) -> Type { return getType(expr); },
161+
[&](Type type) -> Type { return simplifyType(type)->getRValueType(); },
162+
[&](ConstraintLocator *locator) -> Optional<SelectedOverload> {
163+
return getOverloadChoiceIfAvailable(locator);
164+
});
165+
}
166+
155167
/// Return the implicit access kind for a MemberRefExpr with the
156168
/// specified base and member in the specified DeclContext.
157169
static AccessSemantics
@@ -7412,6 +7424,21 @@ ProtocolConformanceRef Solution::resolveConformance(
74127424
return ProtocolConformanceRef::forInvalid();
74137425
}
74147426

7427+
Type Solution::getType(const Expr *expr) const {
7428+
auto result = llvm::find_if(
7429+
addedNodeTypes, [&](const std::pair<TypedNode, Type> &node) -> bool {
7430+
if (auto *e = node.first.dyn_cast<const Expr *>())
7431+
return expr == e;
7432+
return false;
7433+
});
7434+
7435+
if (result != addedNodeTypes.end())
7436+
return result->second;
7437+
7438+
auto &cs = getConstraintSystem();
7439+
return cs.getType(expr);
7440+
}
7441+
74157442
void Solution::setExprTypes(Expr *expr) const {
74167443
if (!expr)
74177444
return;

lib/Sema/CSBindings.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,22 @@ bool ConstraintSystem::PotentialBindings::isViable(
228228
return true;
229229
}
230230

231+
bool ConstraintSystem::PotentialBindings::favoredOverDisjunction() const {
232+
if (IsHole || FullyBound)
233+
return false;
234+
235+
// If this bindings are for a closure and there are no holes,
236+
// it shouldn't matter whether it there are any type variables
237+
// or not because e.g. parameter type can have type variables,
238+
// but we still want to resolve closure body early (instead of
239+
// attempting any disjunction) to gain additional contextual
240+
// information.
241+
if (TypeVar->getImpl().isClosureType())
242+
return true;
243+
244+
return !InvolvesTypeVariables;
245+
}
246+
231247
static bool hasNilLiteralConstraint(TypeVariableType *typeVar,
232248
const ConstraintSystem &CS) {
233249
// Look for a literal-conformance constraint on the type variable.
@@ -353,6 +369,11 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
353369

354370
result.InvolvesTypeVariables = true;
355371

372+
if (constraint->getKind() == ConstraintKind::Subtype &&
373+
kind == AllowedBindingKind::Subtypes) {
374+
result.SubtypeOf.insert(bindingTypeVar);
375+
}
376+
356377
// If we've already set addOptionalSupertypeBindings, or we aren't
357378
// allowing supertype bindings, we're done.
358379
if (addOptionalSupertypeBindings || kind != AllowedBindingKind::Supertypes)
@@ -525,6 +546,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
525546
}
526547

527548
case ConstraintKind::Defaultable:
549+
case ConstraintKind::DefaultClosureType:
528550
// Do these in a separate pass.
529551
if (getFixedTypeRecursive(constraint->getFirstType(), true)
530552
->getAs<TypeVariableType>() == typeVar) {
@@ -749,6 +771,15 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
749771
if (!exactTypes.insert(type->getCanonicalType()).second)
750772
continue;
751773

774+
if (constraint->getKind() == ConstraintKind::DefaultClosureType) {
775+
// If there are no other possible bindings for this closure
776+
// let's default it to the type inferred from its parameters/body,
777+
// otherwise we should only attempt contextual types as a
778+
// top-level closure type.
779+
if (!result.Bindings.empty())
780+
continue;
781+
}
782+
752783
result.addPotentialBinding({type, AllowedBindingKind::Exact, constraint});
753784
}
754785

lib/Sema/CSDiagnostics.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,18 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
639639
case ConstraintLocator::ContextualType: {
640640
auto purpose = getContextualTypePurpose();
641641
assert(!(purpose == CTP_Unused && purpose == CTP_CannotFail));
642+
643+
// If this is call to a closure e.g. `let _: A = { B() }()`
644+
// let's point diagnostic to its result.
645+
if (auto *call = dyn_cast<CallExpr>(anchor)) {
646+
auto *fnExpr = call->getFn();
647+
if (auto *closure = dyn_cast<ClosureExpr>(fnExpr)) {
648+
purpose = CTP_ClosureResult;
649+
if (closure->hasSingleExpressionBody())
650+
anchor = closure->getSingleExpressionBody();
651+
}
652+
}
653+
642654
diagnostic = getDiagnosticFor(purpose);
643655
break;
644656
}
@@ -1958,6 +1970,11 @@ bool ContextualFailure::diagnoseAsError() {
19581970
return true;
19591971
}
19601972

1973+
if (auto *call = dyn_cast<CallExpr>(anchor)) {
1974+
if (isa<ClosureExpr>(call->getFn()))
1975+
CTP = CTP_ClosureResult;
1976+
}
1977+
19611978
if (auto msg = getDiagnosticFor(CTP, toType->isExistentialType())) {
19621979
diagnostic = *msg;
19631980
break;
@@ -2621,7 +2638,15 @@ bool ContextualFailure::trySequenceSubsequenceFixIts(
26212638
if (auto *CE = dyn_cast<CoerceExpr>(anchor)) {
26222639
anchor = CE->getSubExpr();
26232640
}
2624-
2641+
2642+
if (auto *call = dyn_cast<CallExpr>(anchor)) {
2643+
auto *fnExpr = call->getFn();
2644+
if (auto *closure = dyn_cast<ClosureExpr>(fnExpr)) {
2645+
if (closure->hasSingleExpressionBody())
2646+
anchor = closure->getSingleExpressionBody();
2647+
}
2648+
}
2649+
26252650
auto range = anchor->getSourceRange();
26262651
diagnostic.fixItInsert(range.Start, "String(");
26272652
diagnostic.fixItInsertAfter(range.End, ")");

0 commit comments

Comments
 (0)