Skip to content

Commit 62b2570

Browse files
authored
Merge pull request #32215 from DougGregor/one-way-closure-params
[Experiment] One-way closure parameters
2 parents 77d4134 + 64f903f commit 62b2570

File tree

9 files changed

+73
-7
lines changed

9 files changed

+73
-7
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,10 @@ namespace swift {
549549
/// Enable constraint solver support for experimental
550550
/// operator protocol designator feature.
551551
bool SolverEnableOperatorDesignatedTypes = false;
552-
552+
553+
/// Enable experimental support for one-way constraints for the
554+
/// parameters of closures.
555+
bool EnableOneWayClosureParameters = false;
553556
};
554557
} // end namespace swift
555558

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ def experimental_print_full_convention :
642642
HelpText<"When emitting a module interface, emit additional @convention "
643643
"arguments, regardless of whether they were written in the source">;
644644

645+
def experimental_one_way_closure_params :
646+
Flag<["-"], "experimental-one-way-closure-params">,
647+
HelpText<"Enable experimental support for one-way closure parameters">;
648+
645649
def prebuilt_module_cache_path :
646650
Separate<["-"], "prebuilt-module-cache-path">,
647651
HelpText<"Directory of prebuilt modules for loading module interfaces">;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,8 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args,
724724

725725
Opts.SolverEnableOperatorDesignatedTypes |=
726726
Args.hasArg(OPT_solver_enable_operator_designated_types);
727+
Opts.EnableOneWayClosureParameters |=
728+
Args.hasArg(OPT_experimental_one_way_closure_params);
727729

728730
Opts.DebugConstraintSolver |= Args.hasArg(OPT_debug_constraints);
729731
Opts.DebugGenericSignatures |= Args.hasArg(OPT_debug_generic_signatures);

lib/Sema/CSBindings.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
710710
}
711711
break;
712712

713-
case ConstraintKind::OneWayEqual: {
713+
case ConstraintKind::OneWayEqual:
714+
case ConstraintKind::OneWayBindParam: {
714715
// Don't produce any bindings if this type variable is on the left-hand
715716
// side of a one-way binding.
716717
auto firstType = constraint->getFirstType();

lib/Sema/CSSimplify.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
13221322
case ConstraintKind::FunctionInput:
13231323
case ConstraintKind::FunctionResult:
13241324
case ConstraintKind::OneWayEqual:
1325+
case ConstraintKind::OneWayBindParam:
13251326
case ConstraintKind::DefaultClosureType:
13261327
llvm_unreachable("Not a conversion");
13271328
}
@@ -1387,6 +1388,7 @@ static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1,
13871388
case ConstraintKind::FunctionInput:
13881389
case ConstraintKind::FunctionResult:
13891390
case ConstraintKind::OneWayEqual:
1391+
case ConstraintKind::OneWayBindParam:
13901392
case ConstraintKind::DefaultClosureType:
13911393
return false;
13921394
}
@@ -1699,6 +1701,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
16991701
case ConstraintKind::FunctionInput:
17001702
case ConstraintKind::FunctionResult:
17011703
case ConstraintKind::OneWayEqual:
1704+
case ConstraintKind::OneWayBindParam:
17021705
case ConstraintKind::DefaultClosureType:
17031706
llvm_unreachable("Not a relational constraint");
17041707
}
@@ -4406,6 +4409,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
44064409
case ConstraintKind::FunctionInput:
44074410
case ConstraintKind::FunctionResult:
44084411
case ConstraintKind::OneWayEqual:
4412+
case ConstraintKind::OneWayBindParam:
44094413
case ConstraintKind::DefaultClosureType:
44104414
llvm_unreachable("Not a relational constraint");
44114415
}
@@ -7121,9 +7125,16 @@ ConstraintSystem::simplifyOneWayConstraint(
71217125
return SolutionKind::Solved;
71227126
}
71237127

