Skip to content

Commit 9e24746

Browse files
committed
Sema: Implement new behavior of extensions with non-copyable generics
We want extensions to introduce default Copyable/Escapable just like other generic contexts, so that once Optional adopts ~Copyable, an `extension Optional` actually adds `Wrapped: Copyable` by default.
1 parent 4a46717 commit 9e24746

File tree

10 files changed

+38
-41
lines changed

10 files changed

+38
-41
lines changed

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,10 @@ InferredGenericSignatureRequest::evaluate(
791791
return false;
792792
};
793793

794+
// "Local" generic parameters to which we apply default Copyable and
795+
// Escapable.
796+
SmallVector<Type, 4> paramTypes;
797+
794798
if (genericParamList) {
795799
// Extensions never have a parent signature.
796800
assert(genericParamList->getOuterParameters() == nullptr || !parentSig);
@@ -807,6 +811,10 @@ InferredGenericSignatureRequest::evaluate(
807811
// We walk them backwards to order outer parameters before inner
808812
// parameters.
809813
for (auto *gpList : llvm::reverse(gpLists)) {
814+
for (auto *gpDecl : *gpList) {
815+
paramTypes.push_back(gpDecl->getDeclaredInterfaceType());
816+
}
817+
810818
assert(gpList->size() > 0 &&
811819
"Parsed an empty generic parameter list?");
812820

@@ -864,15 +872,16 @@ InferredGenericSignatureRequest::evaluate(
864872

865873
desugarRequirements(requirements, inverses, errors);
866874

875+
if (!genericParamList && allowConcreteGenericParams) {
876+
for (auto paramTy : genericParams) {
877+
paramTypes.push_back(paramTy);
878+
}
879+
}
880+
867881
// After realizing requirements, expand default requirements only for local
868882
// generic parameters, as the outer parameters have already been expanded.
869-
SmallVector<Type, 4> localGPs;
870-
if (genericParamList)
871-
for (auto *gtpd : genericParamList->getParams())
872-
localGPs.push_back(gtpd->getDeclaredInterfaceType());
873-
874-
InverseRequirement::expandDefaults(ctx, localGPs, requirements);
875-
applyInverses(ctx, localGPs, inverses, requirements, errors);
883+
InverseRequirement::expandDefaults(ctx, paramTypes, requirements);
884+
applyInverses(ctx, paramTypes, inverses, requirements, errors);
876885

877886
// Re-order requirements so that inferred requirements appear last. This
878887
// ensures that if an inferred requirement is redundant with some other
@@ -947,7 +956,7 @@ InferredGenericSignatureRequest::evaluate(
947956
if (attempt == 0) {
948957
machine->computeRequirementDiagnostics(errors, inverses, loc);
949958
diagnoseRequirementErrors(ctx, errors,
950-
allowConcreteGenericParams
959+
(allowConcreteGenericParams || !genericParamList)
951960
? AllowConcreteTypePolicy::All
952961
: AllowConcreteTypePolicy::AssocTypes);
953962
}
@@ -978,7 +987,7 @@ InferredGenericSignatureRequest::evaluate(
978987
std::move(machine));
979988
}
980989

981-
if (!allowConcreteGenericParams) {
990+
if (genericParamList && !allowConcreteGenericParams) {
982991
for (auto genericParam : result.getInnermostGenericParams()) {
983992
auto reduced = result.getReducedType(genericParam);
984993

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3073,7 +3073,7 @@ SerializeAttrGenericSignatureRequest::evaluate(Evaluator &evaluator,
30733073
WhereClauseOwner(const_cast<AbstractFunctionDecl *>(FD), attr),
30743074
/*addedRequirements=*/{},
30753075
/*inferenceSources=*/{},
3076-
/*allowConcreteGenericParams=*/true};
3076+
/*allowConcreteGenericParams=*/false};
30773077

30783078
auto specializedSig = evaluateOrDefault(Ctx.evaluator, request,
30793079
GenericSignatureWithError())

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -679,9 +679,6 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
679679
}
680680
}
681681

682-
if (!genericParams && where)
683-
allowConcreteGenericParams = true;
684-
685682
GenericSignature parentSig;
686683
SmallVector<TypeLoc, 2> inferenceSources;
687684
SmallVector<Requirement, 2> extraReqs;
@@ -793,7 +790,9 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
793790
// the right sugared types, since we don't want to expose the
794791
// name of the generic parameter of BuiltinTupleDecl itself.
795792
if (extraReqs.empty() && !ext->getTrailingWhereClause() &&
796-
!isa<BuiltinTupleDecl>(extendedNominal)) {
793+
!isa<BuiltinTupleDecl>(extendedNominal) &&
794+
!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
795+
// FIXME: Recover this optimization even with NoncopyableGenerics on.
797796
return parentSig;
798797
}
799798

test/Generics/inverse_generics.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,13 @@ typealias err1 = RequireCopyable<Maybe<NC>>
138138
typealias err2 = RequireCopyable<NC>
139139
// expected-error@-1{{type 'NC' does not conform to protocol 'Copyable'}}
140140

141-
// plain extension doesn't treat Self as Copyable
142-
extension Maybe {
141+
extension Maybe where Wrapped: ~Copyable {
143142
func check1(_ t: RequireCopyable<Self>) {}
144143
// expected-error@-1 {{type 'Wrapped' does not conform to protocol 'Copyable'}}
145144
// expected-error@-2 {{'RequireCopyable' requires that 'Wrapped' conform to 'Copyable'}}
146145
}
147146

148-
extension Maybe where Self: Copyable {
147+
extension Maybe {
149148
func check2(_ t: RequireCopyable<Self>) {}
150149
}
151150

@@ -181,8 +180,7 @@ enum EnumExtendo {}
181180
extension EnumExtendo: ~Copyable {} // expected-error {{cannot apply inverse '~Copyable' to extension}}
182181

183182
extension NeedsCopyable where Self: ~Copyable {}
184-
// expected-error@-1 {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
185-
// expected-error@-2 {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
183+
// expected-error@-1 {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
186184

187185
protocol NoCopyP: ~Copyable {}
188186

test/Generics/inverse_protocols.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ protocol Eq: ~Copyable {
77
func different(from: borrowing Self) -> Bool
88
}
99

10-
extension Eq {
10+
extension Eq where Self: ~Copyable {
1111
func different(from other: borrowing Self) -> Bool { !same(as: other) }
1212
}
1313

test/Generics/inverse_scoping.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ protocol P {
1919

2020
protocol U {}
2121

22-
extension U where Self: ~Copyable {} // expected-error {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
22+
extension U where Self: ~Copyable {}
2323
// expected-error@-1 {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
2424

25-
extension P {
25+
extension P where Self: ~Copyable {
2626
func g() where Self: ~Copyable, // expected-error {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
2727
// FIXME: why no similar 2nd error as Escapable here on Self?
2828

@@ -53,7 +53,7 @@ struct S<T> {
5353
{}
5454
}
5555

56-
extension S where T: NoCopyReq & ~Copyable {} // expected-error {{cannot add inverse constraint 'T: ~Copyable' on generic parameter 'T' defined in outer scope}}
56+
extension S where T: NoCopyReq & ~Copyable {}
5757
// expected-error@-1 {{'T' required to be 'Copyable' but is marked with '~Copyable'}}
5858

5959
struct ExtraInverse<T: ~Copyable> {

test/Generics/inverse_signatures.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ struct ImplicitCond<T: ~Escapable & ~Copyable> {}
202202

203203
// CHECK-LABEL: ExtensionDecl line={{.*}} base=ImplicitCond
204204
// CHECK-NEXT: (normal_conformance type="ImplicitCond<T>" protocol="Empty")
205-
extension ImplicitCond: Empty {}
205+
extension ImplicitCond: Empty where T: ~Copyable, T: ~Escapable {}
206206

207207

208208
// NOTE: the following extensions were implicitly synthesized, so they appear at the end!

test/ModuleInterface/Inputs/Swiftskell.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,12 @@ public protocol Eq: ~Copyable {
1919
static func /=(_ a: borrowing Self, _ b: borrowing Self) -> Bool
2020
}
2121

22-
public extension Eq {
22+
public extension Eq where Self: ~Copyable {
2323
static func /=(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
2424
return !(a == b)
2525
}
2626
}
2727

28-
public extension Eq where Self: Equatable {
29-
static func ==(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
30-
return a == b
31-
}
32-
}
33-
3428
/// MARK: Result
3529
public enum Either<Success, Failure: Error> {
3630
case success(Success)
@@ -70,13 +64,13 @@ public enum Maybe<Value: ~Copyable> {
7064
case nothing
7165
}
7266

73-
extension Maybe: Show {
67+
extension Maybe: Show where Value: ~Copyable {
7468
public borrowing func show() -> String {
7569
fatalError("need borrowing switches")
7670
}
7771
}
7872

79-
extension Maybe: Eq where Value: Eq {
73+
extension Maybe: Eq where Value: Eq, Value: ~Copyable {
8074
public static func ==(_ a: borrowing Self, _ b: borrowing Self) -> Bool {
8175
fatalError("need borrowing switches")
8276
}

test/ModuleInterface/noncopyable_generics.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ import NoncopyableGenerics_Misc
108108
// Synthesized conditional conformances are next
109109

110110
// CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics
111-
// CHECK-MISC-NEXT: extension {{.*}}.Hello : Swift.Copyable where T : Swift.Copyable {
111+
// CHECK-MISC-NEXT: extension {{.*}}.Hello : Swift.Copyable where T : ~Escapable {
112112

113113
////////////////////////////////////////////////////////////////////////
114114
// At the end, ensure there are no synthesized Copyable extensions
@@ -127,10 +127,7 @@ import Swiftskell
127127
// CHECK-NEXT: public protocol Eq : ~Copyable {
128128

129129
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
130-
// CHECK-NEXT: extension Swiftskell.Eq {
131-
132-
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
133-
// CHECK-NEXT: extension Swiftskell.Eq where Self : Swift.Equatable {
130+
// CHECK-NEXT: extension Swiftskell.Eq where Self : ~Copyable {
134131

135132
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
136133
// CHECK-NEXT: public protocol Generator : ~Copyable {
@@ -143,10 +140,10 @@ import Swiftskell
143140
// CHECK-NEXT: public enum Maybe<Value> where Value : ~Copyable {
144141

145142
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
146-
// CHECK-NEXT: extension Swiftskell.Maybe : Swiftskell.Show {
143+
// CHECK-NEXT: extension Swiftskell.Maybe : Swiftskell.Show where Value : ~Copyable {
147144

148145
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
149-
// CHECK-NEXT: extension Swiftskell.Maybe : Swiftskell.Eq where Value : Swiftskell.Eq {
146+
// CHECK-NEXT: extension Swiftskell.Maybe : Swiftskell.Eq where Value : Swiftskell.Eq, Value : ~Copyable {
150147

151148
// CHECK: #if compiler(>=5.3) && $NoncopyableGenerics
152149
// CHECK-NEXT: public func maybe<A, B>(_ defaultVal: B, _ fn: (consuming A) -> B) -> (consuming Swiftskell.Maybe<A>) -> B where A : ~Copyable

test/Serialization/noncopyable_generics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
// CHECK-PRINT-DAG: protocol Generator<Value> {
2121
// CHECK-PRINT-DAG: enum Maybe<Wrapped> where Wrapped : ~Copyable {
22-
// CHECK-PRINT-DAG: extension Maybe : Copyable where Wrapped : Copyable {
22+
// CHECK-PRINT-DAG: extension Maybe : Copyable {
2323
// CHECK-PRINT-DAG: func ncIdentity<T>(_ t: consuming T) -> T where T : ~Copyable
2424
// CHECK-PRINT-DAG: protocol Either<Left, Right> : ~Copyable {
2525
// CHECK-PRINT-DAG: associatedtype Left : ~Copyable

0 commit comments

Comments
 (0)