diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 041d4fe58d050..7a22a73291fd6 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -263,7 +263,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { /// If this DeclContext is a protocol extension, return the extended protocol. ProtocolDecl *getAsProtocolExtensionContext() const; - + + /// Retrieve the nearest enclosing nominal type context. + NominalTypeDecl *getEnclosingNominalContext() const; + /// \brief Retrieve the generic parameter 'Self' from a protocol or /// protocol extension. /// diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1c93436e3b9a7..4e2e1be343468 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1428,7 +1428,7 @@ ERROR(requires_conformance_nonprotocol,none, ERROR(requires_not_suitable_archetype,none, "%select{|first |second }0type %1 in %select{conformance|same-type}2 " "requirement does not refer to a generic parameter or associated type", - (int, TypeLoc, int)) + (int, Type, int)) ERROR(requires_no_same_type_archetype,none, "neither type in same-type refers to a generic parameter or " "associated type", @@ -1713,13 +1713,9 @@ ERROR(broken_equatable_eq_operator,none, ERROR(no_equal_overload_for_int,none, "no overload of '==' for Int", ()) -// Dynamic Self -ERROR(dynamic_self_non_method,none, +// Self +ERROR(self_non_method,none, "%select{global|local}0 function cannot return 'Self'", (bool)) -ERROR(dynamic_self_struct_enum,none, - "%select{struct|enum}0 method cannot return 'Self'; " - "did you mean to use the %select{struct|enum}0 type %1?", - (int, Identifier)) // Duplicate declarations ERROR(duplicate_enum_element,none, @@ -2572,9 +2568,8 @@ ERROR(array_literal_intrinsics_not_found,none, "Array", ()) ERROR(bool_intrinsics_not_found,none, "broken standard library: cannot find intrinsic operations on Bool", ()) -ERROR(self_in_nominal,none, - "'Self' is only available in a protocol or as the result of a " - "method in a class; did you mean %0?", (Identifier)) +ERROR(self_outside_nominal,none, + "'Self' is only available in a type", ()) ERROR(class_super_access,none, "class %select{must be declared " "%select{private|fileprivate|internal|PUBLIC}2" diff --git a/lib/AST/ArchetypeBuilder.cpp b/lib/AST/ArchetypeBuilder.cpp index ddc245bd1b761..d345c4f2f1d60 100644 --- a/lib/AST/ArchetypeBuilder.cpp +++ b/lib/AST/ArchetypeBuilder.cpp @@ -1427,7 +1427,7 @@ bool ArchetypeBuilder::addRequirement(const RequirementRepr &Req) { // FIXME: Poor location information. // FIXME: Delay diagnostic until after type validation? Diags.diagnose(Req.getColonLoc(), diag::requires_not_suitable_archetype, - 0, Req.getSubjectLoc(), 0); + 0, Req.getSubjectLoc().getType(), 0); return true; } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 49bb7e96078ea..a63d2fdf1ceb5 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -105,6 +105,17 @@ ProtocolDecl *DeclContext::getAsProtocolExtensionContext() const { getAsGenericTypeOrGenericTypeExtensionContext()); } +NominalTypeDecl * DeclContext::getEnclosingNominalContext() const { + auto dc = this; + while (dc->isLocalContext()) + dc = dc->getParent(); + + if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext()) + return nominal; + + return nullptr; +} + GenericTypeParamDecl *DeclContext::getProtocolSelf() const { auto *proto = getAsProtocolOrProtocolExtensionContext(); assert(proto && "not a protocol"); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 2c7d59a5e42cf..2bfae96a17ac0 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -431,6 +431,18 @@ resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC) { auto Lookup = lookupUnqualified(DC, Name, Loc, LookupOptions); if (!Lookup) { + // Recover from not finding 'Self' in a nominal type, if we are + // in a type context we can return the TypeExpr + if (Name.getBaseName() == Context.Id_Self) { + if (auto nominal = DC->getEnclosingNominalContext()) + return TypeExpr::createForDecl(Loc, nominal, false); + + // Warn if 'Self' is referenced outside a nominal type context + diagnose(Loc, diag::self_outside_nominal) + .highlight(UDRE->getSourceRange()); + return new (Context) ErrorExpr(UDRE->getSourceRange()); + } + // If we failed lookup of an operator, check to see it to see if it is // because two operators are juxtaposed e.g. (x*-4) that needs whitespace. // If so, emit specific diagnostics for it. diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 96b6e278603d8..eef6000567310 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -4511,7 +4511,7 @@ class DeclChecker : public DeclVisitor { // Dynamic 'Self' is only permitted on methods. if (!dc->isTypeContext()) { - TC.diagnose(simpleRepr->getIdLoc(), diag::dynamic_self_non_method, + TC.diagnose(simpleRepr->getIdLoc(), diag::self_non_method, dc->isLocalContext()); simpleRepr->setInvalid(); return true; @@ -4522,26 +4522,15 @@ class DeclChecker : public DeclVisitor { auto declaredType = dc->getDeclaredTypeOfContext(); if (declaredType->is()) return false; - auto nominal = declaredType->getAnyNominal(); - if (!isa(nominal) && !isa(nominal)) { - int which; - if (isa(nominal)) - which = 0; - else if (isa(nominal)) - which = 1; - else - llvm_unreachable("Unknown nominal type"); - TC.diagnose(simpleRepr->getIdLoc(), diag::dynamic_self_struct_enum, - which, nominal->getName()) - .fixItReplace(simpleRepr->getIdLoc(), nominal->getName().str()); - simpleRepr->setInvalid(); - return true; + + // 'Self' return types in classes or protocols are dynamic 'Self' + if (isa(nominal) || isa(nominal)) { + // Note that the function has a dynamic Self return type and set + // the return type component to the dynamic self type. + func->setDynamicSelf(true); } - // Note that the function has a dynamic Self return type and set - // the return type component to the dynamic self type. - func->setDynamicSelf(true); return false; } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 28965aa0f4ddc..5d2e949d55094 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -698,17 +698,6 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, return type; } -/// Retrieve the nearest enclosing nominal type context. -static NominalTypeDecl *getEnclosingNominalContext(DeclContext *dc) { - while (dc->isLocalContext()) - dc = dc->getParent(); - - if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext()) - return nominal; - - return nullptr; -} - /// Diagnose a reference to an unknown type. /// /// This routine diagnoses a reference to an unknown type, and @@ -728,28 +717,6 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, UnsatisfiedDependency *unsatisfiedDependency) { // Unqualified lookup case. if (parentType.isNull()) { - // Attempt to refer to 'Self' within a non-protocol nominal - // type. Fix this by replacing 'Self' with the nominal type name. - NominalTypeDecl *nominal = nullptr; - if (comp->getIdentifier() == tc.Context.Id_Self && - !isa(comp) && - (nominal = getEnclosingNominalContext(dc))) { - // Retrieve the nominal type and resolve it within this context. - assert(!isa(nominal) && "Cannot be a protocol"); - auto type = resolveTypeDecl(tc, nominal, comp->getIdLoc(), dc, nullptr, - options, resolver, unsatisfiedDependency); - if (type->is()) - return type; - - // Produce a Fix-It replacing 'Self' with the nominal type name. - tc.diagnose(comp->getIdLoc(), diag::self_in_nominal, nominal->getName()) - .fixItReplace(comp->getIdLoc(), nominal->getName().str()); - comp->overwriteIdentifier(nominal->getName()); - comp->setValue(nominal); - return type; - } - - // Fallback. SourceLoc L = comp->getIdLoc(); SourceRange R = SourceRange(comp->getIdLoc()); @@ -826,19 +793,37 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, resolver, unsatisfiedDependency); } + // Identifier is 'Self' + if (comp->getIdentifier() == TC.Context.Id_Self) { + // Dynamic 'Self' in the result type of a function body. + if (options.contains(TR_DynamicSelfResult)) { + auto func = cast(DC); + assert(func->hasDynamicSelf() && "Not marked as having dynamic Self?"); + + return func->getDynamicSelf(); + } + + // Otherwise it is a concrete reference to the enclosing + // nominal type if we are in a type context. + if (auto nominal = DC->getEnclosingNominalContext()) { + // In protocols, 'Self' is always the 'Self' generic param, + // so don't resolve it here. + if (!nominal->getAsProtocolOrProtocolExtensionContext()) + return resolveTypeDecl(TC, nominal, comp->getIdLoc(), DC, nullptr, + options, resolver, unsatisfiedDependency); + } else { + // Warn if 'Self' is referenced outside a nominal type context. + TC.diagnose(comp->getIdLoc(), diag::self_outside_nominal) + .highlight(comp->getSourceRange()); + comp->setInvalid(); + return ErrorType::get(TC.Context); + } + } + // Resolve the first component, which is the only one that requires // unqualified name lookup. DeclContext *lookupDC = DC; - // Dynamic 'Self' in the result type of a function body. - if (options.contains(TR_DynamicSelfResult) && - comp->getIdentifier() == TC.Context.Id_Self) { - auto func = cast(DC); - assert(func->hasDynamicSelf() && "Not marked as having dynamic Self?"); - - return func->getDynamicSelf(); - } - // For lookups within the generic signature, look at the generic // parameters (only), then move up to the enclosing context. if (options.contains(TR_GenericSignature)) { diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift index 6233f7af3db37..a41deac925181 100644 --- a/test/decl/ext/generic.swift +++ b/test/decl/ext/generic.swift @@ -137,9 +137,7 @@ extension Array where Element == String { } // expected-error{{same-type require extension GenericClass : P3 where T : P3 { } // expected-error{{extension of type 'GenericClass' with constraints cannot have an inheritance clause}} -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@-2{{type 'GenericClass' in conformance requirement does not refer to a generic parameter or associated type}} +extension GenericClass where Self : P3 { } // expected-error{{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 ec917b205931d..69dd76bd9fd52 100644 --- a/test/decl/func/dynamic_self.swift +++ b/test/decl/func/dynamic_self.swift @@ -10,23 +10,21 @@ func inFunction() { } struct S0 { - func f() -> Self { } // expected-error{{struct method cannot return 'Self'; did you mean to use the struct type 'S0'?}}{{15-19=S0}} + 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 'S0'?}}{{16-20=S0}} + func g(_ ds: Self) { } // okay } enum E0 { - func f() -> Self { } // expected-error{{enum method cannot return 'Self'; did you mean to use the enum type 'E0'?}}{{15-19=E0}} + 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 'E0'?}}{{16-20=E0}} + func g(_ ds: Self) { } // okay } 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 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 g(_ ds: Self) { } // okay + func h(_ ds: Self) -> Self { } // okay } protocol P0 { @@ -73,7 +71,7 @@ class C1 { if !b { return self.dynamicType.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 @@ -82,14 +80,13 @@ class C1 { // Type methods have a self of type Self.Type. class func factory(_ b: Bool) -> Self { // Check directly. - var x: Int = self // expected-error{{cannot convert value of type 'Self.Type' to specified type 'Int'}} + var _: 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}} + _ = C1(int: 5) as Self if b { return self.init(int: 5) } - return Self() // expected-error{{use of unresolved identifier 'Self'}} expected-note {{did you mean 'self'?}} + return Self() // expected-error{{missing argument for parameter 'int' in call}} } } diff --git a/test/type/self.swift b/test/type/self.swift index db812aa4ff852..c2b1dd2dda0c8 100644 --- a/test/type/self.swift +++ b/test/type/self.swift @@ -1,15 +1,31 @@ // RUN: %target-parse-verify-swift -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}} +struct S0 { + func foo0() -> Self { return self } + func foo1(_ a: 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}} +class C0 { + func foo0() -> Self { return self } + func foo1(_ a: 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}} +enum E0 { + func foo0() -> Self { return self } + func foo1(_ a: Self) { } +} +// Test generics +struct S1 { + func foo0(_ other: Self) { + _ = Self.self // check lookup of 'Self' metatype + } + func foo1() -> Self { return self } +} +class C1 { + func foo0(_ other: Self) { } + func foo1() -> Self { return self } +} +enum E1 { + func foo0(_ other: Self) { } + func foo1() -> Self { return self } } // rdar://problem/21745221 @@ -19,9 +35,44 @@ struct X { extension X { struct Inner { + func foo0() -> Self { return self } } } 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 'Inner'?}}{{21-25=Inner}} + func foo1(_ other: Self) { } +} + +// Test we are still using dynamic, not concrete, 'Self' +// for class and protocol methods which return 'Self' + +class NonFinal { + func reference() -> Self { + return self + } } +final class Final : NonFinal { +} +protocol Proto { + func copy() -> Self +} +struct Conf : Proto { + func copy() -> Self { + return self + } +} + +func testClass() { + let f0 = Final() + let _: Final = f0.reference() +} +func testProto() { + let p0 = Conf() + let _: Conf = p0.copy() +} + +let _: Self = () // expected-error{{'Self' is only available in a type}} +func noParent() -> Self { fatalError() } // expected-error{{global function cannot return 'Self'}} + +_ = Self.self // expected-error {{'Self' is only available in a type}} +