diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index f822dcbefbb81..f7e5093168de5 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4123,12 +4123,14 @@ struct SelfReferenceKind { return SelfReferenceKind(false, false, false, false); } - /// The type refers to 'Self', but only as the result type of a method. + /// The type refers to 'Self', but only as the type of a property or + /// the result type of a method/subscript. static SelfReferenceKind Result() { return SelfReferenceKind(true, false, false, false); } - /// The type refers to 'Self', but only as the parameter type of a method. + /// The type refers to 'Self', but only as the parameter type + /// of a method/subscript. static SelfReferenceKind Parameter() { return SelfReferenceKind(false, true, false, false); } diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d9a3489de1ab9..a8c0c8e705ddc 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1992,14 +1992,15 @@ NOTE(witness_self_weaken_same_type,none, "consider weakening the same-type requirement %0 == %1 to a superclass " "requirement", (Type, Type)) ERROR(witness_requires_dynamic_self,none, - "method %0 in non-final class %1 must return 'Self' to conform to " - "protocol %2", - (DeclName, Type, Type)) + "%select{%error|method|property|subscript}0 %1 in non-final class %2 " + "must %select{%error|return|specify type|return}0 'Self' " + "to conform to protocol %3", + (RequirementKind, DeclName, Type, Type)) ERROR(witness_requires_class_implementation,none, - "method %0 in non-final class %1 cannot be implemented in a " - "protocol extension because it returns 'Self' and has associated type " - "requirements", - (DeclName, Type)) + "%select{%error|method|%error|subscript}0 %1 in non-final class %2 " + "cannot be implemented in a protocol extension because it returns 'Self' " + "and has associated type requirements", + (RequirementKind, DeclName, Type)) ERROR(witness_not_accessible_proto,none, "%select{initializer %1|method %1|%select{|setter for }2property %1" "|subscript%select{| setter}2}0 must be declared " diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2dbf607223c1a..5331c6b2af90d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4965,12 +4965,13 @@ ProtocolDecl::findProtocolSelfReferences(const ValueDecl *value, return ::findProtocolSelfReferences(this, type, skipAssocTypes); } else { - if (::findProtocolSelfReferences(this, type, - skipAssocTypes)) { - return SelfReferenceKind::Other(); - } - return SelfReferenceKind::None(); + assert(isa(value)); + + return ::findProtocolSelfReferences(this, type, + skipAssocTypes); } + + return SelfReferenceKind::None(); } bool ProtocolDecl::isAvailableInExistential(const ValueDecl *decl) const { diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 183641f752b7d..12edcc2f61db3 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -1061,7 +1061,6 @@ namespace { AccessSemantics semantics) { auto choice = overload.choice; auto openedType = overload.openedType; - auto openedFullType = overload.openedFullType; ValueDecl *member = choice.getDecl(); @@ -1097,13 +1096,15 @@ namespace { return result; } + auto refTy = simplifyType(overload.openedFullType); + // If we're referring to the member of a module, it's just a simple // reference. if (baseTy->is()) { assert(semantics == AccessSemantics::Ordinary && "Direct property access doesn't make sense for this"); auto ref = new (context) DeclRefExpr(memberRef, memberLoc, Implicit); - cs.setType(ref, simplifyType(openedFullType)); + cs.setType(ref, refTy); ref->setFunctionRefKind(choice.getFunctionRefKind()); auto *DSBI = cs.cacheType(new (context) DotSyntaxBaseIgnoredExpr( base, dotLoc, ref, cs.getType(ref))); @@ -1114,8 +1115,6 @@ namespace { (!baseIsInstance && member->isInstanceMember()); bool isPartialApplication = shouldBuildCurryThunk(choice, baseIsInstance); - auto refTy = simplifyType(openedFullType); - // The formal type of the 'self' value for the member's declaration. Type containerTy = getBaseType(refTy->castTo()); @@ -1278,8 +1277,8 @@ namespace { = new (context) MemberRefExpr(base, dotLoc, memberRef, memberLoc, Implicit, semantics); memberRefExpr->setIsSuper(isSuper); + cs.setType(memberRefExpr, refTy->castTo()->getResult()); - cs.setType(memberRefExpr, simplifyType(openedType)); Expr *result = memberRefExpr; closeExistential(result, locator); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index e0086b749bd2b..924acab7f773c 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2078,7 +2078,7 @@ static Type getRequirementTypeForDisplay(ModuleDecl *module, return FunctionType::get(params, result, fnTy->getExtInfo()); } - return substType(type, /*result*/false); + return substType(type, /*result*/ true); } diag::RequirementKind @@ -3343,41 +3343,36 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement, emitDeclaredHereIfNeeded(diags, diagLoc, witness); }); } else if (selfKind.result) { - // The reference to Self occurs in the result type. A non-final class - // can satisfy this requirement with a method that returns Self. + // The reference to Self occurs in the result type of a method/subscript + // or the type of a property. A non-final class can satisfy this requirement + // by holding onto Self accordingly. + if (witness->getDeclContext()->getSelfClassDecl()) { + const bool hasDynamicSelfResult = [&] { + if (auto func = dyn_cast(witness)) { + return func->hasDynamicSelfResult(); + } else if (auto var = dyn_cast(witness)) { + return var->getInterfaceType()->hasDynamicSelfType(); + } - // If the function has a dynamic Self, it's okay. - if (auto func = dyn_cast(witness)) { - if (func->getDeclContext()->getSelfClassDecl() && - !func->hasDynamicSelfResult()) { + return cast(witness) + ->getElementInterfaceType() + ->hasDynamicSelfType(); + }(); + + if (!hasDynamicSelfResult) { diagnoseOrDefer(requirement, false, [witness, requirement](NormalProtocolConformance *conformance) { auto proto = conformance->getProtocol(); auto &diags = proto->getASTContext().Diags; SourceLoc diagLoc = getLocForDiagnosingWitness(conformance,witness); - diags.diagnose(diagLoc, - diag::witness_requires_dynamic_self, + diags.diagnose(diagLoc, diag::witness_requires_dynamic_self, + getProtocolRequirementKind(requirement), requirement->getName(), conformance->getType(), proto->getDeclaredInterfaceType()); emitDeclaredHereIfNeeded(diags, diagLoc, witness); }); } - - // Constructors conceptually also have a dynamic Self - // return type, so they're okay. - } else if (!isa(witness)) { - diagnoseOrDefer(requirement, false, - [witness, requirement](NormalProtocolConformance *conformance) { - auto proto = conformance->getProtocol(); - auto &diags = proto->getASTContext().Diags; - SourceLoc diagLoc = getLocForDiagnosingWitness(conformance, witness); - diags.diagnose(diagLoc, diag::witness_self_non_subtype, - proto->getDeclaredInterfaceType(), - requirement->getName(), - conformance->getType()); - emitDeclaredHereIfNeeded(diags, diagLoc, witness); - }); } } else if (selfKind.requirement) { if (auto targetPair = getAdopteeSelfSameTypeConstraint(classDecl, @@ -3413,8 +3408,8 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement, // constraint that either the requirement not produce 'Self' in a // covariant position, or the type of the requirement does not involve // associated types. - if (auto func = dyn_cast(witness)) { - if (func->getDeclContext()->getExtendedProtocolDecl()) { + if (isa(witness) || isa(witness)) { + if (witness->getDeclContext()->getExtendedProtocolDecl()) { auto selfKindWithAssocTypes = Proto->findProtocolSelfReferences( requirement, /*allowCovariantParameters=*/false, @@ -3427,6 +3422,7 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement, auto &diags = proto->getASTContext().Diags; diags.diagnose(conformance->getLoc(), diag::witness_requires_class_implementation, + getProtocolRequirementKind(requirement), requirement->getName(), conformance->getType()); diags.diagnose(witness, diag::decl_declared_here, diff --git a/test/Interpreter/dynamic_self.swift b/test/Interpreter/dynamic_self.swift index fc6820602611c..9ee543de0f6d3 100644 --- a/test/Interpreter/dynamic_self.swift +++ b/test/Interpreter/dynamic_self.swift @@ -6,27 +6,71 @@ protocol P { func f() -> Self func g() -> Self + subscript() -> Self { get } + var p: Self { get } } protocol CP : class { func f() -> Self func g() -> Self + subscript() -> Self { get } + var p: Self { get } +} + +extension P { + func f() -> Self { + print("[Self := \(Self.self), self is \(type(of: self))] P extension.f()") + return self + } + func g() -> Self { + print("[Self := \(Self.self), self is \(type(of: self))] P extension.g()") + return self + } + subscript() -> Self { + print("[Self := \(Self.self), self is \(type(of: self))] P extension.subscript()") + return self + } + var p: Self { + print("[Self := \(Self.self), self is \(type(of: self))] P extension.p") + return self + } +} + +extension CP { + func f() -> Self { + print("[Self := \(Self.self), self is \(type(of: self))] CP extension.f()") + return self + } + func g() -> Self { + print("[Self := \(Self.self), self is \(type(of: self))] CP extension.g()") + return self + } + subscript() -> Self { + print("[Self := \(Self.self), self is \(type(of: self))] CP extension.subscript()") + return self + } + var p: Self { + print("[Self := \(Self.self), self is \(type(of: self))] CP extension.p") + return self + } } func callDynamicSelfExistential(_ p: P) { - print("Before first call") - var p2 = p.f() - print("Between calls") - p2.g() - print("After second call") + print("callDynamicSelfExistential {") + let p2 = p.f() + let p3 = p2.g() + let p4 = p3[] + let p5 = p4.p + print(" } callDynamicSelfExistential") } func callDynamicSelfClassExistential(_ cp: CP) { - print("Before first call") - var cp2 = cp.f() - print("Between calls") - cp2.g() - print("After second call") + print("callDynamicSelfClassExistential {") + let cp2 = cp.f() + let cp3 = cp2.g() + let cp4 = cp3[] + let cp5 = cp4.p + print(" } callDynamicSelfClassExistential") } struct S : P { @@ -39,54 +83,101 @@ struct S : P { print("S.g()") return self } -} -class C : P, CP { - init() { - print("Allocating C") + subscript() -> S { + print("S.subscript()") + return self + } + + var p: S { + print("S.p") + return self } +} +class C1a : P, CP { func f() -> Self { - print("C.f()") + print("C1a.f()") return self } func g() -> Self { - print("C.g()") + print("C1a.g()") + return self + } + + subscript() -> Self { + print("C1a.subscript()") + return self + } + + var p: Self { + print("C1a.p") return self } } +final class C1b : C1a { + override subscript() -> Self { + print("C1b.subscript()") + return self + } +} + +class C2a : P {} +final class C2b : C2a {} + +class C3a : CP {} +final class C3b : C3a {} print("-------------------------------") -// CHECK: S() as non-class existential -print("S() as non-class existential") -// CHECK-NEXT: Before first call +// CHECK: callDynamicSelfExistential { // CHECK-NEXT: S.f() -// CHECK-NEXT: Between calls // CHECK-NEXT: S.g() -// CHECK-NEXT: After second call +// CHECK-NEXT: S.subscript() +// CHECK-NEXT: S.p +// CHECK-NEXT: } callDynamicSelfExistential callDynamicSelfExistential(S()) -// CHECK-NEXT: C() as non-class existential -print("C() as non-class existential") -// CHECK-NEXT: Allocating C -// CHECK-NEXT: Before first call -// CHECK-NEXT: C.f() -// CHECK-NEXT: Between calls -// CHECK-NEXT: C.g() -// CHECK-NEXT: After second call -callDynamicSelfExistential(C()) - -// CHECK-NEXT: C() as class existential -print("C() as class existential") -// CHECK-NEXT: Allocating C -// CHECK-NEXT: Before first call -// CHECK-NEXT: C.f() -// CHECK-NEXT: Between calls -// CHECK-NEXT: C.g() -// CHECK-NEXT: After second call -callDynamicSelfClassExistential(C()) +// CHECK-NEXT: callDynamicSelfExistential { +// CHECK-NEXT: C1a.f() +// CHECK-NEXT: C1a.g() +// CHECK-NEXT: C1a.subscript() +// CHECK-NEXT: C1a.p +// CHECK-NEXT: } callDynamicSelfExistential +callDynamicSelfExistential(C1a()) + +// CHECK-NEXT: callDynamicSelfExistential { +// CHECK-NEXT: C1a.f() +// CHECK-NEXT: C1a.g() +// CHECK-NEXT: C1b.subscript() +// CHECK-NEXT: C1a.p +// CHECK-NEXT: } callDynamicSelfExistential +callDynamicSelfExistential(C1b()) + +// CHECK-NEXT: callDynamicSelfExistential { +// CHECK-NEXT: [Self := C2a, self is C2b] P extension.f() +// CHECK-NEXT: [Self := C2a, self is C2b] P extension.g() +// CHECK-NEXT: [Self := C2a, self is C2b] P extension.subscript() +// CHECK-NEXT: [Self := C2a, self is C2b] P extension.p +// CHECK-NEXT: } callDynamicSelfExistential +callDynamicSelfExistential(C2b() as C2a) + +// CHECK-NEXT: callDynamicSelfClassExistential { +// CHECK-NEXT: C1a.f() +// CHECK-NEXT: C1a.g() +// CHECK-NEXT: C1a.subscript() +// CHECK-NEXT: C1a.p +// CHECK-NEXT: } callDynamicSelfClassExistential +callDynamicSelfClassExistential(C1a()) + +// CHECK-NEXT: callDynamicSelfClassExistential { +// CHECK-NEXT: [Self := C3b, self is C3b] CP extension.f() +// CHECK-NEXT: [Self := C3b, self is C3b] CP extension.g() +// CHECK-NEXT: [Self := C3b, self is C3b] CP extension.subscript() +// CHECK-NEXT: [Self := C3b, self is C3b] CP extension.p +// CHECK-NEXT: } callDynamicSelfClassExistential +callDynamicSelfClassExistential(C3b() as C3a) print("-------------------------------") diff --git a/test/SILGen/dynamic_self.swift b/test/SILGen/dynamic_self.swift index d2d6df2d163e6..95070d3b15894 100644 --- a/test/SILGen/dynamic_self.swift +++ b/test/SILGen/dynamic_self.swift @@ -8,10 +8,14 @@ protocol P { func f() -> Self + subscript() -> Self { get } + var p: Self { get } } protocol CP : class { func f() -> Self + subscript() -> Self { get } + var p: Self { get } } class X : P, CP { @@ -20,6 +24,12 @@ class X : P, CP { // CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self1XC1f{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed X) -> @owned func f() -> Self { return self } + // CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self1XCACXDycig : $@convention(method) (@guaranteed X) -> @owned X + subscript() -> Self { self } + + // CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self1XC1pACXDvg : $@convention(method) (@guaranteed X) -> @owned X + var p: Self { self } + // CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self1XC7factory{{[_0-9a-zA-Z]*}}FZ : $@convention(method) (Int, @thick X.Type) -> @owned X // CHECK: bb0([[I:%[0-9]+]] : $Int, [[SELF:%[0-9]+]] : $@thick X.Type): // CHECK: [[DYNAMIC_SELF:%[0-9]+]] = unchecked_trivial_bit_cast [[SELF]] : $@thick X.Type to $@thick @dynamic_self X.Type @@ -83,17 +93,65 @@ func testExistentialDispatch(p: P) { // CHECK: destroy_addr [[P_RESULT]] : $*P // CHECK: dealloc_stack [[P_RESULT]] : $*P _ = p.f() + +// CHECK: [[PCOPY_ADDR:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P to $*@opened([[N:".*"]]) P +// CHECK: [[P_RESULT:%[0-9]+]] = alloc_stack $P +// CHECK: [[PCOPY_ADDR_1:%[0-9]+]] = alloc_stack $@opened([[N]]) P +// CHECK: copy_addr [[PCOPY_ADDR]] to [initialization] [[PCOPY_ADDR_1]] : $*@opened([[N]]) P +// CHECK: [[P_P_GETTER:%[0-9]+]] = witness_method $@opened([[N]]) P, #P.p!getter : {{.*}}, [[PCOPY_ADDR]]{{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: [[P_RESULT_ADDR2:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*P, $@opened([[N]]) P +// CHECK: apply [[P_P_GETTER]]<@opened([[N]]) P>([[P_RESULT_ADDR2]], [[PCOPY_ADDR_1]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: destroy_addr [[PCOPY_ADDR_1]] : $*@opened([[N]]) P +// CHECK: destroy_addr [[P_RESULT]] : $*P +// CHECK: dealloc_stack [[PCOPY_ADDR_1]] : $*@opened([[N]]) P +// CHECK: dealloc_stack [[P_RESULT]] : $*P + _ = p.p + +// CHECK: [[PCOPY_ADDR:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*P to $*@opened([[N:".*"]]) P +// CHECK: [[P_RESULT:%[0-9]+]] = alloc_stack $P +// CHECK: [[PCOPY_ADDR_1:%[0-9]+]] = alloc_stack $@opened([[N]]) P +// CHECK: copy_addr [[PCOPY_ADDR]] to [initialization] [[PCOPY_ADDR_1]] : $*@opened([[N]]) P +// CHECK: [[P_SUBSCRIPT_GETTER:%[0-9]+]] = witness_method $@opened([[N]]) P, #P.subscript!getter : {{.*}}, [[PCOPY_ADDR]]{{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: [[P_RESULT_ADDR:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*P, $@opened([[N]]) P +// CHECK: apply [[P_SUBSCRIPT_GETTER]]<@opened([[N]]) P>([[P_RESULT_ADDR]], [[PCOPY_ADDR_1]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: destroy_addr [[PCOPY_ADDR_1]] : $*@opened([[N]]) P +// CHECK: destroy_addr [[P_RESULT]] : $*P +// CHECK: dealloc_stack [[PCOPY_ADDR_1]] : $*@opened([[N]]) P +// CHECK: dealloc_stack [[P_RESULT]] : $*P + _ = p[] } // CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self28testExistentialDispatchClass{{[_0-9a-zA-Z]*}}F : $@convention(thin) (@guaranteed CP) -> () +func testExistentialDispatchClass(cp: CP) { // CHECK: bb0([[CP:%[0-9]+]] : @guaranteed $CP): // CHECK: [[CP_ADDR:%[0-9]+]] = open_existential_ref [[CP]] : $CP to $@opened([[N:".*"]]) CP // CHECK: [[CP_F:%[0-9]+]] = witness_method $@opened([[N]]) CP, #CP.f : {{.*}}, [[CP_ADDR]]{{.*}} : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0 // CHECK: [[CP_F_RESULT:%[0-9]+]] = apply [[CP_F]]<@opened([[N]]) CP>([[CP_ADDR]]) : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0 // CHECK: [[RESULT_EXISTENTIAL:%[0-9]+]] = init_existential_ref [[CP_F_RESULT]] : $@opened([[N]]) CP : $@opened([[N]]) CP, $CP // CHECK: destroy_value [[RESULT_EXISTENTIAL]] -func testExistentialDispatchClass(cp: CP) { _ = cp.f() + +// CHECK: [[CP_ADDR:%[0-9]+]] = open_existential_ref [[CP]] : $CP to $@opened([[N:".*"]]) CP +// CHECK: [[CP_ADDR_1:%[0-9]+]] = copy_value [[CP_ADDR]] : $@opened([[N]]) CP +// CHECK: [[CP_BORROWED:%[0-9]+]] = begin_borrow [[CP_ADDR_1]] : $@opened([[N]]) CP +// CHECK: [[CP_P_GETTER:%[0-9]+]] = witness_method $@opened([[N]]) CP, #CP.p!getter : {{.*}}, [[CP_ADDR]]{{.*}} : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0 +// CHECK: [[APPLY_RESULT:%[0-9]+]] = apply [[CP_P_GETTER]]<@opened([[N]]) CP>([[CP_BORROWED]]) : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0 +// CHECK: end_borrow [[CP_BORROWED]] : $@opened([[N]]) CP +// CHECK: destroy_value [[CP_ADDR_1]] : $@opened([[N]]) CP +// CHECK: [[RESULT_EXISTENTIAL:%[0-9]+]] = init_existential_ref [[APPLY_RESULT]] : $@opened([[N]]) CP : $@opened([[N]]) CP, $CP +// CHECK: destroy_value [[RESULT_EXISTENTIAL]] : $CP + _ = cp.p + +// CHECK: [[CP_ADDR:%[0-9]+]] = open_existential_ref [[CP]] : $CP to $@opened([[N:".*"]]) CP +// CHECK: [[CP_ADDR_1:%[0-9]+]] = copy_value [[CP_ADDR]] : $@opened([[N]]) CP +// CHECK: [[CP_BORROWED:%[0-9]+]] = begin_borrow [[CP_ADDR_1]] : $@opened([[N]]) CP +// CHECK: [[CP_SUBSCRIPT_GETTER:%[0-9]+]] = witness_method $@opened([[N]]) CP, #CP.subscript!getter : {{.*}}, [[CP_ADDR]]{{.*}} : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0 +// CHECK: [[APPLY_RESULT:%[0-9]+]] = apply [[CP_SUBSCRIPT_GETTER]]<@opened([[N]]) CP>([[CP_BORROWED]]) : $@convention(witness_method: CP) <τ_0_0 where τ_0_0 : CP> (@guaranteed τ_0_0) -> @owned τ_0_0 +// CHECK: end_borrow [[CP_BORROWED]] : $@opened([[N]]) CP +// CHECK: destroy_value [[CP_ADDR_1]] : $@opened([[N]]) CP +// CHECK: [[RESULT_EXISTENTIAL:%[0-9]+]] = init_existential_ref [[APPLY_RESULT]] : $@opened([[N]]) CP : $@opened([[N]]) CP, $CP +// CHECK: destroy_value [[RESULT_EXISTENTIAL]] : $CP + _ = cp[] } @objc class ObjC { diff --git a/test/decl/protocol/conforms/inherited.swift b/test/decl/protocol/conforms/inherited.swift index 09461414696e3..08510fdc0bcff 100644 --- a/test/decl/protocol/conforms/inherited.swift +++ b/test/decl/protocol/conforms/inherited.swift @@ -5,7 +5,7 @@ protocol P1 { func f1(_ x: Self?) -> Bool } -// Never inheritable: property with 'Self' in its signature. +// Inheritable: property with 'Self' in its signature. protocol P2 { var prop2: Self { get set } } @@ -13,7 +13,7 @@ protocol P2a { var prop2a: Self { get set } } -// Never inheritable: subscript with 'Self' in its result type. +// Inheritable: subscript with 'Self' in its result type. protocol P3 { subscript (i: Int) -> Self { get } } @@ -94,7 +94,7 @@ class A : P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 { func f1(_ x: A?) -> Bool { return true } // P2 - var prop2: A { // expected-error{{protocol 'P2' requirement 'prop2' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}} + var prop2: A { // expected-error{{property 'prop2' in non-final class 'A' must specify type 'Self' to conform to protocol 'P2'}} get { return self } set {} } @@ -106,7 +106,7 @@ class A : P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 { } // P3 - subscript (i: Int) -> A { // expected-error{{protocol 'P3' requirement 'subscript(_:)' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}} + subscript (i: Int) -> A { // expected-error{{subscript 'subscript(_:)' in non-final class 'A' must return 'Self' to conform to protocol 'P3'}} get { return self } @@ -145,7 +145,7 @@ class A : P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 { } extension A: P2a, P5a, P10a {} -// expected-error@-1 {{protocol 'P2a' requirement 'prop2a' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}} +// expected-error@-1 {{property 'prop2a' in non-final class 'A' must specify type 'Self' to conform to protocol 'P2a'}} // expected-error@-2 {{method 'f5a()' in non-final class 'A' must return 'Self' to conform to protocol 'P5a'}} // expected-error@-3 {{protocol 'P10a' requirement 'f10a' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}} diff --git a/test/decl/protocol/conforms/self.swift b/test/decl/protocol/conforms/self.swift index 78849f8e232eb..6f8603d288f8f 100644 --- a/test/decl/protocol/conforms/self.swift +++ b/test/decl/protocol/conforms/self.swift @@ -7,6 +7,8 @@ protocol P { func returnsSelf() -> Self func hasDefaultTakesT(_: T) func returnsSelfTakesT(_: T) -> Self + + subscript(_: T) -> Self { get } } extension P { @@ -21,19 +23,29 @@ extension P { func returnsSelfTakesT(_: T) -> Self { // expected-note {{'returnsSelfTakesT' declared here}} return self } + + subscript(_: T) -> Self { self } // expected-note {{'subscript(_:)' declared here}} } // This fails -class Class : P {} // expected-error {{method 'returnsSelfTakesT' in non-final class 'Class' cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements}} +class Class : P {} +// expected-error@-1 {{method 'returnsSelfTakesT' in non-final class 'Class' cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements}} +// expected-error@-2 {{subscript 'subscript(_:)' in non-final class 'Class' cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements}} // This succeeds, because the class is final final class FinalClass : P {} -// This succeeds, because we're not using the default implementation +// This succeeds, because we're not using the default implementations class NonFinalClass : P { + // FIXME: An explicit type witness is necessary to avoid an unrelated + // associated type inference bug. + typealias T = Never + func returnsSelfTakesT(_: T) -> Self { return self } + + subscript(_: T) -> Self { self } } // Test for default implementation that comes from a constrained extension diff --git a/test/decl/protocol/req/dynamic_self.swift b/test/decl/protocol/req/dynamic_self.swift index fc9c06fc0449f..758a301ef6f22 100644 --- a/test/decl/protocol/req/dynamic_self.swift +++ b/test/decl/protocol/req/dynamic_self.swift @@ -1,58 +1,88 @@ // RUN: %target-typecheck-verify-swift protocol P { + var p: Self { get } + // expected-note@-1{{protocol requires property 'p' with type 'Self'}} + // expected-note@-2{{protocol requires property 'p' with type 'EError'}} + // expected-note@-3{{protocol requires property 'p' with type 'SError'}} + subscript() -> Self { get } + // expected-note@-1{{protocol requires subscript with type '() -> Self'}} + // expected-note@-2{{protocol requires subscript with type '() -> EError'}} + // expected-note@-3{{protocol requires subscript with type '() -> SError'}} func f() -> Self // expected-note@-1{{protocol requires function 'f()' with type '() -> Self'}} // expected-note@-2{{protocol requires function 'f()' with type '() -> EError'}} // expected-note@-3{{protocol requires function 'f()' with type '() -> SError'}} } -// Error: Missing Self method in a class. +func takesP(_: P) {} // OK + +// Error: Missing witnesses. class W : P {} // expected-error{{type 'W' does not conform to protocol 'P'}} // Okay: Self method in class. class X : P { - func f() -> Self { return self } + var p: Self { self } + subscript() -> Self { self } + func f() -> Self { self } } class Y { - func f() -> Self { return self } + var p: Self { self } + subscript() -> Self { self } + func f() -> Self { self } } class GX : P { - func f() -> Self { return self } + var p: Self { self } + subscript() -> Self { self } + func f() -> Self { self } } // Okay: dynamic Self method in superclass. class Z : Y, P { } -// Erro: Z2 conforms, but subclass would not +// Error: Z2 conforms, but subclass would not. class Z2 : P { - func f() -> Z2 { return self } // expected-error{{method 'f()' in non-final class 'Z2' must return 'Self' to conform to protocol 'P'}} + var p: Z2 { self } //expected-error{{property 'p' in non-final class 'Z2' must specify type 'Self' to conform to protocol 'P'}} + subscript() -> Z2 { self } //expected-error{{subscript 'subscript()' in non-final class 'Z2' must return 'Self' to conform to protocol 'P'}} + func f() -> Z2 { self } // expected-error{{method 'f()' in non-final class 'Z2' must return 'Self' to conform to protocol 'P'}} } // Okay: struct conforms by returning itself struct S : P { - func f() -> S { return self } + var p: S { self } + subscript() -> S { self } + func f() -> S { self } } struct GS : P { - func f() -> GS { return self } + var p: GS { self } + subscript() -> GS { self } + func f() -> GS { self } } struct SError : P { // expected-error{{type 'SError' does not conform to protocol 'P'}} - func f() -> Int { return 0 } // expected-note{{candidate has non-matching type '() -> Int'}} + var p: Int { 0 } // expected-note{{candidate has non-matching type 'Int'}} + subscript() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}} + func f() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}} } // Okay: enum conforms by returning itself enum E : P { - func f() -> E { return self } + var p: E { self } + subscript() -> E { self } + func f() -> E { self } } enum GE : P { - func f() -> GE { return self } + var p: GE { self } + subscript() -> GE { self } + func f() -> GE { self } } enum EError : P { // expected-error{{type 'EError' does not conform to protocol 'P'}} - func f() -> Int { return 0 } // expected-note{{candidate has non-matching type '() -> Int'}} + var p: Int { 0 } // expected-note{{candidate has non-matching type 'Int'}} + subscript() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}} + func f() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}} }