Skip to content

Commit a4fa786

Browse files
committed
Handle a parameter to property behaviors.
For prototyping purposes, we only support a single trailing closure parameter to begin with.
1 parent 2da687b commit a4fa786

File tree

12 files changed

+267
-149
lines changed

12 files changed

+267
-149
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3609,17 +3609,16 @@ enum class AccessStrategy : unsigned char {
36093609
struct BehaviorRecord {
36103610
// The behavior name.
36113611
TypeRepr *ProtocolName;
3612-
// The parameter function, if any.
3613-
FuncDecl *Param;
3612+
// The parameter expression, if any.
3613+
Expr *Param;
36143614

36153615
Optional<NormalProtocolConformance *> Conformance = None;
36163616
// The 'value' property from the behavior protocol that provides the property
36173617
// implementation.
36183618
VarDecl *ValueDecl = nullptr;
36193619

3620-
36213620
BehaviorRecord(TypeRepr *ProtocolName,
3622-
FuncDecl *Param)
3621+
Expr *Param)
36233622
: ProtocolName(ProtocolName), Param(Param)
36243623
{}
36253624

@@ -3919,7 +3918,7 @@ class AbstractStorageDecl : public ValueDecl {
39193918
void setComputedSetter(FuncDecl *Set);
39203919

39213920
/// \brief Add a behavior to a property.
3922-
void addBehavior(TypeRepr *Type, FuncDecl *Param);
3921+
void addBehavior(TypeRepr *Type, Expr *Param);
39233922

39243923
/// \brief Set a materializeForSet accessor for this declaration.
39253924
///

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ ERROR(addressor_with_getter,none,
256256
ERROR(addressor_with_setter,none,
257257
"%select{variable|subscript}0 cannot provide both 'address' and "
258258
"a setter; use an ordinary getter instead", (unsigned))
259+
ERROR(behavior_multiple_vars,none,
260+
"applying property behavior with parameter to multiple variables is "
261+
"not supported", ())
259262

260263
// Import
261264
ERROR(decl_expected_module_name,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,18 +1564,14 @@ ERROR(property_behavior_value_type_doesnt_match,none,
15641564
(Identifier, Type, Identifier, Type))
15651565
NOTE(property_behavior_value_decl_here,none,
15661566
"'value' property declared here", ())
1567-
ERROR(property_behavior_invalid_initialValue_reqt,none,
1568-
"property behavior %0 'initialValue' requirement must be static, "
1569-
"get-only, and of type 'Self.Value'", (Identifier))
1570-
ERROR(property_behavior_requires_initialValue,none,
1571-
"property behavior %0 requires an initializer in the declaration of %1",
1567+
ERROR(property_behavior_invalid_parameter_reqt,none,
1568+
"property behavior %0 has a 'parameter' requirement that is "
1569+
"static or generic", (Identifier))
1570+
ERROR(property_behavior_requires_parameter,none,
1571+
"property behavior %0 requires a parameter in the declaration of %1",
15721572
(Identifier, Identifier))
1573-
ERROR(property_behavior_requires_unique_initialValue,none,
1574-
"property behavior %0 cannot destructure an initializer expression in a "
1575-
"compound pattern",
1576-
(Identifier))
1577-
ERROR(property_behavior_invalid_initializer,none,
1578-
"initializer expression provided, but property behavior %0 does not "
1573+
ERROR(property_behavior_invalid_parameter,none,
1574+
"parameter expression provided, but property behavior %0 does not "
15791575
"use it",
15801576
(Identifier))
15811577

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ IDENTIFIER(generate)
4141
IDENTIFIER(Generator)
4242
IDENTIFIER(hashValue)
4343
IDENTIFIER(init)
44-
IDENTIFIER(initialValue)
4544
IDENTIFIER(initStorage)
4645
IDENTIFIER(load)
4746
IDENTIFIER(next)
@@ -50,6 +49,7 @@ IDENTIFIER(objectAtIndexedSubscript)
5049
IDENTIFIER(objectForKeyedSubscript)
5150
IDENTIFIER(ObjectiveC)
5251
IDENTIFIER_(OptionalNilComparisonType)
52+
IDENTIFIER(parameter)
5353
IDENTIFIER(Protocol)
5454
IDENTIFIER(rawValue)
5555
IDENTIFIER(RawValue)

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2872,7 +2872,7 @@ void AbstractStorageDecl::setComputedSetter(FuncDecl *Set) {
28722872
}
28732873

28742874
void AbstractStorageDecl::addBehavior(TypeRepr *Type,
2875-
FuncDecl *Param) {
2875+
Expr *Param) {
28762876
assert(BehaviorInfo.getPointer() == nullptr && "already set behavior!");
28772877
auto mem = getASTContext().Allocate(sizeof(BehaviorRecord),
28782878
alignof(BehaviorRecord));

lib/Parse/ParseDecl.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3956,14 +3956,64 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
39563956
if (consumeIf(tok::kw___behavior)) {
39573957
auto type = parseType(diag::expected_behavior_name,
39583958
/*handle completion*/ true);
3959-
// TODO: recovery. could scan to next closing bracket
39603959
if (type.isParseError())
39613960
return makeParserError();
39623961
if (type.hasCodeCompletion())
39633962
return makeParserCodeCompletionStatus();
3963+
3964+
// Parse a following trailing closure argument.
3965+
// FIXME: Handle generalized parameters.
3966+
Expr *paramExpr = nullptr;
3967+
if (Tok.is(tok::l_brace)) {
3968+
// Record the variables that we're trying to set up. This allows us
3969+
// to cleanly reject "var x = x" when "x" isn't bound to an enclosing
3970+
// decl (even though names aren't injected into scope when the parameter
3971+
// is parsed).
3972+
SmallVector<VarDecl *, 4> Vars;
3973+
Vars.append(DisabledVars.begin(), DisabledVars.end());
3974+
pattern->collectVariables(Vars);
3975+
3976+
llvm::SaveAndRestore<decltype(DisabledVars)>
3977+
RestoreCurVars(DisabledVars, Vars);
3978+
3979+
llvm::SaveAndRestore<decltype(DisabledVarReason)>
3980+
RestoreReason(DisabledVarReason, diag::var_init_self_referential);
3981+
3982+
// Set up a decl context for the closure.
3983+
// This will be recontextualized to a method we synthesize during
3984+
// type checking.
3985+
if (!CurDeclContext->isLocalContext() && !topLevelDecl && !initContext)
3986+
initContext = Context.createPatternBindingContext(CurDeclContext);
3987+
Optional<ParseFunctionBody> initParser;
3988+
Optional<ContextChange> topLevelParser;
3989+
if (topLevelDecl)
3990+
topLevelParser.emplace(*this, topLevelDecl,
3991+
&State->getTopLevelContext());
3992+
if (initContext)
3993+
initParser.emplace(*this, initContext);
3994+
3995+
auto closure = parseExprClosure();
3996+
usedInitContext = true;
3997+
if (closure.isParseError())
3998+
return makeParserError();
3999+
if (closure.hasCodeCompletion())
4000+
return makeParserCodeCompletionStatus();
4001+
paramExpr = closure.get();
4002+
}
39644003

4004+
unsigned numVars = 0;
39654005
pattern->forEachVariable([&](VarDecl *VD) {
3966-
VD->addBehavior(type.get(), nullptr);
4006+
++numVars;
4007+
// TODO: Support parameter closure with multiple vars. This is tricky
4008+
// since the behavior's parameter type may be dependent on the
4009+
// property type, so we'd need to clone the closure expr for each var
4010+
// to re-type-check it.
4011+
if (numVars > 1 && paramExpr) {
4012+
diagnose(paramExpr->getLoc(), diag::behavior_multiple_vars);
4013+
paramExpr = nullptr;
4014+
}
4015+
4016+
VD->addBehavior(type.get(), paramExpr);
39674017
});
39684018
// If we syntactically match the second decl-var production, with a
39694019
// var-get-set clause, parse the var-get-set clause.

lib/Sema/CodeSynthesis.cpp

Lines changed: 139 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,75 +1293,159 @@ void TypeChecker::completePropertyBehaviorStorage(VarDecl *VD,
12931293
ConcreteDeclRef(Context, Storage->getSetter(), MemberSubs));
12941294
}
12951295

1296-
void TypeChecker::completePropertyBehaviorInitialValue(VarDecl *VD,
1297-
VarDecl *BehaviorInitialValue,
1296+
void TypeChecker::completePropertyBehaviorParameter(VarDecl *VD,
1297+
FuncDecl *BehaviorParameter,
12981298
NormalProtocolConformance *BehaviorConformance,
12991299
ArrayRef<Substitution> SelfInterfaceSubs,
13001300
ArrayRef<Substitution> SelfContextSubs) {
1301-
// Create a property to witness the requirement.
1301+
// Create a method to witness the requirement.
13021302
auto DC = VD->getDeclContext();
13031303
SmallString<64> NameBuf = VD->getName().str();
1304-
NameBuf += ".initialValue";
1305-
auto InitialValueName = Context.getIdentifier(NameBuf);
1306-
// TODO: non-static initialValue
1307-
assert(BehaviorInitialValue->isStatic());
1308-
auto *InitialValue = new (Context) VarDecl(/*static*/ true,
1309-
/*let*/ false,
1310-
VD->getLoc(),
1311-
InitialValueName,
1312-
SelfContextSubs[1].getReplacement(),
1313-
DC);
1314-
InitialValue->setInterfaceType(SelfInterfaceSubs[1].getReplacement());
1315-
InitialValue->setUserAccessible(false);
1316-
// Mark the vardecl to be final, implicit, and private. In a class, this
1317-
// prevents it from being dynamically dispatched.
1318-
if (VD->getDeclContext()->getAsClassOrClassExtensionContext())
1319-
makeFinal(Context, InitialValue);
1320-
InitialValue->setImplicit();
1321-
InitialValue->setAccessibility(Accessibility::Private);
1322-
InitialValue->setIsBeingTypeChecked();
1304+
NameBuf += ".parameter";
1305+
auto ParameterBaseName = Context.getIdentifier(NameBuf);
13231306

1324-
addMemberToContextIfNeeded(InitialValue, DC);
1307+
// Substitute the requirement type into the conforming context.
1308+
auto sig = BehaviorConformance->getProtocol()->getGenericSignatureOfContext();
1309+
auto ParameterTy = BehaviorParameter->getInterfaceType()
1310+
->castTo<AnyFunctionType>()
1311+
->getResult();
13251312

1326-
Pattern *InitialPBDPattern = new (Context) NamedPattern(InitialValue,
1327-
/*implicit*/true);
1328-
InitialPBDPattern = new (Context) TypedPattern(InitialPBDPattern,
1329-
TypeLoc::withoutLoc(SelfContextSubs[1].getReplacement()),
1330-
/*implicit*/ true);
1331-
auto *InitialPBD = PatternBindingDecl::create(Context,
1332-
/*staticloc*/SourceLoc(),
1333-
StaticSpellingKind::KeywordStatic,
1334-
VD->getLoc(),
1335-
InitialPBDPattern, nullptr,
1336-
VD->getDeclContext());
1337-
InitialPBD->setImplicit();
1338-
InitialPBD->setInitializerChecked(0);
1339-
addMemberToContextIfNeeded(InitialPBD, VD->getDeclContext(), VD);
1313+
TypeSubstitutionMap interfaceMap = sig->getSubstitutionMap(SelfInterfaceSubs);
1314+
auto SubstInterfaceTy = ParameterTy.subst(VD->getModuleContext(),
1315+
interfaceMap, SubstOptions());
1316+
assert(SubstInterfaceTy && "storage type substitution failed?!");
13401317

1341-
// Create a getter.
1342-
auto Get = createGetterPrototype(InitialValue, *this);
1343-
addMemberToContextIfNeeded(Get, DC);
1318+
TypeSubstitutionMap contextMap = sig->getSubstitutionMap(SelfContextSubs);
1319+
auto SubstContextTy = ParameterTy.subst(VD->getModuleContext(),
1320+
contextMap, SubstOptions());
1321+
assert(SubstContextTy && "storage type substitution failed?!");
1322+
1323+
auto SubstBodyResultTy = SubstContextTy->castTo<AnyFunctionType>()
1324+
->getResult();
13441325

1345-
// Take the initializer from the PatternBindingDecl for VD.
1346-
auto *InitValue = VD->getParentInitializer();
1347-
auto PBD = VD->getParentPatternBinding();
1348-
unsigned entryIndex = PBD->getPatternEntryIndexForVarDecl(VD);
1349-
PBD->setInit(entryIndex, nullptr);
1350-
PBD->setInitializerChecked(entryIndex);
1326+
// Add the Self type back to the interface and context types.
1327+
if (DC->isTypeContext()) {
1328+
if (DC->isGenericContext()) {
1329+
auto genericSig = DC->getGenericSignatureOfContext();
1330+
SubstInterfaceTy = GenericFunctionType::get(genericSig,
1331+
DC->getSelfInterfaceType(),
1332+
SubstInterfaceTy,
1333+
AnyFunctionType::ExtInfo());
1334+
auto genericParams = DC->getGenericParamsOfContext();
1335+
SubstContextTy = PolymorphicFunctionType::get(DC->getSelfTypeInContext(),
1336+
SubstContextTy,
1337+
genericParams);
1338+
} else {
1339+
SubstInterfaceTy = FunctionType::get(DC->getSelfInterfaceType(),
1340+
SubstInterfaceTy);
1341+
SubstContextTy = FunctionType::get(DC->getSelfTypeInContext(),
1342+
SubstContextTy);
1343+
}
1344+
}
1345+
1346+
// Borrow the parameters from the requirement declaration.
1347+
SmallVector<ParameterList *, 2> ParamLists;
1348+
if (DC->isTypeContext()) {
1349+
auto self = new (Context) ParamDecl(/*let*/ true, SourceLoc(), SourceLoc(),
1350+
Identifier(), SourceLoc(),
1351+
Context.Id_self,
1352+
DC->getSelfTypeInContext(), DC);
1353+
self->setInterfaceType(DC->getSelfInterfaceType());
1354+
self->setImplicit();
1355+
1356+
ParamLists.push_back(ParameterList::create(Context, SourceLoc(),
1357+
self, SourceLoc()));
1358+
ParamLists.back()->get(0)->setImplicit();
1359+
}
1360+
1361+
assert(BehaviorParameter->getParameterLists().size() == 2);
1362+
SmallVector<ParamDecl *, 4> Params;
1363+
SmallVector<Identifier, 4> NameComponents;
1364+
1365+
auto *DeclaredParams = BehaviorParameter->getParameterList(1);
1366+
for (unsigned i : indices(*DeclaredParams)) {
1367+
auto declaredParam = DeclaredParams->get(i);
1368+
auto declaredParamTy = declaredParam->getInterfaceType();
1369+
auto interfaceTy = declaredParamTy.subst(DC->getParentModule(),
1370+
interfaceMap,
1371+
SubstOptions());
1372+
assert(interfaceTy);
1373+
auto contextTy = declaredParamTy.subst(DC->getParentModule(),
1374+
contextMap, SubstOptions());
1375+
assert(contextTy);
1376+
1377+
SmallString<64> ParamNameBuf;
1378+
{
1379+
llvm::raw_svector_ostream names(ParamNameBuf);
1380+
names << "%arg." << i;
1381+
}
1382+
auto param = new (Context) ParamDecl(/*let*/ true, SourceLoc(), SourceLoc(),
1383+
Identifier(),
1384+
SourceLoc(),
1385+
Context.getIdentifier(ParamNameBuf),
1386+
contextTy, DC);
1387+
param->setInterfaceType(interfaceTy);
1388+
param->setImplicit();
1389+
Params.push_back(param);
1390+
NameComponents.push_back(Identifier());
1391+
}
1392+
ParamLists.push_back(ParameterList::create(Context, Params));
1393+
1394+
auto *Parameter = FuncDecl::create(Context, SourceLoc(),
1395+
StaticSpellingKind::None,
1396+
SourceLoc(),
1397+
DeclName(Context, ParameterBaseName,
1398+
NameComponents),
1399+
SourceLoc(), SourceLoc(),
1400+
SourceLoc(), nullptr, SubstContextTy,
1401+
ParamLists,
1402+
TypeLoc::withoutLoc(SubstBodyResultTy),
1403+
DC);
1404+
1405+
Parameter->setInterfaceType(SubstInterfaceTy);
1406+
// Mark the method to be final, implicit, and private. In a class, this
1407+
// prevents it from being dynamically dispatched.
1408+
if (DC->getAsClassOrClassExtensionContext())
1409+
makeFinal(Context, Parameter);
1410+
Parameter->setImplicit();
1411+
Parameter->setAccessibility(Accessibility::Private);
1412+
Parameter->setIsBeingTypeChecked();
1413+
Parameter->setBodyResultType(SubstBodyResultTy);
13511414

13521415
// Recontextualize any closure declcontexts nested in the initializer to
1353-
// realize that they are in the getter function.
1354-
InitValue->walk(RecontextualizeClosures(Get));
1416+
// realize that they are in the parameter function.
1417+
assert(VD->getBehavior()->Param);
1418+
VD->getBehavior()->Param->walk(RecontextualizeClosures(Parameter));
1419+
1420+
// Apply and return the closure in the function context.
1421+
SmallVector<Expr *, 4> argRefs;
1422+
SmallVector<Identifier, 4> argNames;
1423+
for (unsigned i : indices(Params)) {
1424+
auto param = Params[i];
1425+
auto expr = new (Context) DeclRefExpr(param, DeclNameLoc(),
1426+
/*implicit*/ true);
1427+
argRefs.push_back(expr);
1428+
argNames.push_back(DeclaredParams->get(i)->getName());
1429+
}
1430+
auto argTuple = TupleExpr::create(Context, SourceLoc(), argRefs,
1431+
argNames,
1432+
{}, SourceLoc(),
1433+
/*trailing closure*/ false,
1434+
/*implicit*/ true);
1435+
auto apply = new (Context) CallExpr(VD->getBehavior()->Param, argTuple,
1436+
/*implicit*/ true);
13551437

13561438
// Return the expression value.
1357-
auto Ret = new (Context) ReturnStmt(SourceLoc(), InitValue,
1358-
/*implicit*/ true);
1439+
auto Ret = new (Context) ReturnStmt(SourceLoc(), apply,
1440+
/*implicit*/ true);
13591441
auto Body = BraceStmt::create(Context, SourceLoc(), ASTNode(Ret),
13601442
SourceLoc(), /*implicit*/ true);
1361-
Get->setBody(Body);
1443+
Parameter->setBody(Body);
13621444

1363-
InitialValue->makeComputed(SourceLoc(), Get, nullptr, nullptr, SourceLoc());
1364-
InitialValue->setIsBeingTypeChecked(false);
1445+
Parameter->setIsBeingTypeChecked(false);
1446+
typeCheckDecl(Parameter, true);
1447+
typeCheckDecl(Parameter, false);
1448+
addMemberToContextIfNeeded(Parameter, DC);
13651449

13661450
// Add the witnesses to the conformance.
13671451
ArrayRef<Substitution> MemberSubs;
@@ -1370,10 +1454,8 @@ void TypeChecker::completePropertyBehaviorInitialValue(VarDecl *VD,
13701454
->getForwardingSubstitutions(Context);
13711455
}
13721456

1373-
BehaviorConformance->setWitness(BehaviorInitialValue,
1374-
ConcreteDeclRef(Context, InitialValue, MemberSubs));
1375-
BehaviorConformance->setWitness(BehaviorInitialValue->getGetter(),
1376-
ConcreteDeclRef(Context, Get, MemberSubs));
1457+
BehaviorConformance->setWitness(BehaviorParameter,
1458+
ConcreteDeclRef(Context, Parameter, MemberSubs));
13771459
}
13781460

13791461
void TypeChecker::completePropertyBehaviorAccessors(VarDecl *VD,

0 commit comments

Comments
 (0)