Skip to content

Commit dd1d889

Browse files
authored
Merge pull request #9618 from jckarter/keypath-crashes
Fix some compiler crashing issues found by early adopters of keypaths.
2 parents 366f238 + 306fce3 commit dd1d889

26 files changed

+326
-155
lines changed

include/swift/AST/ASTMangler.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,12 @@ class ASTMangler : public Mangler {
114114
Type FromType, Type ToType,
115115
ModuleDecl *Module);
116116

117-
std::string mangleKeyPathGetterThunkHelper(const VarDecl *property);
118-
std::string mangleKeyPathSetterThunkHelper(const VarDecl *property);
117+
std::string mangleKeyPathGetterThunkHelper(const VarDecl *property,
118+
GenericSignature *signature,
119+
CanType baseType);
120+
std::string mangleKeyPathSetterThunkHelper(const VarDecl *property,
121+
GenericSignature *signature,
122+
CanType baseType);
119123

120124
std::string mangleTypeForDebugger(Type decl, const DeclContext *DC,
121125
GenericEnvironment *GE);

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ ERROR(expr_swift_keypath_invalid_component,none,
445445
"invalid component of Swift key path", ())
446446
ERROR(expr_swift_keypath_not_starting_with_type,none,
447447
"a Swift key path must begin with a type", ())
448+
ERROR(expr_swift_keypath_unimplemented_component,none,
449+
"key path support for %0 components is not implemented", (StringRef))
448450
ERROR(expr_smart_keypath_value_covert_to_contextual_type,none,
449451
"KeyPath value type %0 cannot be converted to contextual type %1",
450452
(Type, Type))