7124-
// Translate this constraint into a one-way binding constraint.
7125-
return matchTypes(first, secondSimplified, ConstraintKind::Equal, flags,
7126-
locator);
7128+
// Translate this constraint into an equality or bind-parameter constraint,
7129+
// as appropriate.
7130+
if (kind == ConstraintKind::OneWayEqual) {
7131+
return matchTypes(first, secondSimplified, ConstraintKind::Equal, flags,
7132+
locator);
7133+
}
7134+
7135+
assert(kind == ConstraintKind::OneWayBindParam);
7136+
return matchTypes(
7137+
secondSimplified, first, ConstraintKind::BindParam, flags, locator);
71277138
}
71287139

71297140
static Type getFunctionBuilderTypeFor(ConstraintSystem &cs, unsigned paramIdx,
@@ -7175,12 +7186,27 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
71757186

71767187
Type internalType;
71777188

7189+
bool oneWayConstraints =
7190+
getASTContext().TypeCheckerOpts.EnableOneWayClosureParameters;
71787191
if (paramList->get(i)->getTypeRepr()) {
71797192
// Internal type is the type used in the body of the closure,
71807193
// so "external" type translates to it as follows:
71817194
// - `Int...` -> `[Int]`,
71827195
// - `inout Int` -> `@lvalue Int`.
71837196
internalType = param.getParameterType();
7197+
7198+
// When there are type variables in the type and we have enabled
7199+
// one-way constraints, create a fresh type variable to handle the
7200+
// binding.
7201+
if (oneWayConstraints && internalType->hasTypeVariable()) {
7202+
auto *paramLoc =
7203+
getConstraintLocator(closure, LocatorPathElt::TupleElement(i));
7204+
auto *typeVar = createTypeVariable(paramLoc, TVO_CanBindToLValue |
7205+
TVO_CanBindToNoEscape);
7206+
addConstraint(
7207+
ConstraintKind::OneWayBindParam, typeVar, internalType, paramLoc);
7208+
internalType = typeVar;
7209+
}
71847210
} else {
71857211
auto *paramLoc =
71867212
getConstraintLocator(closure, LocatorPathElt::TupleElement(i));
@@ -7194,7 +7220,13 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
71947220
param.isVariadic() ? ArraySliceType::get(typeVar) : Type(typeVar);
71957221

71967222
auto externalType = param.getOldType();
7197-
addConstraint(ConstraintKind::BindParam, externalType, typeVar, paramLoc);
7223+
if (oneWayConstraints) {
7224+
addConstraint(
7225+
ConstraintKind::OneWayBindParam, typeVar, externalType, paramLoc);
7226+
} else {
7227+
addConstraint(
7228+
ConstraintKind::BindParam, externalType, typeVar, paramLoc);
7229+
}
71987230
}
71997231

72007232
setType(paramList->get(i), internalType);
@@ -9759,6 +9791,7 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
97599791
subflags, locator);
97609792

97619793
case ConstraintKind::OneWayEqual:
9794+
case ConstraintKind::OneWayBindParam:
97629795
return simplifyOneWayConstraint(kind, first, second, subflags, locator);
97639796

97649797
case ConstraintKind::ValueMember:
@@ -10271,6 +10304,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1027110304
return SolutionKind::Unsolved;
1027210305

1027310306
case ConstraintKind::OneWayEqual:
10307+
case ConstraintKind::OneWayBindParam:
1027410308
return simplifyOneWayConstraint(constraint.getKind(),
1027510309
constraint.getFirstType(),
1027610310
constraint.getSecondType(),

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,7 @@ void ConstraintSystem::ArgumentInfoCollector::walk(Type argType) {
16881688
case ConstraintKind::ConformsTo:
16891689
case ConstraintKind::Defaultable:
16901690
case ConstraintKind::OneWayEqual:
1691+
case ConstraintKind::OneWayBindParam:
16911692
case ConstraintKind::DefaultClosureType:
16921693
break;
16931694
}

lib/Sema/Constraint.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
6666
case ConstraintKind::FunctionResult:
6767
case ConstraintKind::OpaqueUnderlyingType:
6868
case ConstraintKind::OneWayEqual:
69+
case ConstraintKind::OneWayBindParam:
6970
assert(!First.isNull());
7071
assert(!Second.isNull());
7172
break;
@@ -138,6 +139,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
138139
case ConstraintKind::FunctionResult:
139140
case ConstraintKind::OpaqueUnderlyingType:
140141
case ConstraintKind::OneWayEqual:
142+
case ConstraintKind::OneWayBindParam:
141143
case ConstraintKind::DefaultClosureType:
142144
llvm_unreachable("Wrong constructor");
143145

@@ -265,6 +267,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
265267
case ConstraintKind::FunctionResult:
266268
case ConstraintKind::OpaqueUnderlyingType:
267269
case ConstraintKind::OneWayEqual:
270+
case ConstraintKind::OneWayBindParam:
268271
case ConstraintKind::DefaultClosureType:
269272
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());
270273

@@ -348,6 +351,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
348351
case ConstraintKind::EscapableFunctionOf: Out << " @escaping type of "; break;
349352
case ConstraintKind::OpenedExistentialOf: Out << " opened archetype of "; break;
350353
case ConstraintKind::OneWayEqual: Out << " one-way bind to "; break;
354+
case ConstraintKind::OneWayBindParam: Out << " one-way bind param to "; break;
351355
case ConstraintKind::DefaultClosureType:
352356
Out << " closure can default to ";
353357
break;
@@ -564,6 +568,7 @@ gatherReferencedTypeVars(Constraint *constraint,
564568
case ConstraintKind::FunctionResult:
565569
case ConstraintKind::OpaqueUnderlyingType:
566570
case ConstraintKind::OneWayEqual:
571+
case ConstraintKind::OneWayBindParam:
567572
case ConstraintKind::DefaultClosureType:
568573
constraint->getFirstType()->getTypeVariables(typeVars);
569574
constraint->getSecondType()->getTypeVariables(typeVars);

lib/Sema/Constraint.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ enum class ConstraintKind : char {
161161
/// type). At that point, this constraint will be treated like an `Equal`
162162
/// constraint.
163163
OneWayEqual,
164+
/// The second type is the type of a function parameter, and the first type
165+
/// is the type of a reference to that function parameter within the body.
166+
/// Once the second type has been fully determined (and mapped down to a
167+
/// concrete type), this constraint will be treated like a 'BindParam'
168+
/// constraint.
169+
OneWayBindParam,
164170
/// If there is no contextual info e.g. `_ = { 42 }` default first type
165171
/// to a second type (inferred closure type). This is effectively a
166172
/// `Defaultable` constraint which a couple of differences:
@@ -549,6 +555,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
549555
case ConstraintKind::OptionalObject:
550556
case ConstraintKind::OpaqueUnderlyingType:
551557
case ConstraintKind::OneWayEqual:
558+
case ConstraintKind::OneWayBindParam:
552559
case ConstraintKind::DefaultClosureType:
553560
return ConstraintClassification::Relational;
554561

@@ -669,7 +676,8 @@ class Constraint final : public llvm::ilist_node<Constraint>,
669676

670677
/// Whether this is a one-way constraint.
671678
bool isOneWayConstraint() const {
672-
return Kind == ConstraintKind::OneWayEqual;
679+
return Kind == ConstraintKind::OneWayEqual ||
680+
Kind == ConstraintKind::OneWayBindParam;
673681
}
674682

675683
/// Retrieve the overload choice for an overload-binding constraint.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 4 -experimental-one-way-closure-params
2+
3+
func testBasic() {
4+
let _: (Float) -> Float = { $0 + 1 }
5+
6+
let _ = { $0 + 1 } // expected-error{{unable to infer type of a closure parameter $0 in the current context}}
7+
}
8+

0 commit comments

Comments
 (0)