From c27f79e3eb9f245bfe98064ad2582366a9a41750 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Sun, 24 Feb 2019 16:48:50 +0000 Subject: [PATCH 01/18] Make Self available to instance member functions (SE-0068?) --- lib/Sema/TypeCheckConstraints.cpp | 10 +++++++ test/decl/func/dynamic_self.swift | 46 +++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index dd9cdcd38a92c..b6fc8f8f31b7e 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -551,6 +551,16 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { }; if (!isConfused) { + if (Name.getBaseName().userFacingName() == "Self") { + DeclName selfName(Context.getIdentifier("self")); + auto selfInstance = lookupUnqualified(DC, selfName, Loc, lookupOptions); + if (!selfInstance.empty()) { + ValueDecl *D = selfInstance.front().getValueDecl(); + Expr *E = new (Context) DeclRefExpr(D, nameLoc, /*Implicit=*/false); + return new (Context) DynamicTypeExpr(Loc, Loc, E, Loc, Type()); + } + } + TypoCorrectionResults corrections(*this, Name, nameLoc); performTypoCorrection(DC, UDRE->getRefKind(), Type(), lookupOptions, corrections); diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index 89c380b9de1d0..be2aaa4d477d7 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -89,7 +89,7 @@ class C1 { 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.Type' does not support explicit initialization}} } // This used to crash because metatype construction went down a @@ -412,4 +412,46 @@ class SelfOperator { func useSelfOperator() { let s = SelfOperator() _ = s + s -} \ No newline at end of file +} + +// These references to Self are now possible + +class A { + let b: Int + required init(a: Int) { + print("\(Self).\(#function)") + b = a + } + static func z() { + print("\(Self.self).\(#function)") + } + class func y() { + print("\(Self).\(#function)") + } + func x() { + print("\(Self.self).\(#function)") + Self.y() + Self.z() + _ = Self.init(a: 77) + } +} + +class B: A { + let a: Int + required convenience init(a: Int) { + print("\(Self).\(#function)") + self.init() + } + init() { + print("\(Self.self).\(#function)") + Self.y() + Self.z() + a = 99 + super.init(a: 88) + } + override class func y() { + print("\(Self).\(#function)") + } +} + +B().x() From d08b319bd5bc13b5b5165372fa48df4ffd90b9f9 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Tue, 26 Feb 2019 19:32:13 +0000 Subject: [PATCH 02/18] Works for value types and static functions. --- lib/Sema/TypeCheckConstraints.cpp | 19 ++++++++++++++----- lib/Sema/TypeCheckType.cpp | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index b6fc8f8f31b7e..d400a25b53502 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -551,12 +551,21 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { }; if (!isConfused) { - if (Name.getBaseName().userFacingName() == "Self") { - DeclName selfName(Context.getIdentifier("self")); - auto selfInstance = lookupUnqualified(DC, selfName, Loc, lookupOptions); - if (!selfInstance.empty()) { - ValueDecl *D = selfInstance.front().getValueDecl(); + if (Name == Context.Id_Self) { +// return new (Context) TypeExpr(TypeLoc::withoutLoc( +// DynamicSelfType::get( +// DC->getInnermostTypeContext() +// ->getSelfTypeInContext() +// //->getDeclaredInterfaceType() +// , Context))); + auto selfs = lookupUnqualified(DC, Context.Id_self, Loc, lookupOptions); + if (!selfs.empty()) { + ValueDecl *D = selfs.front().getValueDecl(); Expr *E = new (Context) DeclRefExpr(D, nameLoc, /*Implicit=*/false); + if (auto func = dyn_cast( + DC->getInnermostMethodContext())) + if (func->isStatic()) + return E; return new (Context) DynamicTypeExpr(Loc, Loc, E, Loc, Type()); } } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index a61611f8d96a7..5d84c30d08608 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1061,6 +1061,8 @@ static Type diagnoseUnknownType(TypeResolution resolution, // type. Fix this by replacing 'Self' with the nominal type name. assert(!isa(nominal) && "Cannot be a protocol"); + return nominal->getDeclaredInterfaceType(); + // 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) From 598dcffd2092ea9ca7b08e1295b9cb43654f43f1 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 27 Feb 2019 21:29:38 +0000 Subject: [PATCH 03/18] Further experiments with TypeExpr --- lib/Sema/TypeCheckConstraints.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index d400a25b53502..e739c0bbb9aee 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -558,6 +558,17 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { // ->getSelfTypeInContext() // //->getDeclaredInterfaceType() // , Context))); +// return new (Context) TypeExpr(TypeLoc::withoutLoc( +// DC->getInnermostTypeContext() +// ->getSelfTypeInContext())); + +// Type SelfType = DC->getInnermostTypeContext()->getSelfInterfaceType(); +// if (ClassType::classof(SelfType.getPointer())) +// SelfType = DynamicSelfType::get(SelfType, Context); +// return new (Context) TypeExpr(TypeLoc(new (Context) +// FixedTypeRepr(DC//->getInnermostTypeContext() +// ->mapTypeIntoContext(SelfType), Loc))); + auto selfs = lookupUnqualified(DC, Context.Id_self, Loc, lookupOptions); if (!selfs.empty()) { ValueDecl *D = selfs.front().getValueDecl(); From 0de016ccf49538af0218796b1070b0cf0df9bf91 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 27 Feb 2019 22:59:04 +0000 Subject: [PATCH 04/18] Move Self processing off diagnostic path --- lib/Sema/TypeCheckType.cpp | 87 +++++++++----------------------------- 1 file changed, 20 insertions(+), 67 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 5d84c30d08608..f5b6b9f8051a8 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1002,36 +1002,6 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, return type; } -static std::string getDeclNameFromContext(DeclContext *dc, - NominalTypeDecl *nominal) { - // We don't allow an unqualified reference to a type inside an - // extension if the type is itself nested inside another type, - // eg: - // - // extension A.B { ... B ... } - // - // Instead, you must write 'A.B'. Calculate the right name to use - // for fixits. - if (!isa(dc)) { - SmallVector idents; - auto *parentNominal = nominal; - while (parentNominal != nullptr) { - idents.push_back(parentNominal->getName()); - parentNominal = parentNominal->getDeclContext()->getSelfNominalTypeDecl(); - } - std::reverse(idents.begin(), idents.end()); - std::string result; - for (auto ident : idents) { - if (!result.empty()) - result += "."; - result += ident.str(); - } - return result; - } else { - return nominal->getName().str(); - } -} - /// Diagnose a reference to an unknown type. /// /// This routine diagnoses a reference to an unknown type, and @@ -1051,43 +1021,6 @@ static Type diagnoseUnknownType(TypeResolution resolution, // Unqualified lookup case. if (parentType.isNull()) { - if (comp->getIdentifier() == ctx.Id_Self && - !isa(comp)) { - DeclContext *nominalDC = nullptr; - 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"); - - return nominal->getDeclaredInterfaceType(); - - // 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) - .fixItReplace(comp->getIdLoc(), name); - - // If this is a requirement, replacing 'Self' with a valid type will - // result in additional unnecessary diagnostics (does not refer to a - // generic parameter or associated type). Simply return an error type. - if (options.is(TypeResolverContext::GenericRequirement)) - return ErrorType::get(ctx); - - auto type = resolution.mapTypeIntoContext( - dc->getInnermostTypeContext()->getSelfInterfaceType()); - - comp->overwriteIdentifier(nominal->getName()); - comp->setValue(nominal, nominalDC->getParent()); - return type; - } - // Attempt to refer to 'Self' from a free function. - diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, - dc->getParent()->isLocalContext()); - - return ErrorType::get(ctx); - } - // Try ignoring access control. DeclContext *lookupDC = dc; NameLookupOptions relookupOptions = lookupOptions; @@ -1320,6 +1253,26 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, return ErrorType::get(ctx); } + if (comp->getIdentifier() == ctx.Id_Self && + !isa(comp)) { + DeclContext *nominalDC = nullptr; + NominalTypeDecl *nominal = nullptr; + auto dc = resolution.getDeclContext(); + 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"); + + return nominal->getDeclaredInterfaceType(); + } + // Attempt to refer to 'Self' from a free function. + diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, + dc->getParent()->isLocalContext()); + + return ErrorType::get(ctx); + } + // If we found nothing, complain and give ourselves a chance to recover. if (current.isNull()) { // If we're not allowed to complain or we couldn't fix the From 87880650b4f1e84010b1ad5c188e5248bf7ebf93 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 27 Feb 2019 22:59:31 +0000 Subject: [PATCH 05/18] diagnostic instead of assertion fail --- include/swift/AST/DiagnosticsSema.def | 3 +++ lib/Sema/ConstraintSystem.cpp | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 6715b5295147e..c088afcff746a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -162,6 +162,9 @@ ERROR(cannot_pass_rvalue_mutating_getter,none, "cannot use mutating getter on immutable value of type %0", (Type)) +ERROR(invalid_generic_context,none, + "generic type can not be used in this context", ()) + ERROR(expression_too_complex,none, "the compiler is unable to type-check this expression in reasonable time; " "try breaking up the expression into distinct sub-expressions", ()) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 2412542f2c583..623e425478121 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -535,7 +535,10 @@ static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type, Type ConstraintSystem::openUnboundGenericType( Type type, ConstraintLocatorBuilder locator) { - assert(!type->hasTypeParameter()); + if (type->hasTypeParameter()) { + TC.diagnose(locator.getAnchor()->getLoc(), diag::invalid_generic_context); + return ErrorType::get(getASTContext()); + } checkNestedTypeConstraints(*this, type, locator); From c703a22cb9487c7318dc4c55e4559331ab6bcd04 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Fri, 1 Mar 2019 17:11:12 +0000 Subject: [PATCH 06/18] TypeExpr of DynamicSelfType now working. --- include/swift/AST/DiagnosticsSema.def | 2 +- lib/Sema/TypeCheckConstraints.cpp | 22 ++++----------- lib/Sema/TypeCheckType.cpp | 40 +++++++++++++-------------- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index c088afcff746a..1e09ee1c34d58 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -163,7 +163,7 @@ ERROR(cannot_pass_rvalue_mutating_getter,none, (Type)) ERROR(invalid_generic_context,none, - "generic type can not be used in this context", ()) + "generic type cannot be used in this context", ()) ERROR(expression_too_complex,none, "the compiler is unable to type-check this expression in reasonable time; " diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index e739c0bbb9aee..fa1b49b71959c 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -552,22 +552,12 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { if (!isConfused) { if (Name == Context.Id_Self) { -// return new (Context) TypeExpr(TypeLoc::withoutLoc( -// DynamicSelfType::get( -// DC->getInnermostTypeContext() -// ->getSelfTypeInContext() -// //->getDeclaredInterfaceType() -// , Context))); -// return new (Context) TypeExpr(TypeLoc::withoutLoc( -// DC->getInnermostTypeContext() -// ->getSelfTypeInContext())); - -// Type SelfType = DC->getInnermostTypeContext()->getSelfInterfaceType(); -// if (ClassType::classof(SelfType.getPointer())) -// SelfType = DynamicSelfType::get(SelfType, Context); -// return new (Context) TypeExpr(TypeLoc(new (Context) -// FixedTypeRepr(DC//->getInnermostTypeContext() -// ->mapTypeIntoContext(SelfType), Loc))); + Type SelfType = DC->getInnermostTypeContext()->getSelfInterfaceType(); + if (SelfType->is() || SelfType->is()) + SelfType = DynamicSelfType::get(SelfType, Context); + SelfType = DC->mapTypeIntoContext(SelfType); + return new (Context) TypeExpr(TypeLoc(new (Context) + FixedTypeRepr(SelfType, Loc), SelfType)); auto selfs = lookupUnqualified(DC, Context.Id_self, Loc, lookupOptions); if (!selfs.empty()) { diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index f5b6b9f8051a8..ad3a4954684c6 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1253,28 +1253,28 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, return ErrorType::get(ctx); } - if (comp->getIdentifier() == ctx.Id_Self && - !isa(comp)) { - DeclContext *nominalDC = nullptr; - NominalTypeDecl *nominal = nullptr; - auto dc = resolution.getDeclContext(); - 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"); - - return nominal->getDeclaredInterfaceType(); - } - // Attempt to refer to 'Self' from a free function. - diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, - dc->getParent()->isLocalContext()); - - return ErrorType::get(ctx); - } - // If we found nothing, complain and give ourselves a chance to recover. if (current.isNull()) { + if (comp->getIdentifier() == ctx.Id_Self && + !isa(comp)) { + DeclContext *nominalDC = nullptr; + NominalTypeDecl *nominal = nullptr; + auto dc = resolution.getDeclContext(); + 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"); + + return nominal->getDeclaredInterfaceType(); + } + // Attempt to refer to 'Self' from a free function. + diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, + dc->getParent()->isLocalContext()); + + return ErrorType::get(ctx); + } + // If we're not allowed to complain or we couldn't fix the // source, bail out. if (options.contains(TypeResolutionFlags::SilenceErrors)) From 49548917b61d9b5f0ac1993802290be706a1d369 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Fri, 1 Mar 2019 19:00:11 +0000 Subject: [PATCH 07/18] Update tests for availability of Self --- lib/Sema/ConstraintSystem.cpp | 4 +- lib/Sema/TypeCheckConstraints.cpp | 24 ++++------ lib/Sema/TypeCheckType.cpp | 10 ++-- test/decl/ext/generic.swift | 2 +- test/decl/func/dynamic_self.swift | 74 ++++++++++++++++++++++------- test/decl/nested/type_in_type.swift | 1 - test/type/self.swift | 8 ++-- 7 files changed, 79 insertions(+), 44 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 623e425478121..bb2d928ac6702 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -536,7 +536,9 @@ static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type, Type ConstraintSystem::openUnboundGenericType( Type type, ConstraintLocatorBuilder locator) { if (type->hasTypeParameter()) { - TC.diagnose(locator.getAnchor()->getLoc(), diag::invalid_generic_context); + auto castExpr = dyn_cast(locator.getAnchor()); + TC.diagnose(castExpr ? castExpr->getCastTypeLoc().getLoc() : + locator.getAnchor()->getLoc(), diag::invalid_generic_context); return ErrorType::get(getASTContext()); } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index fa1b49b71959c..eac1970b15549 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -552,22 +552,14 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { if (!isConfused) { if (Name == Context.Id_Self) { - Type SelfType = DC->getInnermostTypeContext()->getSelfInterfaceType(); - if (SelfType->is() || SelfType->is()) - SelfType = DynamicSelfType::get(SelfType, Context); - SelfType = DC->mapTypeIntoContext(SelfType); - return new (Context) TypeExpr(TypeLoc(new (Context) - FixedTypeRepr(SelfType, Loc), SelfType)); - - auto selfs = lookupUnqualified(DC, Context.Id_self, Loc, lookupOptions); - if (!selfs.empty()) { - ValueDecl *D = selfs.front().getValueDecl(); - Expr *E = new (Context) DeclRefExpr(D, nameLoc, /*Implicit=*/false); - if (auto func = dyn_cast( - DC->getInnermostMethodContext())) - if (func->isStatic()) - return E; - return new (Context) DynamicTypeExpr(Loc, Loc, E, Loc, Type()); + 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))); } } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index ad3a4954684c6..4f8de787473d9 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1255,6 +1255,11 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, // If we found nothing, complain and give ourselves a chance to recover. if (current.isNull()) { + // If we're not allowed to complain or we couldn't fix the + // source, bail out. + if (options.contains(TypeResolutionFlags::SilenceErrors)) + return ErrorType::get(ctx); + if (comp->getIdentifier() == ctx.Id_Self && !isa(comp)) { DeclContext *nominalDC = nullptr; @@ -1275,11 +1280,6 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, return ErrorType::get(ctx); } - // If we're not allowed to complain or we couldn't fix the - // source, bail out. - if (options.contains(TypeResolutionFlags::SilenceErrors)) - return ErrorType::get(ctx); - return diagnoseUnknownType(resolution, nullptr, SourceRange(), comp, options, lookupOptions); } diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift index 66327d330c270..8a539153c3bd1 100644 --- a/test/decl/ext/generic.swift +++ b/test/decl/ext/generic.swift @@ -149,7 +149,7 @@ extension Array where Element == String { } extension GenericClass : P3 where T : P3 { } extension GenericClass where Self : P3 { } -// expected-error@-1{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'GenericClass'?}} {{30-34=GenericClass}} +// expected-error@-1{{type 'GenericClass' in conformance requirement does not refer to a generic parameter or associated type}} protocol P4 { associatedtype T diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index be2aaa4d477d7..b04b941e1b6fc 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -10,23 +10,23 @@ 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 { func f() -> Self { } // okay - 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 'C0'?}}{{16-20=C0}} + func g(_ ds: Self) { } - func h(_ ds: Self) -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C0'?}}{{16-20=C0}} + func h(_ ds: Self) -> Self { } } protocol P0 { @@ -73,7 +73,7 @@ class C1 { if !b { return type(of: self).init(int: 5) } // Can't utter Self within the body of a method. - var _: Self = self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{12-16=C1}} + var _: Self = self // Okay to return 'self', because it has the appropriate type. return self // okay @@ -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 if b { return self.init(int: 5) } - return Self() // expected-error{{non-nominal type 'Self.Type' does not support explicit initialization}} + return Self() // expected-error{{non-nominal type 'Self' does not support explicit initialization}} } // This used to crash because metatype construction went down a @@ -419,27 +419,29 @@ func useSelfOperator() { class A { let b: Int required init(a: Int) { - print("\(Self).\(#function)") + print("\(Self.self).\(#function)") + Self.y() b = a } static func z() { print("\(Self.self).\(#function)") } class func y() { - print("\(Self).\(#function)") + print("\(Self.self).\(#function)") + Self.z() } - func x() { + func x() -> A? { print("\(Self.self).\(#function)") Self.y() Self.z() - _ = Self.init(a: 77) + return Self.init(a: 77) } } class B: A { let a: Int required convenience init(a: Int) { - print("\(Self).\(#function)") + print("\(Self.self).\(#function)") self.init() } init() { @@ -450,8 +452,48 @@ class B: A { super.init(a: 88) } override class func y() { - print("\(Self).\(#function)") + print("override \(Self.self).\(#function)") + } +} + +struct S2 { + let x = 99 + static func x() { + Self.y() + } + static func y() { + print("y()") + } + func foo(a: [Self]) -> Self? { + Self.x() + return Self.init() as Self + } +} + +struct S3 { + let x = 99 + static func x() { + Self.y() + } + static func y() { + print("y()") + } + func foo(a: [Self]) -> Self? { + Self.x() + return Self.init() as? Self + // expected-error@-1 {{cannot convert return expression of type 'S3?' to return type 'S3?'}} + // expected-error@-2 {{generic type cannot be used in this context}} + // expected-error@-3 {{generic type cannot be used in this context}} } } -B().x() +enum E { + static func f() { + print("f()") + } + case e + func h(h: Self) -> Self { + Self.f() + return .e + } +} 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..9108f563894a8 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -1,15 +1,15 @@ // 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 { - 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 'C0'?}}{{21-25=C0}} + func foo(_ other: Self) { } } 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 From 588b6509e5585dc8fa70bb448bc3b8dafbb061cb Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 6 Mar 2019 12:40:46 +0000 Subject: [PATCH 08/18] Cast to Self fixed! --- include/swift/AST/DiagnosticsSema.def | 3 - lib/Sema/ConstraintSystem.cpp | 7 +- lib/Sema/TypeCheckType.cpp | 11 ++- test/decl/func/dynamic_self.swift | 86 +----------------------- test/type/self.swift | 96 +++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 97 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1e09ee1c34d58..6715b5295147e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -162,9 +162,6 @@ ERROR(cannot_pass_rvalue_mutating_getter,none, "cannot use mutating getter on immutable value of type %0", (Type)) -ERROR(invalid_generic_context,none, - "generic type cannot be used in this context", ()) - ERROR(expression_too_complex,none, "the compiler is unable to type-check this expression in reasonable time; " "try breaking up the expression into distinct sub-expressions", ()) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index bb2d928ac6702..2412542f2c583 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -535,12 +535,7 @@ static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type, Type ConstraintSystem::openUnboundGenericType( Type type, ConstraintLocatorBuilder locator) { - if (type->hasTypeParameter()) { - auto castExpr = dyn_cast(locator.getAnchor()); - TC.diagnose(castExpr ? castExpr->getCastTypeLoc().getLoc() : - locator.getAnchor()->getLoc(), diag::invalid_generic_context); - return ErrorType::get(getASTContext()); - } + assert(!type->hasTypeParameter()); checkNestedTypeConstraints(*this, type, locator); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 4f8de787473d9..2a297ae656110 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1267,11 +1267,16 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, auto dc = resolution.getDeclContext(); 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"); - return nominal->getDeclaredInterfaceType(); + Type SelfType = nominal->getDeclaredInterfaceType(); + +// Causes assertion failure: +// Assertion failed: (hasSelfMetadataParam() && "This method can only be called if the " "SILFunction has a self-metadata parameter"), function getSelfMetadataArgument, file /Volumes/Elements/swift-self/swift/include/swift/SIL/SILFunction.h, line 935. +// if (nominalDC->getSelfClassDecl()) +// SelfType = DynamicSelfType::get(SelfType, ctx); + + return resolution.mapTypeIntoContext(SelfType); } // Attempt to refer to 'Self' from a free function. diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index b04b941e1b6fc..26a44c01e84f4 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -412,88 +412,4 @@ class SelfOperator { func useSelfOperator() { let s = SelfOperator() _ = s + s -} - -// These references to Self are now possible - -class A { - let b: Int - required init(a: Int) { - print("\(Self.self).\(#function)") - Self.y() - b = a - } - static func z() { - print("\(Self.self).\(#function)") - } - class func y() { - print("\(Self.self).\(#function)") - Self.z() - } - func x() -> A? { - print("\(Self.self).\(#function)") - Self.y() - Self.z() - return Self.init(a: 77) - } -} - -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)") - } -} - -struct S2 { - let x = 99 - static func x() { - Self.y() - } - static func y() { - print("y()") - } - func foo(a: [Self]) -> Self? { - Self.x() - return Self.init() as Self - } -} - -struct S3 { - let x = 99 - static func x() { - Self.y() - } - static func y() { - print("y()") - } - func foo(a: [Self]) -> Self? { - Self.x() - return Self.init() as? Self - // expected-error@-1 {{cannot convert return expression of type 'S3?' to return type 'S3?'}} - // expected-error@-2 {{generic type cannot be used in this context}} - // expected-error@-3 {{generic type cannot be used in this context}} - } -} - -enum E { - static func f() { - print("f()") - } - case e - func h(h: Self) -> Self { - Self.f() - return .e - } -} +} \ No newline at end of file diff --git a/test/type/self.swift b/test/type/self.swift index 9108f563894a8..0858bfeb71c34 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -43,3 +43,99 @@ 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) { + 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) + return Self.init(a: 77) as? Self as? A + // expected-warning@-1 {{conditional cast from 'Self' to 'A' always succeeds}} + // expected-warning@-2 {{conditional downcast from 'A?' to 'A' does nothing}} + } +} + +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 g() { + _ = Self.init() as? Self + // expected-warning@-1 {{conditional cast from 'Self' to 'C' always succeeds}} + } +} + +struct S2 { + let x = 99 + struct S3 { + let x = 99 + static func x() { + Self.y() + } + 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 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() { + print("f()") + } + case e + func h(h: Self) -> Self { + Self.f() + return .e + } +} From 42220dc197ddf81152012275ef1e4c88ad68cf20 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Thu, 7 Mar 2019 14:08:53 +0000 Subject: [PATCH 09/18] Self not available as type in classes except for return type --- lib/Sema/TypeCheckType.cpp | 94 +++++++++++++++++++++++-------- test/decl/ext/generic.swift | 2 +- test/decl/func/dynamic_self.swift | 10 ++-- test/type/self.swift | 12 ++-- 4 files changed, 83 insertions(+), 35 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 2a297ae656110..185704f2aa2f5 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1002,6 +1002,36 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, return type; } +static std::string getDeclNameFromContext(DeclContext *dc, + NominalTypeDecl *nominal) { + // We don't allow an unqualified reference to a type inside an + // extension if the type is itself nested inside another type, + // eg: + // + // extension A.B { ... B ... } + // + // Instead, you must write 'A.B'. Calculate the right name to use + // for fixits. + if (!isa(dc)) { + SmallVector idents; + auto *parentNominal = nominal; + while (parentNominal != nullptr) { + idents.push_back(parentNominal->getName()); + parentNominal = parentNominal->getDeclContext()->getSelfNominalTypeDecl(); + } + std::reverse(idents.begin(), idents.end()); + std::string result; + for (auto ident : idents) { + if (!result.empty()) + result += "."; + result += ident.str(); + } + return result; + } else { + return nominal->getName().str(); + } +} + /// Diagnose a reference to an unknown type. /// /// This routine diagnoses a reference to an unknown type, and @@ -1021,6 +1051,45 @@ static Type diagnoseUnknownType(TypeResolution resolution, // Unqualified lookup case. if (parentType.isNull()) { + if (comp->getIdentifier() == ctx.Id_Self && + !isa(comp)) { + DeclContext *nominalDC = nullptr; + 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"); + + if (!nominalDC->getSelfClassDecl()) + return resolution.mapTypeIntoContext(nominal + ->getDeclaredInterfaceType()); + + // 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) + .fixItReplace(comp->getIdLoc(), name); + + // If this is a requirement, replacing 'Self' with a valid type will + // result in additional unnecessary diagnostics (does not refer to a + // generic parameter or associated type). Simply return an error type. + if (options.is(TypeResolverContext::GenericRequirement)) + return ErrorType::get(ctx); + + auto type = resolution.mapTypeIntoContext( + dc->getInnermostTypeContext()->getSelfInterfaceType()); + + comp->overwriteIdentifier(nominal->getName()); + comp->setValue(nominal, nominalDC->getParent()); + return type; + } + // Attempt to refer to 'Self' from a free function. + diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, + dc->getParent()->isLocalContext()); + + return ErrorType::get(ctx); + } + // Try ignoring access control. DeclContext *lookupDC = dc; NameLookupOptions relookupOptions = lookupOptions; @@ -1260,31 +1329,6 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, if (options.contains(TypeResolutionFlags::SilenceErrors)) return ErrorType::get(ctx); - if (comp->getIdentifier() == ctx.Id_Self && - !isa(comp)) { - DeclContext *nominalDC = nullptr; - NominalTypeDecl *nominal = nullptr; - auto dc = resolution.getDeclContext(); - if ((nominalDC = dc->getInnermostTypeContext()) && - (nominal = nominalDC->getSelfNominalTypeDecl())) { - assert(!isa(nominal) && "Cannot be a protocol"); - - Type SelfType = nominal->getDeclaredInterfaceType(); - -// Causes assertion failure: -// Assertion failed: (hasSelfMetadataParam() && "This method can only be called if the " "SILFunction has a self-metadata parameter"), function getSelfMetadataArgument, file /Volumes/Elements/swift-self/swift/include/swift/SIL/SILFunction.h, line 935. -// if (nominalDC->getSelfClassDecl()) -// SelfType = DynamicSelfType::get(SelfType, ctx); - - return resolution.mapTypeIntoContext(SelfType); - } - // Attempt to refer to 'Self' from a free function. - diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, - dc->getParent()->isLocalContext()); - - return ErrorType::get(ctx); - } - return diagnoseUnknownType(resolution, nullptr, SourceRange(), comp, options, lookupOptions); } diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift index 8a539153c3bd1..66327d330c270 100644 --- a/test/decl/ext/generic.swift +++ b/test/decl/ext/generic.swift @@ -149,7 +149,7 @@ extension Array where Element == String { } extension GenericClass : P3 where T : P3 { } extension GenericClass where Self : P3 { } -// expected-error@-1{{type 'GenericClass' in conformance requirement does not refer to a generic parameter or associated type}} +// expected-error@-1{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'GenericClass'?}} {{30-34=GenericClass}} protocol P4 { associatedtype T diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index 26a44c01e84f4..944654a7d083c 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -24,9 +24,9 @@ enum E0 { class C0 { func f() -> Self { } // okay - func g(_ ds: 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 'C0'?}}{{16-20=C0}} - func h(_ ds: Self) -> Self { } + func h(_ ds: Self) -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C0'?}}{{16-20=C0}} } protocol P0 { @@ -73,7 +73,7 @@ class C1 { if !b { return type(of: self).init(int: 5) } // Can't utter Self within the body of a method. - var _: Self = self + var _: Self = self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{12-16=C1}} // Okay to return 'self', because it has the appropriate type. return self // okay @@ -85,7 +85,7 @@ 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 + 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}} if b { return self.init(int: 5) } @@ -412,4 +412,4 @@ class SelfOperator { func useSelfOperator() { let s = SelfOperator() _ = s + s -} \ No newline at end of file +} diff --git a/test/type/self.swift b/test/type/self.swift index 0858bfeb71c34..11d27a4a7fe47 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -5,7 +5,7 @@ struct S0 { } class C0 { - func foo(_ other: Self) { } + 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 'C0'?}} } enum E0 { @@ -53,6 +53,7 @@ class A { 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() { @@ -64,9 +65,11 @@ class A { 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 'A' always succeeds}} - // expected-warning@-2 {{conditional downcast from 'A?' to 'A' does nothing}} + // expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'A'?}} + // expected-warning@-2 {{conditional cast from 'Self' to 'A' always succeeds}} + // expected-warning@-3 {{conditional downcast from 'A?' to 'A' does nothing}} } } @@ -93,7 +96,8 @@ class C { } func g() { _ = Self.init() as? Self - // expected-warning@-1 {{conditional cast from 'Self' to 'C' always succeeds}} + // expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C'?}} + // expected-warning@-2 {{conditional cast from 'Self' to 'C' always succeeds}} } } From 619eac4d05f84bd7e524927c6376ce2a5b9aa8a0 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Fri, 8 Mar 2019 09:24:20 +0000 Subject: [PATCH 10/18] Could it be this simple? --- lib/Sema/TypeCheckType.cpp | 10 +++++++--- test/decl/func/dynamic_self.swift | 4 ++-- test/type/self.swift | 11 ++++------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 185704f2aa2f5..8caeb4055a2f4 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1061,9 +1061,13 @@ static Type diagnoseUnknownType(TypeResolution resolution, // type. Fix this by replacing 'Self' with the nominal type name. assert(!isa(nominal) && "Cannot be a protocol"); - if (!nominalDC->getSelfClassDecl()) - return resolution.mapTypeIntoContext(nominal - ->getDeclaredInterfaceType()); + bool insideClass = nominalDC->getSelfClassDecl() != nullptr; + if (!insideClass || options.isAnyExpr()) { + Type SelfType = nominal->getSelfInterfaceType(); + if (insideClass) + SelfType = DynamicSelfType::get(SelfType, ctx); + return resolution.mapTypeIntoContext(SelfType); + } // Produce a Fix-It replacing 'Self' with the nominal type name. auto name = getDeclNameFromContext(dc, nominal); diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index 944654a7d083c..e399a6b831b0a 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -73,7 +73,7 @@ class C1 { if !b { return type(of: self).init(int: 5) } // Can't utter Self within the body of a method. - var _: Self = self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{12-16=C1}} + var _: Self = self // Okay to return 'self', because it has the appropriate type. return self // okay @@ -85,7 +85,7 @@ 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) } diff --git a/test/type/self.swift b/test/type/self.swift index 11d27a4a7fe47..569998d410775 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -5,7 +5,7 @@ struct S0 { } class C0 { - 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 'C0'?}} + 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 'C0'?}}{{21-25=C0}} } enum E0 { @@ -65,11 +65,9 @@ class A { 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-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'A'?}} - // expected-warning@-2 {{conditional cast from 'Self' to 'A' always succeeds}} - // expected-warning@-3 {{conditional downcast from 'A?' to 'A' does nothing}} + // 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'}} } } @@ -96,8 +94,7 @@ class C { } func g() { _ = Self.init() as? Self - // expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C'?}} - // expected-warning@-2 {{conditional cast from 'Self' to 'C' always succeeds}} + // expected-warning@-1 {{conditional cast from 'Self' to 'Self' always succeeds}} } } From 1eb98989f2f4beaf71f74efb378a399eae05a17a Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 13 Mar 2019 12:56:23 +0000 Subject: [PATCH 11/18] Nearly there --- lib/Sema/TypeCheckType.cpp | 2 +- test/type/self.swift | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8caeb4055a2f4..b6022e08b215b 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1062,7 +1062,7 @@ static Type diagnoseUnknownType(TypeResolution resolution, assert(!isa(nominal) && "Cannot be a protocol"); bool insideClass = nominalDC->getSelfClassDecl() != nullptr; - if (!insideClass || options.isAnyExpr()) { + if (!insideClass || dc->isLocalContext() || options.isAnyExpr()) { Type SelfType = nominal->getSelfInterfaceType(); if (insideClass) SelfType = DynamicSelfType::get(SelfType, ctx); diff --git a/test/type/self.swift b/test/type/self.swift index 569998d410775..3131004336126 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -92,6 +92,9 @@ class B: A { 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}} From e9354261e5fac36d6596192f34f9d23e92c4bb76 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 13 Mar 2019 17:54:44 +0000 Subject: [PATCH 12/18] Fix function decls using Self inside methods. --- lib/AST/DeclContext.cpp | 5 ++--- lib/Sema/TypeCheckType.cpp | 10 +++++++--- test/decl/ext/generic.swift | 2 +- test/decl/func/dynamic_self.swift | 2 +- test/type/self.swift | 8 ++++++++ 5 files changed, 19 insertions(+), 8 deletions(-) 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/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index b6022e08b215b..b56f6d387d27c 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1057,18 +1057,22 @@ 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; - if (!insideClass || dc->isLocalContext() || options.isAnyExpr()) { + AbstractFunctionDecl *methodDecl = dc->getInnermostMethodContext(); + bool declaringMethod = methodDecl && + methodDecl->getDeclContext() == dc->getParentForLookup(); + + if (!insideClass || !declaringMethod || + options.getBaseContext() == 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/ext/generic.swift b/test/decl/ext/generic.swift index 66327d330c270..95e655797b034 100644 --- a/test/decl/ext/generic.swift +++ b/test/decl/ext/generic.swift @@ -149,7 +149,7 @@ extension Array where Element == String { } extension GenericClass : P3 where T : P3 { } extension GenericClass where Self : P3 { } -// expected-error@-1{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'GenericClass'?}} {{30-34=GenericClass}} +// expected-error@-1{{type 'Self' in conformance requirement does not refer to a generic parameter or associated type}} protocol P4 { associatedtype T diff --git a/test/decl/func/dynamic_self.swift b/test/decl/func/dynamic_self.swift index e399a6b831b0a..c76ef458c62dd 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -73,7 +73,7 @@ class C1 { if !b { return type(of: self).init(int: 5) } // Can't utter Self within the body of a method. - var _: Self = self + var _: Self = self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{12-16=C1}} // Okay to return 'self', because it has the appropriate type. return self // okay diff --git a/test/type/self.swift b/test/type/self.swift index 3131004336126..0a9fea9611bc8 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -65,6 +65,7 @@ class A { 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'}} @@ -108,6 +109,9 @@ struct S2 { static func x() { Self.y() } + func f() { + func g(_: Self) {} + } static func y() { print("HERE") } @@ -126,6 +130,9 @@ extension S2 { static func y() { print("HERE") } + func f() { + func g(_: Self) {} + } func foo(a: [Self]) -> Self? { Self.x() return Self.init() as? Self @@ -135,6 +142,7 @@ extension S2 { enum E { static func f() { + func g(_: Self) {} print("f()") } case e From ec32f041924e40d87edba6f27ba6b465376fa1d6 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 13 Mar 2019 19:50:18 +0000 Subject: [PATCH 13/18] Fix validation-test/compiler_crashers_2_fixed/0164-sr7989.swift --- validation-test/compiler_crashers_2_fixed/0164-sr7989.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift b/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift index a15fd1e09fad5..1afbee83e2eef 100644 --- a/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift +++ b/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift @@ -8,4 +8,4 @@ struct Var {} extension Var : P2 where N : P1 { } protocol P3 {} -extension Var : P3 where Self : P2 {} // expected-error {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'Var'?}} +extension Var : P3 where Self : P2 {} // expected-error {{type 'Var' in conformance requirement does not refer to a generic parameter or associated type}} From 988e565166228952f42b149fc223f21f08c56ca0 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Wed, 13 Mar 2019 20:42:15 +0000 Subject: [PATCH 14/18] Fix of ./validation-test/compiler_crashers_2_fixed/0179-rdar44963974.swift --- lib/Sema/TypeCheckType.cpp | 5 +++-- test/decl/ext/generic.swift | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index b56f6d387d27c..747a68506e087 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1064,8 +1064,9 @@ static Type diagnoseUnknownType(TypeResolution resolution, bool declaringMethod = methodDecl && methodDecl->getDeclContext() == dc->getParentForLookup(); - if (!insideClass || !declaringMethod || - options.getBaseContext() == TypeResolverContext::ExplicitCastExpr) { + if (((!insideClass || !declaringMethod) && + !options.is(TypeResolverContext::GenericRequirement)) || + options.is(TypeResolverContext::ExplicitCastExpr)) { Type SelfType = nominal->getSelfInterfaceType(); if (insideClass) SelfType = DynamicSelfType::get(SelfType, ctx); diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift index 95e655797b034..66327d330c270 100644 --- a/test/decl/ext/generic.swift +++ b/test/decl/ext/generic.swift @@ -149,7 +149,7 @@ extension Array where Element == String { } extension GenericClass : P3 where T : P3 { } extension GenericClass where Self : P3 { } -// expected-error@-1{{type 'Self' in conformance requirement does not refer to a generic parameter or associated type}} +// expected-error@-1{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'GenericClass'?}} {{30-34=GenericClass}} protocol P4 { associatedtype T From f2dff1759e2f875107d02ed2c4ba9726b97c12ec Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Thu, 14 Mar 2019 00:10:38 +0000 Subject: [PATCH 15/18] "Un-fix" validation-test/compiler_crashers_2_fixed/0164-sr7989.swift --- validation-test/compiler_crashers_2_fixed/0164-sr7989.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift b/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift index 1afbee83e2eef..a15fd1e09fad5 100644 --- a/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift +++ b/validation-test/compiler_crashers_2_fixed/0164-sr7989.swift @@ -8,4 +8,4 @@ struct Var {} extension Var : P2 where N : P1 { } protocol P3 {} -extension Var : P3 where Self : P2 {} // expected-error {{type 'Var' in conformance requirement does not refer to a generic parameter or associated type}} +extension Var : P3 where Self : P2 {} // expected-error {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'Var'?}} From 32fd3554fdd734a95fbb434d45a39c22a4fa54a0 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Thu, 14 Mar 2019 21:15:19 +0000 Subject: [PATCH 16/18] CHANGELOG entry --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80380e6f2f780..a9f65e4b91f25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,13 @@ CHANGELOG +Swift 5.1 +--------- + +* [SR-1340](https://bugs.swift.org/browse/SR-1340): + +`Self` can now be used inside member functions and for function arguments of structs and enums to refer to the containing type. + Swift 5.0 --------- From ae4bf3526b7e301830355763e0bb159967ecbadc Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Thu, 14 Mar 2019 22:55:25 +0000 Subject: [PATCH 17/18] Update CHANGELOG.md Co-Authored-By: johnno1962 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bf6d1ecc25e4..a6e816b46bdf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ CHANGELOG Swift 5.1 --------- -* [SR-1340](https://bugs.swift.org/browse/SR-1340): +* [SE-0068][]: `Self` can now be used inside member functions and for function arguments of structs and enums to refer to the containing type. From a9312c6f97b03d96a9e95ddba0a84b5a8066ce37 Mon Sep 17 00:00:00 2001 From: John Holdsworth Date: Thu, 14 Mar 2019 23:13:40 +0000 Subject: [PATCH 18/18] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6e816b46bdf0..2dd294a966f9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ 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. + `Self` can now be used inside member functions and for function arguments of structs and enums to refer to the containing type. * [SR-7799][]: