Skip to content

Commit d6fc1fd

Browse files
committed
Implement conversions for global-actor-qualified functions.
One can convert from a function value without a global actor to a similar function type that does have a global actor, but one cannot remove or change a global actor on a function type.
1 parent 3a357e9 commit d6fc1fd

File tree

9 files changed

+101
-3
lines changed

9 files changed

+101
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3843,6 +3843,9 @@ ERROR(converting_noattrfunc_to_type,none,
38433843
"may %select{allow it to escape|introduce data races}0",
38443844
(unsigned, Type))
38453845

3846+
ERROR(converting_func_loses_global_actor,none,
3847+
"converting function value of type %0 to %1 loses global actor %2",
3848+
(Type, Type, Type))
38463849
ERROR(capture_across_type_decl,none,
38473850
"%0 declaration cannot close over value %1 defined in outer scope",
38483851
(DescriptiveDeclKind, Identifier))
@@ -4502,7 +4505,6 @@ ERROR(actor_isolation_multiple_attr,none,
45024505
ERROR(global_actor_isolated_synchronous_closure,none,
45034506
"closure isolated to global actor %0 must be 'async'",
45044507
(Type))
4505-
45064508
ERROR(actor_isolation_override_mismatch,none,
45074509
"%0 %1 %2 has different actor isolation from %3 overridden declaration",
45084510
(ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation))

include/swift/Sema/CSFix.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ enum class FixKind : uint8_t {
7474
/// Mark function type as explicitly '@escaping'.
7575
ExplicitlyEscaping,
7676

77+
/// Mark function type as having a particular global actor.
78+
MarkGlobalActorFunction,
79+
7780
/// Arguments have labeling failures - missing/extraneous or incorrect
7881
/// labels attached to the, fix it by suggesting proper labels.
7982
RelabelArguments,
@@ -628,6 +631,23 @@ class MarkExplicitlyEscaping final : public ContextualMismatch {
628631
Type rhs, ConstraintLocator *locator);
629632
};
630633

634+
/// Mark function type as being part of a global actor.
635+
class MarkGlobalActorFunction final : public ContextualMismatch {
636+
MarkGlobalActorFunction(ConstraintSystem &cs, Type lhs, Type rhs,
637+
ConstraintLocator *locator)
638+
: ContextualMismatch(cs, FixKind::MarkGlobalActorFunction, lhs, rhs,
639+
locator) {
640+
}
641+
642+
public:
643+
std::string getName() const override { return "add @escaping"; }
644+
645+
bool diagnose(const Solution &solution, bool asNote = false) const override;
646+
647+
static MarkGlobalActorFunction *create(ConstraintSystem &cs, Type lhs,
648+
Type rhs, ConstraintLocator *locator);
649+
};
650+
631651
/// Introduce a '!' to force an optional unwrap.
632652
class ForceOptional final : public ContextualMismatch {
633653
ForceOptional(ConstraintSystem &cs, Type fromType, Type toType,

include/swift/Sema/ConstraintLocator.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ class LocatorPathElt::PatternMatch final : public StoredPointerElement<Pattern>
747747

748748
class LocatorPathElt::ArgumentAttribute final : public StoredIntegerElement<1> {
749749
public:
750-
enum Attribute : uint8_t { InOut, Escaping, Concurrent };
750+
enum Attribute : uint8_t { InOut, Escaping, Concurrent, GlobalActor };
751751

752752
private:
753753
ArgumentAttribute(Attribute attr)
@@ -768,6 +768,10 @@ class LocatorPathElt::ArgumentAttribute final : public StoredIntegerElement<1> {
768768
return ArgumentAttribute(Attribute::Concurrent);
769769
}
770770

771+
static ArgumentAttribute forGlobalActor() {
772+
return ArgumentAttribute(Attribute::GlobalActor);
773+
}
774+
771775
static bool classof(const LocatorPathElt *elt) {
772776
return elt->getKind() == ConstraintLocator::ArgumentAttribute;
773777
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,21 @@ class VarDeclMultipleReferencesChecker : public ASTWalker {
12941294
int referencesCount() { return count; }
12951295
};
12961296

1297+
bool DroppedGlobalActorFunctionAttr::diagnoseAsError() {
1298+
auto fromFnType = getFromType()->getAs<AnyFunctionType>();
1299+
if (!fromFnType)
1300+
return false;
1301+
1302+
Type fromGlobalActor = fromFnType->getGlobalActor();
1303+
if (!fromGlobalActor)
1304+
return false;
1305+
1306+
emitDiagnostic(
1307+
diag::converting_func_loses_global_actor, getFromType(), getToType(),
1308+
fromGlobalActor);
1309+
return true;
1310+
}
1311+
12971312
bool MissingOptionalUnwrapFailure::diagnoseAsError() {
12981313
if (!getUnwrappedType()->isBool()) {
12991314
if (diagnoseConversionToBool())

lib/Sema/CSDiagnostics.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,17 @@ class AttributedFuncToTypeConversionFailure final : public ContextualFailure {
730730
bool diagnoseParameterUse() const;
731731
};
732732

733+
/// Diagnose failure where a global actor attribute is dropped when
734+
/// trying to convert one function type to another.
735+
class DroppedGlobalActorFunctionAttr final : public ContextualFailure {
736+
public:
737+
DroppedGlobalActorFunctionAttr(const Solution &solution, Type fromType,
738+
Type toType, ConstraintLocator *locator)
739+
: ContextualFailure(solution, fromType, toType, locator) {}
740+
741+
bool diagnoseAsError() override;
742+
};
743+
733744
/// Diagnose failures related to use of the unwrapped optional types,
734745
/// which require some type of force-unwrap e.g. "!" or "try!".
735746
class MissingOptionalUnwrapFailure final : public ContextualFailure {

lib/Sema/CSFix.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,23 @@ MarkExplicitlyEscaping::create(ConstraintSystem &cs, Type lhs, Type rhs,
198198
return new (cs.getAllocator()) MarkExplicitlyEscaping(cs, lhs, rhs, locator);
199199
}
200200

201+
bool MarkGlobalActorFunction::diagnose(const Solution &solution,
202+
bool asNote) const {
203+
DroppedGlobalActorFunctionAttr failure(
204+
solution, getFromType(), getToType(), getLocator());
205+
return failure.diagnose(asNote);
206+
}
207+
208+
MarkGlobalActorFunction *
209+
MarkGlobalActorFunction::create(ConstraintSystem &cs, Type lhs, Type rhs,
210+
ConstraintLocator *locator) {
211+
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>())
212+
locator = cs.getConstraintLocator(
213+
locator, LocatorPathElt::ArgumentAttribute::forGlobalActor());
214+
215+
return new (cs.getAllocator()) MarkGlobalActorFunction(cs, lhs, rhs, locator);
216+
}
217+
201218
bool AddConcurrentAttribute::diagnose(const Solution &solution,
202219
bool asNote) const {
203220
AttributedFuncToTypeConversionFailure failure(

lib/Sema/CSSimplify.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,24 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
20152015
return getTypeMatchFailure(locator);
20162016
}
20172017

2018+
// A global actor can be added or can match, but cannot be removed.
2019+
if (func1->getGlobalActor() || func2->getGlobalActor()) {
2020+
if (func1->getGlobalActor() && func2->getGlobalActor()) {
2021+
// If both have a global actor, match them.
2022+
TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);
2023+
auto result = matchTypes(func1->getGlobalActor(), func2->getGlobalActor(), ConstraintKind::Equal, subflags, locator);
2024+
if (result == SolutionKind::Error)
2025+
return getTypeMatchFailure(locator);
2026+
} else if (func1->getGlobalActor()) {
2027+
// Cannot remove a global actor.
2028+
auto *fix = MarkGlobalActorFunction::create(
2029+
*this, func1, func2, getConstraintLocator(locator));
2030+
2031+
if (recordFix(fix))
2032+
return getTypeMatchFailure(locator);
2033+
}
2034+
}
2035+
20182036
// To contextual type increase the score to avoid ambiguity when solver can
20192037
// find more than one viable binding different only in representation e.g.
20202038
// let _: (@convention(block) () -> Void)? = Bool.random() ? nil : {}
@@ -10897,6 +10915,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1089710915

1089810916
case FixKind::UseSubscriptOperator:
1089910917
case FixKind::ExplicitlyEscaping:
10918+
case FixKind::MarkGlobalActorFunction:
1090010919
case FixKind::RelabelArguments:
1090110920
case FixKind::RemoveCall:
1090210921
case FixKind::RemoveUnwrap:

lib/Sema/ConstraintLocator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,10 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
491491
case AttrLoc::Attribute::Concurrent:
492492
out << "@concurrent";
493493
break;
494+
495+
case AttrLoc::Attribute::GlobalActor:
496+
out << "@<global actor>";
497+
break;
494498
}
495499

496500
break;

test/Concurrency/global_actor_function_types.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ struct OtherGlobalActor {
1313
static let shared = SomeActor()
1414
}
1515

16-
func testConversions(f: @SomeGlobalActor (Int) -> Void) {
16+
func testConversions(f: @escaping @SomeGlobalActor (Int) -> Void, g: @escaping (Int) -> Void) {
1717
let _: Int = f // expected-error{{cannot convert value of type '@SomeGlobalActor (Int) -> Void' to specified type 'Int'}}
18+
19+
let _: (Int) -> Void = f // expected-error{{converting function value of type '@SomeGlobalActor (Int) -> Void' to '(Int) -> Void' loses global actor 'SomeGlobalActor'}}
20+
let _: @SomeGlobalActor (Int) -> Void = g // okay
21+
22+
// FIXME: this could be better.
23+
let _: @OtherGlobalActor (Int) -> Void = f // expected-error{{cannot convert value of type 'SomeGlobalActor' to specified type 'OtherGlobalActor'}}
1824
}

0 commit comments

Comments
 (0)