Skip to content

Commit e86558f

Browse files
authored
Merge pull request swiftlang#30277 from LucianoPAlmeida/SR-12019-dynamically-call-generic-constraint
[SR-12019] Fix assert when dynamicallyCall parameter does not satisfy generic constraint
2 parents 0a6ccd8 + 01145c0 commit e86558f

File tree

8 files changed

+110
-11
lines changed

8 files changed

+110
-11
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,29 @@ class HasDynamicMemberLookupAttributeRequest
19991999
}
20002000
};
20012001

2002+
/// Computes whether the specified type or a super-class/super-protocol has the
2003+
/// @dynamicCallable attribute on it.
2004+
class HasDynamicCallableAttributeRequest
2005+
: public SimpleRequest<HasDynamicCallableAttributeRequest,
2006+
bool(CanType), CacheKind::Cached> {
2007+
public:
2008+
using SimpleRequest::SimpleRequest;
2009+
2010+
private:
2011+
friend SimpleRequest;
2012+
2013+
// Evaluation.
2014+
llvm::Expected<bool> evaluate(Evaluator &evaluator, CanType ty) const;
2015+
2016+
public:
2017+
bool isCached() const {
2018+
// Don't cache types containing type variables, as they must not outlive
2019+
// the constraint system that created them.
2020+
auto ty = std::get<0>(getStorage());
2021+
return !ty->hasTypeVariable();
2022+
}
2023+
};
2024+
20022025
/// Determines the type of a given pattern.
20032026
///
20042027
/// Note that this returns the "raw" pattern type, which can involve

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ SWIFT_REQUEST(TypeChecker, HasCircularRawValueRequest,
8181
bool(EnumDecl *), Cached, NoLocationInfo)
8282
SWIFT_REQUEST(TypeChecker, HasDynamicMemberLookupAttributeRequest,
8383
bool(CanType), Cached, NoLocationInfo)
84+
SWIFT_REQUEST(TypeChecker, HasDynamicCallableAttributeRequest,
85+
bool(CanType), Cached, NoLocationInfo)
8486
SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest,
8587
GenericSignature (ModuleDecl *, GenericSignatureImpl *,
8688
GenericParamSource,

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
838838
/// Return true if the specified type or a super-class/super-protocol has the
839839
/// @dynamicMemberLookup attribute on it.
840840
bool hasDynamicMemberLookupAttribute();
841+
842+
/// Return true if the specified type or a super-class/super-protocol has the
843+
/// @dynamicCallable attribute on it.
844+
bool hasDynamicCallableAttribute();
841845

842846
/// Retrieve the superclass of this type.
843847
///

lib/AST/Type.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,12 +1493,25 @@ bool TypeBase::isCallableNominalType(DeclContext *dc) {
14931493
}
14941494

14951495
bool TypeBase::hasDynamicMemberLookupAttribute() {
1496+
if (!mayHaveMembers())
1497+
return false;
1498+
14961499
auto canTy = getCanonicalType();
14971500
auto &ctx = canTy->getASTContext();
14981501
return evaluateOrDefault(
14991502
ctx.evaluator, HasDynamicMemberLookupAttributeRequest{canTy}, false);
15001503
}
15011504

1505+
bool TypeBase::hasDynamicCallableAttribute() {
1506+
if (!mayHaveMembers())
1507+
return false;
1508+
1509+
auto canTy = getCanonicalType();
1510+
auto &ctx = canTy->getASTContext();
1511+
return evaluateOrDefault(
1512+
ctx.evaluator, HasDynamicCallableAttributeRequest{canTy}, false);
1513+
}
1514+
15021515
Type TypeBase::getSuperclass(bool useArchetypes) {
15031516
auto *nominalDecl = getAnyNominal();
15041517
auto *classDecl = dyn_cast_or_null<ClassDecl>(nominalDecl);

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,12 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(
504504
{LocatorPathElt::ApplyFunction(),
505505
LocatorPathElt::ImplicitCallAsFunction()});
506506
}
507+
508+
// Handling an apply for a nominal type that supports @dynamicCallable.
509+
if (fnTy->hasDynamicCallableAttribute()) {
510+
return getConstraintLocator(anchor, LocatorPathElt::ApplyFunction());
511+
}
512+
507513
return nullptr;
508514
};
509515

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4233,18 +4233,18 @@ IsCallableNominalTypeRequest::evaluate(Evaluator &evaluator, CanType ty,
42334233
});
42344234
}
42354235