include/swift/Basic/LangOptions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ namespace swift {
228228
Swift3ObjCInferenceWarnings WarnSwift3ObjCInference =
229229
Swift3ObjCInferenceWarnings::None;
230230

231-
/// Enable keypaths.
232-
bool EnableExperimentalKeyPaths = true;
231+
/// Enable keypath components that aren't fully implemented.
232+
bool EnableExperimentalKeyPathComponents = false;
233233

234234
/// When a conversion from String to Substring fails, emit a fix-it to append
235235
/// the void subscript '[]'.

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,9 @@ def enable_experimental_property_behaviors :
269269
Flag<["-"], "enable-experimental-property-behaviors">,
270270
HelpText<"Enable experimental property behaviors">;
271271

272-
def enable_experimental_keypaths :
273-
Flag<["-"], "enable-experimental-keypaths">,
274-
HelpText<"Enable experimental keypaths">;
272+
def enable_experimental_keypath_components :
273+
Flag<["-"], "enable-experimental-keypath-components">,
274+
HelpText<"Enable unimplemented keypath component kinds">;
275275

276276
def enable_deserialization_recovery :
277277
Flag<["-"], "enable-deserialization-recovery">,

lib/AST/ASTMangler.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,26 @@ std::string ASTMangler::mangleGlobalVariableFull(const VarDecl *decl) {
226226
return finalize();
227227
}
228228

229-
std::string ASTMangler::mangleKeyPathGetterThunkHelper(const VarDecl *property) {
229+
std::string ASTMangler::mangleKeyPathGetterThunkHelper(const VarDecl *property,
230+
GenericSignature *signature,
231+
CanType baseType) {
230232
beginMangling();
231233
appendEntity(property);
234+
if (signature)
235+
appendGenericSignature(signature);
236+
appendType(baseType);
232237
appendOperator("TK");
233238
return finalize();
234239
}
235240

236-
std::string ASTMangler::mangleKeyPathSetterThunkHelper(const VarDecl *property) {
241+
std::string ASTMangler::mangleKeyPathSetterThunkHelper(const VarDecl *property,
242+
GenericSignature *signature,
243+
CanType baseType) {
237244
beginMangling();
238245
appendEntity(property);
246+
if (signature)
247+
appendGenericSignature(signature);
248+
appendType(baseType);
239249
appendOperator("Tk");
240250
return finalize();
241251
}

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ static bool isPolymorphic(const AbstractStorageDecl *storage) {
11381138
return false;
11391139

11401140
case DeclKind::Protocol:
1141-
return true;
1141+
return !storage->getDeclContext()->isExtensionContext();
11421142

11431143
case DeclKind::Class:
11441144
// Final properties can always be direct, even in classes.

lib/Demangling/Demangler.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,8 +1267,14 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
12671267
case 'k': {
12681268
auto nodeKind = c == 'K' ? Node::Kind::KeyPathGetterThunkHelper
12691269
: Node::Kind::KeyPathSetterThunkHelper;
1270-
auto decl = popNode();
1271-
return createWithChild(nodeKind, decl);
1270+
auto type = popNode();
1271+
auto sigOrDecl = popNode();
1272+
if (sigOrDecl->getKind() == Node::Kind::DependentGenericSignature) {
1273+
auto decl = popNode();
1274+
return createWithChildren(nodeKind, decl, sigOrDecl, type);
1275+
} else {
1276+
return createWithChildren(nodeKind, sigOrDecl, type);
1277+
}
12721278
}
12731279
default:
12741280
return nullptr;

lib/Demangling/NodePrinter.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,10 +1190,24 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
11901190
case Node::Kind::KeyPathGetterThunkHelper:
11911191
Printer << "key path getter for ";
11921192
print(Node->getChild(0));
1193+
Printer << " : ";
1194+
if (Node->getNumChildren() == 2) {
1195+
print(Node->getChild(1));
1196+
} else {
1197+
print(Node->getChild(1));
1198+
print(Node->getChild(2));
1199+
}
11931200
return nullptr;
11941201
case Node::Kind::KeyPathSetterThunkHelper:
11951202
Printer << "key path setter for ";
11961203
print(Node->getChild(0));
1204+
Printer << " : ";
1205+
if (Node->getNumChildren() == 2) {
1206+
print(Node->getChild(1));
1207+
} else {
1208+
print(Node->getChild(1));
1209+
print(Node->getChild(2));
1210+
}
11971211
return nullptr;
11981212
case Node::Kind::FieldOffset: {
11991213
print(Node->getChild(0)); // directness

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -914,8 +914,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
914914
Opts.EnableExperimentalPropertyBehaviors |=
915915
Args.hasArg(OPT_enable_experimental_property_behaviors);
916916

917-
Opts.EnableExperimentalKeyPaths |=
918-
Args.hasArg(OPT_enable_experimental_keypaths);
917+
Opts.EnableExperimentalKeyPathComponents |=
918+
Args.hasArg(OPT_enable_experimental_keypath_components);
919919

920920
Opts.EnableClassResilience |=
921921
Args.hasArg(OPT_enable_class_resilience);

lib/Parse/ParseExpr.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,6 @@ ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
455455
case tok::pound_keyPath:
456456
return parseExprKeyPathObjC();
457457
case tok::backslash:
458-
if (!Context.LangOpts.EnableExperimentalKeyPaths)
459-
return parseExprPostfix(Message, isExprBasic);
460458
return parseExprKeyPath();
461459

462460
case tok::oper_postfix:

lib/SIL/SILVerifier.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3778,8 +3778,69 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
37783778
case KeyPathPatternComponent::Kind::SettableProperty: {
37793779
require(component.getComputedPropertyIndices().empty(),
37803780
"subscripts not implemented");
3781+
3782+
// Getter should be <Sig...> @convention(thin) (@in Base) -> @out Result
3783+
{
3784+
auto getter = component.getComputedPropertyGetter();
3785+
auto substGetterType = getter->getLoweredFunctionType()
3786+
->substGenericArgs(F.getModule(), KPI->getSubstitutions());
3787+
require(substGetterType->getRepresentation() ==
3788+
SILFunctionTypeRepresentation::Thin,
3789+
"getter should be a thin function");
3790+
3791+
// TODO: indexes
3792+
require(substGetterType->getNumParameters() == 1,
3793+
"getter should have one parameter");
3794+
auto baseParam = substGetterType->getSelfParameter();
3795+
require(baseParam.getConvention() == ParameterConvention::Indirect_In,
3796+
"getter base parameter should be @in");
3797+
require(baseParam.getType() == loweredBaseTy.getSwiftRValueType(),
3798+
"getter base parameter should match base of component");
3799+
require(substGetterType->getNumResults() == 1,
3800+
"getter should have one result");
3801+
auto result = substGetterType->getResults()[0];
3802+
require(result.getConvention() == ResultConvention::Indirect,
3803+
"getter result should be @out");
3804+
require(result.getType() == loweredComponentTy.getSwiftRValueType(),
3805+
"getter result should match the maximal abstraction of the "
3806+
"formal component type");
3807+
}
3808+
3809+
if (kind == KeyPathPatternComponent::Kind::SettableProperty) {
3810+
// Setter should be
3811+
// <Sig...> @convention(thin) (@in Result, @in Base) -> ()
3812+
3813+
auto setter = component.getComputedPropertySetter();
3814+
auto substSetterType = setter->getLoweredFunctionType()
3815+
->substGenericArgs(F.getModule(), KPI->getSubstitutions());
3816+
3817+
require(substSetterType->getRepresentation() ==
3818+
SILFunctionTypeRepresentation::Thin,
3819+
"getter should be a thin function");
3820+
3821+
// TODO: indexes
3822+
require(substSetterType->getNumParameters() == 2,
3823+
"setter should have two parameters");
3824+
auto baseParam = substSetterType->getSelfParameter();
3825+
require(baseParam.getConvention() ==
3826+
ParameterConvention::Indirect_In
3827+
|| baseParam.getConvention() ==
3828+
ParameterConvention::Indirect_Inout,
3829+
"setter base parameter should be @in or @inout");
3830+
auto newValueParam = substSetterType->getParameters()[0];
3831+
require(newValueParam.getConvention() ==
3832+
ParameterConvention::Indirect_In,
3833+
"setter value parameter should be @in");
3834+
3835+
require(newValueParam.getType() ==
3836+
loweredComponentTy.getSwiftRValueType(),
3837+
"setter value should match the maximal abstraction of the "
3838+
"formal component type");
3839+
3840+
require(substSetterType->getNumResults() == 0,
3841+
"setter should have no results");
3842+
}
37813843

3782-
// TODO: Verify the signatures of the getter and setter
37833844
break;
37843845
}
37853846
}

0 commit comments

Comments
 (0)