Skip to content

Commit b159576

Browse files
authored
Merge pull request #64059 from kavon/staging-bootstrap-with-copyable
Turn on the `Copyable` as an inferred generic constraint by default
2 parents 1715a1e + 3a77083 commit b159576

17 files changed

+164
-41
lines changed

lib/AST/Module.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,16 @@ LookupConformanceInModuleRequest::evaluate(
17241724
return getBuiltinBuiltinTypeConformance(type, builtinType, protocol);
17251725
}
17261726

1727+
// Specific handling of Copyable for pack expansions.
1728+
if (auto packExpansion = type->getAs<PackExpansionType>()) {
1729+
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
1730+
auto patternType = packExpansion->getPatternType();
1731+
return (patternType->isTypeParameter()
1732+
? ProtocolConformanceRef(protocol)
1733+
: mod->lookupConformance(patternType, protocol));
1734+
}
1735+
}
1736+
17271737
auto nominal = type->getAnyNominal();
17281738

17291739
// If we don't have a nominal type, there are no conformances.
@@ -1768,9 +1778,12 @@ LookupConformanceInModuleRequest::evaluate(
17681778
if (nominal->isMoveOnly()) {
17691779
return ProtocolConformanceRef::forInvalid();
17701780
} else {
1771-
// FIXME: this should probably follow the Sendable case in that
1772-
// we should synthesize and append a ProtocolConformance to the `conformances` list.
1773-
return ProtocolConformanceRef(protocol);
1781+
// Specifically do not create a concrete conformance to Copyable. At
1782+
// this stage, we don't even want Copyable to appear in swiftinterface
1783+
// files, which will happen for a marker protocol that's registered
1784+
// in a nominal type's conformance table. We can reconsider this
1785+
// decision later once there's a clearer picture of noncopyable generics
1786+
return ProtocolConformanceRef(protocol);
17741787
}
17751788
} else {
17761789
// Was unable to infer the missing conformance.

lib/AST/ProtocolConformance.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,11 +1241,6 @@ static SmallVector<ProtocolConformance *, 2> findSynthesizedConformances(
12411241
// Concrete types may synthesize some conformances
12421242
if (!isa<ProtocolDecl>(nominal)) {
12431243
trySynthesize(KnownProtocolKind::Sendable);
1244-
1245-
// FIXME(kavon): make sure this conformance doesn't show up in swiftinterfaces
1246-
// before do this synthesis unconditionally.
1247-
if (dc->getASTContext().LangOpts.hasFeature(Feature::MoveOnly))
1248-
trySynthesize(KnownProtocolKind::Copyable);
12491244
}
12501245

12511246
/// Distributed actors can synthesize Encodable/Decodable, so look for those

lib/Sema/CSBindings.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,19 @@ void BindingSet::finalize(
501501

502502
if (TransitiveProtocols.has_value()) {
503503
for (auto *constraint : *TransitiveProtocols) {
504-
auto protocolTy = constraint->getSecondType();
504+
Type protocolTy = constraint->getSecondType();
505+
506+
// The Copyable protocol can't have members, yet will be a
507+
// constraint of basically all type variables, so don't suggest it.
508+
//
509+
// NOTE: worth considering for all marker protocols, but keep in
510+
// mind that you're allowed to extend them with members!
511+
if (auto p = protocolTy->getAs<ProtocolType>()) {
512+
if (ProtocolDecl *decl = p->getDecl())
513+
if (decl->isSpecificProtocol(KnownProtocolKind::Copyable))
514+
continue;
515+
}
516+
505517
addBinding({protocolTy, AllowedBindingKind::Exact, constraint});
506518
}
507519
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,17 +1828,12 @@ TypeVariableType *ConstraintSystem::openGenericParameter(
18281828
assert(result.second);
18291829
(void)result;
18301830

1831-
// When move-only types are available, add a constraint to force generic
1832-
// parameters to conform to a "Copyable" protocol.
1833-
if (getASTContext().LangOpts.hasFeature(Feature::MoveOnly)) {
1834-
ProtocolDecl *copyable = TypeChecker::getProtocol(
1835-
getASTContext(), SourceLoc(), KnownProtocolKind::Copyable);
1836-
1837-
// FIXME(kavon): there's a dependency ordering issues here with the
1838-
// protocol being defined in the stdlib, because when trying to build
1839-
// the stdlib itself, or a Swift program with -parse-stdlib, we can't
1840-
// load the protocol to add this constraint. (rdar://104898230)
1841-
assert(copyable && "stdlib is missing _Copyable protocol!");
1831+
// Add a constraint that generic parameters conform to Copyable.
1832+
// This lookup only can fail if the stdlib (i.e. the Swift module) has not
1833+
// been loaded because you've passed `-parse-stdlib` and are not building the
1834+
// stdlib itself (which would have `-module-name Swift` too).
1835+
if (auto *copyable = TypeChecker::getProtocol(getASTContext(), SourceLoc(),
1836+
KnownProtocolKind::Copyable)) {
18421837
addConstraint(
18431838
ConstraintKind::ConformsTo, typeVar,
18441839
copyable->getDeclaredInterfaceType(),

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4618,7 +4618,7 @@ swift::checkTypeWitness(Type type, AssociatedTypeDecl *assocType,
46184618
if (type->isPureMoveOnly()) {
46194619
// describe the failure reason as it not conforming to Copyable
46204620
auto *copyable = ctx.getProtocol(KnownProtocolKind::Copyable);
4621-
assert(copyable && "missing _Copyable from stdlib!");
4621+
assert(copyable && "missing _Copyable protocol!");
46224622
return CheckTypeWitnessResult(copyable->getDeclaredInterfaceType());
46234623
}
46244624

lib/Sema/TypeCheckType.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,7 +2301,6 @@ bool TypeResolver::diagnoseMoveOnlyMissingOwnership(
23012301
diagnose(repr->getLoc(),
23022302
diag::moveonly_parameter_missing_ownership);
23032303

2304-
// FIXME: this should be 'borrowing'
23052304
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
23062305
"borrowing", "for an immutable reference")
23072306
.fixItInsert(repr->getStartLoc(), "borrowing ");
@@ -2310,7 +2309,6 @@ bool TypeResolver::diagnoseMoveOnlyMissingOwnership(
23102309
"inout", "for a mutable reference")
23112310
.fixItInsert(repr->getStartLoc(), "inout ");
23122311

2313-
// FIXME: this should be 'consuming'
23142312
diagnose(repr->getLoc(), diag::moveonly_parameter_ownership_suggestion,
23152313
"consuming", "to take the value from the caller")
23162314
.fixItInsert(repr->getStartLoc(), "consuming ");

stdlib/public/core/Misc.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,9 @@ public func _unsafePerformance<T>(_ c: () -> T) -> T {
155155
return c()
156156
}
157157

158-
159-
/// This is not a protocol you can explicitly use in your programs.
160-
/// It exists for the compiler and type checker for diagnostic purposes.
161-
@_marker public protocol _Copyable { }
158+
/// This marker protocol represents types that support copying.
159+
/// This type is not yet available for use to express explicit
160+
/// constraints on generics in your programs. It is currently
161+
/// only used internally by the compiler.
162+
@available(*, unavailable)
163+
@_marker public protocol _Copyable {}

test/Concurrency/async_overload_filtering.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func filter_async(_: String) -> Void {}
1717
var a: String? = nil
1818

1919
// CHECK: attempting disjunction choice $T0 bound to decl async_overload_filtering.(file).filter_async(fn2:)
20+
// CHECK-NEXT: added constraint: {{.*}} conforms to _Copyable
2021
// CHECK-NEXT: overload set choice binding $T0 := {{.*}}
2122
// CHECK-NEXT: (considering -> ({{.*}}) -> {{.*}} applicable fn {{.*}}
2223
// CHECK: increasing 'sync-in-asynchronous' score by 1

test/Constraints/moveonly_constraints.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ func checkCasting(_ b: any Box, _ mo: __shared MO, _ a: Any) {
150150

151151
let _: Sendable = (MO(), MO()) // expected-error {{move-only type '(MO, MO)' cannot be used with generics yet}}
152152
let _: Sendable = MO() // expected-error {{move-only type 'MO' cannot be used with generics yet}}
153-
let _: _Copyable = mo // expected-error {{move-only type 'MO' cannot be used with generics yet}}
153+
let _: _Copyable = mo // expected-error {{'_Copyable' is unavailable}}
154+
// expected-error@-1 {{move-only type 'MO' cannot be used with generics yet}}
154155
let _: AnyObject = MO() // expected-error {{move-only type 'MO' cannot be used with generics yet}}
155156
let _: Any = mo // expected-error {{move-only type 'MO' cannot be used with generics yet}}
156157

@@ -163,8 +164,6 @@ func checkCasting(_ b: any Box, _ mo: __shared MO, _ a: Any) {
163164
_ = a as MO // expected-error {{cannot convert value of type 'Any' to type 'MO' in coercion}}
164165
_ = b as MO // expected-error {{cannot convert value of type 'any Box' to type 'MO' in coercion}}
165166

166-
// FIXME(kavon): make sure at runtime these casts actually fail, or just make them errors? (rdar://104900293)
167-
168167
_ = MO() is AnyHashable // expected-warning {{cast from 'MO' to unrelated type 'AnyHashable' always fails}}
169168
// expected-error@-1 {{move-only types cannot be conditionally cast}}
170169
_ = MO() is AnyObject // expected-warning {{cast from 'MO' to unrelated type 'AnyObject' always fails}}

test/Constraints/rdar68155466.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import Foundation
99
}
1010
}
1111

12-
struct Loop< // expected-note {{required by generic struct 'Loop' where 'ID' = '() -> Int'}}
12+
// FIXME: the diagnostic below ideally should have been emitted (rdar://106241733)
13+
struct Loop< // note {{required by generic struct 'Loop' where 'ID' = '() -> Int'}}
1314
Data : RandomAccessCollection,
1415
ID : Hashable,
1516
Content
@@ -25,4 +26,5 @@ func data() -> [A] {
2526
}
2627

2728
_ = Loop(data(), id: \.uniqueID) { $0 } // expected-error {{key path cannot refer to instance method 'uniqueID()'}}
28-
// expected-error@-1 {{type '() -> Int' cannot conform to 'Hashable'}} expected-note@-1 {{only concrete types such as structs, enums and classes can conform to protocols}}
29+
// FIXME: the diagnostics below ideally should have been emitted (rdar://106241733)
30+
// error@-1 {{type '() -> Int' cannot conform to 'Hashable'}} note@-1 {{only concrete types such as structs, enums and classes can conform to protocols}}

0 commit comments

Comments
 (0)