4236-
llvm::Expected<bool>
4237-
HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator,
4238-
CanType ty) const {
4236+
template <class DynamicAttribute>
4237+
static bool checkForDynamicAttribute(CanType ty,
4238+
llvm::function_ref<bool (Type)> hasAttribute) {
42394239
// If this is an archetype type, check if any types it conforms to
42404240
// (superclass or protocols) have the attribute.
42414241
if (auto archetype = dyn_cast<ArchetypeType>(ty)) {
42424242
for (auto proto : archetype->getConformsTo()) {
4243-
if (proto->getDeclaredType()->hasDynamicMemberLookupAttribute())
4243+
if (hasAttribute(proto->getDeclaredType()))
42444244
return true;
42454245
}
42464246
if (auto superclass = archetype->getSuperclass()) {
4247-
if (superclass->hasDynamicMemberLookupAttribute())
4247+
if (hasAttribute(superclass))
42484248
return true;
42494249
}
42504250
}
@@ -4253,33 +4253,50 @@ HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator,
42534253
// attribute.
42544254
if (auto protocolComp = dyn_cast<ProtocolCompositionType>(ty)) {
42554255
for (auto member : protocolComp->getMembers()) {
4256-
if (member->hasDynamicMemberLookupAttribute())
4256+
if (hasAttribute(member))
42574257
return true;
42584258
}
42594259
}
42604260

42614261
// Otherwise, this must be a nominal type.
4262-
// Dynamic member lookup doesn't work for tuples, etc.
4262+
// Neither Dynamic member lookup nor Dynamic Callable doesn't
4263+
// work for tuples, etc.
42634264
auto nominal = ty->getAnyNominal();
42644265
if (!nominal)
42654266
return false;
42664267

42674268
// If this type has the attribute on it, then yes!
4268-
if (nominal->getAttrs().hasAttribute<DynamicMemberLookupAttr>())
4269+
if (nominal->getAttrs().hasAttribute<DynamicAttribute>())
42694270
return true;
42704271

42714272
// Check the protocols the type conforms to.
42724273
for (auto proto : nominal->getAllProtocols()) {
4273-
if (proto->getDeclaredType()->hasDynamicMemberLookupAttribute())
4274+
if (hasAttribute(proto->getDeclaredType()))
42744275
return true;
42754276
}
42764277

42774278
// Check the superclass if present.
42784279
if (auto classDecl = dyn_cast<ClassDecl>(nominal)) {
42794280
if (auto superclass = classDecl->getSuperclass()) {
4280-
if (superclass->hasDynamicMemberLookupAttribute())
4281+
if (hasAttribute(superclass))
42814282
return true;
42824283
}
42834284
}
42844285
return false;
42854286
}
4287+
4288+
llvm::Expected<bool>
4289+
HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator,
4290+
CanType ty) const {
4291+
return checkForDynamicAttribute<DynamicMemberLookupAttr>(ty, [](Type type) {
4292+
return type->hasDynamicMemberLookupAttribute();
4293+
});
4294+
}
4295+
4296+
llvm::Expected<bool>
4297+
HasDynamicCallableAttributeRequest::evaluate(Evaluator &evaluator,
4298+
CanType ty) const {
4299+
return checkForDynamicAttribute<DynamicCallableAttr>(ty, [](Type type) {
4300+
return type->hasDynamicCallableAttribute();
4301+
});
4302+
}

test/Misc/stats_dir_tracer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %target-swiftc_driver -o %t/main -module-name main -stats-output-dir %t %s -trace-stats-events
33
// RUN: %FileCheck -input-file %t/*.csv %s
44

5-
// CHECK-DAG: {{[0-9]+,[0-9]+,"exit","typecheck-expr","Sema.NumConstraintScopes",[0-9]+,[0-9]+,"Sequence","\[.*stats_dir_tracer.swift.*\]"}}
5+
// CHECK-DAG: {{[0-9]+,[0-9]+,"exit","check-conformance","Sema.NumConstraintScopes",[0-9]+,[0-9]+,"Bar: Proto module main",".*stats_dir_tracer.swift.*"}}
66
// CHECK-DAG: {{[0-9]+,[0-9]+,"exit","SuperclassDeclRequest","Sema.SuperclassDeclRequest",[0-9]+,[0-9]+,"Bar","\[.*stats_dir_tracer.swift.*\]"}}
77

88
public func foo() {

test/attr/attr_dynamic_callable.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,3 +487,37 @@ struct B {
487487

488488
B()("hello") // ok
489489
B()("\(1)") // ok
490+
491+
// SR-12019
492+
@dynamicCallable
493+
struct SR12019_S {
494+
func dynamicallyCall<T: StringProtocol>(withArguments: [T]) { // expected-note {{where 'T' = 'Int'}}
495+
print("hi")
496+
}
497+
}
498+
499+
@dynamicCallable
500+
protocol SR12019 {
501+
func dynamicallyCall<T: StringProtocol>(withArguments: [T]) // expected-note 2{{where 'T' = 'Int'}}
502+
}
503+
504+
class SR12019Class: SR12019 {
505+
func dynamicallyCall<T: StringProtocol>(withArguments: [T]) {} // expected-note {{where 'T' = 'Int'}}
506+
}
507+
508+
class SR12019SubClass: SR12019Class {}
509+
510+
let sr12019s = SR12019_S()
511+
sr12019s(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}}
512+
513+
// Protocol composition
514+
let sr12019: SR12019&AnyObject = SR12019Class()
515+
sr12019(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}}
516+
517+
// Protocol
518+
let sr12019c: SR12019 = SR12019Class()
519+
sr12019c(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}}
520+
521+
// Subclass
522+
let sr12019sub = SR12019SubClass()
523+
sr12019sub(1) // expected-error {{instance method 'dynamicallyCall(withArguments:)' requires that 'Int' conform to 'StringProtocol'}}

0 commit comments

Comments
 (0)