diff --git a/CHANGELOG.md b/CHANGELOG.md index 03597647efe9e..2dd294a966f9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ CHANGELOG Swift 5.1 --------- +* [SE-0068][]: + + `Self` can now be used inside member functions and for function arguments of structs and enums to refer to the containing type. + * [SR-7799][]: Enum cases can now be matched against an optional enum without diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 1951dd0e73dd6..33af8d76293dd 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -223,9 +223,8 @@ bool DeclContext::isTypeContext() const { DeclContext *DeclContext::getInnermostTypeContext() { auto dc = this; do { - if (auto decl = dc->getAsDecl()) - if (isa(decl) || isa(decl)) - return dc; + if (dc->isTypeContext()) + return dc; } while ((dc = dc->getParent())); return nullptr; diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 5574e65ada1f8..daee66f83b21d 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -551,6 +551,18 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { }; if (!isConfused) { + if (Name == Context.Id_Self) { + if (DeclContext *typeContext = DC->getInnermostTypeContext()){ + Type SelfType = typeContext->getSelfInterfaceType(); + + if (typeContext->getSelfClassDecl()) + SelfType = DynamicSelfType::get(SelfType, Context); + SelfType = DC->mapTypeIntoContext(SelfType); + return new (Context) TypeExpr(TypeLoc(new (Context) + FixedTypeRepr(SelfType, Loc))); + } + } + TypoCorrectionResults corrections(*this, Name, nameLoc); performTypoCorrection(DC, UDRE->getRefKind(), Type(), lookupOptions, corrections); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 9cece60fca78a..07a79cebe8b6e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1057,10 +1057,23 @@ static Type diagnoseUnknownType(TypeResolution resolution, NominalTypeDecl *nominal = nullptr; if ((nominalDC = dc->getInnermostTypeContext()) && (nominal = nominalDC->getSelfNominalTypeDecl())) { - // Attempt to refer to 'Self' within a non-protocol nominal - // type. Fix this by replacing 'Self' with the nominal type name. assert(!isa(nominal) && "Cannot be a protocol"); + bool insideClass = nominalDC->getSelfClassDecl() != nullptr; + AbstractFunctionDecl *methodDecl = dc->getInnermostMethodContext(); + bool declaringMethod = methodDecl && + methodDecl->getDeclContext() == dc->getParentForLookup(); + + if (((!insideClass || !declaringMethod) && + !options.is(TypeResolverContext::GenericRequirement)) || + options.is(TypeResolverContext::ExplicitCastExpr)) { + Type SelfType = nominal->getSelfInterfaceType(); + if (insideClass) + SelfType = DynamicSelfType::get(SelfType, ctx); + return resolution.mapTypeIntoContext(SelfType); + } + + // Attempt to refer to 'Self' within a non-protocol nominal type. // Produce a Fix-It replacing 'Self' with the nominal type name. auto name = getDeclNameFromContext(dc, nominal); diags.diagnose(comp->getIdLoc(), diag::self_in_nominal, name) diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index 89c380b9de1d0..c76ef458c62dd 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -10,15 +10,15 @@ func inFunction() { } struct S0 { - func f() -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{15-19=S0}} + func f() -> Self { } - func g(_ ds: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{16-20=S0}} + func g(_ ds: Self) { } } enum E0 { - func f() -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{15-19=E0}} + func f() -> Self { } - func g(_ ds: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{16-20=E0}} + func g(_ ds: Self) { } } class C0 { @@ -85,11 +85,11 @@ class C1 { var x: Int = self // expected-error{{cannot convert value of type 'Self.Type' to specified type 'Int'}} // Can't utter Self within the body of a method. - var c1 = C1(int: 5) as Self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{28-32=C1}} + var c1 = C1(int: 5) as Self // expected-error{{'C1' is not convertible to 'Self'; did you mean to use 'as!' to force downcast?}} if b { return self.init(int: 5) } - return Self() // expected-error{{use of unresolved identifier 'Self'; did you mean 'self'?}} + return Self() // expected-error{{non-nominal type 'Self' does not support explicit initialization}} } // This used to crash because metatype construction went down a @@ -412,4 +412,4 @@ class SelfOperator { func useSelfOperator() { let s = SelfOperator() _ = s + s -} \ No newline at end of file +} diff --git a/test/decl/nested/type_in_type.swift b/test/decl/nested/type_in_type.swift index 6543b11344d78..6945639a0afda 100644 --- a/test/decl/nested/type_in_type.swift +++ b/test/decl/nested/type_in_type.swift @@ -417,7 +417,6 @@ extension OuterGeneric.MidNonGeneric { } func doMoreStuffWrong() -> Self { - // expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'OuterGeneric.MidNonGeneric'?}} } } diff --git a/test/type/self.swift b/test/type/self.swift index 815842946a6ea..0a9fea9611bc8 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -1,7 +1,7 @@ // RUN: %target-typecheck-verify-swift -swift-version 5 struct S0 { - func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{21-25=S0}} + func foo(_ other: Self) { } } class C0 { @@ -9,7 +9,7 @@ class C0 { } enum E0 { - func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{21-25=E0}} + func foo(_ other: Self) { } } // rdar://problem/21745221 @@ -23,7 +23,7 @@ extension X { } extension X.Inner { - func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'X.Inner'?}}{{21-25=X.Inner}} + func foo(_ other: Self) { } } // SR-695 @@ -43,3 +43,111 @@ final class FinalMario : Mario { } } +// These references to Self are now possible (SE-0068) + +class A { + let b: Int + required init(a: Int) { + print("\(Self.self).\(#function)") + Self.y() + b = a + } + static func z(n: Self? = nil) { + // expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'A'?}} + print("\(Self.self).\(#function)") + } + class func y() { + print("\(Self.self).\(#function)") + Self.z() + } + func x() -> A? { + print("\(Self.self).\(#function)") + Self.y() + Self.z() + let _: Self = Self.init(a: 66) + // expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'A'?}} + return Self.init(a: 77) as? Self as? A + // expected-warning@-1 {{conditional cast from 'Self' to 'Self' always succeeds}} + // expected-warning@-2 {{conditional downcast from 'Self?' to 'A' is equivalent to an implicit conversion to an optional 'A'}} + } +} + +class B: A { + let a: Int + required convenience init(a: Int) { + print("\(Self.self).\(#function)") + self.init() + } + init() { + print("\(Self.self).\(#function)") + Self.y() + Self.z() + a = 99 + super.init(a: 88) + } + override class func y() { + print("override \(Self.self).\(#function)") + } +} + +class C { + required init() { + } + func f() { + func g(_: Self) {} + } + func g() { + _ = Self.init() as? Self + // expected-warning@-1 {{conditional cast from 'Self' to 'Self' always succeeds}} + } +} + +struct S2 { + let x = 99 + struct S3 { + let x = 99 + static func x() { + Self.y() + } + func f() { + func g(_: Self) {} + } + static func y() { + print("HERE") + } + func foo(a: [Self]) -> Self? { + Self.x() + return Self.init() as? Self + // expected-warning@-1 {{conditional cast from 'S2.S3' to 'S2.S3' always succeeds}} + } + } +} + +extension S2 { + static func x() { + Self.y() + } + static func y() { + print("HERE") + } + func f() { + func g(_: Self) {} + } + func foo(a: [Self]) -> Self? { + Self.x() + return Self.init() as? Self + // expected-warning@-1 {{conditional cast from 'S2' to 'S2' always succeeds}} + } +} + +enum E { + static func f() { + func g(_: Self) {} + print("f()") + } + case e + func h(h: Self) -> Self { + Self.f() + return .e + } +}